view src/gtk/windowcallbacks.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/Flash.h"
31 #include "../gba/GBASound.h"
32 #include "../gb/GB.h"
33 #include "../gb/gbGlobals.h"
34 #include "../gb/gbPrinter.h"
35 #include "../common/Util.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 void Window::vOnFileOpen()
65 {
66 while (m_poFileOpenDialog->run() == Gtk::RESPONSE_OK)
67 {
68 if (bLoadROM(m_poFileOpenDialog->get_filename()))
69 {
70 break;
71 }
72 }
73 m_poFileOpenDialog->hide();
74 }
76 void Window::vOnFileLoad()
77 {
78 std::string sSaveDir = m_poDirConfig->sGetKey("saves");
80 #ifdef GTKMM20
82 Gtk::FileSelection oDialog(_("Load game"));
83 oDialog.set_transient_for(*this);
85 if (sSaveDir == "")
86 {
87 oDialog.set_filename(Glib::path_get_dirname(m_sRomFile) + "/");
88 }
89 else
90 {
91 oDialog.set_filename(sSaveDir + "/");
92 }
94 #else // ! GTKMM20
96 Gtk::FileChooserDialog oDialog(*this, _("Load game"));
97 oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
98 oDialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
100 if (sSaveDir == "")
101 {
102 oDialog.set_current_folder(Glib::path_get_dirname(m_sRomFile));
103 }
104 else
105 {
106 oDialog.set_current_folder(sSaveDir);
107 oDialog.add_shortcut_folder(sSaveDir);
108 }
110 Gtk::FileFilter oSaveFilter;
111 oSaveFilter.set_name(_("VisualBoyAdvance save game"));
112 oSaveFilter.add_pattern("*.[sS][gG][mM]");
114 oDialog.add_filter(oSaveFilter);
116 #endif // ! GTKMM20
118 while (oDialog.run() == Gtk::RESPONSE_OK)
119 {
120 if (m_stEmulator.emuReadState(oDialog.get_filename().c_str()))
121 {
122 break;
123 }
124 }
125 }
127 void Window::vOnFileSave()
128 {
129 Glib::ustring sSaveDir = m_poDirConfig->sGetKey("saves");
131 #ifdef GTKMM20
133 Gtk::FileSelection oDialog(_("Save game"));
134 oDialog.set_transient_for(*this);
136 if (sSaveDir == "")
137 {
138 oDialog.set_filename(sCutSuffix(m_sRomFile));
139 }
140 else
141 {
142 oDialog.set_filename(sSaveDir + "/" +
143 sCutSuffix(Glib::path_get_basename(m_sRomFile)));
144 }
146 #else // ! GTKMM20
148 Gtk::FileChooserDialog oDialog(*this, _("Save game"),
149 Gtk::FILE_CHOOSER_ACTION_SAVE);
150 oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
151 oDialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
153 if (sSaveDir == "")
154 {
155 oDialog.set_current_folder(Glib::path_get_dirname(m_sRomFile));
156 }
157 else
158 {
159 oDialog.set_current_folder(sSaveDir);
160 oDialog.add_shortcut_folder(sSaveDir);
161 }
162 oDialog.set_current_name(sCutSuffix(Glib::path_get_basename(m_sRomFile)));
164 Gtk::FileFilter oSaveFilter;
165 oSaveFilter.set_name(_("VisualBoyAdvance save game"));
166 oSaveFilter.add_pattern("*.[sS][gG][mM]");
168 oDialog.add_filter(oSaveFilter);
170 #endif // ! GTKMM20
172 while (oDialog.run() == Gtk::RESPONSE_OK)
173 {
174 Glib::ustring sFile = oDialog.get_filename();
175 if (! bHasSuffix(sFile, ".sgm", false))
176 {
177 sFile += ".sgm";
178 }
180 if (Glib::file_test(sFile, Glib::FILE_TEST_EXISTS))
181 {
182 Gtk::MessageDialog oConfirmDialog(*this,
183 _("File already exists. Overwrite it?"),
184 #ifndef GTKMM20
185 false,
186 #endif // ! GTKMM20
187 Gtk::MESSAGE_QUESTION,
188 Gtk::BUTTONS_YES_NO);
189 if (oConfirmDialog.run() != Gtk::RESPONSE_YES)
190 {
191 continue;
192 }
193 }
195 if (m_stEmulator.emuWriteState(sFile.c_str()))
196 {
197 break;
198 }
199 }
200 }
202 void Window::vOnLoadGameMostRecent()
203 {
204 int iMostRecent = -1;
205 time_t uiTimeMax;
207 for (int i = 0; i < 10; i++)
208 {
209 if (! m_astGameSlot[i].m_bEmpty
210 && (iMostRecent < 0 || m_astGameSlot[i].m_uiTime > uiTimeMax))
211 {
212 iMostRecent = i;
213 uiTimeMax = m_astGameSlot[i].m_uiTime;
214 }
215 }
217 if (iMostRecent >= 0)
218 {
219 vOnLoadGame(iMostRecent + 1);
220 }
221 }
223 void Window::vOnLoadGameAutoToggled(Gtk::CheckMenuItem * _poCMI)
224 {
225 m_poCoreConfig->vSetKey("load_game_auto", _poCMI->get_active());
226 }
228 void Window::vOnLoadGame(int _iSlot)
229 {
230 int i = _iSlot - 1;
231 if (! m_astGameSlot[i].m_bEmpty)
232 {
233 m_stEmulator.emuReadState(m_astGameSlot[i].m_sFile.c_str());
234 m_poFilePauseItem->set_active(false);
235 }
236 }
238 void Window::vOnSaveGameOldest()
239 {
240 int iOldest = -1;
241 time_t uiTimeMin;
243 for (int i = 0; i < 10; i++)
244 {
245 if (! m_astGameSlot[i].m_bEmpty
246 && (iOldest < 0 || m_astGameSlot[i].m_uiTime < uiTimeMin))
247 {
248 iOldest = i;
249 uiTimeMin = m_astGameSlot[i].m_uiTime;
250 }
251 }
253 if (iOldest >= 0)
254 {
255 vOnSaveGame(iOldest + 1);
256 }
257 else
258 {
259 vOnSaveGame(1);
260 }
261 }
263 void Window::vOnSaveGame(int _iSlot)
264 {
265 int i = _iSlot - 1;
266 m_stEmulator.emuWriteState(m_astGameSlot[i].m_sFile.c_str());
267 vUpdateGameSlots();
268 }
270 void Window::vOnFilePauseToggled(Gtk::CheckMenuItem * _poCMI)
271 {
272 m_bPaused = _poCMI->get_active();
273 if (emulating)
274 {
275 if (m_bPaused)
276 {
277 vStopEmu();
278 soundPause();
279 }
280 else
281 {
282 vStartEmu();
283 soundResume();
284 }
285 }
286 }
288 void Window::vOnFileReset()
289 {
290 if (emulating)
291 {
292 m_stEmulator.emuReset(true);
293 m_poFilePauseItem->set_active(false);
294 }
295 }
297 void Window::vOnRecentReset()
298 {
299 m_listHistory.clear();
300 vClearHistoryMenu();
301 }
303 void Window::vOnRecentFreezeToggled(Gtk::CheckMenuItem * _poCMI)
304 {
305 m_poRecentResetItem->set_sensitive(! _poCMI->get_active());
306 m_poHistoryConfig->vSetKey("freeze", _poCMI->get_active());
307 }
309 void Window::vOnRecentFile(std::string _sFile)
310 {
311 bLoadROM(_sFile);
312 }
314 void Window::vOnImportBatteryFile()
315 {
316 std::string BatteryDir = m_poDirConfig->sGetKey("batteries");
318 #ifdef GTKMM20
320 Gtk::FileSelection oDialog(_("Import battery file"));
321 oDialog.set_transient_for(*this);
323 if (BatteryDir == "")
324 {
325 oDialog.set_filename(Glib::path_get_dirname(m_sRomFile) + "/");
326 }
327 else
328 {
329 oDialog.set_filename(BatteryDir + "/");
330 }
332 #else // ! GTKMM20
334 Gtk::FileChooserDialog oDialog(*this, _("Import battery file"));
335 oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
336 oDialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
338 if (BatteryDir == "")
339 {
340 oDialog.set_current_folder(Glib::path_get_dirname(m_sRomFile));
341 }
342 else
343 {
344 oDialog.set_current_folder(BatteryDir);
345 oDialog.add_shortcut_folder(BatteryDir);
346 }
348 Gtk::FileFilter oBatteryFilter;
349 oBatteryFilter.set_name(_("Battery file"));
350 oBatteryFilter.add_pattern("*.[sS][aA][vV]");
352 Gtk::FileFilter oFlashFilter;
353 oFlashFilter.set_name(_("Flash save"));
354 oFlashFilter.add_pattern("*.[dD][aA][tT]");
356 oDialog.add_filter(oBatteryFilter);
357 oDialog.add_filter(oFlashFilter);
359 #endif // ! GTKMM20
361 while (oDialog.run() == Gtk::RESPONSE_OK)
362 {
363 Gtk::MessageDialog oConfirmDialog(*this,
364 _("Importing a battery file will erase any saved games and reset the emulator. Do you want to continue?"),
365 #ifndef GTKMM20
366 false,
367 #endif // ! GTKMM20
368 Gtk::MESSAGE_QUESTION,
369 Gtk::BUTTONS_YES_NO);
370 if (oConfirmDialog.run() != Gtk::RESPONSE_YES)
371 {
372 continue;
373 }
375 if (m_stEmulator.emuReadBattery(oDialog.get_filename().c_str()))
376 {
377 m_stEmulator.emuReset(false);
378 break;
379 }
380 else
381 {
382 vPopupError(_("Failed to import battery file %s."),
383 oDialog.get_filename().c_str());
384 }
385 }
386 }
388 void Window::vOnExportBatteryFile()
389 {
390 std::string sBatteryDir = m_poDirConfig->sGetKey("batteries");
392 #ifdef GTKMM20
394 Gtk::FileSelection oDialog(_("Export battery file"));
395 oDialog.set_transient_for(*this);
397 if (sBatteryDir == "")
398 {
399 oDialog.set_filename(sCutSuffix(m_sRomFile));
400 }
401 else
402 {
403 oDialog.set_filename(sBatteryDir + "/" +
404 sCutSuffix(Glib::path_get_basename(m_sRomFile)));
405 }
407 #else // ! GTKMM20
409 Gtk::FileChooserDialog oDialog(*this, _("Export battery file"),
410 Gtk::FILE_CHOOSER_ACTION_SAVE);
411 oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
412 oDialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
414 if (sBatteryDir == "")
415 {
416 oDialog.set_current_folder(Glib::path_get_dirname(m_sRomFile));
417 }
418 else
419 {
420 oDialog.set_current_folder(sBatteryDir);
421 oDialog.add_shortcut_folder(sBatteryDir);
422 }
423 oDialog.set_current_name(sCutSuffix(Glib::path_get_basename(m_sRomFile)));
425 Gtk::FileFilter oBatteryFilter;
426 oBatteryFilter.set_name(_("Battery file"));
427 oBatteryFilter.add_pattern("*.[sS][aA][vV]");
429 Gtk::FileFilter oFlashFilter;
430 oFlashFilter.set_name(_("Flash save"));
431 oFlashFilter.add_pattern("*.[dD][aA][tT]");
433 oDialog.add_filter(oBatteryFilter);
434 oDialog.add_filter(oFlashFilter);
436 #endif // ! GTKMM20
438 while (oDialog.run() == Gtk::RESPONSE_OK)
439 {
440 Glib::ustring sFile = oDialog.get_filename();
441 Glib::ustring sExt;
443 #ifdef GTKMM20
445 sExt = ".sav";
447 #else // ! GTKMM20
449 if (oDialog.get_filter() == &oBatteryFilter)
450 {
451 sExt = ".sav";
452 }
453 else
454 {
455 sExt = ".dat";
456 }
458 #endif // ! GTKMM20
460 if (! bHasSuffix(sFile, sExt, false))
461 {
462 sFile += sExt;
463 }
465 if (Glib::file_test(sFile, Glib::FILE_TEST_EXISTS))
466 {
467 Gtk::MessageDialog oConfirmDialog(*this,
468 _("File already exists. Overwrite it?"),
469 #ifndef GTKMM20
470 false,
471 #endif // ! GTKMM20
472 Gtk::MESSAGE_QUESTION,
473 Gtk::BUTTONS_YES_NO);
474 if (oConfirmDialog.run() != Gtk::RESPONSE_YES)
475 {
476 continue;
477 }
478 }
480 bool bResult;
481 if (m_eCartridge == CartridgeGB)
482 {
483 bResult = gbWriteBatteryFile(sFile.c_str(), false);
484 }
485 else
486 {
487 bResult = m_stEmulator.emuWriteBattery(sFile.c_str());
488 }
490 if (bResult)
491 {
492 break;
493 }
494 else
495 {
496 vPopupError(_("Failed to export battery file %s."),
497 sFile.c_str());
498 }
499 }
500 }
502 void Window::vOnFileScreenCapture()
503 {
504 std::string sCaptureDir = m_poDirConfig->sGetKey("captures");
506 #ifdef GTKMM20
508 Gtk::FileSelection oDialog(_("Save screenshot"));
509 oDialog.set_transient_for(*this);
511 if (sCaptureDir == "")
512 {
513 oDialog.set_filename(sCutSuffix(m_sRomFile));
514 }
515 else
516 {
517 oDialog.set_filename(sCaptureDir + "/" +
518 sCutSuffix(Glib::path_get_basename(m_sRomFile)));
519 }
521 #else // ! GTKMM20
523 Gtk::FileChooserDialog oDialog(*this, _("Save screenshot"),
524 Gtk::FILE_CHOOSER_ACTION_SAVE);
525 oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
526 oDialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
528 if (sCaptureDir == "")
529 {
530 oDialog.set_current_folder(Glib::path_get_dirname(m_sRomFile));
531 }
532 else
533 {
534 oDialog.set_current_folder(sCaptureDir);
535 oDialog.add_shortcut_folder(sCaptureDir);
536 }
537 oDialog.set_current_name(sCutSuffix(Glib::path_get_basename(m_sRomFile)));
539 Gtk::FileFilter oPngFilter;
540 oPngFilter.set_name(_("PNG image"));
541 oPngFilter.add_pattern("*.[pP][nN][gG]");
543 Gtk::FileFilter oBmpFilter;
544 oBmpFilter.set_name(_("BMP image"));
545 oBmpFilter.add_pattern("*.[bB][mM][pP]");
547 oDialog.add_filter(oPngFilter);
548 oDialog.add_filter(oBmpFilter);
550 if (m_poCoreConfig->sGetKey("screenshot_format") == "bmp")
551 {
552 oDialog.set_filter(oBmpFilter);
553 }
555 #endif // ! GTKMM20
557 while (oDialog.run() == Gtk::RESPONSE_OK)
558 {
559 Glib::ustring sFile = oDialog.get_filename();
560 Glib::ustring sExt;
562 #ifdef GTKMM20
564 sExt = "." + m_poCoreConfig->sGetKey("screenshot_format");
566 #else // ! GTKMM20
568 if (oDialog.get_filter() == &oPngFilter)
569 {
570 sExt = ".png";
571 }
572 else
573 {
574 sExt = ".bmp";
575 }
577 #endif // ! GTKMM20
579 if (! bHasSuffix(sFile, sExt, false))
580 {
581 sFile += sExt;
582 }
584 if (Glib::file_test(sFile, Glib::FILE_TEST_EXISTS))
585 {
586 Gtk::MessageDialog oConfirmDialog(*this,
587 _("File already exists. Overwrite it?"),
588 #ifndef GTKMM20
589 false,
590 #endif // ! GTKMM20
591 Gtk::MESSAGE_QUESTION,
592 Gtk::BUTTONS_YES_NO);
593 if (oConfirmDialog.run() != Gtk::RESPONSE_YES)
594 {
595 continue;
596 }
597 }
599 bool bResult;
600 if (sExt == ".png")
601 {
602 bResult = m_stEmulator.emuWritePNG(sFile.c_str());
603 }
604 else
605 {
606 bResult = m_stEmulator.emuWriteBMP(sFile.c_str());
607 }
609 if (bResult)
610 {
611 break;
612 }
613 }
614 }
616 void Window::vOnFileClose()
617 {
618 if (m_eCartridge != CartridgeNone)
619 {
620 soundPause();
621 vStopEmu();
622 vSetDefaultTitle();
623 vDrawDefaultScreen();
624 vSaveBattery();
625 m_stEmulator.emuCleanUp();
626 m_eCartridge = CartridgeNone;
627 emulating = 0;
629 vUpdateGameSlots();
631 for (std::list<Gtk::Widget *>::iterator it = m_listSensitiveWhenPlaying.begin();
632 it != m_listSensitiveWhenPlaying.end();
633 it++)
634 {
635 (*it)->set_sensitive(false);
636 }
638 m_poFilePauseItem->set_active(false);
639 }
640 }
642 void Window::vOnFileExit()
643 {
644 hide();
645 }
647 void Window::vOnFrameskipToggled(Gtk::CheckMenuItem * _poCMI, int _iValue)
648 {
649 if (! _poCMI->get_active())
650 {
651 return;
652 }
654 if (_iValue >= 0 && _iValue <= 9)
655 {
656 m_poCoreConfig->vSetKey("frameskip", _iValue);
657 gbFrameSkip = _iValue;
658 systemFrameSkip = _iValue;
659 m_bAutoFrameskip = false;
660 }
661 else
662 {
663 m_poCoreConfig->vSetKey("frameskip", "auto");
664 gbFrameSkip = 0;
665 systemFrameSkip = 0;
666 m_bAutoFrameskip = true;
667 }
668 }
670 void Window::vOnThrottleToggled(Gtk::CheckMenuItem * _poCMI, int _iPercent)
671 {
672 if (! _poCMI->get_active())
673 {
674 return;
675 }
677 vSetThrottle(_iPercent);
679 // Initialize the frameskip adjustment each time throttle is changed
680 if (m_bAutoFrameskip)
681 {
682 systemFrameSkip = 0;
683 }
684 }
686 void Window::vOnThrottleOther(Gtk::CheckMenuItem * _poCMI)
687 {
688 if (! _poCMI->get_active())
689 {
690 return;
691 }
693 Glib::RefPtr<Xml> poXml;
694 poXml = Xml::create(PKGDATADIR "/vba.glade", "ThrottleDialog");
696 Gtk::Dialog * poDialog = dynamic_cast<Gtk::Dialog *>(poXml->get_widget("ThrottleDialog"));
697 Gtk::SpinButton * poSpin = dynamic_cast<Gtk::SpinButton *>(poXml->get_widget("ThrottleSpin"));
699 poDialog->set_transient_for(*this);
701 if (m_iThrottle != 0)
702 {
703 poSpin->set_value(m_iThrottle);
704 }
705 else
706 {
707 poSpin->set_value(100);
708 }
710 if (poDialog->run() == Gtk::RESPONSE_OK)
711 {
712 vSetThrottle(poSpin->get_value_as_int());
713 }
715 delete poDialog;
716 vSelectBestThrottleItem();
717 }
719 void Window::vOnVideoScaleToggled(Gtk::CheckMenuItem * _poCMI, int _iScale)
720 {
721 if (! _poCMI->get_active())
722 {
723 return;
724 }
726 m_poDisplayConfig->vSetKey("scale", _iScale);
727 vUpdateScreen();
728 }
730 void Window::vOnLayerToggled(Gtk::CheckMenuItem * _poCMI, int _iLayer)
731 {
732 int iMask = (0x0100 << _iLayer);
733 if (_poCMI->get_active())
734 {
735 layerSettings |= iMask;
736 }
737 else
738 {
739 layerSettings &= ~iMask;
740 }
741 layerEnable = DISPCNT & layerSettings;
743 const char * acsLayers[] =
744 {
745 "layer_bg0",
746 "layer_bg1",
747 "layer_bg2",
748 "layer_bg3",
749 "layer_obj",
750 "layer_win0",
751 "layer_win1",
752 "layer_objwin"
753 };
754 m_poCoreConfig->vSetKey(acsLayers[_iLayer], _poCMI->get_active());
755 }
757 void Window::vOnDirectories()
758 {
759 Glib::RefPtr<Xml> poXml;
760 poXml = Xml::create(PKGDATADIR "/vba.glade", "DirectoriesDialog");
762 struct
763 {
764 const char * m_csKey;
765 const char * m_csEntry;
766 const char * m_csResetButton;
767 const char * m_csSelectButton;
768 }
769 astRow[] =
770 {
771 { "gba_roms", "GBARomsDirEntry", "GBARomsDirResetButton", "GBARomsDirSelectButton" },
772 { "gb_roms", "GBRomsDirEntry", "GBRomsDirResetButton", "GBRomsDirSelectButton" },
773 { "batteries", "BatteriesDirEntry", "BatteriesDirResetButton", "BatteriesDirSelectButton" },
774 { "saves", "SavesDirEntry", "SavesDirResetButton", "SavesDirSelectButton" },
775 { "captures", "CapturesDirEntry", "CapturesDirResetButton", "CapturesDirSelectButton" }
776 };
778 for (guint i = 0; i < G_N_ELEMENTS(astRow); i++)
779 {
780 Gtk::Entry * poEntry = dynamic_cast<Gtk::Entry *>(poXml->get_widget(astRow[i].m_csEntry));
781 Gtk::Button * poReset = dynamic_cast<Gtk::Button *>(poXml->get_widget(astRow[i].m_csResetButton));
782 Gtk::Button * poSelect = dynamic_cast<Gtk::Button *>(poXml->get_widget(astRow[i].m_csSelectButton));
784 poEntry->set_text(m_poDirConfig->sGetKey(astRow[i].m_csKey));
786 poReset->signal_clicked().connect(SigC::bind<Gtk::Entry *>(
787 SigC::slot(*this, &Window::vOnDirectoryReset),
788 poEntry));
789 poSelect->signal_clicked().connect(SigC::bind<Gtk::Entry *>(
790 SigC::slot(*this, &Window::vOnDirectorySelect),
791 poEntry));
792 }
794 Gtk::Dialog * poDialog = dynamic_cast<Gtk::Dialog *>(poXml->get_widget("DirectoriesDialog"));
795 poDialog->set_transient_for(*this);
797 if (poDialog->run() == Gtk::RESPONSE_OK)
798 {
799 for (guint i = 0; i < G_N_ELEMENTS(astRow); i++)
800 {
801 Gtk::Entry * poEntry = dynamic_cast<Gtk::Entry *>(poXml->get_widget(astRow[i].m_csEntry));
802 Glib::ustring sDir = poEntry->get_text();
803 if (! Glib::file_test(sDir, Glib::FILE_TEST_IS_DIR))
804 {
805 sDir = "";
806 }
807 m_poDirConfig->vSetKey(astRow[i].m_csKey, sDir);
808 }
810 // Needed if saves dir changed
811 vUpdateGameSlots();
812 }
814 delete poDialog;
815 }
817 void Window::vOnDirectoryReset(Gtk::Entry * _poEntry)
818 {
819 _poEntry->set_text("");
820 }
822 void Window::vOnDirectorySelect(Gtk::Entry * _poEntry)
823 {
824 #ifdef GTKMM20
826 Gtk::FileSelection oDialog(_("Select directory"));
827 oDialog.set_transient_for(*this);
829 if (_poEntry->get_text() != "")
830 {
831 oDialog.set_filename(_poEntry->get_text() + "/");
832 }
834 if (oDialog.run() == Gtk::RESPONSE_OK)
835 {
836 std::string sFile = oDialog.get_filename();
837 if (! Glib::file_test(sFile, Glib::FILE_TEST_IS_DIR))
838 {
839 sFile = Glib::path_get_dirname(sFile);
840 }
841 _poEntry->set_text(sFile);
842 }
844 #else // ! GTKMM20
846 Gtk::FileChooserDialog oDialog(*this, _("Select directory"),
847 Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
848 oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
849 oDialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
851 if (_poEntry->get_text() != "")
852 {
853 oDialog.add_shortcut_folder(_poEntry->get_text());
854 oDialog.set_current_folder(_poEntry->get_text());
855 }
857 if (oDialog.run() == Gtk::RESPONSE_OK)
858 {
859 _poEntry->set_text(oDialog.get_filename());
860 }
862 #endif // ! GTKMM20
863 }
865 void Window::vOnPauseWhenInactiveToggled(Gtk::CheckMenuItem * _poCMI)
866 {
867 m_poDisplayConfig->vSetKey("pause_when_inactive", _poCMI->get_active());
868 }
870 void Window::vOnSelectBios()
871 {
872 #ifdef GTKMM20
874 Gtk::FileSelection oDialog(_("Select BIOS file"));
875 oDialog.set_transient_for(*this);
877 if (m_poCoreConfig->sGetKey("bios_file") != "")
878 {
879 oDialog.set_filename(m_poCoreConfig->sGetKey("bios_file"));
880 }
882 #else // ! GTKMM20
884 Gtk::FileChooserDialog oDialog(*this, _("Select BIOS file"));
885 oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
886 oDialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
888 if (m_poCoreConfig->sGetKey("bios_file") != "")
889 {
890 oDialog.set_filename(m_poCoreConfig->sGetKey("bios_file"));
891 }
893 const char * acsPattern[] =
894 {
895 "*.[bB][iI][nN]", "*.[aA][gG][bB]", "*.[gG][bB][aA]",
896 "*.[bB][iI][oO][sS]", "*.[zZ][iI][pP]", "*.[zZ]", "*.[gG][zZ]"
897 };
899 Gtk::FileFilter oAllFilter;
900 oAllFilter.set_name(_("All files"));
901 oAllFilter.add_pattern("*");
903 Gtk::FileFilter oBiosFilter;
904 oBiosFilter.set_name(_("Gameboy Advance BIOS"));
905 for (guint i = 0; i < G_N_ELEMENTS(acsPattern); i++)
906 {
907 oBiosFilter.add_pattern(acsPattern[i]);
908 }
910 oDialog.add_filter(oAllFilter);
911 oDialog.add_filter(oBiosFilter);
913 oDialog.set_filter(oBiosFilter);
915 #endif // ! GTKMM20
917 while (oDialog.run() == Gtk::RESPONSE_OK)
918 {
919 if (Glib::file_test(oDialog.get_filename(), Glib::FILE_TEST_IS_REGULAR))
920 {
921 m_poCoreConfig->vSetKey("bios_file", oDialog.get_filename());
922 m_poUseBiosItem->set_sensitive();
923 break;
924 }
925 }
926 }
928 void Window::vOnUseBiosToggled(Gtk::CheckMenuItem * _poCMI)
929 {
930 m_poCoreConfig->vSetKey("use_bios_file", _poCMI->get_active());
931 }
933 void Window::vOnShowSpeedToggled(Gtk::CheckMenuItem * _poCMI, int _iShowSpeed)
934 {
935 if (! _poCMI->get_active())
936 {
937 return;
938 }
940 m_eShowSpeed = (EShowSpeed)_iShowSpeed;
941 if (m_eShowSpeed == ShowNone)
942 {
943 vSetDefaultTitle();
944 }
945 m_poDisplayConfig->vSetKey("show_speed", _iShowSpeed);
946 }
948 void Window::vOnSaveTypeToggled(Gtk::CheckMenuItem * _poCMI, int _iSaveType)
949 {
950 if (! _poCMI->get_active())
951 {
952 return;
953 }
955 cpuSaveType = _iSaveType;
956 m_poCoreConfig->vSetKey("save_type", _iSaveType);
957 }
959 void Window::vOnFlashSizeToggled(Gtk::CheckMenuItem * _poCMI, int _iFlashSize)
960 {
961 if (! _poCMI->get_active())
962 {
963 return;
964 }
966 if (_iFlashSize == 64)
967 {
968 flashSetSize(0x10000);
969 }
970 else
971 {
972 flashSetSize(0x20000);
973 }
974 m_poCoreConfig->vSetKey("flash_size", _iFlashSize);
975 }
977 void Window::vOnScreenshotFormatToggled(Gtk::CheckMenuItem * _poCMI, std::string _sFormat)
978 {
979 if (! _poCMI->get_active())
980 {
981 return;
982 }
984 m_poCoreConfig->vSetKey("screenshot_format", _sFormat);
985 }
987 void Window::vOnSoundStatusToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundStatus)
988 {
989 if (! _poCMI->get_active())
990 {
991 return;
992 }
994 std::string sSoundStatus;
995 switch (_iSoundStatus)
996 {
997 case SoundOff:
998 soundOffFlag = true;
999 if (systemSoundOn)
1001 soundShutdown();
1003 sSoundStatus = "off";
1004 break;
1005 case SoundMute:
1006 soundDisableChannels(0x30f);
1007 sSoundStatus = "mute";
1008 break;
1009 case SoundOn:
1010 if (soundOffFlag)
1012 soundOffFlag = false;
1013 if (! soundInit())
1015 m_poSoundOffItem->set_active();
1016 return;
1019 soundEnableChannels(0x30f);
1020 sSoundStatus = "on";
1021 break;
1023 m_poSoundConfig->vSetKey("status", sSoundStatus);
1026 void Window::vOnSoundEchoToggled(Gtk::CheckMenuItem * _poCMI)
1028 soundEcho = _poCMI->get_active();
1029 m_poSoundConfig->vSetKey("echo", soundEcho);
1032 void Window::vOnSoundLowPassToggled(Gtk::CheckMenuItem * _poCMI)
1034 soundLowPass = _poCMI->get_active();
1035 m_poSoundConfig->vSetKey("low_pass", soundLowPass);
1038 void Window::vOnSoundReverseToggled(Gtk::CheckMenuItem * _poCMI)
1040 soundReverse = _poCMI->get_active();
1041 m_poSoundConfig->vSetKey("reverse_stereo", soundReverse);
1044 void Window::vOnSoundChannelToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundChannel)
1046 int iShift = _iSoundChannel;
1047 if (_iSoundChannel > 3)
1049 iShift += 4;
1051 int iFlag = 1 << iShift;
1052 int iActive = soundGetEnabledChannels() & 0x30f;
1053 if (_poCMI->get_active())
1055 iActive |= iFlag;
1057 else
1059 iActive &= ~iFlag;
1061 soundEnableChannels(iActive);
1062 soundDisableChannels(~iActive & 0x30f);
1064 const char * acsChannels[] =
1066 "channel_1",
1067 "channel_2",
1068 "channel_3",
1069 "channel_4",
1070 "channel_A",
1071 "channel_B"
1072 };
1073 m_poSoundConfig->vSetKey(acsChannels[_iSoundChannel], _poCMI->get_active());
1076 void Window::vOnSoundQualityToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundQuality)
1078 if (! _poCMI->get_active())
1080 return;
1083 m_eSoundQuality = (ESoundQuality)_iSoundQuality;
1084 if (m_eCartridge == CartridgeGBA)
1086 soundSetQuality(_iSoundQuality);
1088 else if (m_eCartridge == CartridgeGB)
1090 gbSoundSetQuality(_iSoundQuality);
1092 m_poSoundConfig->vSetKey("quality", _iSoundQuality);
1095 void Window::vOnSoundVolumeToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundVolume)
1097 if (! _poCMI->get_active())
1099 return;
1102 soundVolume = _iSoundVolume;
1103 m_poSoundConfig->vSetKey("volume", _iSoundVolume);
1106 void Window::vOnGBBorderToggled(Gtk::CheckMenuItem * _poCMI)
1108 gbBorderOn = _poCMI->get_active();
1109 if (emulating && m_eCartridge == CartridgeGB && _poCMI->get_active())
1111 gbSgbRenderBorder();
1113 vUpdateScreen();
1114 m_poCoreConfig->vSetKey("gb_border", _poCMI->get_active());
1117 void Window::vOnGBPrinterToggled(Gtk::CheckMenuItem * _poCMI)
1119 if (_poCMI->get_active())
1121 gbSerialFunction = gbPrinterSend;
1123 else
1125 gbSerialFunction = NULL;
1127 m_poCoreConfig->vSetKey("gb_printer", _poCMI->get_active());
1130 void Window::vOnEmulatorTypeToggled(Gtk::CheckMenuItem * _poCMI, int _iEmulatorType)
1132 gbEmulatorType = _iEmulatorType;
1133 m_poCoreConfig->vSetKey("emulator_type", _iEmulatorType);
1136 void Window::vOnFilter2xToggled(Gtk::CheckMenuItem * _poCMI, int _iFilter2x)
1138 if (! _poCMI->get_active())
1140 return;
1143 m_poScreenArea->vSetFilter2x((EFilter2x)_iFilter2x);
1144 if (emulating)
1146 vDrawScreen();
1148 m_poDisplayConfig->vSetKey("filter2x", _iFilter2x);
1151 void Window::vOnFilterIBToggled(Gtk::CheckMenuItem * _poCMI, int _iFilterIB)
1153 if (! _poCMI->get_active())
1155 return;
1158 m_poScreenArea->vSetFilterIB((EFilterIB)_iFilterIB);
1159 if (emulating)
1161 vDrawScreen();
1163 m_poDisplayConfig->vSetKey("filterIB", _iFilterIB);
1166 #ifdef MMX
1167 void Window::vOnDisableMMXToggled(Gtk::CheckMenuItem * _poCMI)
1169 cpu_mmx = ! _poCMI->get_active();
1170 m_poDisplayConfig->vSetKey("filter_disable_mmx", _poCMI->get_active());
1172 #endif // MMX
1174 void Window::vOnJoypadConfigure(int _iJoypad)
1176 Glib::RefPtr<Xml> poXml;
1177 poXml = Xml::create(PKGDATADIR "/vba.glade", "JoypadConfigDialog");
1179 JoypadConfigDialog * poDialog = NULL;
1180 poXml->get_widget_derived<JoypadConfigDialog>("JoypadConfigDialog", poDialog);
1181 poDialog->set_transient_for(*this);
1182 poDialog->vSetConfig(m_oJoypads[_iJoypad - 1]);
1184 if (poDialog->run() == Gtk::RESPONSE_OK)
1186 m_oJoypads[_iJoypad - 1] = poDialog->stGetConfig();
1187 if (_iJoypad == m_poInputConfig->oGetKey<int>("active_joypad"))
1189 if (m_poKeymap != NULL)
1191 delete m_poKeymap;
1193 m_poKeymap = m_oJoypads[_iJoypad - 1].poCreateKeymap();
1197 delete poDialog;
1200 void Window::vOnJoypadToggled(Gtk::CheckMenuItem * _poCMI, int _iJoypad)
1202 if (! _poCMI->get_active())
1204 return;
1207 if (m_poKeymap != NULL)
1209 delete m_poKeymap;
1211 m_poKeymap = m_oJoypads[_iJoypad - 1].poCreateKeymap();
1213 m_poInputConfig->vSetKey("active_joypad", _iJoypad);
1216 void Window::vOnAutofireToggled(Gtk::CheckMenuItem * _poCMI, u32 _uiKeyFlag)
1218 if (_poCMI->get_active())
1220 m_uiAutofireState |= _uiKeyFlag;
1222 else
1224 m_uiAutofireState &= ~_uiKeyFlag;
1227 std::string sKey;
1228 if (_uiKeyFlag == KeyFlagA)
1230 sKey = "autofire_A";
1232 else if (_uiKeyFlag == KeyFlagB)
1234 sKey = "autofire_B";
1236 else if (_uiKeyFlag == KeyFlagL)
1238 sKey = "autofire_L";
1240 else if (_uiKeyFlag == KeyFlagR)
1242 sKey = "autofire_R";
1244 m_poInputConfig->vSetKey(sKey, _poCMI->get_active());
1247 void Window::vOnGDBWait()
1249 Glib::RefPtr<Xml> poXml;
1250 poXml = Xml::create(PKGDATADIR "/vba.glade", "TcpPortDialog");
1252 Gtk::Dialog * poDialog = dynamic_cast<Gtk::Dialog *>(poXml->get_widget("TcpPortDialog"));
1253 Gtk::SpinButton * poSpin = dynamic_cast<Gtk::SpinButton *>(poXml->get_widget("TcpPortSpin"));
1255 poDialog->set_transient_for(*this);
1257 int iPort = 55555;
1258 poSpin->set_value(iPort);
1260 bool bOk = false;
1261 if (poDialog->run() == Gtk::RESPONSE_OK)
1263 bOk = true;
1264 iPort = poSpin->get_value_as_int();
1266 delete poDialog;
1268 if (! bOk)
1270 return;
1273 m_eCartridge = CartridgeGBA;
1274 m_sRomFile = "gnu_stub";
1275 m_stEmulator = GBASystem;
1277 rom = (u8 *) malloc(0x2000000);
1278 workRAM = (u8 *) calloc(1, 0x40000);
1279 bios = (u8 *) calloc(1, 0x4000);
1280 internalRAM = (u8 *) calloc(1, 0x8000);
1281 paletteRAM = (u8 *) calloc(1, 0x400);
1282 vram = (u8 *) calloc(1, 0x20000);
1283 oam = (u8 *) calloc(1, 0x400);
1284 pix = (u8 *) calloc(1, 4 * m_iGBAScreenWidth * m_iGBAScreenHeight);
1285 ioMem = (u8 *) calloc(1, 0x400);
1287 useBios = m_poCoreConfig->oGetKey<bool>("use_bios_file");
1288 //CPUInit(m_poCoreConfig->sGetKey("bios_file").c_str(), useBios);
1289 CPUInit();
1290 CPUReset();
1292 for (std::list<Gtk::Widget *>::iterator it = m_listSensitiveWhenPlaying.begin();
1293 it != m_listSensitiveWhenPlaying.end();
1294 it++)
1296 (*it)->set_sensitive();
1299 if (m_poCoreConfig->oGetKey<bool>("load_game_auto"))
1301 vOnLoadGameMostRecent();
1304 vStartEmu();
1306 emulating = 1;
1308 dbgMain = remoteStubMain;
1309 dbgSignal = remoteStubSignal;
1310 dbgOutput = remoteOutput;
1311 debugger = true;
1313 remoteSetProtocol(0);
1314 remoteSetPort(iPort);
1315 remoteInit();
1318 void Window::vOnGDBLoadAndWait()
1320 bool bLoaded = false;
1322 while (m_poFileOpenDialog->run() == Gtk::RESPONSE_OK)
1324 if (bLoadROM(m_poFileOpenDialog->get_filename()))
1326 bLoaded = true;
1327 break;
1330 m_poFileOpenDialog->hide();
1332 if (! bLoaded)
1334 return;
1337 if (m_eCartridge != CartridgeGBA)
1339 vPopupError(_("Only GBA images are supported."));
1340 vOnFileClose();
1341 return;
1344 Glib::RefPtr<Xml> poXml;
1345 poXml = Xml::create(PKGDATADIR "/vba.glade", "TcpPortDialog");
1347 Gtk::Dialog * poDialog = dynamic_cast<Gtk::Dialog *>(poXml->get_widget("TcpPortDialog"));
1348 Gtk::SpinButton * poSpin = dynamic_cast<Gtk::SpinButton *>(poXml->get_widget("TcpPortSpin"));
1350 poDialog->set_transient_for(*this);
1352 int iPort = 55555;
1353 poSpin->set_value(iPort);
1355 bool bOk = false;
1356 if (poDialog->run() == Gtk::RESPONSE_OK)
1358 bOk = true;
1359 iPort = poSpin->get_value_as_int();
1361 delete poDialog;
1363 if (! bOk)
1365 return;
1368 dbgMain = remoteStubMain;
1369 dbgSignal = remoteStubSignal;
1370 dbgOutput = remoteOutput;
1371 debugger = true;
1373 remoteSetProtocol(0);
1374 remoteSetPort(iPort);
1375 remoteInit();
1378 void Window::vOnGDBBreak()
1380 if (armState)
1382 armNextPC -= 4;
1383 reg[15].I -= 4;
1385 else
1387 armNextPC -= 2;
1388 reg[15].I -= 2;
1391 debugger = true;
1394 void Window::vOnGDBDisconnect()
1396 remoteCleanUp();
1397 debugger = false;
1400 void Window::vOnHelpAbout()
1402 Glib::RefPtr<Xml> poXml;
1403 poXml = Xml::create(PKGDATADIR "/vba.glade", "AboutDialog");
1405 Gtk::Dialog * poDialog = dynamic_cast<Gtk::Dialog *>(poXml->get_widget("AboutDialog"));
1406 poDialog->set_transient_for(*this);
1408 Gtk::Image oIcon(PKGDATADIR "/vba-64.png");
1409 oIcon.show();
1410 Gtk::Container * poIconContainer = dynamic_cast<Gtk::Container *>(poXml->get_widget("AboutIconContainer"));
1411 poIconContainer->add(oIcon);
1413 Gtk::Label * poLabel = dynamic_cast<Gtk::Label *>(poXml->get_widget("VersionLabel"));
1414 poLabel->set_markup("<b><big>" PACKAGE " " VERSION "</big></b>");
1416 poDialog->run();
1417 delete poDialog;
1420 bool Window::bOnEmuIdle()
1422 if (debugger && m_stEmulator.emuHasDebugger)
1424 dbgMain();
1425 return true;
1428 if (m_uiThrottleDelay != 0)
1430 u32 uiTime = SDL_GetTicks();
1431 if (uiTime - m_uiThrottleLastTime >= m_uiThrottleDelay)
1433 m_uiThrottleDelay = 0;
1434 m_uiThrottleLastTime = uiTime;
1436 else
1438 return true;
1442 m_stEmulator.emuMain(m_stEmulator.emuCount);
1443 return true;
1446 bool Window::on_focus_in_event(GdkEventFocus * _pstEvent)
1448 if (emulating
1449 && ! m_bPaused
1450 && m_poDisplayConfig->oGetKey<bool>("pause_when_inactive"))
1452 vStartEmu();
1453 soundResume();
1455 return false;
1458 bool Window::on_focus_out_event(GdkEventFocus * _pstEvent)
1460 if (emulating
1461 && ! m_bPaused
1462 && m_poDisplayConfig->oGetKey<bool>("pause_when_inactive"))
1464 vStopEmu();
1465 soundPause();
1467 return false;
1470 bool Window::on_key_press_event(GdkEventKey * _pstEvent)
1472 EKey eKey;
1474 if ((_pstEvent->state & Gtk::AccelGroup::get_default_mod_mask())
1475 || (eKey = m_poKeymap->eGetKey(_pstEvent->hardware_keycode)) == KeyNone)
1477 return Gtk::Window::on_key_press_event(_pstEvent);
1480 switch (eKey)
1482 case KeyA:
1483 m_uiJoypadState |= KeyFlagA;
1484 break;
1485 case KeyB:
1486 m_uiJoypadState |= KeyFlagB;
1487 break;
1488 case KeySelect:
1489 m_uiJoypadState |= KeyFlagSelect;
1490 break;
1491 case KeyStart:
1492 m_uiJoypadState |= KeyFlagStart;
1493 break;
1494 case KeyRight:
1495 m_uiJoypadState |= KeyFlagRight;
1496 m_uiJoypadState &= ~KeyFlagLeft;
1497 break;
1498 case KeyLeft:
1499 m_uiJoypadState |= KeyFlagLeft;
1500 m_uiJoypadState &= ~KeyFlagRight;
1501 break;
1502 case KeyUp:
1503 m_uiJoypadState |= KeyFlagUp;
1504 m_uiJoypadState &= ~KeyFlagDown;
1505 break;
1506 case KeyDown:
1507 m_uiJoypadState |= KeyFlagDown;
1508 m_uiJoypadState &= ~KeyFlagUp;
1509 break;
1510 case KeyR:
1511 m_uiJoypadState |= KeyFlagR;
1512 break;
1513 case KeyL:
1514 m_uiJoypadState |= KeyFlagL;
1515 break;
1516 case KeySpeed:
1517 m_uiJoypadState |= KeyFlagSpeed;
1518 break;
1519 case KeyCapture:
1520 m_uiJoypadState |= KeyFlagCapture;
1521 break;
1522 case KeyNone:
1523 break;
1525 return true;
1528 bool Window::on_key_release_event(GdkEventKey * _pstEvent)
1530 EKey eKey;
1532 if ((_pstEvent->state & Gtk::AccelGroup::get_default_mod_mask())
1533 || (eKey = m_poKeymap->eGetKey(_pstEvent->hardware_keycode)) == KeyNone)
1535 return Gtk::Window::on_key_release_event(_pstEvent);
1538 switch (eKey)
1540 case KeyA:
1541 m_uiJoypadState &= ~KeyFlagA;
1542 break;
1543 case KeyB:
1544 m_uiJoypadState &= ~KeyFlagB;
1545 break;
1546 case KeySelect:
1547 m_uiJoypadState &= ~KeyFlagSelect;
1548 break;
1549 case KeyStart:
1550 m_uiJoypadState &= ~KeyFlagStart;
1551 break;
1552 case KeyRight:
1553 m_uiJoypadState &= ~KeyFlagRight;
1554 break;
1555 case KeyLeft:
1556 m_uiJoypadState &= ~KeyFlagLeft;
1557 break;
1558 case KeyUp:
1559 m_uiJoypadState &= ~KeyFlagUp;
1560 break;
1561 case KeyDown:
1562 m_uiJoypadState &= ~KeyFlagDown;
1563 break;
1564 case KeyR:
1565 m_uiJoypadState &= ~KeyFlagR;
1566 break;
1567 case KeyL:
1568 m_uiJoypadState &= ~KeyFlagL;
1569 break;
1570 case KeySpeed:
1571 m_uiJoypadState &= ~KeyFlagSpeed;
1572 break;
1573 case KeyCapture:
1574 m_uiJoypadState &= ~KeyFlagCapture;
1575 break;
1576 case KeyNone:
1577 break;
1579 return true;
1582 } // namespace VBA