view src/gtk/window.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line source
1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #include "window.h"
21 #include <sys/stat.h>
23 #include <stdio.h>
24 #include <time.h>
26 #include <SDL.h>
28 #include "../gba/GBA.h"
29 #include "../gba/GBAGlobals.h"
30 #include "../gba/GBASound.h"
31 #include "../gb/GB.h"
32 #include "../gb/gbGlobals.h"
33 #include "../gb/gbPrinter.h"
34 #include "../common/Util.h"
36 #include "menuitem.h"
37 #include "tools.h"
38 #include "intl.h"
40 extern int systemRenderedFrames;
41 extern int systemFPS;
42 extern bool debugger;
43 extern int RGB_LOW_BITS_MASK;
44 extern void (*dbgMain)();
45 extern void (*dbgSignal)(int, int);
46 extern void (*dbgOutput)(char *, u32);
47 extern void remoteInit();
48 extern void remoteCleanUp();
49 extern void remoteStubMain();
50 extern void remoteStubSignal(int, int);
51 extern void remoteOutput(char *, u32);
52 extern void remoteSetProtocol(int);
53 extern void remoteSetPort(int);
55 #ifdef MMX
56 extern "C" bool cpu_mmx;
57 #endif // MMX
59 namespace VBA
60 {
62 using Gnome::Glade::Xml;
64 Window * Window::m_poInstance = NULL;
66 Window::Window(GtkWindow * _pstWindow, const Glib::RefPtr<Xml> & _poXml) :
67 Gtk::Window (_pstWindow),
68 m_iGBScreenWidth (160),
69 m_iGBScreenHeight (144),
70 m_iSGBScreenWidth (256),
71 m_iSGBScreenHeight(224),
72 m_iGBAScreenWidth (240),
73 m_iGBAScreenHeight(160),
74 m_iFrameskipMin (0),
75 m_iFrameskipMax (9),
76 m_iThrottleMin (5),
77 m_iThrottleMax (1000),
78 m_iScaleMin (1),
79 m_iScaleMax (6),
80 m_iShowSpeedMin (ShowNone),
81 m_iShowSpeedMax (ShowDetailed),
82 m_iSaveTypeMin (SaveAuto),
83 m_iSaveTypeMax (SaveNone),
84 m_iSoundQualityMin(Sound44K),
85 m_iSoundQualityMax(Sound11K),
86 m_iSoundVolumeMin (Sound100),
87 m_iSoundVolumeMax (Sound50),
88 m_iEmulatorTypeMin(EmulatorAuto),
89 m_iEmulatorTypeMax(EmulatorSGB2),
90 m_iFilter2xMin (FirstFilter),
91 m_iFilter2xMax (LastFilter),
92 m_iFilterIBMin (FirstFilterIB),
93 m_iFilterIBMax (LastFilterIB),
94 m_iJoypadMin (1),
95 m_iJoypadMax (4)
96 {
97 m_poXml = _poXml;
98 m_poFileOpenDialog = NULL;
99 m_iScreenWidth = m_iGBAScreenWidth;
100 m_iScreenHeight = m_iGBAScreenHeight;
101 m_eCartridge = CartridgeNone;
102 m_uiJoypadState = 0;
104 vInitSystem();
105 vInitSDL();
107 Gtk::Container * poC;
108 poC = dynamic_cast<Gtk::Container *>(_poXml->get_widget("ScreenContainer"));
109 m_poScreenArea = Gtk::manage(new ScreenArea(m_iScreenWidth, m_iScreenHeight));
110 poC->add(*m_poScreenArea);
111 vDrawDefaultScreen();
112 m_poScreenArea->show();
114 // Get config
115 //
116 vInitConfig();
118 m_sUserDataDir = Glib::get_home_dir() + "/.gvba";
119 m_sConfigFile = m_sUserDataDir + "/config";
121 if (! Glib::file_test(m_sUserDataDir, Glib::FILE_TEST_EXISTS))
122 {
123 mkdir(m_sUserDataDir.c_str(), 0777);
124 }
125 if (Glib::file_test(m_sConfigFile, Glib::FILE_TEST_EXISTS))
126 {
127 vLoadConfig(m_sConfigFile);
128 vCheckConfig();
129 }
130 else
131 {
132 vSaveConfig(m_sConfigFile);
133 }
135 vCreateFileOpenDialog();
136 vLoadHistoryFromConfig();
137 vLoadJoypadsFromConfig();
139 Gtk::MenuItem * poMI;
140 Gtk::CheckMenuItem * poCMI;
142 // File menu
143 //
144 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("FileOpen"));
145 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnFileOpen));
147 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("FileLoad"));
148 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnFileLoad));
149 m_listSensitiveWhenPlaying.push_back(poMI);
151 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("FileSave"));
152 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnFileSave));
153 m_listSensitiveWhenPlaying.push_back(poMI);
155 for (int i = 0; i < 10; i++)
156 {
157 char csName[20];
158 snprintf(csName, 20, "LoadGameSlot%d", i + 1);
159 m_apoLoadGameItem[i] = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget(csName));
160 snprintf(csName, 20, "SaveGameSlot%d", i + 1);
161 m_apoSaveGameItem[i] = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget(csName));
163 m_apoLoadGameItem[i]->signal_activate().connect(SigC::bind<int>(
164 SigC::slot(*this, &Window::vOnLoadGame),
165 i + 1));
166 m_apoSaveGameItem[i]->signal_activate().connect(SigC::bind<int>(
167 SigC::slot(*this, &Window::vOnSaveGame),
168 i + 1));
169 }
170 vUpdateGameSlots();
172 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("LoadGameMostRecent"));
173 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnLoadGameMostRecent));
174 m_listSensitiveWhenPlaying.push_back(poMI);
176 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("LoadGameAuto"));
177 poCMI->set_active(m_poCoreConfig->oGetKey<bool>("load_game_auto"));
178 vOnLoadGameAutoToggled(poCMI);
179 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
180 SigC::slot(*this, &Window::vOnLoadGameAutoToggled),
181 poCMI));
183 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("SaveGameOldest"));
184 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnSaveGameOldest));
185 m_listSensitiveWhenPlaying.push_back(poMI);
187 m_poFilePauseItem = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("FilePause"));
188 m_poFilePauseItem->set_active(false);
189 vOnFilePauseToggled(m_poFilePauseItem);
190 m_poFilePauseItem->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
191 SigC::slot(*this, &Window::vOnFilePauseToggled),
192 m_poFilePauseItem));
193 m_listSensitiveWhenPlaying.push_back(m_poFilePauseItem);
195 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("FileReset"));
196 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnFileReset));
197 m_listSensitiveWhenPlaying.push_back(poMI);
199 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("FileScreenCapture"));
200 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnFileScreenCapture));
201 m_listSensitiveWhenPlaying.push_back(poMI);
203 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("FileClose"));
204 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnFileClose));
205 m_listSensitiveWhenPlaying.push_back(poMI);
207 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("FileExit"));
208 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnFileExit));
210 // Recent menu
211 //
212 m_poRecentMenu = dynamic_cast<Gtk::Menu *>(_poXml->get_widget("RecentMenu_menu"));
213 vUpdateHistoryMenu();
215 m_poRecentResetItem = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("RecentReset"));
216 m_poRecentResetItem->signal_activate().connect(SigC::slot(*this, &Window::vOnRecentReset));
218 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("RecentFreeze"));
219 poCMI->set_active(m_poHistoryConfig->oGetKey<bool>("freeze"));
220 vOnRecentFreezeToggled(poCMI);
221 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
222 SigC::slot(*this, &Window::vOnRecentFreezeToggled),
223 poCMI));
225 // Import menu
226 //
227 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("ImportBatteryFile"));
228 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnImportBatteryFile));
229 m_listSensitiveWhenPlaying.push_back(poMI);
231 // Export menu
232 //
233 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("ExportBatteryFile"));
234 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnExportBatteryFile));
235 m_listSensitiveWhenPlaying.push_back(poMI);
237 // Frameskip menu
238 //
239 struct
240 {
241 const char * m_csName;
242 const int m_iFrameskip;
243 }
244 astFrameskip[] =
245 {
246 { "FrameskipAutomatic", -1 },
247 { "Frameskip0", 0 },
248 { "Frameskip1", 1 },
249 { "Frameskip2", 2 },
250 { "Frameskip3", 3 },
251 { "Frameskip4", 4 },
252 { "Frameskip5", 5 },
253 { "Frameskip6", 6 },
254 { "Frameskip7", 7 },
255 { "Frameskip8", 8 },
256 { "Frameskip9", 9 }
257 };
258 int iDefaultFrameskip;
259 if (m_poCoreConfig->sGetKey("frameskip") == "auto")
260 {
261 iDefaultFrameskip = -1;
262 }
263 else
264 {
265 iDefaultFrameskip = m_poCoreConfig->oGetKey<int>("frameskip");
266 }
267 for (guint i = 0; i < G_N_ELEMENTS(astFrameskip); i++)
268 {
269 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astFrameskip[i].m_csName));
270 if (astFrameskip[i].m_iFrameskip == iDefaultFrameskip)
271 {
272 poCMI->set_active();
273 vOnFrameskipToggled(poCMI, iDefaultFrameskip);
274 }
275 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
276 SigC::slot(*this, &Window::vOnFrameskipToggled),
277 poCMI, astFrameskip[i].m_iFrameskip));
278 }
280 // Throttle menu
281 //
282 struct
283 {
284 const char * m_csName;
285 const int m_iThrottle;
286 }
287 astThrottle[] =
288 {
289 { "ThrottleNoThrottle", 0 },
290 { "Throttle25", 25 },
291 { "Throttle50", 50 },
292 { "Throttle100", 100 },
293 { "Throttle150", 150 },
294 { "Throttle200", 200 }
295 };
296 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("ThrottleOther"));
297 poCMI->set_active();
298 poCMI->signal_activate().connect(SigC::bind<Gtk::CheckMenuItem *>(
299 SigC::slot(*this, &Window::vOnThrottleOther),
300 poCMI));
302 int iDefaultThrottle = m_poCoreConfig->oGetKey<int>("throttle");
303 for (guint i = 0; i < G_N_ELEMENTS(astThrottle); i++)
304 {
305 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astThrottle[i].m_csName));
306 if (astThrottle[i].m_iThrottle == iDefaultThrottle)
307 {
308 poCMI->set_active();
309 }
310 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
311 SigC::slot(*this, &Window::vOnThrottleToggled),
312 poCMI, astThrottle[i].m_iThrottle));
313 }
314 vSetThrottle(iDefaultThrottle);
316 // Video menu
317 //
318 struct
319 {
320 const char * m_csName;
321 const int m_iScale;
322 }
323 astVideoScale[] =
324 {
325 { "Video1x", 1 },
326 { "Video2x", 2 },
327 { "Video3x", 3 },
328 { "Video4x", 4 },
329 { "Video5x", 5 },
330 { "Video6x", 6 }
331 };
332 int iDefaultScale = m_poDisplayConfig->oGetKey<int>("scale");
333 for (guint i = 0; i < G_N_ELEMENTS(astVideoScale); i++)
334 {
335 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astVideoScale[i].m_csName));
336 if (astVideoScale[i].m_iScale == iDefaultScale)
337 {
338 poCMI->set_active();
339 vOnVideoScaleToggled(poCMI, iDefaultScale);
340 }
341 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
342 SigC::slot(*this, &Window::vOnVideoScaleToggled),
343 poCMI, astVideoScale[i].m_iScale));
344 }
346 // Layers menu
347 //
348 struct
349 {
350 const char * m_csName;
351 const char * m_csKey;
352 const int m_iLayer;
353 }
354 astLayer[] =
355 {
356 { "LayersBg0", "layer_bg0", 0 },
357 { "LayersBg1", "layer_bg1", 1 },
358 { "LayersBg2", "layer_bg2", 2 },
359 { "LayersBg3", "layer_bg3", 3 },
360 { "LayersObj", "layer_obj", 4 },
361 { "LayersWin0", "layer_win0", 5 },
362 { "LayersWin1", "layer_win1", 6 },
363 { "LayersObjWin", "layer_objwin", 7 }
364 };
365 for (guint i = 0; i < G_N_ELEMENTS(astLayer); i++)
366 {
367 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astLayer[i].m_csName));
368 poCMI->set_active(m_poCoreConfig->oGetKey<bool>(astLayer[i].m_csKey));
369 vOnLayerToggled(poCMI, astLayer[i].m_iLayer);
370 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
371 SigC::slot(*this, &Window::vOnLayerToggled),
372 poCMI, astLayer[i].m_iLayer));
373 }
375 // Emulator menu
376 //
377 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("EmulatorDirectories"));
378 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnDirectories));
380 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("EmulatorPauseWhenInactive"));
381 poCMI->set_active(m_poDisplayConfig->oGetKey<bool>("pause_when_inactive"));
382 vOnPauseWhenInactiveToggled(poCMI);
383 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
384 SigC::slot(*this, &Window::vOnPauseWhenInactiveToggled),
385 poCMI));
387 m_poUseBiosItem = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("EmulatorUseBios"));
388 m_poUseBiosItem->set_active(m_poCoreConfig->oGetKey<bool>("use_bios_file"));
389 if (m_poCoreConfig->sGetKey("bios_file") == "")
390 {
391 m_poUseBiosItem->set_sensitive(false);
392 }
393 m_poUseBiosItem->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
394 SigC::slot(*this, &Window::vOnUseBiosToggled),
395 m_poUseBiosItem));
397 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("EmulatorSelectBios"));
398 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnSelectBios));
400 // Show speed menu
401 //
402 struct
403 {
404 const char * m_csName;
405 const EShowSpeed m_eShowSpeed;
406 }
407 astShowSpeed[] =
408 {
409 { "ShowSpeedNone", ShowNone },
410 { "ShowSpeedPercentage", ShowPercentage },
411 { "ShowSpeedDetailed", ShowDetailed }
412 };
413 EShowSpeed eDefaultShowSpeed = (EShowSpeed)m_poDisplayConfig->oGetKey<int>("show_speed");
414 for (guint i = 0; i < G_N_ELEMENTS(astShowSpeed); i++)
415 {
416 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astShowSpeed[i].m_csName));
417 if (astShowSpeed[i].m_eShowSpeed == eDefaultShowSpeed)
418 {
419 poCMI->set_active();
420 vOnShowSpeedToggled(poCMI, eDefaultShowSpeed);
421 }
422 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
423 SigC::slot(*this, &Window::vOnShowSpeedToggled),
424 poCMI, astShowSpeed[i].m_eShowSpeed));
425 }
427 // Save type menu
428 //
429 struct
430 {
431 const char * m_csName;
432 const ESaveType m_eSaveType;
433 }
434 astSaveType[] =
435 {
436 { "SaveTypeAutomatic", SaveAuto },
437 { "SaveTypeEeprom", SaveEEPROM },
438 { "SaveTypeSram", SaveSRAM },
439 { "SaveTypeFlash", SaveFlash },
440 { "SaveTypeEepromSensor", SaveEEPROMSensor },
441 { "SaveTypeNone", SaveNone }
442 };
443 ESaveType eDefaultSaveType = (ESaveType)m_poCoreConfig->oGetKey<int>("save_type");
444 for (guint i = 0; i < G_N_ELEMENTS(astSaveType); i++)
445 {
446 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astSaveType[i].m_csName));
447 if (astSaveType[i].m_eSaveType == eDefaultSaveType)
448 {
449 poCMI->set_active();
450 vOnSaveTypeToggled(poCMI, eDefaultSaveType);
451 }
452 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
453 SigC::slot(*this, &Window::vOnSaveTypeToggled),
454 poCMI, astSaveType[i].m_eSaveType));
455 }
457 // Flash size menu
458 //
459 struct
460 {
461 const char * m_csName;
462 const int m_iFlashSize;
463 }
464 astFlashSize[] =
465 {
466 { "SaveTypeFlash64K", 64 },
467 { "SaveTypeFlash128K", 128 }
468 };
469 int iDefaultFlashSize = m_poCoreConfig->oGetKey<int>("flash_size");
470 for (guint i = 0; i < G_N_ELEMENTS(astFlashSize); i++)
471 {
472 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astFlashSize[i].m_csName));
473 if (astFlashSize[i].m_iFlashSize == iDefaultFlashSize)
474 {
475 poCMI->set_active();
476 vOnFlashSizeToggled(poCMI, iDefaultFlashSize);
477 }
478 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
479 SigC::slot(*this, &Window::vOnFlashSizeToggled),
480 poCMI, astFlashSize[i].m_iFlashSize));
481 }
483 // Screenshot format menu
484 //
485 struct
486 {
487 const char * m_csName;
488 const char * m_csScreenshotFormat;
489 }
490 astScreenshotFormat[] =
491 {
492 { "ScreenshotFormatPNG", "png" },
493 { "ScreenshotFormatBMP", "bmp" }
494 };
495 std::string sDefaultScreenshotFormat = m_poCoreConfig->sGetKey("screenshot_format");
496 for (guint i = 0; i < G_N_ELEMENTS(astScreenshotFormat); i++)
497 {
498 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astScreenshotFormat[i].m_csName));
499 if (astScreenshotFormat[i].m_csScreenshotFormat == sDefaultScreenshotFormat)
500 {
501 poCMI->set_active();
502 vOnScreenshotFormatToggled(poCMI, sDefaultScreenshotFormat);
503 }
504 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, std::string>(
505 SigC::slot(*this, &Window::vOnScreenshotFormatToggled),
506 poCMI, std::string(astScreenshotFormat[i].m_csScreenshotFormat)));
507 }
509 // Sound menu
510 //
511 std::string sDefaultSoundStatus = m_poSoundConfig->sGetKey("status");
513 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("SoundOff"));
514 if (sDefaultSoundStatus == "off")
515 {
516 poCMI->set_active();
517 vOnSoundStatusToggled(poCMI, SoundOff);
518 }
519 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
520 SigC::slot(*this, &Window::vOnSoundStatusToggled),
521 poCMI, SoundOff));
522 m_poSoundOffItem = poCMI;
524 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("SoundMute"));
525 if (sDefaultSoundStatus == "mute")
526 {
527 poCMI->set_active();
528 vOnSoundStatusToggled(poCMI, SoundMute);
529 }
530 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
531 SigC::slot(*this, &Window::vOnSoundStatusToggled),
532 poCMI, SoundMute));
534 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("SoundOn"));
535 if (sDefaultSoundStatus == "on")
536 {
537 poCMI->set_active();
538 vOnSoundStatusToggled(poCMI, SoundOn);
539 }
540 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
541 SigC::slot(*this, &Window::vOnSoundStatusToggled),
542 poCMI, SoundOn));
544 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("SoundEcho"));
545 poCMI->set_active(m_poSoundConfig->oGetKey<bool>("echo"));
546 vOnSoundEchoToggled(poCMI);
547 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
548 SigC::slot(*this, &Window::vOnSoundEchoToggled),
549 poCMI));
551 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("SoundLowPass"));
552 poCMI->set_active(m_poSoundConfig->oGetKey<bool>("low_pass"));
553 vOnSoundLowPassToggled(poCMI);
554 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
555 SigC::slot(*this, &Window::vOnSoundLowPassToggled),
556 poCMI));
558 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("SoundReverseStereo"));
559 poCMI->set_active(m_poSoundConfig->oGetKey<bool>("reverse_stereo"));
560 vOnSoundReverseToggled(poCMI);
561 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
562 SigC::slot(*this, &Window::vOnSoundReverseToggled),
563 poCMI));
565 struct
566 {
567 const char * m_csName;
568 const char * m_csKey;
569 const int m_iSoundChannel;
570 }
571 astSoundChannel[] =
572 {
573 { "SoundChannel1", "channel_1", 0 },
574 { "SoundChannel2", "channel_2", 1 },
575 { "SoundChannel3", "channel_3", 2 },
576 { "SoundChannel4", "channel_4", 3 },
577 { "SoundChannelA", "channel_A", 4 },
578 { "SoundChannelB", "channel_B", 5 }
579 };
580 for (guint i = 0; i < G_N_ELEMENTS(astSoundChannel); i++)
581 {
582 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astSoundChannel[i].m_csName));
583 poCMI->set_active(m_poSoundConfig->oGetKey<bool>(astSoundChannel[i].m_csKey));
584 vOnSoundChannelToggled(poCMI, astSoundChannel[i].m_iSoundChannel);
585 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
586 SigC::slot(*this, &Window::vOnSoundChannelToggled),
587 poCMI, astSoundChannel[i].m_iSoundChannel));
588 }
590 struct
591 {
592 const char * m_csName;
593 const ESoundQuality m_eSoundQuality;
594 }
595 astSoundQuality[] =
596 {
597 { "Sound11Khz", Sound11K },
598 { "Sound22Khz", Sound22K },
599 { "Sound44Khz", Sound44K }
600 };
601 ESoundQuality eDefaultSoundQuality = (ESoundQuality)m_poSoundConfig->oGetKey<int>("quality");
602 for (guint i = 0; i < G_N_ELEMENTS(astSoundQuality); i++)
603 {
604 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astSoundQuality[i].m_csName));
605 if (astSoundQuality[i].m_eSoundQuality == eDefaultSoundQuality)
606 {
607 poCMI->set_active();
608 vOnSoundQualityToggled(poCMI, eDefaultSoundQuality);
609 }
610 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
611 SigC::slot(*this, &Window::vOnSoundQualityToggled),
612 poCMI, astSoundQuality[i].m_eSoundQuality));
613 }
615 // Volume menu
616 //
617 struct
618 {
619 const char * m_csName;
620 const ESoundVolume m_eSoundVolume;
621 }
622 astSoundVolume[] =
623 {
624 { "Volume25", Sound25 },
625 { "Volume50", Sound50 },
626 { "Volume100", Sound100 },
627 { "Volume200", Sound200 },
628 { "Volume300", Sound300 },
629 { "Volume400", Sound400 }
630 };
631 ESoundVolume eDefaultSoundVolume = (ESoundVolume)m_poSoundConfig->oGetKey<int>("volume");
632 for (guint i = 0; i < G_N_ELEMENTS(astSoundVolume); i++)
633 {
634 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astSoundVolume[i].m_csName));
635 if (astSoundVolume[i].m_eSoundVolume == eDefaultSoundVolume)
636 {
637 poCMI->set_active();
638 vOnSoundVolumeToggled(poCMI, eDefaultSoundVolume);
639 }
640 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
641 SigC::slot(*this, &Window::vOnSoundVolumeToggled),
642 poCMI, astSoundVolume[i].m_eSoundVolume));
643 }
645 // Gameboy menu
646 //
647 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("GameboyBorder"));
648 poCMI->set_active(m_poCoreConfig->oGetKey<bool>("gb_border"));
649 vOnGBBorderToggled(poCMI);
650 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
651 SigC::slot(*this, &Window::vOnGBBorderToggled),
652 poCMI));
654 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("GameboyPrinter"));
655 poCMI->set_active(m_poCoreConfig->oGetKey<bool>("gb_printer"));
656 vOnGBPrinterToggled(poCMI);
657 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
658 SigC::slot(*this, &Window::vOnGBPrinterToggled),
659 poCMI));
661 struct
662 {
663 const char * m_csName;
664 const EEmulatorType m_eEmulatorType;
665 }
666 astEmulatorType[] =
667 {
668 { "GameboyAutomatic", EmulatorAuto },
669 { "GameboyGba", EmulatorGBA },
670 { "GameboyCgb", EmulatorCGB },
671 { "GameboySgb", EmulatorSGB },
672 { "GameboySgb2", EmulatorSGB2 },
673 { "GameboyGb", EmulatorGB }
674 };
675 EEmulatorType eDefaultEmulatorType = (EEmulatorType)m_poCoreConfig->oGetKey<int>("emulator_type");
676 for (guint i = 0; i < G_N_ELEMENTS(astEmulatorType); i++)
677 {
678 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astEmulatorType[i].m_csName));
679 if (astEmulatorType[i].m_eEmulatorType == eDefaultEmulatorType)
680 {
681 poCMI->set_active();
682 vOnEmulatorTypeToggled(poCMI, eDefaultEmulatorType);
683 }
684 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
685 SigC::slot(*this, &Window::vOnEmulatorTypeToggled),
686 poCMI, astEmulatorType[i].m_eEmulatorType));
687 }
689 // Filter menu
690 //
691 struct
692 {
693 const char * m_csName;
694 const EFilter2x m_eFilter2x;
695 }
696 astFilter2x[] =
697 {
698 { "FilterNone", FilterNone },
699 { "FilterTVMode", FilterScanlinesTV },
700 { "Filter2xSaI", Filter2xSaI },
701 { "FilterSuper2xSaI", FilterSuper2xSaI },
702 { "FilterSuperEagle", FilterSuperEagle },
703 { "FilterPixelate", FilterPixelate },
704 { "FilterMotionBlur", FilterMotionBlur },
705 { "FilterAdvanceMame2x", FilterAdMame2x },
706 { "FilterSimple2x", FilterSimple2x },
707 { "FilterBilinear", FilterBilinear },
708 { "FilterBilinearPlus", FilterBilinearPlus },
709 { "FilterScanlines", FilterScanlines },
710 { "FilterHq2x", FilterHq2x },
711 { "FilterLq2x", FilterLq2x }
712 };
713 EFilter2x eDefaultFilter2x = (EFilter2x)m_poDisplayConfig->oGetKey<int>("filter2x");
714 for (guint i = 0; i < G_N_ELEMENTS(astFilter2x); i++)
715 {
716 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astFilter2x[i].m_csName));
717 if (astFilter2x[i].m_eFilter2x == eDefaultFilter2x)
718 {
719 poCMI->set_active();
720 vOnFilter2xToggled(poCMI, eDefaultFilter2x);
721 }
722 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
723 SigC::slot(*this, &Window::vOnFilter2xToggled),
724 poCMI, astFilter2x[i].m_eFilter2x));
725 }
727 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget("FilterDisableMmx"));
728 #ifdef MMX
729 poCMI->set_active(m_poDisplayConfig->oGetKey<bool>("filter_disable_mmx"));
730 vOnDisableMMXToggled(poCMI);
731 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *>(
732 SigC::slot(*this, &Window::vOnDisableMMXToggled),
733 poCMI));
734 #else // ! MMX
735 poCMI->set_active();
736 poCMI->set_sensitive(false);
737 #endif // ! MMX
739 // Interframe blending menu
740 //
741 struct
742 {
743 const char * m_csName;
744 const EFilterIB m_eFilterIB;
745 }
746 astFilterIB[] =
747 {
748 { "IFBNone", FilterIBNone },
749 { "IFBSmart", FilterIBSmart },
750 { "IFBMotionBlur", FilterIBMotionBlur }
751 };
752 EFilterIB eDefaultFilterIB = (EFilterIB)m_poDisplayConfig->oGetKey<int>("filterIB");
753 for (guint i = 0; i < G_N_ELEMENTS(astFilterIB); i++)
754 {
755 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astFilterIB[i].m_csName));
756 if (astFilterIB[i].m_eFilterIB == eDefaultFilterIB)
757 {
758 poCMI->set_active();
759 vOnFilterIBToggled(poCMI, eDefaultFilterIB);
760 }
761 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
762 SigC::slot(*this, &Window::vOnFilterIBToggled),
763 poCMI, astFilterIB[i].m_eFilterIB));
764 }
766 // Joypad menu
767 //
768 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("JoypadConfigure1"));
769 poMI->signal_activate().connect(SigC::bind<int>(
770 SigC::slot(*this, &Window::vOnJoypadConfigure), 1));
772 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("JoypadConfigure2"));
773 poMI->signal_activate().connect(SigC::bind<int>(
774 SigC::slot(*this, &Window::vOnJoypadConfigure), 2));
776 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("JoypadConfigure3"));
777 poMI->signal_activate().connect(SigC::bind<int>(
778 SigC::slot(*this, &Window::vOnJoypadConfigure), 3));
780 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("JoypadConfigure4"));
781 poMI->signal_activate().connect(SigC::bind<int>(
782 SigC::slot(*this, &Window::vOnJoypadConfigure), 4));
784 int iDefaultJoypad = m_poInputConfig->oGetKey<int>("active_joypad");
785 for (int i = m_iJoypadMin; i <= m_iJoypadMax; i++)
786 {
787 char csName[20];
788 snprintf(csName, sizeof(csName), "Joypad%d", i);
790 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(csName));
791 if (i == iDefaultJoypad)
792 {
793 poCMI->set_active();
794 vOnJoypadToggled(poCMI, iDefaultJoypad);
795 }
796 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, int>(
797 SigC::slot(*this, &Window::vOnJoypadToggled),
798 poCMI, i));
799 }
801 // Autofire menu
802 //
803 struct
804 {
805 const char * m_csName;
806 const char * m_csKey;
807 const EKeyFlag m_eKeyFlag;
808 }
809 astAutofire[] =
810 {
811 { "AutofireA", "autofire_A", KeyFlagA },
812 { "AutofireB", "autofire_B", KeyFlagB },
813 { "AutofireL", "autofire_L", KeyFlagL },
814 { "AutofireR", "autofire_R", KeyFlagR }
815 };
816 for (guint i = 0; i < G_N_ELEMENTS(astAutofire); i++)
817 {
818 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(_poXml->get_widget(astAutofire[i].m_csName));
819 poCMI->set_active(m_poInputConfig->oGetKey<bool>(astAutofire[i].m_csKey));
820 vOnAutofireToggled(poCMI, astAutofire[i].m_eKeyFlag);
821 poCMI->signal_toggled().connect(SigC::bind<Gtk::CheckMenuItem *, u32>(
822 SigC::slot(*this, &Window::vOnAutofireToggled),
823 poCMI, astAutofire[i].m_eKeyFlag));
824 }
826 // GDB menu
827 //
828 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("GdbWait"));
829 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnGDBWait));
831 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("GdbLoadAndWait"));
832 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnGDBLoadAndWait));
834 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("GdbBreak"));
835 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnGDBBreak));
837 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("GdbDisconnect"));
838 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnGDBDisconnect));
840 // Help menu
841 //
842 poMI = dynamic_cast<Gtk::MenuItem *>(_poXml->get_widget("HelpAbout"));
843 poMI->signal_activate().connect(SigC::slot(*this, &Window::vOnHelpAbout));
845 // Init widgets sensitivity
846 for (std::list<Gtk::Widget *>::iterator it = m_listSensitiveWhenPlaying.begin();
847 it != m_listSensitiveWhenPlaying.end();
848 it++)
849 {
850 (*it)->set_sensitive(false);
851 }
853 if (m_poInstance == NULL)
854 {
855 m_poInstance = this;
856 }
857 else
858 {
859 abort();
860 }
861 }
863 Window::~Window()
864 {
865 vOnFileClose();
866 vSaveHistoryToConfig();
867 vSaveJoypadsToConfig();
868 vSaveConfig(m_sConfigFile);
870 if (m_poFileOpenDialog != NULL)
871 {
872 delete m_poFileOpenDialog;
873 }
875 if (m_poKeymap != NULL)
876 {
877 delete m_poKeymap;
878 }
880 m_poInstance = NULL;
881 }
883 void Window::vInitSystem()
884 {
885 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
886 systemRedShift = 3;
887 systemGreenShift = 11;
888 systemBlueShift = 19;
889 RGB_LOW_BITS_MASK = 0x00010101;
890 #else
891 systemRedShift = 27;
892 systemGreenShift = 19;
893 systemBlueShift = 11;
894 RGB_LOW_BITS_MASK = 0x01010100;
895 #endif
897 systemColorDepth = 32;
898 systemDebug = 0;
899 systemVerbose = 0;
900 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
901 systemFrameSkip = 0;
902 systemSoundOn = false;
903 soundOffFlag = true;
905 systemRenderedFrames = 0;
906 systemFPS = 0;
908 emulating = 0;
909 debugger = false;
911 for (int i = 0; i < 0x10000; i++)
912 {
913 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
914 systemColorMap32[i] = (((i & 0x1f) << systemRedShift)
915 | (((i & 0x3e0) >> 5) << systemGreenShift)
916 | (((i & 0x7c00) >> 10) << systemBlueShift));
917 #else
918 systemColorMap32[i] = (((i & 0x1f) << systemRedShift)
919 | (((i & 0x3e0) >> 5) << systemGreenShift)
920 | (((i & 0x7c00) >> 10) << systemBlueShift));
921 #endif
922 }
924 gbFrameSkip = 0;
926 for (int i = 0; i < 24; )
927 {
928 systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
929 systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10);
930 systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
931 systemGbPalette[i++] = 0;
932 }
934 Init_2xSaI(32);
935 }
937 void Window::vInitSDL()
938 {
939 static bool bDone = false;
941 if (bDone)
942 return;
944 int iFlags = (SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
946 if (SDL_Init(iFlags) < 0)
947 {
948 fprintf(stderr, "Failed to init SDL: %s", SDL_GetError());
949 abort();
950 }
952 bDone = true;
953 }
955 void Window::vInitConfig()
956 {
957 m_oConfig.vClear();
959 // History section
960 //
961 m_poHistoryConfig = m_oConfig.poAddSection("History");
962 m_poHistoryConfig->vSetKey("freeze", false );
963 m_poHistoryConfig->vSetKey("0", "" );
964 m_poHistoryConfig->vSetKey("1", "" );
965 m_poHistoryConfig->vSetKey("2", "" );
966 m_poHistoryConfig->vSetKey("3", "" );
967 m_poHistoryConfig->vSetKey("4", "" );
968 m_poHistoryConfig->vSetKey("5", "" );
969 m_poHistoryConfig->vSetKey("6", "" );
970 m_poHistoryConfig->vSetKey("7", "" );
971 m_poHistoryConfig->vSetKey("8", "" );
972 m_poHistoryConfig->vSetKey("9", "" );
974 // Directories section
975 //
976 m_poDirConfig = m_oConfig.poAddSection("Directories");
977 m_poDirConfig->vSetKey("gb_roms", "" );
978 m_poDirConfig->vSetKey("gba_roms", "" );
979 m_poDirConfig->vSetKey("batteries", "" );
980 m_poDirConfig->vSetKey("saves", "" );
981 m_poDirConfig->vSetKey("captures", "" );
983 // Core section
984 //
985 m_poCoreConfig = m_oConfig.poAddSection("Core");
986 m_poCoreConfig->vSetKey("load_game_auto", false );
987 m_poCoreConfig->vSetKey("frameskip", "auto" );
988 m_poCoreConfig->vSetKey("throttle", 0 );
989 m_poCoreConfig->vSetKey("layer_bg0", true );
990 m_poCoreConfig->vSetKey("layer_bg1", true );
991 m_poCoreConfig->vSetKey("layer_bg2", true );
992 m_poCoreConfig->vSetKey("layer_bg3", true );
993 m_poCoreConfig->vSetKey("layer_obj", true );
994 m_poCoreConfig->vSetKey("layer_win0", true );
995 m_poCoreConfig->vSetKey("layer_win1", true );
996 m_poCoreConfig->vSetKey("layer_objwin", true );
997 m_poCoreConfig->vSetKey("use_bios_file", false );
998 m_poCoreConfig->vSetKey("bios_file", "" );
999 m_poCoreConfig->vSetKey("save_type", SaveAuto );
1000 m_poCoreConfig->vSetKey("flash_size", 64 );
1001 m_poCoreConfig->vSetKey("gb_border", true );
1002 m_poCoreConfig->vSetKey("gb_printer", false );
1003 m_poCoreConfig->vSetKey("emulator_type", EmulatorAuto );
1004 m_poCoreConfig->vSetKey("screenshot_format", "png" );
1006 // Display section
1007 //
1008 m_poDisplayConfig = m_oConfig.poAddSection("Display");
1009 m_poDisplayConfig->vSetKey("scale", 1 );
1010 m_poDisplayConfig->vSetKey("show_speed", ShowPercentage );
1011 m_poDisplayConfig->vSetKey("pause_when_inactive", true );
1012 m_poDisplayConfig->vSetKey("filter2x", FilterNone );
1013 m_poDisplayConfig->vSetKey("filterIB", FilterIBNone );
1014 #ifdef MMX
1015 m_poDisplayConfig->vSetKey("filter_disable_mmx", false );
1016 #endif // MMX
1018 // Sound section
1019 //
1020 m_poSoundConfig = m_oConfig.poAddSection("Sound");
1021 m_poSoundConfig->vSetKey("status", "on" );
1022 m_poSoundConfig->vSetKey("echo", false );
1023 m_poSoundConfig->vSetKey("low_pass", false );
1024 m_poSoundConfig->vSetKey("reverse_stereo", false );
1025 m_poSoundConfig->vSetKey("channel_1", true );
1026 m_poSoundConfig->vSetKey("channel_2", true );
1027 m_poSoundConfig->vSetKey("channel_3", true );
1028 m_poSoundConfig->vSetKey("channel_4", true );
1029 m_poSoundConfig->vSetKey("channel_A", true );
1030 m_poSoundConfig->vSetKey("channel_B", true );
1031 m_poSoundConfig->vSetKey("quality", Sound22K );
1032 m_poSoundConfig->vSetKey("volume", Sound100 );
1034 // Input section
1035 //
1036 JoypadConfig oJoypadConfig;
1037 oJoypadConfig.vSetDefault();
1038 m_poInputConfig = m_oConfig.poAddSection("Input");
1039 m_poInputConfig->vSetKey("active_joypad", m_iJoypadMin );
1040 for (int i = m_iJoypadMin; i <= m_iJoypadMax; i++)
1042 char csPrefix[20];
1043 snprintf(csPrefix, sizeof(csPrefix), "joypad%d_", i);
1044 std::string sPrefix(csPrefix);
1045 m_poInputConfig->vSetKey(sPrefix + "up", oJoypadConfig.m_uiUp );
1046 m_poInputConfig->vSetKey(sPrefix + "down", oJoypadConfig.m_uiDown );
1047 m_poInputConfig->vSetKey(sPrefix + "left", oJoypadConfig.m_uiLeft );
1048 m_poInputConfig->vSetKey(sPrefix + "right", oJoypadConfig.m_uiRight );
1049 m_poInputConfig->vSetKey(sPrefix + "A", oJoypadConfig.m_uiA );
1050 m_poInputConfig->vSetKey(sPrefix + "B", oJoypadConfig.m_uiB );
1051 m_poInputConfig->vSetKey(sPrefix + "L", oJoypadConfig.m_uiL );
1052 m_poInputConfig->vSetKey(sPrefix + "R", oJoypadConfig.m_uiR );
1053 m_poInputConfig->vSetKey(sPrefix + "select", oJoypadConfig.m_uiSelect );
1054 m_poInputConfig->vSetKey(sPrefix + "start", oJoypadConfig.m_uiStart );
1055 m_poInputConfig->vSetKey(sPrefix + "speed", oJoypadConfig.m_uiSpeed );
1056 m_poInputConfig->vSetKey(sPrefix + "capture", oJoypadConfig.m_uiCapture );
1058 m_poInputConfig->vSetKey("autofire_A", false );
1059 m_poInputConfig->vSetKey("autofire_B", false );
1060 m_poInputConfig->vSetKey("autofire_L", false );
1061 m_poInputConfig->vSetKey("autofire_R", false );
1064 void Window::vCheckConfig()
1066 int iValue;
1067 int iAdjusted;
1068 std::string sValue;
1070 // Directories section
1071 //
1072 sValue = m_poDirConfig->sGetKey("gb_roms");
1073 if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_DIR))
1075 m_poDirConfig->vSetKey("gb_roms", "");
1077 sValue = m_poDirConfig->sGetKey("gba_roms");
1078 if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_DIR))
1080 m_poDirConfig->vSetKey("gba_roms", "");
1082 sValue = m_poDirConfig->sGetKey("batteries");
1083 if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_DIR))
1085 m_poDirConfig->vSetKey("batteries", "");
1087 sValue = m_poDirConfig->sGetKey("saves");
1088 if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_DIR))
1090 m_poDirConfig->vSetKey("saves", "");
1092 sValue = m_poDirConfig->sGetKey("captures");
1093 if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_DIR))
1095 m_poDirConfig->vSetKey("captures", "");
1098 // Core section
1099 //
1100 if (m_poCoreConfig->sGetKey("frameskip") != "auto")
1102 iValue = m_poCoreConfig->oGetKey<int>("frameskip");
1103 iAdjusted = CLAMP(iValue, m_iFrameskipMin, m_iFrameskipMax);
1104 if (iValue != iAdjusted)
1106 m_poCoreConfig->vSetKey("frameskip", iAdjusted);
1110 iValue = m_poCoreConfig->oGetKey<int>("throttle");
1111 if (iValue != 0)
1113 iAdjusted = CLAMP(iValue, m_iThrottleMin, m_iThrottleMax);
1114 if (iValue != iAdjusted)
1116 m_poCoreConfig->vSetKey("throttle", iAdjusted);
1120 sValue = m_poCoreConfig->sGetKey("bios_file");
1121 if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_REGULAR))
1123 m_poCoreConfig->vSetKey("bios_file", "");
1125 if (m_poCoreConfig->sGetKey("bios_file") == "")
1127 m_poCoreConfig->vSetKey("use_bios_file", false);
1130 iValue = m_poCoreConfig->oGetKey<int>("save_type");
1131 if (iValue != 0)
1133 iAdjusted = CLAMP(iValue, m_iSaveTypeMin, m_iSaveTypeMax);
1134 if (iValue != iAdjusted)
1136 m_poCoreConfig->vSetKey("save_type", iAdjusted);
1140 iValue = m_poCoreConfig->oGetKey<int>("flash_size");
1141 if (iValue != 64 && iValue != 128)
1143 m_poCoreConfig->vSetKey("flash_size", 64);
1146 iValue = m_poCoreConfig->oGetKey<int>("emulator_type");
1147 iAdjusted = CLAMP(iValue, m_iEmulatorTypeMin, m_iEmulatorTypeMax);
1148 if (iValue != iAdjusted)
1150 m_poCoreConfig->vSetKey("emulator_type", iAdjusted);
1153 sValue = m_poCoreConfig->sGetKey("screenshot_format");
1154 if (sValue != "png" && sValue != "bmp")
1156 sValue = "png";
1159 // Display section
1160 //
1161 iValue = m_poDisplayConfig->oGetKey<int>("scale");
1162 iAdjusted = CLAMP(iValue, m_iScaleMin, m_iScaleMax);
1163 if (iValue != iAdjusted)
1165 m_poDisplayConfig->vSetKey("scale", iAdjusted);
1168 iValue = m_poDisplayConfig->oGetKey<int>("show_speed");
1169 iAdjusted = CLAMP(iValue, m_iShowSpeedMin, m_iShowSpeedMax);
1170 if (iValue != iAdjusted)
1172 m_poDisplayConfig->vSetKey("show_speed", iAdjusted);
1175 iValue = m_poDisplayConfig->oGetKey<int>("filter2x");
1176 iAdjusted = CLAMP(iValue, m_iFilter2xMin, m_iFilter2xMax);
1177 if (iValue != iAdjusted)
1179 m_poDisplayConfig->vSetKey("filter2x", iAdjusted);
1182 iValue = m_poDisplayConfig->oGetKey<int>("filterIB");
1183 iAdjusted = CLAMP(iValue, m_iFilterIBMin, m_iFilterIBMax);
1184 if (iValue != iAdjusted)
1186 m_poDisplayConfig->vSetKey("filterIB", iAdjusted);
1189 // Sound section
1190 //
1191 sValue = m_poSoundConfig->sGetKey("status");
1192 if (sValue != "off" && sValue != "on" && sValue != "mute")
1194 m_poSoundConfig->vSetKey("status", "on");
1197 iValue = m_poSoundConfig->oGetKey<int>("quality");
1198 iAdjusted = CLAMP(iValue, m_iSoundQualityMin, m_iSoundQualityMax);
1199 if (iValue != iAdjusted)
1201 m_poSoundConfig->vSetKey("quality", iAdjusted);
1204 iValue = m_poSoundConfig->oGetKey<int>("volume");
1205 iAdjusted = CLAMP(iValue, m_iSoundVolumeMin, m_iSoundVolumeMax);
1206 if (iValue != iAdjusted)
1208 m_poSoundConfig->vSetKey("volume", iAdjusted);
1211 // Input section
1212 //
1213 iValue = m_poInputConfig->oGetKey<int>("active_joypad");
1214 iAdjusted = CLAMP(iValue, m_iJoypadMin, m_iJoypadMax);
1215 if (iValue != iAdjusted)
1217 m_poInputConfig->vSetKey("active_joypad", iAdjusted);
1221 void Window::vLoadConfig(const std::string & _rsFile)
1223 try
1225 m_oConfig.vLoad(_rsFile, false, false);
1227 catch (const Glib::Error & e)
1229 vPopupError(e.what().c_str());
1233 void Window::vSaveConfig(const std::string & _rsFile)
1235 try
1237 m_oConfig.vSave(_rsFile);
1239 catch (const Glib::Error & e)
1241 vPopupError(e.what().c_str());
1245 void Window::vLoadHistoryFromConfig()
1247 char csKey[] = "0";
1248 for (int i = 0; i < 10; i++, csKey[0]++)
1250 std::string sFile = m_poHistoryConfig->sGetKey(csKey);
1251 if (sFile == "")
1253 break;
1255 m_listHistory.push_back(sFile);
1259 void Window::vSaveHistoryToConfig()
1261 char csKey[] = "0";
1262 for (std::list<std::string>::const_iterator it = m_listHistory.begin();
1263 it != m_listHistory.end();
1264 it++, csKey[0]++)
1266 m_poHistoryConfig->vSetKey(csKey, *it);
1270 void Window::vHistoryAdd(const std::string & _rsFile)
1272 if (m_poHistoryConfig->oGetKey<bool>("freeze"))
1274 return;
1277 m_listHistory.remove(_rsFile);
1278 m_listHistory.push_front(_rsFile);
1279 if (m_listHistory.size() > 10)
1281 m_listHistory.pop_back();
1284 vUpdateHistoryMenu();
1287 void Window::vClearHistoryMenu()
1289 Gtk::Menu_Helpers::MenuList::iterator it = m_poRecentMenu->items().begin();
1290 for (int i = 0; i < 3; i++, it++)
1293 m_poRecentMenu->items().erase(it, m_poRecentMenu->items().end());
1296 void Window::vUpdateHistoryMenu()
1298 vClearHistoryMenu();
1300 guint uiAccelKey = GDK_F1;
1301 for (std::list<std::string>::const_iterator it = m_listHistory.begin();
1302 it != m_listHistory.end();
1303 it++, uiAccelKey++)
1305 Gtk::Image * poImage = Gtk::manage(new Gtk::Image(Gtk::Stock::OPEN, Gtk::ICON_SIZE_MENU));
1306 Glib::ustring sLabel = Glib::path_get_basename(*it);
1307 VBA::ImageMenuItem * poIMI = Gtk::manage(new VBA::ImageMenuItem(*poImage, sLabel));
1309 m_oTooltips.set_tip(*poIMI, *it);
1311 poIMI->signal_activate().connect(SigC::bind<std::string>(
1312 SigC::slot(*this, &Window::vOnRecentFile),
1313 *it));
1315 poIMI->set_accel_key(Gtk::AccelKey(uiAccelKey, Gdk::CONTROL_MASK));
1316 poIMI->accelerate(*this);
1318 poIMI->show();
1319 m_poRecentMenu->items().push_back(*poIMI);
1323 void Window::vLoadJoypadsFromConfig()
1325 m_oJoypads.clear();
1327 for (int i = m_iJoypadMin; i <= m_iJoypadMax; i++)
1329 char csPrefix[20];
1330 snprintf(csPrefix, sizeof(csPrefix), "joypad%d_", i);
1331 std::string sPrefix(csPrefix);
1333 JoypadConfig oJoypadConfig;
1334 oJoypadConfig.m_uiUp = m_poInputConfig->oGetKey<guint>(sPrefix + "up");
1335 oJoypadConfig.m_uiDown = m_poInputConfig->oGetKey<guint>(sPrefix + "down");
1336 oJoypadConfig.m_uiLeft = m_poInputConfig->oGetKey<guint>(sPrefix + "left");
1337 oJoypadConfig.m_uiRight = m_poInputConfig->oGetKey<guint>(sPrefix + "right");
1338 oJoypadConfig.m_uiA = m_poInputConfig->oGetKey<guint>(sPrefix + "A");
1339 oJoypadConfig.m_uiB = m_poInputConfig->oGetKey<guint>(sPrefix + "B");
1340 oJoypadConfig.m_uiL = m_poInputConfig->oGetKey<guint>(sPrefix + "L");
1341 oJoypadConfig.m_uiR = m_poInputConfig->oGetKey<guint>(sPrefix + "R");
1342 oJoypadConfig.m_uiSelect = m_poInputConfig->oGetKey<guint>(sPrefix + "select");
1343 oJoypadConfig.m_uiStart = m_poInputConfig->oGetKey<guint>(sPrefix + "start");
1344 oJoypadConfig.m_uiSpeed = m_poInputConfig->oGetKey<guint>(sPrefix + "speed");
1345 oJoypadConfig.m_uiCapture = m_poInputConfig->oGetKey<guint>(sPrefix + "capture");
1347 m_oJoypads.push_back(oJoypadConfig);
1351 void Window::vSaveJoypadsToConfig()
1353 for (int i = m_iJoypadMin; i <= m_iJoypadMax; i++)
1355 char csPrefix[20];
1356 snprintf(csPrefix, sizeof(csPrefix), "joypad%d_", i);
1357 std::string sPrefix(csPrefix);
1359 m_poInputConfig->vSetKey(sPrefix + "up", m_oJoypads[i - 1].m_uiUp );
1360 m_poInputConfig->vSetKey(sPrefix + "down", m_oJoypads[i - 1].m_uiDown );
1361 m_poInputConfig->vSetKey(sPrefix + "left", m_oJoypads[i - 1].m_uiLeft );
1362 m_poInputConfig->vSetKey(sPrefix + "right", m_oJoypads[i - 1].m_uiRight );
1363 m_poInputConfig->vSetKey(sPrefix + "A", m_oJoypads[i - 1].m_uiA );
1364 m_poInputConfig->vSetKey(sPrefix + "B", m_oJoypads[i - 1].m_uiB );
1365 m_poInputConfig->vSetKey(sPrefix + "L", m_oJoypads[i - 1].m_uiL );
1366 m_poInputConfig->vSetKey(sPrefix + "R", m_oJoypads[i - 1].m_uiR );
1367 m_poInputConfig->vSetKey(sPrefix + "select", m_oJoypads[i - 1].m_uiSelect );
1368 m_poInputConfig->vSetKey(sPrefix + "start", m_oJoypads[i - 1].m_uiStart );
1369 m_poInputConfig->vSetKey(sPrefix + "speed", m_oJoypads[i - 1].m_uiSpeed );
1370 m_poInputConfig->vSetKey(sPrefix + "capture", m_oJoypads[i - 1].m_uiCapture );
1374 void Window::vUpdateScreen()
1376 if (m_eCartridge == CartridgeGB)
1378 if (gbBorderOn)
1380 m_iScreenWidth = m_iSGBScreenWidth;
1381 m_iScreenHeight = m_iSGBScreenHeight;
1382 gbBorderLineSkip = m_iSGBScreenWidth;
1383 gbBorderColumnSkip = (m_iSGBScreenWidth - m_iGBScreenWidth) / 2;
1384 gbBorderRowSkip = (m_iSGBScreenHeight - m_iGBScreenHeight) / 2;
1386 else
1388 m_iScreenWidth = m_iGBScreenWidth;
1389 m_iScreenHeight = m_iGBScreenHeight;
1390 gbBorderLineSkip = m_iGBScreenWidth;
1391 gbBorderColumnSkip = 0;
1392 gbBorderRowSkip = 0;
1395 else if (m_eCartridge == CartridgeGBA)
1397 m_iScreenWidth = m_iGBAScreenWidth;
1398 m_iScreenHeight = m_iGBAScreenHeight;
1401 g_return_if_fail(m_iScreenWidth >= 1 && m_iScreenHeight >= 1);
1403 m_poScreenArea->vSetSize(m_iScreenWidth, m_iScreenHeight);
1404 m_poScreenArea->vSetScale(m_poDisplayConfig->oGetKey<int>("scale"));
1406 resize(1, 1);
1408 if (emulating)
1410 vDrawScreen();
1412 else
1414 vDrawDefaultScreen();
1418 bool Window::bLoadROM(const std::string & _rsFile)
1420 vOnFileClose();
1422 m_sRomFile = _rsFile;
1423 const char * csFile = _rsFile.c_str();
1425 IMAGE_TYPE eType = utilFindType(csFile);
1426 if (eType == IMAGE_UNKNOWN)
1428 vPopupError(_("Unknown file type %s"), csFile);
1429 return false;
1432 bool bLoaded = false;
1433 if (eType == IMAGE_GB)
1435 bLoaded = gbLoadRom(csFile);
1436 if (bLoaded)
1438 m_eCartridge = CartridgeGB;
1439 m_stEmulator = GBSystem;
1442 else if (eType == IMAGE_GBA)
1444 int iSize = CPULoadRom(csFile);
1445 bLoaded = (iSize > 0);
1446 if (bLoaded)
1448 m_eCartridge = CartridgeGBA;
1449 m_stEmulator = GBASystem;
1451 useBios = m_poCoreConfig->oGetKey<bool>("use_bios_file");
1452 //CPUInit(m_poCoreConfig->sGetKey("bios_file").c_str(), useBios);
1453 CPUInit();
1454 CPUReset();
1456 // If the bios file was rejected by CPUInit
1457 if (m_poCoreConfig->oGetKey<bool>("use_bios_file") && ! useBios)
1459 m_poUseBiosItem->set_active(false);
1460 m_poUseBiosItem->set_sensitive(false);
1461 m_poCoreConfig->vSetKey("bios_file", "");
1466 if (! bLoaded)
1468 return false;
1471 vLoadBattery();
1472 vUpdateScreen();
1474 debugger = false; // May cause conflicts
1475 emulating = 1;
1476 m_bWasEmulating = false;
1477 m_uiThrottleDelay = 0;
1479 if (m_eCartridge == CartridgeGBA)
1481 soundSetQuality(m_eSoundQuality);
1483 else
1485 gbSoundSetQuality(m_eSoundQuality);
1488 vUpdateGameSlots();
1489 vHistoryAdd(_rsFile);
1491 for (std::list<Gtk::Widget *>::iterator it = m_listSensitiveWhenPlaying.begin();
1492 it != m_listSensitiveWhenPlaying.end();
1493 it++)
1495 (*it)->set_sensitive();
1498 if (m_poCoreConfig->oGetKey<bool>("load_game_auto"))
1500 vOnLoadGameMostRecent();
1503 vStartEmu();
1505 return true;
1508 void Window::vPopupError(const char * _csFormat, ...)
1510 va_list args;
1511 va_start(args, _csFormat);
1512 char * csMsg = g_strdup_vprintf(_csFormat, args);
1513 va_end(args);
1515 Gtk::MessageDialog oDialog(*this,
1516 csMsg,
1517 #ifndef GTKMM20
1518 false,
1519 #endif // ! GTKMM20
1520 Gtk::MESSAGE_ERROR,
1521 Gtk::BUTTONS_OK);
1522 oDialog.run();
1523 g_free(csMsg);
1526 void Window::vPopupErrorV(const char * _csFormat, va_list _args)
1528 char * csMsg = g_strdup_vprintf(_csFormat, _args);
1530 Gtk::MessageDialog oDialog(*this,
1531 csMsg,
1532 #ifndef GTKMM20
1533 false,
1534 #endif // ! GTKMM20
1535 Gtk::MESSAGE_ERROR,
1536 Gtk::BUTTONS_OK);
1537 oDialog.run();
1538 g_free(csMsg);
1541 void Window::vDrawScreen()
1543 m_poScreenArea->vDrawPixels(pix);
1546 void Window::vDrawDefaultScreen()
1548 m_poScreenArea->vDrawColor(0x000000); // Black
1551 void Window::vSetDefaultTitle()
1553 set_title("VBA");
1556 void Window::vShowSpeed(int _iSpeed)
1558 char csTitle[50];
1560 if (m_eShowSpeed == ShowPercentage)
1562 snprintf(csTitle, 50, "VBA - %d%%", _iSpeed);
1563 set_title(csTitle);
1565 else if (m_eShowSpeed == ShowDetailed)
1567 snprintf(csTitle, 50, "VBA - %d%% (%d, %d fps)",
1568 _iSpeed, systemFrameSkip, systemFPS);
1569 set_title(csTitle);
1573 void Window::vComputeFrameskip(int _iRate)
1575 static u32 uiLastTime = 0;
1576 static int iFrameskipAdjust = 0;
1578 u32 uiTime = SDL_GetTicks();
1580 if (m_bWasEmulating)
1582 int iWantedSpeed = 100;
1584 if (m_iThrottle > 0)
1586 if (! speedup)
1588 u32 uiDiff = uiTime - m_uiThrottleLastTime;
1589 int iTarget = 1000000 / (_iRate * m_iThrottle);
1590 int iDelay = iTarget - uiDiff;
1591 if (iDelay > 0)
1593 m_uiThrottleDelay = iDelay;
1596 iWantedSpeed = m_iThrottle;
1599 if (m_bAutoFrameskip)
1601 u32 uiDiff = uiTime - uiLastTime;
1602 int iSpeed = iWantedSpeed;
1604 if (uiDiff != 0)
1606 iSpeed = (1000000 / _iRate) / uiDiff;
1609 if (iSpeed >= iWantedSpeed - 2)
1611 iFrameskipAdjust++;
1612 if (iFrameskipAdjust >= 3)
1614 iFrameskipAdjust = 0;
1615 if (systemFrameSkip > 0)
1617 systemFrameSkip--;
1621 else
1623 if (iSpeed < iWantedSpeed - 20)
1625 iFrameskipAdjust -= ((iWantedSpeed - 10) - iSpeed) / 5;
1627 else if (systemFrameSkip < 9)
1629 iFrameskipAdjust--;
1632 if (iFrameskipAdjust <= -2)
1634 iFrameskipAdjust += 2;
1635 if (systemFrameSkip < 9)
1637 systemFrameSkip++;
1643 else
1645 m_bWasEmulating = true;
1648 uiLastTime = uiTime;
1649 m_uiThrottleLastTime = uiTime;
1652 void Window::vCaptureScreen(int _iNum)
1654 std::string sBaseName;
1655 std::string sCaptureDir = m_poDirConfig->sGetKey("captures");
1656 if (sCaptureDir == "")
1658 sBaseName = sCutSuffix(m_sRomFile);
1660 else
1662 sBaseName = sCaptureDir + "/" + sCutSuffix(Glib::path_get_basename(m_sRomFile));
1664 std::string sFormat = m_poCoreConfig->sGetKey("screenshot_format");
1666 char * csFile = g_strdup_printf("%s_%02d.%s",
1667 sBaseName.c_str(),
1668 _iNum,
1669 sFormat.c_str());
1670 if (sFormat == "png")
1672 m_stEmulator.emuWritePNG(csFile);
1674 else
1676 m_stEmulator.emuWriteBMP(csFile);
1678 g_free(csFile);
1681 u32 Window::uiReadJoypad()
1683 u32 uiJoypad = m_uiJoypadState;
1685 if (m_uiAutofireState != 0)
1687 uiJoypad &= ~m_uiAutofireState;
1688 if (m_bAutofireToggle)
1690 uiJoypad |= m_uiAutofireState;
1692 m_bAutofireToggle = ! m_bAutofireToggle;
1695 return uiJoypad;
1698 void Window::vCreateFileOpenDialog()
1700 if (m_poFileOpenDialog != NULL)
1702 return;
1705 std::string sGBDir = m_poDirConfig->sGetKey("gb_roms");
1706 std::string sGBADir = m_poDirConfig->sGetKey("gba_roms");
1708 #ifdef GTKMM20
1710 Gtk::FileSelection * poDialog = new Gtk::FileSelection(_("Open"));
1711 poDialog->set_transient_for(*this);
1713 if (sGBADir != "")
1715 poDialog->set_filename(sGBADir + "/");
1717 else if (sGBDir != "")
1719 poDialog->set_filename(sGBDir + "/");
1722 #else // ! GTKMM20
1724 Gtk::FileChooserDialog * poDialog = new Gtk::FileChooserDialog(*this, _("Open"));
1725 poDialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1726 poDialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1728 if (sGBDir != "")
1730 poDialog->add_shortcut_folder(sGBDir);
1731 poDialog->set_current_folder(sGBDir);
1734 if (sGBADir != "" && sGBADir != sGBDir)
1736 poDialog->add_shortcut_folder(sGBADir);
1737 poDialog->set_current_folder(sGBADir);
1740 const char * acsPattern[] =
1742 // GBA
1743 "*.[bB][iI][nN]", "*.[aA][gG][bB]", "*.[gG][bB][aA]",
1744 // GB
1745 "*.[gG][bB]", "*.[sS][gG][bB]", "*.[cC][gG][bB]", "*.[gG][bB][cC]",
1746 // Both
1747 "*.[mM][bB]", "*.[eE][lL][fF]", "*.[zZ][iI][pP]", "*.[zZ]", "*.[gG][zZ]"
1748 };
1750 Gtk::FileFilter oAllGBAFilter;
1751 oAllGBAFilter.set_name(_("All Gameboy Advance files"));
1752 for (guint i = 0; i < G_N_ELEMENTS(acsPattern); i++)
1754 oAllGBAFilter.add_pattern(acsPattern[i]);
1757 Gtk::FileFilter oGBAFilter;
1758 oGBAFilter.set_name(_("Gameboy Advance files"));
1759 for (int i = 0; i < 3; i++)
1761 oGBAFilter.add_pattern(acsPattern[i]);
1764 Gtk::FileFilter oGBFilter;
1765 oGBFilter.set_name(_("Gameboy files"));
1766 for (int i = 3; i < 7; i++)
1768 oGBFilter.add_pattern(acsPattern[i]);
1771 poDialog->add_filter(oAllGBAFilter);
1772 poDialog->add_filter(oGBAFilter);
1773 poDialog->add_filter(oGBFilter);
1775 #endif // ! GTKMM20
1777 m_poFileOpenDialog = poDialog;
1780 void Window::vLoadBattery()
1782 std::string sBattery;
1783 std::string sDir = m_poDirConfig->sGetKey("batteries");
1784 if (sDir == "")
1786 sBattery = sCutSuffix(m_sRomFile) + ".sav";
1788 else
1790 sBattery = sDir + "/" + sCutSuffix(Glib::path_get_basename(m_sRomFile)) + ".sav";
1793 if (m_stEmulator.emuReadBattery(sBattery.c_str()))
1795 systemScreenMessage(_("Loaded battery"));
1799 void Window::vSaveBattery()
1801 std::string sBattery;
1802 std::string sDir = m_poDirConfig->sGetKey("batteries");
1803 if (sDir == "")
1805 sBattery = sCutSuffix(m_sRomFile) + ".sav";
1807 else
1809 sBattery = sDir + "/" + sCutSuffix(Glib::path_get_basename(m_sRomFile)) + ".sav";
1812 if (m_stEmulator.emuWriteBattery(sBattery.c_str()))
1814 systemScreenMessage(_("Saved battery"));
1818 void Window::vStartEmu()
1820 if (m_oEmuSig.connected())
1822 return;
1825 m_oEmuSig = Glib::signal_idle().connect(SigC::slot(*this, &Window::bOnEmuIdle),
1826 Glib::PRIORITY_DEFAULT_IDLE);
1829 void Window::vStopEmu()
1831 m_oEmuSig.disconnect();
1832 m_bWasEmulating = false;
1835 void Window::vSetThrottle(int _iPercent)
1837 m_iThrottle = _iPercent;
1838 m_poCoreConfig->vSetKey("throttle", _iPercent);
1841 void Window::vSelectBestThrottleItem()
1843 struct
1845 const char * m_csName;
1846 const int m_iThrottle;
1848 astThrottle[] =
1850 { "ThrottleNoThrottle", 0 },
1851 { "Throttle25", 25 },
1852 { "Throttle50", 50 },
1853 { "Throttle100", 100 },
1854 { "Throttle150", 150 },
1855 { "Throttle200", 200 }
1856 };
1857 for (guint i = 0; i < G_N_ELEMENTS(astThrottle); i++)
1859 Gtk::CheckMenuItem * poCMI;
1860 poCMI = dynamic_cast<Gtk::CheckMenuItem *>(m_poXml->get_widget(astThrottle[i].m_csName));
1861 if (astThrottle[i].m_iThrottle == m_iThrottle)
1863 poCMI->set_active();
1868 void Window::vUpdateGameSlots()
1870 if (m_eCartridge == CartridgeNone)
1872 std::string sDateTime = _("----/--/-- --:--:--");
1874 for (int i = 0; i < 10; i++)
1876 char csPrefix[10];
1877 snprintf(csPrefix, sizeof(csPrefix), "%2d ", i + 1);
1879 Gtk::Label * poLabel;
1880 poLabel = dynamic_cast<Gtk::Label *>(m_apoLoadGameItem[i]->get_child());
1881 poLabel->set_text(csPrefix + sDateTime);
1882 m_apoLoadGameItem[i]->set_sensitive(false);
1884 poLabel = dynamic_cast<Gtk::Label *>(m_apoSaveGameItem[i]->get_child());
1885 poLabel->set_text(csPrefix + sDateTime);
1886 m_apoSaveGameItem[i]->set_sensitive(false);
1888 m_astGameSlot[i].m_bEmpty = true;
1891 else
1893 std::string sFileBase;
1894 std::string sDir = m_poDirConfig->sGetKey("saves");
1895 if (sDir == "")
1897 sFileBase = sCutSuffix(m_sRomFile);
1899 else
1901 sFileBase = sDir + "/" + sCutSuffix(Glib::path_get_basename(m_sRomFile));
1904 const char * csDateFormat = _("%Y/%m/%d %H:%M:%S");
1906 for (int i = 0; i < 10; i++)
1908 char csPrefix[10];
1909 snprintf(csPrefix, sizeof(csPrefix), "%2d ", i + 1);
1911 char csSlot[10];
1912 snprintf(csSlot, sizeof(csSlot), "%d", i + 1);
1913 m_astGameSlot[i].m_sFile = sFileBase + csSlot + ".sgm";
1915 std::string sDateTime;
1916 struct stat stStat;
1917 if (stat(m_astGameSlot[i].m_sFile.c_str(), &stStat) == -1)
1919 sDateTime = _("----/--/-- --:--:--");
1920 m_astGameSlot[i].m_bEmpty = true;
1922 else
1924 char csDateTime[30];
1925 strftime(csDateTime, sizeof(csDateTime), csDateFormat,
1926 localtime(&stStat.st_mtime));
1927 sDateTime = csDateTime;
1928 m_astGameSlot[i].m_bEmpty = false;
1929 m_astGameSlot[i].m_uiTime = stStat.st_mtime;
1932 Gtk::Label * poLabel;
1933 poLabel = dynamic_cast<Gtk::Label *>(m_apoLoadGameItem[i]->get_child());
1934 poLabel->set_text(csPrefix + sDateTime);
1935 m_apoLoadGameItem[i]->set_sensitive(! m_astGameSlot[i].m_bEmpty);
1937 poLabel = dynamic_cast<Gtk::Label *>(m_apoSaveGameItem[i]->get_child());
1938 poLabel->set_text(csPrefix + sDateTime);
1939 m_apoSaveGameItem[i]->set_sensitive();
1944 } // VBA namespace