diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..8d7a95cc --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,192 @@ +SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeScripts) +INCLUDE(CMakeScripts/CMakeDetermineASMCompiler.cmake) +INCLUDE(CMakeScripts/CMakeASMInformation.cmake) + +PROJECT(VBA-M ASM C CXX) + +FIND_PACKAGE ( ZLIB REQUIRED ) +FIND_PACKAGE ( PNG REQUIRED ) +FIND_PACKAGE ( OpenGL REQUIRED ) +FIND_PACKAGE ( PkgConfig REQUIRED ) + +PKG_CHECK_MODULES ( GTKMM gtkmm-2.4 ) +PKG_CHECK_MODULES ( GLIBMM glibmm-2.4 ) +PKG_CHECK_MODULES ( GLADEMM libglademm-2.4 ) +PKG_CHECK_MODULES ( PORTAUDIO portaudio-2.0 ) +PKG_CHECK_MODULES ( SDL sdl ) + +IF(${SDL_FOUND}) + SET( CAN_BUILD_VBAM 1 ) +ELSE(${SDL_FOUND}) + SET( CAN_BUILD_VBAM 0 ) +ENDIF(${SDL_FOUND}) + +IF(${GLIBMM_FOUND} AND ${GTKMM_FOUND} AND ${GLADEMM_FOUND} AND ${PORTAUDIO_FOUND}) + SET( CAN_BUILD_GVBAM 1 ) +ELSE(${GLIBMM_FOUND} AND ${GTKMM_FOUND} AND ${GLADEMM_FOUND} AND ${PORTAUDIO_FOUND}) + SET( CAN_BUILD_GVBAM 0 ) +ENDIF(${GLIBMM_FOUND} AND ${GTKMM_FOUND} AND ${GLADEMM_FOUND} AND ${PORTAUDIO_FOUND}) + +ADD_DEFINITIONS (-DHAVE_NETINET_IN_H -DHAVE_ARPA_INET_H -DHAVE_ZLIB_H -DFINAL_VERSION -DBKPT_SUPPORT -DSDL -DUSE_OPENGL -DC_CORE -DSYSCONFDIR='"/etc"') + +ADD_DEFINITIONS (-DVERSION='"1.8.0"' -DPKGDATADIR='"src/gtk"' -DPACKAGE='') + +SET( CMAKE_ASM_FLAGS "-Isrc/hq/asm/ -O1 -DELF") +SET( CMAKE_C_FLAGS "-O3") +SET( CMAKE_CXX_FLAGS "-O3") + +SET(SRC_MAIN + src/2xSaI.cpp + src/admame.cpp + src/armdis.cpp + src/bilinear.cpp + src/bios.cpp + src/Cheats.cpp + src/CheatSearch.cpp + src/EEprom.cpp src/elf.cpp + src/Flash.cpp + src/Globals.cpp + src/interframe.cpp + src/hq2x.cpp + src/Mode0.cpp + src/Mode1.cpp + src/Mode2.cpp + src/Mode3.cpp + src/Mode4.cpp + src/Mode5.cpp + src/pixel.cpp + src/remote.cpp + src/RTC.cpp + src/scanline.cpp + src/Sound.cpp + src/Sram.cpp + src/Util.cpp + src/expr.cpp + src/exprNode.cpp + src/expr-lex.cpp + src/memgzio.c +) + +SET(SRC_AGB + src/agb/agbprint.cpp + src/agb/GBA.cpp + src/agb/gbafilter.cpp + src/agb/GBAGfx.cpp + src/agb/GBA-thumb.cpp + src/agb/GBA-arm.cpp +) + +SET(SRC_DMG + src/dmg/GB.cpp + src/dmg/gbCheats.cpp + src/dmg/gbDis.cpp + src/dmg/gbGfx.cpp + src/dmg/gbGlobals.cpp + src/dmg/gbMemory.cpp + src/dmg/gbPrinter.cpp + src/dmg/gbSGB.cpp + src/dmg/gbSound.cpp + src/dmg/gb_apu/Blip_Buffer.cpp + src/dmg/gb_apu/Effects_Buffer.cpp + src/dmg/gb_apu/Gb_Apu.cpp + src/dmg/gb_apu/Gb_Apu_State.cpp + src/dmg/gb_apu/Gb_Oscs.cpp + src/dmg/gb_apu/Multi_Buffer.cpp +) + +SET(SRC_SDL + src/sdl/debugger.cpp + src/sdl/SDL.cpp + src/sdl/dummy.cpp + src/sdl/filters.cpp + src/sdl/text.cpp + src/sdl/sndSDL.cpp +) + +SET(SRC_FEX_MINI + src/fex_mini.cpp +) + +SET(SRC_HQ_C + src/hq/c/hq_implementation.cpp +) + +SET(SRC_HQ_ASM + src/hq/asm/hq3x_16.asm + src/hq/asm/hq3x_32.asm + src/hq/asm/hq4x_16.asm + src/hq/asm/hq4x_32.asm + src/hq/asm/hq3x32.cpp +) + +SET(SRC_GTK + src/gtk/configfile.cpp + src/gtk/input.cpp + src/gtk/main.cpp + src/gtk/system.cpp + src/gtk/windowcallbacks.cpp + src/gtk/filters.cpp + src/gtk/joypadconfig.cpp + src/gtk/screenarea.cpp + src/gtk/tools.cpp + src/gtk/window.cpp + src/gtk/sndPortAudio.cpp +) + +IF(CMAKE_ASM_COMPILER_LOADED) + SET(SRC_HQ ${SRC_HQ_ASM}) +ELSE(CMAKE_ASM_COMPILER_LOADED) + SET(SRC_HQ ${SRC_HQ_C}) +ENDIF(CMAKE_ASM_COMPILER_LOADED) + +include_directories( + ${GTKMM_INCLUDE_DIRS} + ${GLADEMM_INCLUDE_DIRS} + ${SDL_INCLUDE_DIR} +) + +ADD_LIBRARY ( + vbamcore + ${PROJECT_SRCS} + ${SRC_MAIN} + ${SRC_AGB} + ${SRC_DMG} + ${SRC_FEX_MINI} +) + +IF(${CAN_BUILD_VBAM}) + ADD_EXECUTABLE ( + vbam + WIN32 + MACOSX_BUNDLE + ${SRC_SDL} + ${SRC_HQ} + ) + + TARGET_LINK_LIBRARIES ( + vbam + vbamcore + ${SDL_LIBRARIES} + ${ZLIB_LIBRARY} + ${PNG_LIBRARY} + ${OPENGL_LIBRARY} + ) +ENDIF(${CAN_BUILD_VBAM}) + +IF(${CAN_BUILD_GVBAM}) + ADD_EXECUTABLE ( + gvbam + WIN32 + MACOSX_BUNDLE + ${SRC_GTK} + ) + + TARGET_LINK_LIBRARIES ( + gvbam + vbamcore + ${ZLIB_LIBRARY} + ${PNG_LIBRARY} + ${GLADEMM_LIBRARIES} + ${PORTAUDIO_LIBRARIES} + ) +ENDIF(${CAN_BUILD_GVBAM}) diff --git a/CMakeScripts/CMakeASMCompiler.cmake.in b/CMakeScripts/CMakeASMCompiler.cmake.in new file mode 100644 index 00000000..a23bcd74 --- /dev/null +++ b/CMakeScripts/CMakeASMCompiler.cmake.in @@ -0,0 +1,12 @@ +SET(CMAKE_ASM_COMPILER "@CMAKE_ASM_COMPILER@") +SET(CMAKE_ASM_COMPILER_LOADED 1) +SET(CMAKE_ASM_COMPILER_ENV_VAR "ASM") + +SET(CMAKE_ASM_SOURCE_FILE_EXTENSIONS nasm;asm;nas) +SET(CMAKE_ASM_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) +SET(CMAKE_ASM_LINKER_PREFERENCE None) +IF(UNIX) + SET(CMAKE_ASM_OUTPUT_EXTENSION .o) +ELSE(UNIX) + SET(CMAKE_ASM_OUTPUT_EXTENSION .obj) +ENDIF(UNIX) diff --git a/CMakeScripts/CMakeASMInformation.cmake b/CMakeScripts/CMakeASMInformation.cmake new file mode 100644 index 00000000..165695d4 --- /dev/null +++ b/CMakeScripts/CMakeASMInformation.cmake @@ -0,0 +1,11 @@ +IF(NOT CMAKE_ASM_COMPILE_OBJECT) + IF(UNIX AND NOT CYGWIN) + SET(CMAKE_ASM_COMPILE_OBJECT " -f elf -o ") + ENDIF(UNIX AND NOT CYGWIN) + IF(CYGWIN) + SET(CMAKE_ASM_COMPILE_OBJECT " -f gnuwin32 -o ") + ENDIF(CYGWIN) + IF(WIN32) + SET(CMAKE_ASM_COMPILE_OBJECT " -f win32 -DWIN32 -o -c ") + ENDIF(WIN32) +ENDIF(NOT CMAKE_ASM_COMPILE_OBJECT) diff --git a/CMakeScripts/CMakeDetermineASMCompiler.cmake b/CMakeScripts/CMakeDetermineASMCompiler.cmake new file mode 100644 index 00000000..edbe7bea --- /dev/null +++ b/CMakeScripts/CMakeDetermineASMCompiler.cmake @@ -0,0 +1,11 @@ +IF(NOT CMAKE_ASM_COMPILER) + FIND_PROGRAM(CMAKE_ASM_COMPILER NAMES nasm ) +ENDIF(NOT CMAKE_ASM_COMPILER) +MARK_AS_ADVANCED(CMAKE_ASM_COMPILER) + +# configure variables set in this file for fast reload later on +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/CMakeScripts/CMakeASMCompiler.cmake.in + ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeASMCompiler.cmake +IMMEDIATE) + +SET(CMAKE_ASM_COMPILER_ENV_VAR "ASM") diff --git a/src/System.h b/src/System.h index 49e8ab83..68c31502 100644 --- a/src/System.h +++ b/src/System.h @@ -127,6 +127,7 @@ extern int systemVerbose; extern int systemFrameSkip; extern int systemSaveUpdateCounter; extern int systemSpeed; +extern int systemThrottle; #define SYSTEM_SAVE_UPDATED 30 #define SYSTEM_SAVE_NOT_UPDATED 0 diff --git a/src/gtk/configfile.cpp b/src/gtk/configfile.cpp new file mode 100644 index 00000000..3b50457d --- /dev/null +++ b/src/gtk/configfile.cpp @@ -0,0 +1,262 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "configfile.h" + +#include +#include + +#include +#include + +namespace VBA +{ +namespace Config +{ + +using std::string; +using Glib::IOChannel; + +Line::Line(const string & _rsKey, const string & _rsValue) : + m_sKey(_rsKey), + m_sValue(_rsValue) +{ +} + +Section::Section(const string & _rsName) : + m_sName(_rsName) +{ +} + +bool Section::bKeyExists(const string & _rsKey) +{ + for (iterator it = begin(); it != end(); it++) + { + if (it->m_sKey == _rsKey) + { + return true; + } + } + return false; +} + +void Section::vSetKey(const string & _rsKey, const string & _rsValue) +{ + for (iterator it = begin(); it != end(); it++) + { + if (it->m_sKey == _rsKey) + { + it->m_sValue = _rsValue; + return; + } + } + push_back(Line(_rsKey, _rsValue)); +} + +string Section::sGetKey(const string & _rsKey) const +{ + for (const_iterator it = begin(); it != end(); it++) + { + if (it->m_sKey == _rsKey) + { + return it->m_sValue; + } + } + throw KeyNotFound(m_sName, _rsKey); +} + +void Section::vRemoveKey(const string & _rsKey) +{ + for (iterator it = begin(); it != end(); it++) + { + if (it->m_sKey == _rsKey) + { + erase(it); + return; + } + } +} + +File::File() +{ +} + +File::File(const string & _rsFile) +{ + vLoad(_rsFile); +} + +File::~File() +{ +} + +bool File::bSectionExists(const string & _rsName) +{ + for (iterator it = begin(); it != end(); it++) + { + if (it->sGetName() == _rsName) + { + return true; + } + } + return false; +} + +Section * File::poAddSection(const string & _rsName) +{ + Section * poSection = NULL; + for (iterator it = begin(); it != end(); it++) + { + if (it->sGetName() == _rsName) + { + poSection = &(*it); + } + } + if (poSection == NULL) + { + push_back(Section(_rsName)); + poSection = &back(); + } + return poSection; +} + +Section * File::poGetSection(const string & _rsName) +{ + for (iterator it = begin(); it != end(); it++) + { + if (it->sGetName() == _rsName) + { + return &(*it); + } + } + throw SectionNotFound(_rsName); +} + +void File::vRemoveSection(const string & _rsName) +{ + for (iterator it = begin(); it != end(); it++) + { + if (it->sGetName() == _rsName) + { + erase(it); + return; + } + } +} + +void File::vLoad(const string & _rsFile, + bool _bAddSection, + bool _bAddKey) +{ + string sBuffer = Glib::file_get_contents(_rsFile); + Section * poSection = NULL; + char ** lines = g_strsplit(sBuffer.c_str(), "\n", 0); + char * tmp; + int i = 0; + while (lines[i]) + { + if (lines[i][0] == '[') + { + if ((tmp = strchr(lines[i], ']'))) + { + *tmp = '\0'; + if (_bAddSection) + { + poSection = poAddSection(&lines[i][1]); + } + else + { + try + { + poSection = poGetSection(&lines[i][1]); + } + catch (...) + { + poSection = NULL; + } + } + } + } + else if (lines[i][0] != '#' && poSection != NULL) + { + if ((tmp = strchr(lines[i], '='))) + { + *tmp = '\0'; + tmp++; + if (_bAddKey || poSection->bKeyExists(lines[i])) + { + poSection->vSetKey(lines[i], tmp); + } + } + } + i++; + } + g_strfreev(lines); +} + +void File::vSave(const string & _rsFile) +{ + Glib::RefPtr poFile = IOChannel::create_from_file(_rsFile, "w"); + poFile->set_encoding(""); + + for (const_iterator poSection = begin(); + poSection != end(); + poSection++) + { + string sName = "[" + poSection->sGetName() + "]\n"; + poFile->write(sName); + + for (Section::const_iterator poLine = poSection->begin(); + poLine != poSection->end(); + poLine++) + { + string sLine = poLine->m_sKey + "=" + poLine->m_sValue + "\n"; + poFile->write(sLine); + } + poFile->write("\n"); + } +} + +void File::vClear() +{ + clear(); +} + +std::ostream & operator<<(std::ostream & _roOut, const File & _roFile) +{ + for (File::const_iterator poSection = _roFile.begin(); + poSection != _roFile.end(); + poSection++) + { + string sName = "[" + poSection->sGetName() + "]\n"; + _roOut << sName; + + for (Section::const_iterator poLine = poSection->begin(); + poLine != poSection->end(); + poLine++) + { + string sLine = poLine->m_sKey + "=" + poLine->m_sValue + "\n"; + _roOut << sLine; + } + _roOut << "\n"; + } + return _roOut; +} + +} // namespace Config +} // namespace VBA diff --git a/src/gtk/configfile.h b/src/gtk/configfile.h new file mode 100644 index 00000000..15b9dfc9 --- /dev/null +++ b/src/gtk/configfile.h @@ -0,0 +1,204 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_CONFIGFILE_H__ +#define __VBA_CONFIGFILE_H__ + +#include +#include +#include +#include + +namespace VBA +{ +namespace Config +{ + +class NotFound +{ +public: + virtual ~NotFound() {} + +protected: + NotFound() {} +}; + +class SectionNotFound : public NotFound +{ +public: + SectionNotFound(const std::string & _rsName) : + m_sName(_rsName) + { + } + virtual ~SectionNotFound() {} + + inline std::string sGetName() const { return m_sName; } + +private: + std::string m_sName; +}; + +class KeyNotFound : public NotFound +{ +public: + KeyNotFound(const std::string & _rsSection, const std::string & _rsKey) : + m_sSection(_rsSection), + m_sKey(_rsKey) + { + } + virtual ~KeyNotFound() {} + + inline std::string sGetSection() const { return m_sSection; } + inline std::string sGetKey() const { return m_sKey; } + +private: + std::string m_sSection; + std::string m_sKey; +}; + +class Line +{ +public: + Line(const std::string & _rsKey, const std::string & _rsValue); + + std::string m_sKey; + std::string m_sValue; +}; + +class Section : private std::list +{ +public: + explicit Section(const std::string & _rsName); + + inline std::string sGetName() const { return m_sName; } + + bool bKeyExists(const std::string & _rsKey); + void vSetKey(const std::string & _rsKey, const std::string & _rsValue); + std::string sGetKey(const std::string & _rsKey) const; + void vRemoveKey(const std::string & _rsKey); + + template + void vSetKey(const std::string & _rsKey, const T & _rValue); + + template + T oGetKey(const std::string & _rsKey) const; + + // read only + typedef std::list::const_iterator const_iterator; + inline const_iterator begin() const + { + return std::list::begin(); + } + inline const_iterator end() const + { + return std::list::end(); + } + +private: + inline iterator begin() + { + return std::list::begin(); + } + inline iterator end() + { + return std::list::end(); + } + + std::string m_sName; +}; + +class File : private std::list
+{ +public: + File(); + File(const std::string & _rsFile); + virtual ~File(); + + bool bSectionExists(const std::string & _rsName); + Section * poAddSection(const std::string & _rsName); + Section * poGetSection(const std::string & _rsName); + void vRemoveSection(const std::string & _rsName); + void vLoad(const std::string & _rsFile, + bool _bAddSection = true, + bool _bAddKey = true); + void vSave(const std::string & _rsFile); + void vClear(); + + // read only + typedef std::list
::const_iterator const_iterator; + inline const_iterator begin() const + { + return std::list
::begin(); + } + inline const_iterator end() const + { + return std::list
::end(); + } + +private: + inline iterator begin() + { + return std::list
::begin(); + } + inline iterator end() + { + return std::list
::end(); + } +}; + +// debug +std::ostream & operator<<(std::ostream & _roOut, const File & _roConfig); + +template +void Section::vSetKey(const std::string & _rsKey, const T & _rValue) +{ + std::ostringstream oOut; + oOut << _rValue; + for (iterator it = begin(); it != end(); it++) + { + if (it->m_sKey == _rsKey) + { + it->m_sValue = oOut.str(); + return; + } + } + push_back(Line(_rsKey, oOut.str())); +} + +template +T Section::oGetKey(const std::string & _rsKey) const +{ + T oValue; + for (const_iterator it = begin(); it != end(); it++) + { + if (it->m_sKey == _rsKey) + { + std::istringstream oIn(it->m_sValue); + oIn >> oValue; + return oValue; + } + } + throw KeyNotFound(m_sName, _rsKey); +} + +} // namespace Config +} // namespace VBA + + +#endif // __VBA_CONFIGFILE_H__ diff --git a/src/gtk/filters.cpp b/src/gtk/filters.cpp new file mode 100644 index 00000000..75e465de --- /dev/null +++ b/src/gtk/filters.cpp @@ -0,0 +1,57 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "filters.h" + +namespace VBA +{ + +static const Filter2x apvFilters2x[][2] = +{ + { NULL, NULL }, + { _2xSaI, _2xSaI32 }, + { Super2xSaI, Super2xSaI32 }, + { SuperEagle, SuperEagle32 }, + { Pixelate, Pixelate32 }, + { AdMame2x, AdMame2x32 }, + { Bilinear, Bilinear32 }, + { BilinearPlus, BilinearPlus32 }, + { Scanlines, Scanlines32 }, + { ScanlinesTV, ScanlinesTV32 }, + { hq2x, hq2x32 }, + { lq2x, lq2x32 } +}; + +static const FilterIB apvFiltersIB[][2] = +{ + { NULL, NULL }, + { SmartIB, SmartIB32 }, + { MotionBlurIB, MotionBlurIB32 } +}; + +Filter2x pvGetFilter2x(EFilter2x _eFilter2x, EFilterDepth _eDepth) +{ + return apvFilters2x[_eFilter2x][_eDepth]; +} + +FilterIB pvGetFilterIB(EFilterIB _eFilterIB, EFilterDepth _eDepth) +{ + return apvFiltersIB[_eFilterIB][_eDepth]; +} + +} // namespace VBA diff --git a/src/gtk/filters.h b/src/gtk/filters.h new file mode 100644 index 00000000..f174e253 --- /dev/null +++ b/src/gtk/filters.h @@ -0,0 +1,100 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_FILTERS_H__ +#define __VBA_FILTERS_H__ + +#include "../System.h" + +int Init_2xSaI(u32); + +void _2xSaI (u8 *, u32, u8 *, u8 *, u32, int, int); +void _2xSaI32 (u8 *, u32, u8 *, u8 *, u32, int, int); +void Super2xSaI (u8 *, u32, u8 *, u8 *, u32, int, int); +void Super2xSaI32 (u8 *, u32, u8 *, u8 *, u32, int, int); +void SuperEagle (u8 *, u32, u8 *, u8 *, u32, int, int); +void SuperEagle32 (u8 *, u32, u8 *, u8 *, u32, int, int); +void Pixelate (u8 *, u32, u8 *, u8 *, u32, int, int); +void Pixelate32 (u8 *, u32, u8 *, u8 *, u32, int, int); +void AdMame2x (u8 *, u32, u8 *, u8 *, u32, int, int); +void AdMame2x32 (u8 *, u32, u8 *, u8 *, u32, int, int); +void Bilinear (u8 *, u32, u8 *, u8 *, u32, int, int); +void Bilinear32 (u8 *, u32, u8 *, u8 *, u32, int, int); +void BilinearPlus (u8 *, u32, u8 *, u8 *, u32, int, int); +void BilinearPlus32(u8 *, u32, u8 *, u8 *, u32, int, int); +void Scanlines (u8 *, u32, u8 *, u8 *, u32, int, int); +void Scanlines32 (u8 *, u32, u8 *, u8 *, u32, int, int); +void ScanlinesTV (u8 *, u32, u8 *, u8 *, u32, int, int); +void ScanlinesTV32 (u8 *, u32, u8 *, u8 *, u32, int, int); +void hq2x (u8 *, u32, u8 *, u8 *, u32, int, int); +void hq2x32 (u8 *, u32, u8 *, u8 *, u32, int, int); +void lq2x (u8 *, u32, u8 *, u8 *, u32, int, int); +void lq2x32 (u8 *, u32, u8 *, u8 *, u32, int, int); + +void SmartIB (u8 *, u32, int, int); +void SmartIB32 (u8 *, u32, int, int); +void MotionBlurIB (u8 *, u32, int, int); +void MotionBlurIB32(u8 *, u32, int, int); + +namespace VBA +{ + +typedef void (*Filter2x)(u8 *, u32, u8 *, u8 *, u32, int, int); +typedef void (*FilterIB)(u8 *, u32, int, int); + +enum EFilter2x +{ + FirstFilter, + FilterNone = FirstFilter, + Filter2xSaI, + FilterSuper2xSaI, + FilterSuperEagle, + FilterPixelate, + FilterAdMame2x, + FilterBilinear, + FilterBilinearPlus, + FilterScanlines, + FilterScanlinesTV, + FilterHq2x, + FilterLq2x, + LastFilter = FilterLq2x +}; + +enum EFilterIB +{ + FirstFilterIB, + FilterIBNone = FirstFilterIB, + FilterIBSmart, + FilterIBMotionBlur, + LastFilterIB = FilterIBMotionBlur +}; + +enum EFilterDepth +{ + FilterDepth16, + FilterDepth32 +}; + +Filter2x pvGetFilter2x(EFilter2x _eFilter2x, EFilterDepth _eDepth); +FilterIB pvGetFilterIB(EFilterIB _eFilterIB, EFilterDepth _eDepth); + +} // namespace VBA + + +#endif // __VBA_FILTERS_H__ diff --git a/src/gtk/icons/vba-m.png b/src/gtk/icons/vba-m.png new file mode 100644 index 00000000..b2d68afb Binary files /dev/null and b/src/gtk/icons/vba-m.png differ diff --git a/src/gtk/input.cpp b/src/gtk/input.cpp new file mode 100644 index 00000000..5eecbf11 --- /dev/null +++ b/src/gtk/input.cpp @@ -0,0 +1,53 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "input.h" + +#include + +namespace VBA +{ + +Keymap::Keymap() +{ + m_pstTable = g_hash_table_new(g_direct_hash, g_direct_equal); + if (m_pstTable == NULL) + { + throw std::bad_alloc(); + } +} + +Keymap::~Keymap() +{ + g_hash_table_destroy(m_pstTable); +} + +void Keymap::vRegister(guint _uiVal, EKey _eKey) +{ + g_hash_table_insert(m_pstTable, + GUINT_TO_POINTER(_uiVal), + GUINT_TO_POINTER(_eKey)); +} + +void Keymap::vClear() +{ + g_hash_table_destroy(m_pstTable); + m_pstTable = g_hash_table_new(g_direct_hash, g_direct_equal); +} + +} // namespace VBA diff --git a/src/gtk/input.h b/src/gtk/input.h new file mode 100644 index 00000000..5b2b21e6 --- /dev/null +++ b/src/gtk/input.h @@ -0,0 +1,92 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_INPUT_H__ +#define __VBA_INPUT_H__ + +#include + +namespace VBA +{ + +enum EKey +{ + KeyNone, + // GBA keys + KeyA, + KeyB, + KeySelect, + KeyStart, + KeyRight, + KeyLeft, + KeyUp, + KeyDown, + KeyR, + KeyL, + // VBA extension + KeySpeed, + KeyCapture +}; + +enum EKeyFlag +{ + // GBA keys + KeyFlagA = 1 << 0, + KeyFlagB = 1 << 1, + KeyFlagSelect = 1 << 2, + KeyFlagStart = 1 << 3, + KeyFlagRight = 1 << 4, + KeyFlagLeft = 1 << 5, + KeyFlagUp = 1 << 6, + KeyFlagDown = 1 << 7, + KeyFlagR = 1 << 8, + KeyFlagL = 1 << 9, + // VBA extension + KeyFlagSpeed = 1 << 10, + KeyFlagCapture = 1 << 11, +}; + +class Keymap +{ + public: + Keymap(); + ~Keymap(); + + void vRegister(guint _uiVal, EKey _eKey); + void vClear(); + inline EKey eGetKey(guint _uiVal); + + private: + GHashTable * m_pstTable; + + // noncopyable + Keymap(const Keymap &); + Keymap & operator=(const Keymap &); +}; + +inline EKey Keymap::eGetKey(guint _uiVal) +{ + return (EKey)GPOINTER_TO_UINT(g_hash_table_lookup(m_pstTable, + GUINT_TO_POINTER(_uiVal))); +} + +} // namespace VBA + + +#endif // __VBA_INPUT_H__ diff --git a/src/gtk/intl.h b/src/gtk/intl.h new file mode 100644 index 00000000..4247fb18 --- /dev/null +++ b/src/gtk/intl.h @@ -0,0 +1,38 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_INTL_H__ +#define __VBA_INTL_H__ + +#ifdef ENABLE_NLS +# include +# define _(String) gettext(String) +# define N_(String) (String) +#else +# define _(String) (String) +# define N_(String) (String) +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,String) (String) +# define dcgettext(Domain,String,Type) (String) +# define bindtextdomain(Domain,Directory) (Domain) +#endif + + +#endif // __VBA_INTL_H__ diff --git a/src/gtk/joypadconfig.cpp b/src/gtk/joypadconfig.cpp new file mode 100644 index 00000000..56202232 --- /dev/null +++ b/src/gtk/joypadconfig.cpp @@ -0,0 +1,276 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "joypadconfig.h" + +#include + +#include "intl.h" + +namespace VBA +{ + +guint * JoypadConfig::puiAt(int _iIndex) +{ + guint * puiMember; + + switch (_iIndex) + { + case 0: + puiMember = &m_uiUp; + break; + case 1: + puiMember = &m_uiDown; + break; + case 2: + puiMember = &m_uiLeft; + break; + case 3: + puiMember = &m_uiRight; + break; + case 4: + puiMember = &m_uiA; + break; + case 5: + puiMember = &m_uiB; + break; + case 6: + puiMember = &m_uiL; + break; + case 7: + puiMember = &m_uiR; + break; + case 8: + puiMember = &m_uiSelect; + break; + case 9: + puiMember = &m_uiStart; + break; + case 10: + puiMember = &m_uiSpeed; + break; + case 11: + puiMember = &m_uiCapture; + break; + default: + puiMember = NULL; + } + + return puiMember; +} + +int JoypadConfig::iFind(guint _uiKeycode) +{ + for (guint i = 0; i < 12; i++) + { + if (*puiAt(i) == _uiKeycode) + { + return i; + } + } + + return -1; +} + +void JoypadConfig::vSetDefault() +{ + guint auiKeyval[] = + { + GDK_Up, GDK_Down, GDK_Left, GDK_Right, + GDK_z, GDK_x, GDK_a, GDK_s, + GDK_BackSpace, GDK_Return, + GDK_space, GDK_F12 + }; + + for (guint i = 0; i < G_N_ELEMENTS(auiKeyval); i++) + { + GdkKeymapKey * pstKeys; + int iKeys; + + if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), + auiKeyval[i], + &pstKeys, + &iKeys)) + { + *puiAt(i) = pstKeys[0].keycode; + g_free(pstKeys); + } + else + { + *puiAt(i) = 0; + } + } +} + +Keymap * JoypadConfig::poCreateKeymap() const +{ + Keymap * poKeymap = new Keymap(); + + poKeymap->vRegister(m_uiUp, KeyUp ); + poKeymap->vRegister(m_uiDown, KeyDown ); + poKeymap->vRegister(m_uiLeft, KeyLeft ); + poKeymap->vRegister(m_uiRight, KeyRight ); + poKeymap->vRegister(m_uiA, KeyA ); + poKeymap->vRegister(m_uiB, KeyB ); + poKeymap->vRegister(m_uiL, KeyL ); + poKeymap->vRegister(m_uiR, KeyR ); + poKeymap->vRegister(m_uiSelect, KeySelect ); + poKeymap->vRegister(m_uiStart, KeyStart ); + poKeymap->vRegister(m_uiSpeed, KeySpeed ); + poKeymap->vRegister(m_uiCapture, KeyCapture ); + + return poKeymap; +} + +JoypadConfigDialog::JoypadConfigDialog(GtkDialog * _pstDialog, + const Glib::RefPtr & _poXml) : + Gtk::Dialog(_pstDialog) +{ + m_puiCurrentKeyCode = NULL; + + memset(&m_oConfig, 0, sizeof(m_oConfig)); + + m_poOkButton = dynamic_cast(_poXml->get_widget("JoypadOkButton")); + + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadUpEntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadDownEntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadLeftEntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadRightEntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadAEntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadBEntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadLEntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadREntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadSelectEntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadStartEntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadSpeedEntry"))); + m_oEntries.push_back(dynamic_cast(_poXml->get_widget("JoypadCaptureEntry"))); + + for (guint i = 0; i < m_oEntries.size(); i++) + { + Gtk::Entry * poEntry = m_oEntries[i]; + + poEntry->signal_focus_in_event().connect(sigc::bind( + sigc::mem_fun(*this, &JoypadConfigDialog::bOnEntryFocusIn), + i)); + poEntry->signal_focus_out_event().connect(sigc::mem_fun(*this, &JoypadConfigDialog::bOnEntryFocusOut)); + } + + vUpdateEntries(); +} + +JoypadConfigDialog::~JoypadConfigDialog() +{ +} + +void JoypadConfigDialog::vSetConfig(const JoypadConfig & _roConfig) +{ + m_oConfig = _roConfig; + vUpdateEntries(); +} + +void JoypadConfigDialog::vUpdateEntries() +{ + for (guint i = 0; i < m_oEntries.size(); i++) + { + guint uiKeyval = 0; + gdk_keymap_translate_keyboard_state(gdk_keymap_get_default(), + *m_oConfig.puiAt(i), + (GdkModifierType)0, + 0, + &uiKeyval, + NULL, + NULL, + NULL); + const char * csName = gdk_keyval_name(uiKeyval); + if (csName == NULL) + { + m_oEntries[i]->set_text(_("")); + } + else + { + m_oEntries[i]->set_text(csName); + } + } +} + +bool JoypadConfigDialog::bOnEntryFocusIn(GdkEventFocus * _pstEvent, + guint _uiEntry) +{ + m_uiCurrentEntry = _uiEntry; + m_puiCurrentKeyCode = m_oConfig.puiAt(_uiEntry); + + return false; +} + +bool JoypadConfigDialog::bOnEntryFocusOut(GdkEventFocus * _pstEvent) +{ + m_puiCurrentKeyCode = NULL; + + return false; +} + +bool JoypadConfigDialog::on_key_press_event(GdkEventKey * _pstEvent) +{ + if (m_puiCurrentKeyCode == NULL) + { + return Gtk::Dialog::on_key_press_event(_pstEvent); + } + + *m_puiCurrentKeyCode = 0; + int iFound = m_oConfig.iFind(_pstEvent->hardware_keycode); + if (iFound >= 0) + { + *m_oConfig.puiAt(iFound) = 0; + m_oEntries[iFound]->set_text(_("")); + } + + *m_puiCurrentKeyCode = _pstEvent->hardware_keycode; + + guint uiKeyval = 0; + gdk_keymap_translate_keyboard_state(gdk_keymap_get_default(), + _pstEvent->hardware_keycode, + (GdkModifierType)0, + 0, + &uiKeyval, + NULL, + NULL, + NULL); + + const char * csName = gdk_keyval_name(uiKeyval); + if (csName == NULL) + { + m_oEntries[m_uiCurrentEntry]->set_text(_("")); + } + else + { + m_oEntries[m_uiCurrentEntry]->set_text(csName); + } + + if (m_uiCurrentEntry + 1 < m_oEntries.size()) + { + m_oEntries[m_uiCurrentEntry + 1]->grab_focus(); + } + else + { + m_poOkButton->grab_focus(); + } + + return true; +} + +} // namespace VBA diff --git a/src/gtk/joypadconfig.h b/src/gtk/joypadconfig.h new file mode 100644 index 00000000..8fb860c6 --- /dev/null +++ b/src/gtk/joypadconfig.h @@ -0,0 +1,84 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_JOYPADCONFIG_H__ +#define __VBA_JOYPADCONFIG_H__ + +#include + +#include +#include + +#include "input.h" + +namespace VBA +{ + +class JoypadConfig +{ +public: + guint m_uiUp; + guint m_uiDown; + guint m_uiLeft; + guint m_uiRight; + guint m_uiA; + guint m_uiB; + guint m_uiL; + guint m_uiR; + guint m_uiSelect; + guint m_uiStart; + guint m_uiSpeed; + guint m_uiCapture; + + guint * puiAt(int _iIndex); + int iFind(guint _uiKeycode); + void vSetDefault(); + Keymap * poCreateKeymap() const; +}; + +class JoypadConfigDialog : public Gtk::Dialog +{ +public: + JoypadConfigDialog(GtkDialog * _pstDialog, + const Glib::RefPtr & _poXml); + virtual ~JoypadConfigDialog(); + + void vSetConfig(const JoypadConfig & _roConfig); + inline JoypadConfig stGetConfig() const { return m_oConfig; } + +protected: + bool bOnEntryFocusIn(GdkEventFocus * _pstEvent, guint _uiEntry); + bool bOnEntryFocusOut(GdkEventFocus * _pstEvent); + + bool on_key_press_event(GdkEventKey * _pstEvent); + +private: + JoypadConfig m_oConfig; + Gtk::Button * m_poOkButton; + std::vector m_oEntries; + guint * m_puiCurrentKeyCode; + guint m_uiCurrentEntry; + + void vUpdateEntries(); +}; + +} // namespace VBA + + +#endif // __VBA_JOYPADCONFIG_H__ diff --git a/src/gtk/main.cpp b/src/gtk/main.cpp new file mode 100644 index 00000000..a0fd6a3c --- /dev/null +++ b/src/gtk/main.cpp @@ -0,0 +1,159 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include +#include "../getopt.h" + +#include + +#include +#include +#include +#include + +#include "window.h" +#include "intl.h" + +using Gnome::Glade::Xml; + +static const char * csProgramName; + +static int iShowHelp; +static int iShowVersion; + +// Non-characters used for long options that have no equivalent short option +enum +{ + IGNORED_OPTION = CHAR_MAX + 1 +}; + +static const char csShortOptions[] = "V"; + +static const struct option astLongOptions[] = +{ + { "help", no_argument, &iShowHelp, IGNORED_OPTION }, + { "version", no_argument, NULL, 'V' }, + { 0, 0, 0, 0 } +}; + +static void vUsage(int iStatus) +{ + if (iStatus != 0) + { + g_printerr(_("Try `%s --help' for more information.\n"), csProgramName); + } + else + { + g_print(_("Usage: %s [option ...] [file]\n"), csProgramName); + g_print(_("\ +\n\ +Options:\n\ + --help Output this help.\n\ + -V, --version Output version information.\n\ +")); + } + + exit(iStatus); +} + +static void vSetDefaultWindowIcon() +{ + Glib::RefPtr pixBuf= Gdk::Pixbuf::create_from_file(PKGDATADIR "/icons/vba-m.png"); + Gtk::Window::set_default_icon(pixBuf); +} + +int main(int argc, char * argv[]) +{ + csProgramName = argv[0]; + +#ifdef ENABLE_NLS + setlocale(LC_ALL, ""); + bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); + textdomain(GETTEXT_PACKAGE); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); +#endif // ENABLE_NLS + + Gtk::Main oKit(argc, argv); + + int iOpt; + while ((iOpt = getopt_long(argc, argv, csShortOptions, astLongOptions, NULL)) + != -1) + { + switch (iOpt) + { + case 'V': + iShowVersion = 1; + break; + case 0: + // Long options + break; + default: + vUsage(1); + break; + } + } + + if (iShowVersion) + { + g_print(_("VisualBoyAdvance version %s [GTK+]\n"), VERSION); + exit(0); + } + + if (iShowHelp) + { + vUsage(0); + } + + vSetDefaultWindowIcon(); + + Glib::RefPtr poXml; + try + { + poXml = Xml::create(PKGDATADIR "/vba.glade", "MainWindow"); + } + catch (const Xml::Error & e) + { + Gtk::MessageDialog oDialog(e.what(), + false, + Gtk::MESSAGE_ERROR, + Gtk::BUTTONS_OK); + oDialog.run(); + return 1; + } + + VBA::Window * poWindow = NULL; + poXml->get_widget_derived("MainWindow", poWindow); + + if (optind < argc) + { + // Display the window before loading the file + poWindow->show(); + while (Gtk::Main::events_pending()) + { + Gtk::Main::iteration(); + } + + poWindow->bLoadROM(argv[optind]); + } + + Gtk::Main::run(*poWindow); + delete poWindow; + + return 0; +} diff --git a/src/gtk/menuitem.h b/src/gtk/menuitem.h new file mode 100644 index 00000000..6d3f3573 --- /dev/null +++ b/src/gtk/menuitem.h @@ -0,0 +1,76 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_MENUITEM_H__ +#define __VBA_MENUITEM_H__ + +#include +#include + +namespace VBA +{ + +class MenuItem : public Gtk::MenuItem +{ +public: + MenuItem() + {} + + MenuItem(Gtk::Widget & _roWidget) : + Gtk::MenuItem(_roWidget) + {} + + MenuItem(const Glib::ustring & _rsLabel, bool _bMnemonic = false) : + Gtk::MenuItem(_rsLabel, _bMnemonic) + {} + + inline void set_accel_key(const Gtk::AccelKey & _roAccelKey) + { + Gtk::MenuItem::set_accel_key(_roAccelKey); + } +}; + +class ImageMenuItem : public Gtk::ImageMenuItem +{ +public: + ImageMenuItem() + {} + + ImageMenuItem(Widget & _roImage, const Glib::ustring & _rsLabel, bool _bMnemonic = false) : + Gtk::ImageMenuItem(_roImage, _rsLabel, _bMnemonic) + {} + + ImageMenuItem(const Glib::ustring & _rsLabel, bool _bMnemonic = false) : + Gtk::ImageMenuItem(_rsLabel, _bMnemonic) + {} + + ImageMenuItem(const Gtk::StockID & _roId) : + Gtk::ImageMenuItem(_roId) + {} + + inline void set_accel_key(const Gtk::AccelKey & _roAccelKey) + { + Gtk::MenuItem::set_accel_key(_roAccelKey); + } +}; + +} // namespace VBA + + +#endif // __VBA_MENUITEM_H__ diff --git a/src/gtk/screenarea.cpp b/src/gtk/screenarea.cpp new file mode 100644 index 00000000..ee4f494a --- /dev/null +++ b/src/gtk/screenarea.cpp @@ -0,0 +1,293 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "screenarea.h" + +#include + +namespace VBA +{ + +ScreenArea::ScreenArea(int _iWidth, int _iHeight, int _iScale) : + m_puiPixels(NULL), + m_puiDelta(NULL), + m_vFilter2x(NULL), + m_vFilterIB(NULL), + m_bShowCursor(true) +{ + g_assert(_iWidth >= 1 && _iHeight >= 1 && _iScale >= 1); + + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iScale = _iScale; + vUpdateSize(); + + set_events(Gdk::EXPOSURE_MASK + | Gdk::POINTER_MOTION_MASK + | Gdk::ENTER_NOTIFY_MASK + | Gdk::LEAVE_NOTIFY_MASK); + + char aiEmptyData[8]; + memset(aiEmptyData, 0, sizeof(aiEmptyData)); + Glib::RefPtr poSource = Gdk::Bitmap::create(aiEmptyData, 8, 8); + Glib::RefPtr poMask = Gdk::Bitmap::create(aiEmptyData, 8, 8); + Gdk::Color oFg; + Gdk::Color oBg; + oFg.set_rgb(0, 0, 0); + oBg.set_rgb(0, 0, 0); + + m_poEmptyCursor = new Gdk::Cursor(poSource, poMask, oFg, oBg, 0, 0); +} + +ScreenArea::~ScreenArea() +{ + if (m_puiPixels != NULL) + { + delete[] m_puiPixels; + } + + if (m_puiDelta != NULL) + { + delete[] m_puiDelta; + } + + if (m_poEmptyCursor != NULL) + { + delete m_poEmptyCursor; + } +} + +void ScreenArea::vSetSize(int _iWidth, int _iHeight) +{ + g_return_if_fail(_iWidth >= 1 && _iHeight >= 1); + + if (_iWidth != m_iWidth || _iHeight != m_iHeight) + { + m_iWidth = _iWidth; + m_iHeight = _iHeight; + vUpdateSize(); + } +} + +void ScreenArea::vSetScale(int _iScale) +{ + g_return_if_fail(_iScale >= 1); + + if (_iScale != m_iScale) + { + m_iScale = _iScale; + vUpdateSize(); + } +} + +void ScreenArea::vSetFilter2x(EFilter2x _eFilter2x) +{ + m_vFilter2x = pvGetFilter2x(_eFilter2x, FilterDepth32); +} + +void ScreenArea::vSetFilterIB(EFilterIB _eFilterIB) +{ + m_vFilterIB = pvGetFilterIB(_eFilterIB, FilterDepth32); +} + +void ScreenArea::vDrawPixels(u8 * _puiData) +{ + if (m_vFilterIB != NULL) + { + m_vFilterIB(_puiData + m_iAreaWidth * 2 + 4, + m_iAreaWidth * 2 + 4, + m_iWidth, + m_iHeight); + } + + if (m_iScale == 1) + { + u32 * puiSrc = (u32 *)_puiData + m_iWidth + 1; + u32 * puiPixel = m_puiPixels; + for (int y = 0; y < m_iHeight; y++) + { + for (int x = 0; x < m_iWidth; x++) + { + *puiPixel++ = *puiSrc++; + } + puiSrc++; + } + } + else if (m_iScale == 2 && m_vFilter2x != NULL) + { + m_vFilter2x(_puiData + m_iAreaWidth * 2 + 4, + m_iAreaWidth * 2 + 4, + m_puiDelta, + (u8 *)m_puiPixels, + m_iRowStride, + m_iWidth, + m_iHeight); + } + else + { + u32 * puiSrc = (u32 *)_puiData + m_iWidth + 1; + u32 * puiSrc2; + u32 * puiPixel = m_puiPixels; + for (int y = 0; y < m_iHeight; y++) + { + for (int j = 0; j < m_iScale; j++) + { + puiSrc2 = puiSrc; + for (int x = 0; x < m_iWidth; x++) + { + for (int i = 0; i < m_iScale; i++) + { + *puiPixel++ = *puiSrc2; + } + puiSrc2++; + } + } + puiSrc = puiSrc2 + 1; + } + } + + queue_draw_area(0, 0, m_iAreaWidth, m_iAreaHeight); +} + +void ScreenArea::vDrawColor(u32 _uiColor) +{ + _uiColor = GUINT32_TO_BE(_uiColor) << 8; + + u32 * puiPixel = m_puiPixels; + u32 * puiEnd = m_puiPixels + m_iAreaWidth * m_iAreaHeight; + while (puiPixel != puiEnd) + { + *puiPixel++ = _uiColor; + } + + queue_draw_area(0, 0, m_iAreaWidth, m_iAreaHeight); +} + +void ScreenArea::vUpdateSize() +{ + if (m_puiPixels != NULL) + { + delete[] m_puiPixels; + } + + if (m_puiDelta != NULL) + { + delete[] m_puiDelta; + } + + m_iAreaWidth = m_iScale * m_iWidth; + m_iAreaHeight = m_iScale * m_iHeight; + m_iRowStride = m_iAreaWidth * 4; + + m_puiPixels = new u32[m_iAreaWidth * m_iAreaHeight]; + + m_puiDelta = new u8[(m_iWidth + 2) * (m_iHeight + 2) * 4]; + memset(m_puiDelta, 255, (m_iWidth + 2) * (m_iHeight + 2) * 4); + + set_size_request(m_iAreaWidth, m_iAreaHeight); +} + +void ScreenArea::vStartCursorTimeout() +{ + m_oCursorSig.disconnect(); + m_oCursorSig = Glib::signal_timeout().connect( + sigc::mem_fun(*this, &ScreenArea::bOnCursorTimeout), + 2000); +} + +void ScreenArea::vStopCursorTimeout() +{ + m_oCursorSig.disconnect(); +} + +void ScreenArea::vHideCursor() +{ + get_window()->set_cursor(*m_poEmptyCursor); + m_bShowCursor = false; +} + +void ScreenArea::vShowCursor() +{ + get_window()->set_cursor(); + m_bShowCursor = true; +} + +bool ScreenArea::on_expose_event(GdkEventExpose * _pstEvent) +{ + if (_pstEvent->area.x + _pstEvent->area.width > m_iAreaWidth + || _pstEvent->area.y + _pstEvent->area.height > m_iAreaHeight) + { + return false; + } + + guchar * puiAreaPixels = (guchar *)m_puiPixels; + + if (_pstEvent->area.x != 0) + { + puiAreaPixels += _pstEvent->area.x << 2; + } + + if (_pstEvent->area.y != 0) + { + puiAreaPixels += _pstEvent->area.y * m_iRowStride; + } + + get_window()->draw_rgb_32_image(get_style()->get_fg_gc(get_state()), + _pstEvent->area.x, + _pstEvent->area.y, + _pstEvent->area.width, + _pstEvent->area.height, + Gdk::RGB_DITHER_MAX, + puiAreaPixels, + m_iRowStride); + return true; +} + +bool ScreenArea::on_motion_notify_event(GdkEventMotion * _pstEvent) +{ + if (! m_bShowCursor) + { + vShowCursor(); + } + vStartCursorTimeout(); + return false; +} + +bool ScreenArea::on_enter_notify_event(GdkEventCrossing * _pstEvent) +{ + vStartCursorTimeout(); + return false; +} + +bool ScreenArea::on_leave_notify_event(GdkEventCrossing * _pstEvent) +{ + vStopCursorTimeout(); + if (! m_bShowCursor) + { + vShowCursor(); + } + return false; +} + +bool ScreenArea::bOnCursorTimeout() +{ + vHideCursor(); + return false; +} + +} // namespace VBA diff --git a/src/gtk/screenarea.h b/src/gtk/screenarea.h new file mode 100644 index 00000000..983dcc9d --- /dev/null +++ b/src/gtk/screenarea.h @@ -0,0 +1,77 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_SCREENAREA_H__ +#define __VBA_SCREENAREA_H__ + +#include +#include + +#include "filters.h" + +namespace VBA +{ + +class ScreenArea : public Gtk::DrawingArea +{ +public: + ScreenArea(int _iWidth, int _iHeight, int _iScale = 1); + virtual ~ScreenArea(); + + void vSetSize(int _iWidth, int _iHeight); + void vSetScale(int _iScale); + void vSetFilter2x(EFilter2x _eFilter2x); + void vSetFilterIB(EFilterIB _eFilterIB); + void vDrawPixels(u8 * _puiData); + void vDrawColor(u32 _uiColor); // 0xRRGGBB + +protected: + virtual bool on_expose_event(GdkEventExpose * _pstEvent); + virtual bool on_motion_notify_event(GdkEventMotion * _pstEvent); + virtual bool on_enter_notify_event(GdkEventCrossing * _pstEvent); + virtual bool on_leave_notify_event(GdkEventCrossing * _pstEvent); + virtual bool bOnCursorTimeout(); + +private: + int m_iWidth; + int m_iHeight; + int m_iScale; + int m_iAreaWidth; + int m_iAreaHeight; + int m_iRowStride; + u32 * m_puiPixels; + u8 * m_puiDelta; + Filter2x m_vFilter2x; + FilterIB m_vFilterIB; + + bool m_bShowCursor; + Gdk::Cursor * m_poEmptyCursor; + SigC::Connection m_oCursorSig; + + void vUpdateSize(); + void vStartCursorTimeout(); + void vStopCursorTimeout(); + void vHideCursor(); + void vShowCursor(); +}; + +} // namespace VBA + + +#endif // __VBA_SCREENAREA_H__ diff --git a/src/gtk/system.cpp b/src/gtk/system.cpp new file mode 100644 index 00000000..a6aaf688 --- /dev/null +++ b/src/gtk/system.cpp @@ -0,0 +1,179 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include +#include + +#include "../agb/GBA.h" +#include "../dmg/gb.h" +#include "../dmg/gbGlobals.h" +#include "../Util.h" +#include "../Sound.h" + +#include "window.h" +#include "intl.h" + +// Required vars, used by the emulator core +// +int systemRedShift; +int systemGreenShift; +int systemBlueShift; +int systemColorDepth; +int systemDebug; +int systemVerbose; +int systemSaveUpdateCounter; +int systemFrameSkip; +u32 systemColorMap32[0x10000]; +u16 systemColorMap16[0x10000]; +u16 systemGbPalette[24]; +int systemThrottle = 0; + +int emulating; +bool debugger; +int RGB_LOW_BITS_MASK; + +// Extra vars, only used for the GUI +// +int systemRenderedFrames; +int systemFPS; + +inline VBA::Window * GUI() +{ + return VBA::Window::poGetInstance(); +} + +void systemMessage(int _iId, const char * _csFormat, ...) +{ + va_list args; + va_start(args, _csFormat); + + GUI()->vPopupErrorV(_(_csFormat), args); + + va_end(args); +} + +void systemDrawScreen() +{ + GUI()->vDrawScreen(); + systemRenderedFrames++; +} + +bool systemReadJoypads() +{ + return true; +} + +u32 systemReadJoypad(int) +{ + return GUI()->uiReadJoypad(); +} + +void systemShowSpeed(int _iSpeed) +{ + systemFPS = systemRenderedFrames; + systemRenderedFrames = 0; + + GUI()->vShowSpeed(_iSpeed); +} + +void system10Frames(int _iRate) +{ + GUI()->vComputeFrameskip(_iRate); +} + +void systemFrame() +{ +} + +void systemSetTitle(const char * _csTitle) +{ + GUI()->set_title(_csTitle); +} + +void systemScreenCapture(int _iNum) +{ + GUI()->vCaptureScreen(_iNum); +} + +u32 systemGetClock() +{ + Glib::TimeVal time; + time.assign_current_time(); + return time.as_double() * 1000; +} + +void systemUpdateMotionSensor() +{ +} + +int systemGetSensorX() +{ + return 0; +} + +int systemGetSensorY() +{ + return 0; +} + +void systemGbPrint(u8 * _puiData, + int _iPages, + int _iFeed, + int _iPalette, + int _iContrast) +{ +} + +void systemScreenMessage(const char * _csMsg) +{ +} + +bool systemCanChangeSoundQuality() +{ + return true; +} + +bool systemPauseOnFrame() +{ + return false; +} + +void systemGbBorderOn() +{ +} + +void debuggerMain() +{ +} + +void debuggerSignal(int, int) +{ +} + +void debuggerOutput(const char *, u32) +{ +} + +void debuggerBreakOnWrite(u32 address, u32 oldvalue, u32 value, int size, int t) +{ +} + +void (*dbgMain)() = debuggerMain; +void (*dbgSignal)(int, int) = debuggerSignal; +void (*dbgOutput)(const char *, u32) = debuggerOutput; diff --git a/src/gtk/tools.cpp b/src/gtk/tools.cpp new file mode 100644 index 00000000..6e1a0650 --- /dev/null +++ b/src/gtk/tools.cpp @@ -0,0 +1,65 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "tools.h" + +namespace VBA +{ + +std::string sCutSuffix(const std::string & _rsString, + const std::string & _rsSep) +{ + return _rsString.substr(0, _rsString.find_last_of(_rsSep)); +} + +Glib::ustring sCutSuffix(const Glib::ustring & _rsString, + const Glib::ustring & _rsSep) +{ + return _rsString.substr(0, _rsString.find_last_of(_rsSep)); +} + +bool bHasSuffix(const Glib::ustring & _rsString, + const Glib::ustring & _rsSuffix, + bool _bCaseSensitive) +{ + if (_rsSuffix.size() > _rsString.size()) + { + return false; + } + + Glib::ustring sEnd = _rsString.substr(_rsString.size() - _rsSuffix.size()); + + if (_bCaseSensitive) + { + if (_rsSuffix == sEnd) + { + return true; + } + } + else + { + if (_rsSuffix.lowercase() == sEnd.lowercase()) + { + return true; + } + } + + return false; +} + +} // namespace VBA diff --git a/src/gtk/tools.h b/src/gtk/tools.h new file mode 100644 index 00000000..6dca2288 --- /dev/null +++ b/src/gtk/tools.h @@ -0,0 +1,42 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_TOOLS_H__ +#define __VBA_TOOLS_H__ + +#include +#include + +namespace VBA +{ + +std::string sCutSuffix(const std::string & _rsString, + const std::string & _rsSep = "."); + +Glib::ustring sCutSuffix(const Glib::ustring & _rsString, + const Glib::ustring & _rsSep = "."); + +bool bHasSuffix(const Glib::ustring & _rsString, + const Glib::ustring & _rsSuffix, + bool _bCaseSensitive = true); + +} + + +#endif // __VBA_TOOLS_H__ diff --git a/src/gtk/vba.glade b/src/gtk/vba.glade new file mode 100644 index 00000000..16e7725a --- /dev/null +++ b/src/gtk/vba.glade @@ -0,0 +1,3569 @@ + + + + + + + VBA + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + + + + True + False + 0 + + + + True + GTK_SHADOW_OUT + GTK_POS_LEFT + GTK_POS_TOP + + + + True + + + + True + _File + True + + + + + + + True + _Open... + True + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + _Load... + True + + + + + + + True + _Save... + True + + + + + + + True + Loa_d game + True + + + + + + + True + Most recent + True + + + + + + True + Auto load most recent + True + False + + + + + + True + + + + + + True + Slot1 + True + + + + + + + True + Slot2 + True + + + + + + + True + Slot3 + True + + + + + + + True + Slot4 + True + + + + + + + True + Slot5 + True + + + + + + + True + Slot6 + True + + + + + + + True + Slot7 + True + + + + + + + True + Slot8 + True + + + + + + + True + Slot9 + True + + + + + + + True + Slot10 + True + + + + + + + + + + + True + S_ave game + True + + + + + + + True + Oldest slot + True + + + + + + True + + + + + + True + Slot1 + True + + + + + + + True + Slot2 + True + + + + + + + True + Slot3 + True + + + + + + + True + Slot4 + True + + + + + + + True + Slot5 + True + + + + + + + True + Slot6 + True + + + + + + + True + Slot7 + True + + + + + + + True + Slot8 + True + + + + + + + True + Slot9 + True + + + + + + + True + Slot10 + True + + + + + + + + + + + True + + + + + + True + _Pause + True + False + + + + + + + True + _Reset + True + + + + + + + True + + + + + + True + Rece_nt + True + + + + + + + True + _Reset + True + + + + + + True + _Freeze + True + False + + + + + + True + + + + + + + + + + True + + + + + + True + _Import + True + + + + + + + True + _Battery file... + True + + + + + + + + + + True + E_xport + True + + + + + + + True + _Battery file... + True + + + + + + + + + + True + + + + + + True + Screen capt_ure... + True + + + + + + True + + + + + + True + _Close + True + + + + True + gtk-close + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _Exit + True + + + + + True + gtk-quit + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Options + True + + + + + + + True + _Frameskip + True + + + + + + + True + _Throttle + True + + + + + + + True + _No throttle + True + True + + + + + + True + 25% + True + False + ThrottleNoThrottle + + + + + + True + 50% + True + False + ThrottleNoThrottle + + + + + + True + 100% + True + False + ThrottleNoThrottle + + + + + + True + 150% + True + False + ThrottleNoThrottle + + + + + + True + 200% + True + False + ThrottleNoThrottle + + + + + + True + _Other... + True + False + ThrottleNoThrottle + + + + + + + + + + True + + + + + + True + _Automatic + True + True + + + + + + True + _0 + True + False + FrameskipAutomatic + + + + + + True + _1 + True + False + FrameskipAutomatic + + + + + + True + _2 + True + False + FrameskipAutomatic + + + + + + True + _3 + True + False + FrameskipAutomatic + + + + + + True + _4 + True + False + FrameskipAutomatic + + + + + + True + _5 + True + False + FrameskipAutomatic + + + + + + True + _6 + True + False + FrameskipAutomatic + + + + + + True + _7 + True + False + FrameskipAutomatic + + + + + + True + _8 + True + False + FrameskipAutomatic + + + + + + True + _9 + True + False + FrameskipAutomatic + + + + + + + + + + True + _Video + True + + + + + + + True + _1x + True + True + + + + + + True + _2x + True + False + Video1x + + + + + + True + _3x + True + False + Video1x + + + + + + True + _4x + True + False + Video1x + + + + + + True + _5x + True + False + Video1x + + + + + + True + _6x + True + False + Video1x + + + + + + True + + + + + + True + _Layers + True + + + + + + + True + BG0 + True + False + + + + + + + True + BG1 + True + False + + + + + + + True + BG2 + True + False + + + + + + + True + BG3 + True + False + + + + + + + True + OBJ + True + False + + + + + + + True + WIN0 + True + False + + + + + + + True + WIN1 + True + False + + + + + + + True + OBJWIN + True + False + + + + + + + + + + + + + + + True + _Emulator + True + + + + + + + True + Directories... + True + + + + + + True + Pause when inactive window + True + False + + + + + + True + Show speed + True + + + + + + + True + None + True + True + + + + + + True + Percentage + True + False + ShowSpeedNone + + + + + + True + Detailed + True + False + ShowSpeedNone + + + + + + + + + + True + Save type + True + + + + + + + True + _Automatic + True + True + + + + + + True + EEPROM + True + False + SaveTypeAutomatic + + + + + + True + SRAM + True + False + SaveTypeAutomatic + + + + + + True + Flash + True + False + SaveTypeAutomatic + + + + + + True + EEPROM+Sensor + True + False + SaveTypeAutomatic + + + + + + True + None + True + False + SaveTypeAutomatic + + + + + + True + + + + + + True + Flash 64K + True + True + + + + + + True + Flash 128K + True + False + SaveTypeFlash64K + + + + + + + + + + True + + + + + + True + _Select BIOS file... + True + + + + + + True + _Use BIOS file + True + False + + + + + + True + + + + + + True + Screenshot format + True + + + + + + + True + _PNG + True + True + + + + + + True + _BMP + True + False + ScreenshotFormatPNG + + + + + + + + + + + + + + True + _Sound + True + + + + + + + True + O_ff + True + True + + + + + + True + _Mute + True + False + SoundOff + + + + + + True + _On + True + False + SoundOff + + + + + + True + + + + + + True + Echo + True + False + + + + + + True + Low pass filter + True + False + + + + + + True + Reverse stereo + True + False + + + + + + True + + + + + + True + Channel _1 + True + False + + + + + + True + Channel _2 + True + False + + + + + + True + Channel _3 + True + False + + + + + + True + Channel _4 + True + False + + + + + + True + Channel _A + True + False + + + + + + True + Channel _B + True + False + + + + + + True + + + + + + True + 11 _Khz + True + True + + + + + + True + 22 K_hz + True + False + Sound11Khz + + + + + + True + 44 Kh_z + True + False + Sound11Khz + + + + + + True + + + + + + True + _Volume + True + + + + + + + True + 25% + True + True + + + + + + True + 50% + True + False + Volume25 + + + + + + True + 100% + True + False + Volume25 + + + + + + True + 200% + True + False + Volume25 + + + + + + True + 300% + True + False + Volume25 + + + + + + True + 400% + True + False + Volume25 + + + + + + + + + + + + + + True + _Gameboy + True + + + + + + + True + _Border + True + False + + + + + + True + _Printer + True + False + + + + + + True + + + + + + True + _Automatic + True + True + + + + + + True + _GBA + True + False + GameboyAutomatic + + + + + + True + _CGB/GBC + True + False + GameboyAutomatic + + + + + + True + _SGB + True + False + GameboyAutomatic + + + + + + True + SGB_2 + True + False + GameboyAutomatic + + + + + + True + G_B + True + False + GameboyAutomatic + + + + + + + + + + True + F_ilter + True + + + + + + + True + Interframe _blending + True + + + + + + + True + _None + True + True + + + + + + True + _Smart + True + False + IFBNone + + + + + + True + _Motion Blur + True + False + IFBNone + + + + + + + + + + True + + + + + + True + _None + True + True + + + + + + True + _TV Mode + True + False + FilterNone + + + + + + True + _2xSaI + True + False + FilterNone + + + + + + True + _Super 2xSaI + True + False + FilterNone + + + + + + True + Super _Eagle + True + False + FilterNone + + + + + + True + _Pixelate + True + False + FilterNone + + + + + + True + _AdvanceMAME 2x + True + False + FilterNone + + + + + + True + Bilinea_r + True + False + FilterNone + + + + + + True + Bilinear Pl_us + True + False + FilterNone + + + + + + True + S_canlines + True + False + FilterNone + + + + + + True + h_q2x + True + False + FilterNone + + + + + + True + _lq2x + True + False + FilterNone + + + + + + True + + + + + + + + + + + True + _Joypad + True + + + + + + + True + _Configure + True + + + + + + + True + _1... + True + + + + + + True + _2... + True + + + + + + True + _3... + True + + + + + + True + _4... + True + + + + + + + + + + True + + + + + + True + _1 + True + True + + + + + + True + _2 + True + False + Joypad1 + + + + + + True + _3 + True + False + Joypad1 + + + + + + True + _4 + True + False + Joypad1 + + + + + + True + + + + + + True + _Autofire + True + + + + + + + True + _A + True + False + + + + + + + True + _B + True + False + + + + + + + True + _L + True + False + + + + + + + True + _R + True + False + + + + + + + + + + + + + + + + + + + True + _Tools + True + + + + + + + True + _GDB + True + + + + + + + True + _Wait connection... + True + + + + + + True + _Load and wait... + True + + + + + + True + _Break + True + + + + + + True + _Disconnect + True + + + + + + + + + + + + + + True + _Help + True + + + + + + + True + _About + True + + + + + + + + + + + 0 + False + True + + + + + + True + 0.5 + 0.5 + 0 + 0 + + + + + + + 0 + True + True + + + + + + + + About VBA + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + -7 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 0.5 + 0.5 + 0 + 0 + + + + + + + 0 + True + True + + + + + + True + True + + False + True + GTK_JUSTIFY_CENTER + False + True + 0.5 + 0.5 + 5 + 5 + + + 0 + True + False + + + + + + True + True + An emulator for Gameboy(TM) and GameboyAdvance(TM). + False + False + GTK_JUSTIFY_CENTER + True + True + 0.5 + 0.5 + 5 + 5 + + + 0 + True + False + + + + + + True + True + <i>Special thanks to Yann Parmentier aka "kohai" for the icons.</i> + False + True + GTK_JUSTIFY_LEFT + False + True + 0.5 + 0.5 + 5 + 5 + + + 0 + True + False + + + + + + True + True + <small>Copyright (C) 2004 Forgotten and the VBA development team</small> + False + True + GTK_JUSTIFY_CENTER + True + True + 0.5 + 0.5 + 5 + 5 + + + 0 + True + False + + + + + + + + Throttle + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 0.5 + 0.5 + 0 + 0 + + + + True + False + 0 + + + + True + Throttle : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + True + True + + + + + + True + True + 1 + 0 + True + GTK_UPDATE_ALWAYS + True + True + 100 5 1000 1 25 25 + + + 0 + True + True + + + + + + True + % + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + 0 + True + True + + + + + + + 0 + True + True + + + + + + + + Directories + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 5 + 4 + False + 0 + 0 + + + + True + GBA roms : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 0 + 1 + fill + expand + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + expand + + + + + + True + True + GTK_RELIEF_NONE + + + + True + gtk-cancel + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 2 + 3 + 0 + 1 + fill + expand + + + + + + True + True + GTK_RELIEF_NONE + + + + True + gtk-open + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 3 + 4 + 0 + 1 + fill + expand + + + + + + True + GB roms : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 1 + 2 + fill + expand + + + + + + True + True + GTK_RELIEF_NONE + + + + True + gtk-open + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 3 + 4 + 1 + 2 + fill + expand + + + + + + True + Batteries : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 2 + 3 + fill + expand + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 2 + 3 + expand + + + + + + True + True + GTK_RELIEF_NONE + + + + True + gtk-open + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 3 + 4 + 2 + 3 + fill + expand + + + + + + True + True + GTK_RELIEF_NONE + + + + True + gtk-cancel + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 2 + 3 + 2 + 3 + fill + expand + + + + + + True + Saves : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 3 + 4 + fill + expand + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 3 + 4 + expand + + + + + + True + True + GTK_RELIEF_NONE + + + + True + gtk-cancel + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 2 + 3 + 3 + 4 + fill + expand + + + + + + True + True + GTK_RELIEF_NONE + + + + True + gtk-open + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 3 + 4 + 3 + 4 + fill + expand + + + + + + True + Captures : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 4 + 5 + fill + expand + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 4 + 5 + expand + + + + + + True + True + GTK_RELIEF_NONE + + + + True + gtk-cancel + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 2 + 3 + 4 + 5 + fill + expand + + + + + + True + True + GTK_RELIEF_NONE + + + + True + gtk-open + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 3 + 4 + 4 + 5 + fill + expand + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 1 + 2 + expand + + + + + + True + True + GTK_RELIEF_NONE + + + + True + gtk-cancel + 4 + 0.5 + 0.5 + 0 + 0 + + + + + 2 + 3 + 1 + 2 + fill + expand + + + + + 0 + True + True + + + + + + + + Joypad config + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 0.5 + 0.5 + 0 + 1 + + + + True + 12 + 2 + False + 5 + 0 + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + fill + expand + + + + + + True + Down : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 1 + 2 + fill + expand + + + + + + True + Left : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 2 + 3 + fill + expand + + + + + + True + Right : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 3 + 4 + fill + expand + + + + + + True + Button A : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 4 + 5 + fill + expand + + + + + + True + Button B : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 5 + 6 + fill + expand + + + + + + True + Button L : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 6 + 7 + fill + expand + + + + + + True + Button R : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 7 + 8 + fill + expand + + + + + + True + Select : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 8 + 9 + fill + expand + + + + + + True + Start : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 9 + 10 + fill + expand + + + + + + True + Speed : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 10 + 11 + fill + expand + + + + + + True + Capture : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 11 + 12 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 1 + 2 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 2 + 3 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 3 + 4 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 4 + 5 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 5 + 6 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 6 + 7 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 7 + 8 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 8 + 9 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 9 + 10 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 10 + 11 + fill + expand + + + + + + True + True + False + True + 0 + + True + * + False + + + 1 + 2 + 11 + 12 + fill + expand + + + + + + True + Up : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + 1 + 0 + 1 + fill + expand + + + + + + + 0 + True + True + + + + + + + + TCP port + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + False + True + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + -6 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 0.5 + 0.5 + 0 + 0 + + + + True + False + 0 + + + + True + Port : + False + False + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + + + 0 + True + True + + + + + + True + True + 1 + 0 + True + GTK_UPDATE_ALWAYS + True + True + 55555 1 65535 1 100 100 + + + 0 + True + True + + + + + + + 0 + True + True + + + + + + + diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp new file mode 100644 index 00000000..31579f0c --- /dev/null +++ b/src/gtk/window.cpp @@ -0,0 +1,1869 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "window.h" + +#include + +#include +#include + +#include "../agb/GBA.h" +#include "../dmg/gb.h" +#include "../dmg/gbGlobals.h" +#include "../dmg/gbPrinter.h" +#include "../Sound.h" +#include "../Util.h" + +#include "menuitem.h" +#include "tools.h" +#include "intl.h" + +extern int systemRenderedFrames; +extern int systemFPS; +extern bool debugger; +extern int RGB_LOW_BITS_MASK; +extern void remoteInit(); +extern void remoteCleanUp(); +extern void remoteStubMain(); +extern void remoteStubSignal(int, int); +extern void remoteOutput(const char *, u32); +extern void remoteSetProtocol(int); +extern void remoteSetPort(int); + +namespace VBA +{ + +using Gnome::Glade::Xml; + +Window * Window::m_poInstance = NULL; + +Window::Window(GtkWindow * _pstWindow, const Glib::RefPtr & _poXml) : + Gtk::Window (_pstWindow), + m_iGBScreenWidth (160), + m_iGBScreenHeight (144), + m_iSGBScreenWidth (256), + m_iSGBScreenHeight(224), + m_iGBAScreenWidth (240), + m_iGBAScreenHeight(160), + m_iFrameskipMin (0), + m_iFrameskipMax (9), + m_iThrottleMin (5), + m_iThrottleMax (1000), + m_iScaleMin (1), + m_iScaleMax (6), + m_iShowSpeedMin (ShowNone), + m_iShowSpeedMax (ShowDetailed), + m_iSaveTypeMin (SaveAuto), + m_iSaveTypeMax (SaveNone), + m_iSoundQualityMin(Sound44K), + m_iSoundQualityMax(Sound11K), + m_iSoundVolumeMin (Sound100), + m_iSoundVolumeMax (Sound50), + m_iEmulatorTypeMin(EmulatorAuto), + m_iEmulatorTypeMax(EmulatorSGB2), + m_iFilter2xMin (FirstFilter), + m_iFilter2xMax (LastFilter), + m_iFilterIBMin (FirstFilterIB), + m_iFilterIBMax (LastFilterIB), + m_iJoypadMin (1), + m_iJoypadMax (4) +{ + m_poXml = _poXml; + m_poFileOpenDialog = NULL; + m_iScreenWidth = m_iGBAScreenWidth; + m_iScreenHeight = m_iGBAScreenHeight; + m_eCartridge = CartridgeNone; + m_uiJoypadState = 0; + + vInitSystem(); + + Gtk::Container * poC; + poC = dynamic_cast(_poXml->get_widget("ScreenContainer")); + m_poScreenArea = Gtk::manage(new ScreenArea(m_iScreenWidth, m_iScreenHeight)); + poC->add(*m_poScreenArea); + vDrawDefaultScreen(); + m_poScreenArea->show(); + + // Get config + // + vInitConfig(); + + m_sUserDataDir = Glib::get_home_dir() + "/.gvba"; + m_sConfigFile = m_sUserDataDir + "/config"; + + if (! Glib::file_test(m_sUserDataDir, Glib::FILE_TEST_EXISTS)) + { + mkdir(m_sUserDataDir.c_str(), 0777); + } + if (Glib::file_test(m_sConfigFile, Glib::FILE_TEST_EXISTS)) + { + vLoadConfig(m_sConfigFile); + vCheckConfig(); + } + else + { + vSaveConfig(m_sConfigFile); + } + + vCreateFileOpenDialog(); + vLoadHistoryFromConfig(); + vLoadJoypadsFromConfig(); + + Gtk::MenuItem * poMI; + Gtk::CheckMenuItem * poCMI; + + // File menu + // + poMI = dynamic_cast(_poXml->get_widget("FileOpen")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnFileOpen)); + + poMI = dynamic_cast(_poXml->get_widget("FileLoad")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnFileLoad)); + m_listSensitiveWhenPlaying.push_back(poMI); + + poMI = dynamic_cast(_poXml->get_widget("FileSave")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnFileSave)); + m_listSensitiveWhenPlaying.push_back(poMI); + + for (int i = 0; i < 10; i++) + { + char csName[20]; + snprintf(csName, 20, "LoadGameSlot%d", i + 1); + m_apoLoadGameItem[i] = dynamic_cast(_poXml->get_widget(csName)); + snprintf(csName, 20, "LoadGameSlot%d", i + 1); + m_apoSaveGameItem[i] = dynamic_cast(_poXml->get_widget(csName)); + + m_apoLoadGameItem[i]->signal_activate().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnLoadGame), + i + 1)); + m_apoSaveGameItem[i]->signal_activate().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSaveGame), + i + 1)); + } + vUpdateGameSlots(); + + poMI = dynamic_cast(_poXml->get_widget("LoadGameMostRecent")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnLoadGameMostRecent)); + m_listSensitiveWhenPlaying.push_back(poMI); + + poCMI = dynamic_cast(_poXml->get_widget("LoadGameAuto")); + poCMI->set_active(m_poCoreConfig->oGetKey("load_game_auto")); + vOnLoadGameAutoToggled(poCMI); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnLoadGameAutoToggled), + poCMI)); + + poMI = dynamic_cast(_poXml->get_widget("SaveGameOldest")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnSaveGameOldest)); + m_listSensitiveWhenPlaying.push_back(poMI); + + m_poFilePauseItem = dynamic_cast(_poXml->get_widget("FilePause")); + m_poFilePauseItem->set_active(false); + vOnFilePauseToggled(m_poFilePauseItem); + m_poFilePauseItem->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnFilePauseToggled), + m_poFilePauseItem)); + m_listSensitiveWhenPlaying.push_back(m_poFilePauseItem); + + poMI = dynamic_cast(_poXml->get_widget("FileReset")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnFileReset)); + m_listSensitiveWhenPlaying.push_back(poMI); + + poMI = dynamic_cast(_poXml->get_widget("FileScreenCapture")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnFileScreenCapture)); + m_listSensitiveWhenPlaying.push_back(poMI); + + poMI = dynamic_cast(_poXml->get_widget("FileClose")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnFileClose)); + m_listSensitiveWhenPlaying.push_back(poMI); + + poMI = dynamic_cast(_poXml->get_widget("FileExit")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnFileExit)); + + // Recent menu + // + m_poRecentMenu = dynamic_cast(_poXml->get_widget("RecentMenu_menu")); + vUpdateHistoryMenu(); + + m_poRecentResetItem = dynamic_cast(_poXml->get_widget("RecentReset")); + m_poRecentResetItem->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnRecentReset)); + + poCMI = dynamic_cast(_poXml->get_widget("RecentFreeze")); + poCMI->set_active(m_poHistoryConfig->oGetKey("freeze")); + vOnRecentFreezeToggled(poCMI); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnRecentFreezeToggled), + poCMI)); + + // Import menu + // + poMI = dynamic_cast(_poXml->get_widget("ImportBatteryFile")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnImportBatteryFile)); + m_listSensitiveWhenPlaying.push_back(poMI); + + // Export menu + // + poMI = dynamic_cast(_poXml->get_widget("ExportBatteryFile")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnExportBatteryFile)); + m_listSensitiveWhenPlaying.push_back(poMI); + + // Frameskip menu + // + struct + { + const char * m_csName; + const int m_iFrameskip; + } + astFrameskip[] = + { + { "FrameskipAutomatic", -1 }, + { "Frameskip0", 0 }, + { "Frameskip1", 1 }, + { "Frameskip2", 2 }, + { "Frameskip3", 3 }, + { "Frameskip4", 4 }, + { "Frameskip5", 5 }, + { "Frameskip6", 6 }, + { "Frameskip7", 7 }, + { "Frameskip8", 8 }, + { "Frameskip9", 9 } + }; + int iDefaultFrameskip; + if (m_poCoreConfig->sGetKey("frameskip") == "auto") + { + iDefaultFrameskip = -1; + } + else + { + iDefaultFrameskip = m_poCoreConfig->oGetKey("frameskip"); + } + for (guint i = 0; i < G_N_ELEMENTS(astFrameskip); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astFrameskip[i].m_csName)); + if (astFrameskip[i].m_iFrameskip == iDefaultFrameskip) + { + poCMI->set_active(); + vOnFrameskipToggled(poCMI, iDefaultFrameskip); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnFrameskipToggled), + poCMI, astFrameskip[i].m_iFrameskip)); + } + + // Throttle menu + // + struct + { + const char * m_csName; + const int m_iThrottle; + } + astThrottle[] = + { + { "ThrottleNoThrottle", 0 }, + { "Throttle25", 25 }, + { "Throttle50", 50 }, + { "Throttle100", 100 }, + { "Throttle150", 150 }, + { "Throttle200", 200 } + }; + poCMI = dynamic_cast(_poXml->get_widget("ThrottleOther")); + poCMI->set_active(); + poCMI->signal_activate().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnThrottleOther), + poCMI)); + + int iDefaultThrottle = m_poCoreConfig->oGetKey("throttle"); + for (guint i = 0; i < G_N_ELEMENTS(astThrottle); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astThrottle[i].m_csName)); + if (astThrottle[i].m_iThrottle == iDefaultThrottle) + { + poCMI->set_active(); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnThrottleToggled), + poCMI, astThrottle[i].m_iThrottle)); + } + vSetThrottle(iDefaultThrottle); + + // Video menu + // + struct + { + const char * m_csName; + const int m_iScale; + } + astVideoScale[] = + { + { "Video1x", 1 }, + { "Video2x", 2 }, + { "Video3x", 3 }, + { "Video4x", 4 }, + { "Video5x", 5 }, + { "Video6x", 6 } + }; + int iDefaultScale = m_poDisplayConfig->oGetKey("scale"); + for (guint i = 0; i < G_N_ELEMENTS(astVideoScale); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astVideoScale[i].m_csName)); + if (astVideoScale[i].m_iScale == iDefaultScale) + { + poCMI->set_active(); + vOnVideoScaleToggled(poCMI, iDefaultScale); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnVideoScaleToggled), + poCMI, astVideoScale[i].m_iScale)); + } + + // Layers menu + // + struct + { + const char * m_csName; + const char * m_csKey; + const int m_iLayer; + } + astLayer[] = + { + { "LayersBg0", "layer_bg0", 0 }, + { "LayersBg1", "layer_bg1", 1 }, + { "LayersBg2", "layer_bg2", 2 }, + { "LayersBg3", "layer_bg3", 3 }, + { "LayersObj", "layer_obj", 4 }, + { "LayersWin0", "layer_win0", 5 }, + { "LayersWin1", "layer_win1", 6 }, + { "LayersObjWin", "layer_objwin", 7 } + }; + for (guint i = 0; i < G_N_ELEMENTS(astLayer); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astLayer[i].m_csName)); + poCMI->set_active(m_poCoreConfig->oGetKey(astLayer[i].m_csKey)); + vOnLayerToggled(poCMI, astLayer[i].m_iLayer); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnLayerToggled), + poCMI, astLayer[i].m_iLayer)); + } + + // Emulator menu + // + poMI = dynamic_cast(_poXml->get_widget("EmulatorDirectories")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnDirectories)); + + poCMI = dynamic_cast(_poXml->get_widget("EmulatorPauseWhenInactive")); + poCMI->set_active(m_poDisplayConfig->oGetKey("pause_when_inactive")); + vOnPauseWhenInactiveToggled(poCMI); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnPauseWhenInactiveToggled), + poCMI)); + + m_poUseBiosItem = dynamic_cast(_poXml->get_widget("EmulatorUseBios")); + m_poUseBiosItem->set_active(m_poCoreConfig->oGetKey("use_bios_file")); + if (m_poCoreConfig->sGetKey("bios_file") == "") + { + m_poUseBiosItem->set_sensitive(false); + } + m_poUseBiosItem->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnUseBiosToggled), + m_poUseBiosItem)); + + poMI = dynamic_cast(_poXml->get_widget("EmulatorSelectBios")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnSelectBios)); + + // Show speed menu + // + struct + { + const char * m_csName; + const EShowSpeed m_eShowSpeed; + } + astShowSpeed[] = + { + { "ShowSpeedNone", ShowNone }, + { "ShowSpeedPercentage", ShowPercentage }, + { "ShowSpeedDetailed", ShowDetailed } + }; + EShowSpeed eDefaultShowSpeed = (EShowSpeed)m_poDisplayConfig->oGetKey("show_speed"); + for (guint i = 0; i < G_N_ELEMENTS(astShowSpeed); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astShowSpeed[i].m_csName)); + if (astShowSpeed[i].m_eShowSpeed == eDefaultShowSpeed) + { + poCMI->set_active(); + vOnShowSpeedToggled(poCMI, eDefaultShowSpeed); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnShowSpeedToggled), + poCMI, astShowSpeed[i].m_eShowSpeed)); + } + + // Save type menu + // + struct + { + const char * m_csName; + const ESaveType m_eSaveType; + } + astSaveType[] = + { + { "SaveTypeAutomatic", SaveAuto }, + { "SaveTypeEeprom", SaveEEPROM }, + { "SaveTypeSram", SaveSRAM }, + { "SaveTypeFlash", SaveFlash }, + { "SaveTypeEepromSensor", SaveEEPROMSensor }, + { "SaveTypeNone", SaveNone } + }; + ESaveType eDefaultSaveType = (ESaveType)m_poCoreConfig->oGetKey("save_type"); + for (guint i = 0; i < G_N_ELEMENTS(astSaveType); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astSaveType[i].m_csName)); + if (astSaveType[i].m_eSaveType == eDefaultSaveType) + { + poCMI->set_active(); + vOnSaveTypeToggled(poCMI, eDefaultSaveType); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSaveTypeToggled), + poCMI, astSaveType[i].m_eSaveType)); + } + + // Flash size menu + // + struct + { + const char * m_csName; + const int m_iFlashSize; + } + astFlashSize[] = + { + { "SaveTypeFlash64K", 64 }, + { "SaveTypeFlash128K", 128 } + }; + int iDefaultFlashSize = m_poCoreConfig->oGetKey("flash_size"); + for (guint i = 0; i < G_N_ELEMENTS(astFlashSize); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astFlashSize[i].m_csName)); + if (astFlashSize[i].m_iFlashSize == iDefaultFlashSize) + { + poCMI->set_active(); + vOnFlashSizeToggled(poCMI, iDefaultFlashSize); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnFlashSizeToggled), + poCMI, astFlashSize[i].m_iFlashSize)); + } + + // Screenshot format menu + // + struct + { + const char * m_csName; + const char * m_csScreenshotFormat; + } + astScreenshotFormat[] = + { + { "ScreenshotFormatPNG", "png" }, + { "ScreenshotFormatBMP", "bmp" } + }; + std::string sDefaultScreenshotFormat = m_poCoreConfig->sGetKey("screenshot_format"); + for (guint i = 0; i < G_N_ELEMENTS(astScreenshotFormat); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astScreenshotFormat[i].m_csName)); + if (astScreenshotFormat[i].m_csScreenshotFormat == sDefaultScreenshotFormat) + { + poCMI->set_active(); + vOnScreenshotFormatToggled(poCMI, sDefaultScreenshotFormat); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnScreenshotFormatToggled), + poCMI, std::string(astScreenshotFormat[i].m_csScreenshotFormat))); + } + + // Sound menu + // + std::string sDefaultSoundStatus = m_poSoundConfig->sGetKey("status"); + + poCMI = dynamic_cast(_poXml->get_widget("SoundOff")); + if (sDefaultSoundStatus == "off") + { + poCMI->set_active(); + vOnSoundStatusToggled(poCMI, SoundOff); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSoundStatusToggled), + poCMI, SoundOff)); + m_poSoundOffItem = poCMI; + + poCMI = dynamic_cast(_poXml->get_widget("SoundMute")); + if (sDefaultSoundStatus == "mute") + { + poCMI->set_active(); + vOnSoundStatusToggled(poCMI, SoundMute); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSoundStatusToggled), + poCMI, SoundMute)); + + poCMI = dynamic_cast(_poXml->get_widget("SoundOn")); + if (sDefaultSoundStatus == "on") + { + poCMI->set_active(); + vOnSoundStatusToggled(poCMI, SoundOn); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSoundStatusToggled), + poCMI, SoundOn)); + + poCMI = dynamic_cast(_poXml->get_widget("SoundEcho")); + poCMI->set_active(m_poSoundConfig->oGetKey("echo")); + vOnSoundEchoToggled(poCMI); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSoundEchoToggled), + poCMI)); + + poCMI = dynamic_cast(_poXml->get_widget("SoundLowPass")); + poCMI->set_active(m_poSoundConfig->oGetKey("low_pass")); + vOnSoundLowPassToggled(poCMI); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSoundLowPassToggled), + poCMI)); + + poCMI = dynamic_cast(_poXml->get_widget("SoundReverseStereo")); + poCMI->set_active(m_poSoundConfig->oGetKey("reverse_stereo")); + vOnSoundReverseToggled(poCMI); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSoundReverseToggled), + poCMI)); + + struct + { + const char * m_csName; + const char * m_csKey; + const int m_iSoundChannel; + } + astSoundChannel[] = + { + { "SoundChannel1", "channel_1", 0 }, + { "SoundChannel2", "channel_2", 1 }, + { "SoundChannel3", "channel_3", 2 }, + { "SoundChannel4", "channel_4", 3 }, + { "SoundChannelA", "channel_A", 4 }, + { "SoundChannelB", "channel_B", 5 } + }; + for (guint i = 0; i < G_N_ELEMENTS(astSoundChannel); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astSoundChannel[i].m_csName)); + poCMI->set_active(m_poSoundConfig->oGetKey(astSoundChannel[i].m_csKey)); + vOnSoundChannelToggled(poCMI, astSoundChannel[i].m_iSoundChannel); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSoundChannelToggled), + poCMI, astSoundChannel[i].m_iSoundChannel)); + } + + struct + { + const char * m_csName; + const ESoundQuality m_eSoundQuality; + } + astSoundQuality[] = + { + { "Sound11Khz", Sound11K }, + { "Sound22Khz", Sound22K }, + { "Sound44Khz", Sound44K } + }; + ESoundQuality eDefaultSoundQuality = (ESoundQuality)m_poSoundConfig->oGetKey("quality"); + for (guint i = 0; i < G_N_ELEMENTS(astSoundQuality); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astSoundQuality[i].m_csName)); + if (astSoundQuality[i].m_eSoundQuality == eDefaultSoundQuality) + { + poCMI->set_active(); + vOnSoundQualityToggled(poCMI, eDefaultSoundQuality); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSoundQualityToggled), + poCMI, astSoundQuality[i].m_eSoundQuality)); + } + + // Volume menu + // + struct + { + const char * m_csName; + const ESoundVolume m_eSoundVolume; + } + astSoundVolume[] = + { + { "Volume25", Sound25 }, + { "Volume50", Sound50 }, + { "Volume100", Sound100 }, + { "Volume200", Sound200 }, + { "Volume300", Sound300 }, + { "Volume400", Sound400 } + }; + ESoundVolume eDefaultSoundVolume = (ESoundVolume)m_poSoundConfig->oGetKey("volume"); + for (guint i = 0; i < G_N_ELEMENTS(astSoundVolume); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astSoundVolume[i].m_csName)); + if (astSoundVolume[i].m_eSoundVolume == eDefaultSoundVolume) + { + poCMI->set_active(); + vOnSoundVolumeToggled(poCMI, eDefaultSoundVolume); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnSoundVolumeToggled), + poCMI, astSoundVolume[i].m_eSoundVolume)); + } + + // Gameboy menu + // + poCMI = dynamic_cast(_poXml->get_widget("GameboyBorder")); + poCMI->set_active(m_poCoreConfig->oGetKey("gb_border")); + vOnGBBorderToggled(poCMI); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnGBBorderToggled), + poCMI)); + + poCMI = dynamic_cast(_poXml->get_widget("GameboyPrinter")); + poCMI->set_active(m_poCoreConfig->oGetKey("gb_printer")); + vOnGBPrinterToggled(poCMI); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnGBPrinterToggled), + poCMI)); + + struct + { + const char * m_csName; + const EEmulatorType m_eEmulatorType; + } + astEmulatorType[] = + { + { "GameboyAutomatic", EmulatorAuto }, + { "GameboyGba", EmulatorGBA }, + { "GameboyCgb", EmulatorCGB }, + { "GameboySgb", EmulatorSGB }, + { "GameboySgb2", EmulatorSGB2 }, + { "GameboyGb", EmulatorGB } + }; + EEmulatorType eDefaultEmulatorType = (EEmulatorType)m_poCoreConfig->oGetKey("emulator_type"); + for (guint i = 0; i < G_N_ELEMENTS(astEmulatorType); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astEmulatorType[i].m_csName)); + if (astEmulatorType[i].m_eEmulatorType == eDefaultEmulatorType) + { + poCMI->set_active(); + vOnEmulatorTypeToggled(poCMI, eDefaultEmulatorType); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnEmulatorTypeToggled), + poCMI, astEmulatorType[i].m_eEmulatorType)); + } + + // Filter menu + // + struct + { + const char * m_csName; + const EFilter2x m_eFilter2x; + } + astFilter2x[] = + { + { "FilterNone", FilterNone }, + { "FilterTVMode", FilterScanlinesTV }, + { "Filter2xSaI", Filter2xSaI }, + { "FilterSuper2xSaI", FilterSuper2xSaI }, + { "FilterSuperEagle", FilterSuperEagle }, + { "FilterPixelate", FilterPixelate }, + { "FilterAdvanceMame2x", FilterAdMame2x }, + { "FilterBilinear", FilterBilinear }, + { "FilterBilinearPlus", FilterBilinearPlus }, + { "FilterScanlines", FilterScanlines }, + { "FilterHq2x", FilterHq2x }, + { "FilterLq2x", FilterLq2x } + }; + EFilter2x eDefaultFilter2x = (EFilter2x)m_poDisplayConfig->oGetKey("filter2x"); + for (guint i = 0; i < G_N_ELEMENTS(astFilter2x); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astFilter2x[i].m_csName)); + if (astFilter2x[i].m_eFilter2x == eDefaultFilter2x) + { + poCMI->set_active(); + vOnFilter2xToggled(poCMI, eDefaultFilter2x); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnFilter2xToggled), + poCMI, astFilter2x[i].m_eFilter2x)); + } + + // Interframe blending menu + // + struct + { + const char * m_csName; + const EFilterIB m_eFilterIB; + } + astFilterIB[] = + { + { "IFBNone", FilterIBNone }, + { "IFBSmart", FilterIBSmart }, + { "IFBMotionBlur", FilterIBMotionBlur } + }; + EFilterIB eDefaultFilterIB = (EFilterIB)m_poDisplayConfig->oGetKey("filterIB"); + for (guint i = 0; i < G_N_ELEMENTS(astFilterIB); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astFilterIB[i].m_csName)); + if (astFilterIB[i].m_eFilterIB == eDefaultFilterIB) + { + poCMI->set_active(); + vOnFilterIBToggled(poCMI, eDefaultFilterIB); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnFilterIBToggled), + poCMI, astFilterIB[i].m_eFilterIB)); + } + + // Joypad menu + // + poMI = dynamic_cast(_poXml->get_widget("JoypadConfigure1")); + poMI->signal_activate().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnJoypadConfigure), 1)); + + poMI = dynamic_cast(_poXml->get_widget("JoypadConfigure2")); + poMI->signal_activate().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnJoypadConfigure), 2)); + + poMI = dynamic_cast(_poXml->get_widget("JoypadConfigure3")); + poMI->signal_activate().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnJoypadConfigure), 3)); + + poMI = dynamic_cast(_poXml->get_widget("JoypadConfigure4")); + poMI->signal_activate().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnJoypadConfigure), 4)); + + int iDefaultJoypad = m_poInputConfig->oGetKey("active_joypad"); + for (int i = m_iJoypadMin; i <= m_iJoypadMax; i++) + { + char csName[20]; + snprintf(csName, sizeof(csName), "Joypad%d", i); + + poCMI = dynamic_cast(_poXml->get_widget(csName)); + if (i == iDefaultJoypad) + { + poCMI->set_active(); + vOnJoypadToggled(poCMI, iDefaultJoypad); + } + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnJoypadToggled), + poCMI, i)); + } + + // Autofire menu + // + struct + { + const char * m_csName; + const char * m_csKey; + const EKeyFlag m_eKeyFlag; + } + astAutofire[] = + { + { "AutofireA", "autofire_A", KeyFlagA }, + { "AutofireB", "autofire_B", KeyFlagB }, + { "AutofireL", "autofire_L", KeyFlagL }, + { "AutofireR", "autofire_R", KeyFlagR } + }; + for (guint i = 0; i < G_N_ELEMENTS(astAutofire); i++) + { + poCMI = dynamic_cast(_poXml->get_widget(astAutofire[i].m_csName)); + poCMI->set_active(m_poInputConfig->oGetKey(astAutofire[i].m_csKey)); + vOnAutofireToggled(poCMI, astAutofire[i].m_eKeyFlag); + poCMI->signal_toggled().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnAutofireToggled), + poCMI, astAutofire[i].m_eKeyFlag)); + } + + // GDB menu + // + poMI = dynamic_cast(_poXml->get_widget("GdbWait")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnGDBWait)); + + poMI = dynamic_cast(_poXml->get_widget("GdbLoadAndWait")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnGDBLoadAndWait)); + + poMI = dynamic_cast(_poXml->get_widget("GdbBreak")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnGDBBreak)); + + poMI = dynamic_cast(_poXml->get_widget("GdbDisconnect")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnGDBDisconnect)); + + // Help menu + // + poMI = dynamic_cast(_poXml->get_widget("HelpAbout")); + poMI->signal_activate().connect(sigc::mem_fun(*this, &Window::vOnHelpAbout)); + + // Init widgets sensitivity + for (std::list::iterator it = m_listSensitiveWhenPlaying.begin(); + it != m_listSensitiveWhenPlaying.end(); + it++) + { + (*it)->set_sensitive(false); + } + + if (m_poInstance == NULL) + { + m_poInstance = this; + } + else + { + abort(); + } +} + +Window::~Window() +{ + vOnFileClose(); + vSaveHistoryToConfig(); + vSaveJoypadsToConfig(); + vSaveConfig(m_sConfigFile); + + if (m_poFileOpenDialog != NULL) + { + delete m_poFileOpenDialog; + } + + if (m_poKeymap != NULL) + { + delete m_poKeymap; + } + + m_poInstance = NULL; +} + +void Window::vInitSystem() +{ +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + systemRedShift = 3; + systemGreenShift = 11; + systemBlueShift = 19; + RGB_LOW_BITS_MASK = 0x00010101; +#else + systemRedShift = 27; + systemGreenShift = 19; + systemBlueShift = 11; + RGB_LOW_BITS_MASK = 0x01010100; +#endif + + systemColorDepth = 32; + systemDebug = 0; + systemVerbose = 0; + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + systemFrameSkip = 2; + soundOffFlag = true; + + systemRenderedFrames = 0; + systemFPS = 0; + + emulating = 0; + debugger = false; + + for (int i = 0; i < 0x10000; i++) + { + systemColorMap32[i] = (((i & 0x1f) << systemRedShift) + | (((i & 0x3e0) >> 5) << systemGreenShift) + | (((i & 0x7c00) >> 10) << systemBlueShift)); + } + + gbFrameSkip = 0; + + for (int i = 0; i < 24; ) + { + systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10); + systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10); + systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10); + systemGbPalette[i++] = 0; + } + + Init_2xSaI(32); +} + +void Window::vInitConfig() +{ + m_oConfig.vClear(); + + // History section + // + m_poHistoryConfig = m_oConfig.poAddSection("History"); + m_poHistoryConfig->vSetKey("freeze", false ); + m_poHistoryConfig->vSetKey("0", "" ); + m_poHistoryConfig->vSetKey("1", "" ); + m_poHistoryConfig->vSetKey("2", "" ); + m_poHistoryConfig->vSetKey("3", "" ); + m_poHistoryConfig->vSetKey("4", "" ); + m_poHistoryConfig->vSetKey("5", "" ); + m_poHistoryConfig->vSetKey("6", "" ); + m_poHistoryConfig->vSetKey("7", "" ); + m_poHistoryConfig->vSetKey("8", "" ); + m_poHistoryConfig->vSetKey("9", "" ); + + // Directories section + // + m_poDirConfig = m_oConfig.poAddSection("Directories"); + m_poDirConfig->vSetKey("gb_roms", "" ); + m_poDirConfig->vSetKey("gba_roms", "" ); + m_poDirConfig->vSetKey("batteries", "" ); + m_poDirConfig->vSetKey("saves", "" ); + m_poDirConfig->vSetKey("captures", "" ); + + // Core section + // + m_poCoreConfig = m_oConfig.poAddSection("Core"); + m_poCoreConfig->vSetKey("load_game_auto", false ); + m_poCoreConfig->vSetKey("frameskip", "auto" ); + m_poCoreConfig->vSetKey("throttle", 0 ); + m_poCoreConfig->vSetKey("layer_bg0", true ); + m_poCoreConfig->vSetKey("layer_bg1", true ); + m_poCoreConfig->vSetKey("layer_bg2", true ); + m_poCoreConfig->vSetKey("layer_bg3", true ); + m_poCoreConfig->vSetKey("layer_obj", true ); + m_poCoreConfig->vSetKey("layer_win0", true ); + m_poCoreConfig->vSetKey("layer_win1", true ); + m_poCoreConfig->vSetKey("layer_objwin", true ); + m_poCoreConfig->vSetKey("use_bios_file", false ); + m_poCoreConfig->vSetKey("bios_file", "" ); + m_poCoreConfig->vSetKey("save_type", SaveAuto ); + m_poCoreConfig->vSetKey("flash_size", 64 ); + m_poCoreConfig->vSetKey("gb_border", true ); + m_poCoreConfig->vSetKey("gb_printer", false ); + m_poCoreConfig->vSetKey("emulator_type", EmulatorAuto ); + m_poCoreConfig->vSetKey("screenshot_format", "png" ); + + // Display section + // + m_poDisplayConfig = m_oConfig.poAddSection("Display"); + m_poDisplayConfig->vSetKey("scale", 1 ); + m_poDisplayConfig->vSetKey("show_speed", ShowPercentage ); + m_poDisplayConfig->vSetKey("pause_when_inactive", true ); + m_poDisplayConfig->vSetKey("filter2x", FilterNone ); + m_poDisplayConfig->vSetKey("filterIB", FilterIBNone ); + + // Sound section + // + m_poSoundConfig = m_oConfig.poAddSection("Sound"); + m_poSoundConfig->vSetKey("status", "on" ); + m_poSoundConfig->vSetKey("echo", false ); + m_poSoundConfig->vSetKey("low_pass", false ); + m_poSoundConfig->vSetKey("reverse_stereo", false ); + m_poSoundConfig->vSetKey("channel_1", true ); + m_poSoundConfig->vSetKey("channel_2", true ); + m_poSoundConfig->vSetKey("channel_3", true ); + m_poSoundConfig->vSetKey("channel_4", true ); + m_poSoundConfig->vSetKey("channel_A", true ); + m_poSoundConfig->vSetKey("channel_B", true ); + m_poSoundConfig->vSetKey("quality", Sound22K ); + m_poSoundConfig->vSetKey("volume", Sound100 ); + + // Input section + // + JoypadConfig oJoypadConfig; + oJoypadConfig.vSetDefault(); + m_poInputConfig = m_oConfig.poAddSection("Input"); + m_poInputConfig->vSetKey("active_joypad", m_iJoypadMin ); + for (int i = m_iJoypadMin; i <= m_iJoypadMax; i++) + { + char csPrefix[20]; + snprintf(csPrefix, sizeof(csPrefix), "joypad%d_", i); + std::string sPrefix(csPrefix); + m_poInputConfig->vSetKey(sPrefix + "up", oJoypadConfig.m_uiUp ); + m_poInputConfig->vSetKey(sPrefix + "down", oJoypadConfig.m_uiDown ); + m_poInputConfig->vSetKey(sPrefix + "left", oJoypadConfig.m_uiLeft ); + m_poInputConfig->vSetKey(sPrefix + "right", oJoypadConfig.m_uiRight ); + m_poInputConfig->vSetKey(sPrefix + "A", oJoypadConfig.m_uiA ); + m_poInputConfig->vSetKey(sPrefix + "B", oJoypadConfig.m_uiB ); + m_poInputConfig->vSetKey(sPrefix + "L", oJoypadConfig.m_uiL ); + m_poInputConfig->vSetKey(sPrefix + "R", oJoypadConfig.m_uiR ); + m_poInputConfig->vSetKey(sPrefix + "select", oJoypadConfig.m_uiSelect ); + m_poInputConfig->vSetKey(sPrefix + "start", oJoypadConfig.m_uiStart ); + m_poInputConfig->vSetKey(sPrefix + "speed", oJoypadConfig.m_uiSpeed ); + m_poInputConfig->vSetKey(sPrefix + "capture", oJoypadConfig.m_uiCapture ); + } + m_poInputConfig->vSetKey("autofire_A", false ); + m_poInputConfig->vSetKey("autofire_B", false ); + m_poInputConfig->vSetKey("autofire_L", false ); + m_poInputConfig->vSetKey("autofire_R", false ); +} + +void Window::vCheckConfig() +{ + int iValue; + int iAdjusted; + std::string sValue; + + // Directories section + // + sValue = m_poDirConfig->sGetKey("gb_roms"); + if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_DIR)) + { + m_poDirConfig->vSetKey("gb_roms", ""); + } + sValue = m_poDirConfig->sGetKey("gba_roms"); + if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_DIR)) + { + m_poDirConfig->vSetKey("gba_roms", ""); + } + sValue = m_poDirConfig->sGetKey("batteries"); + if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_DIR)) + { + m_poDirConfig->vSetKey("batteries", ""); + } + sValue = m_poDirConfig->sGetKey("saves"); + if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_DIR)) + { + m_poDirConfig->vSetKey("saves", ""); + } + sValue = m_poDirConfig->sGetKey("captures"); + if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_DIR)) + { + m_poDirConfig->vSetKey("captures", ""); + } + + // Core section + // + if (m_poCoreConfig->sGetKey("frameskip") != "auto") + { + iValue = m_poCoreConfig->oGetKey("frameskip"); + iAdjusted = CLAMP(iValue, m_iFrameskipMin, m_iFrameskipMax); + if (iValue != iAdjusted) + { + m_poCoreConfig->vSetKey("frameskip", iAdjusted); + } + } + + iValue = m_poCoreConfig->oGetKey("throttle"); + if (iValue != 0) + { + iAdjusted = CLAMP(iValue, m_iThrottleMin, m_iThrottleMax); + if (iValue != iAdjusted) + { + m_poCoreConfig->vSetKey("throttle", iAdjusted); + } + } + + sValue = m_poCoreConfig->sGetKey("bios_file"); + if (sValue != "" && ! Glib::file_test(sValue, Glib::FILE_TEST_IS_REGULAR)) + { + m_poCoreConfig->vSetKey("bios_file", ""); + } + if (m_poCoreConfig->sGetKey("bios_file") == "") + { + m_poCoreConfig->vSetKey("use_bios_file", false); + } + + iValue = m_poCoreConfig->oGetKey("save_type"); + if (iValue != 0) + { + iAdjusted = CLAMP(iValue, m_iSaveTypeMin, m_iSaveTypeMax); + if (iValue != iAdjusted) + { + m_poCoreConfig->vSetKey("save_type", iAdjusted); + } + } + + iValue = m_poCoreConfig->oGetKey("flash_size"); + if (iValue != 64 && iValue != 128) + { + m_poCoreConfig->vSetKey("flash_size", 64); + } + + iValue = m_poCoreConfig->oGetKey("emulator_type"); + iAdjusted = CLAMP(iValue, m_iEmulatorTypeMin, m_iEmulatorTypeMax); + if (iValue != iAdjusted) + { + m_poCoreConfig->vSetKey("emulator_type", iAdjusted); + } + + sValue = m_poCoreConfig->sGetKey("screenshot_format"); + if (sValue != "png" && sValue != "bmp") + { + sValue = "png"; + } + + // Display section + // + iValue = m_poDisplayConfig->oGetKey("scale"); + iAdjusted = CLAMP(iValue, m_iScaleMin, m_iScaleMax); + if (iValue != iAdjusted) + { + m_poDisplayConfig->vSetKey("scale", iAdjusted); + } + + iValue = m_poDisplayConfig->oGetKey("show_speed"); + iAdjusted = CLAMP(iValue, m_iShowSpeedMin, m_iShowSpeedMax); + if (iValue != iAdjusted) + { + m_poDisplayConfig->vSetKey("show_speed", iAdjusted); + } + + iValue = m_poDisplayConfig->oGetKey("filter2x"); + iAdjusted = CLAMP(iValue, m_iFilter2xMin, m_iFilter2xMax); + if (iValue != iAdjusted) + { + m_poDisplayConfig->vSetKey("filter2x", iAdjusted); + } + + iValue = m_poDisplayConfig->oGetKey("filterIB"); + iAdjusted = CLAMP(iValue, m_iFilterIBMin, m_iFilterIBMax); + if (iValue != iAdjusted) + { + m_poDisplayConfig->vSetKey("filterIB", iAdjusted); + } + + // Sound section + // + sValue = m_poSoundConfig->sGetKey("status"); + if (sValue != "off" && sValue != "on" && sValue != "mute") + { + m_poSoundConfig->vSetKey("status", "on"); + } + + iValue = m_poSoundConfig->oGetKey("quality"); + iAdjusted = CLAMP(iValue, m_iSoundQualityMin, m_iSoundQualityMax); + if (iValue != iAdjusted) + { + m_poSoundConfig->vSetKey("quality", iAdjusted); + } + + iValue = m_poSoundConfig->oGetKey("volume"); + iAdjusted = CLAMP(iValue, m_iSoundVolumeMin, m_iSoundVolumeMax); + if (iValue != iAdjusted) + { + m_poSoundConfig->vSetKey("volume", iAdjusted); + } + + // Input section + // + iValue = m_poInputConfig->oGetKey("active_joypad"); + iAdjusted = CLAMP(iValue, m_iJoypadMin, m_iJoypadMax); + if (iValue != iAdjusted) + { + m_poInputConfig->vSetKey("active_joypad", iAdjusted); + } +} + +void Window::vLoadConfig(const std::string & _rsFile) +{ + try + { + m_oConfig.vLoad(_rsFile, false, false); + } + catch (const Glib::Error & e) + { + vPopupError(e.what().c_str()); + } +} + +void Window::vSaveConfig(const std::string & _rsFile) +{ + try + { + m_oConfig.vSave(_rsFile); + } + catch (const Glib::Error & e) + { + vPopupError(e.what().c_str()); + } +} + +void Window::vLoadHistoryFromConfig() +{ + char csKey[] = "0"; + for (int i = 0; i < 10; i++, csKey[0]++) + { + std::string sFile = m_poHistoryConfig->sGetKey(csKey); + if (sFile == "") + { + break; + } + m_listHistory.push_back(sFile); + } +} + +void Window::vSaveHistoryToConfig() +{ + char csKey[] = "0"; + for (std::list::const_iterator it = m_listHistory.begin(); + it != m_listHistory.end(); + it++, csKey[0]++) + { + m_poHistoryConfig->vSetKey(csKey, *it); + } +} + +void Window::vHistoryAdd(const std::string & _rsFile) +{ + if (m_poHistoryConfig->oGetKey("freeze")) + { + return; + } + + m_listHistory.remove(_rsFile); + m_listHistory.push_front(_rsFile); + if (m_listHistory.size() > 10) + { + m_listHistory.pop_back(); + } + + vUpdateHistoryMenu(); +} + +void Window::vClearHistoryMenu() +{ + Gtk::Menu_Helpers::MenuList::iterator it = m_poRecentMenu->items().begin(); + for (int i = 0; i < 3; i++, it++) + ; + + m_poRecentMenu->items().erase(it, m_poRecentMenu->items().end()); +} + +void Window::vUpdateHistoryMenu() +{ + vClearHistoryMenu(); + + guint uiAccelKey = GDK_F1; + for (std::list::const_iterator it = m_listHistory.begin(); + it != m_listHistory.end(); + it++, uiAccelKey++) + { + Gtk::Image * poImage = Gtk::manage(new Gtk::Image(Gtk::Stock::OPEN, Gtk::ICON_SIZE_MENU)); + Glib::ustring sLabel = Glib::path_get_basename(*it); + VBA::ImageMenuItem * poIMI = Gtk::manage(new VBA::ImageMenuItem(*poImage, sLabel)); + + m_oTooltips.set_tip(*poIMI, *it); + + poIMI->signal_activate().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnRecentFile), + *it)); + + poIMI->set_accel_key(Gtk::AccelKey(uiAccelKey, Gdk::CONTROL_MASK)); + poIMI->accelerate(*this); + + poIMI->show(); + m_poRecentMenu->items().push_back(*poIMI); + } +} + +void Window::vLoadJoypadsFromConfig() +{ + m_oJoypads.clear(); + + for (int i = m_iJoypadMin; i <= m_iJoypadMax; i++) + { + char csPrefix[20]; + snprintf(csPrefix, sizeof(csPrefix), "joypad%d_", i); + std::string sPrefix(csPrefix); + + JoypadConfig oJoypadConfig; + oJoypadConfig.m_uiUp = m_poInputConfig->oGetKey(sPrefix + "up"); + oJoypadConfig.m_uiDown = m_poInputConfig->oGetKey(sPrefix + "down"); + oJoypadConfig.m_uiLeft = m_poInputConfig->oGetKey(sPrefix + "left"); + oJoypadConfig.m_uiRight = m_poInputConfig->oGetKey(sPrefix + "right"); + oJoypadConfig.m_uiA = m_poInputConfig->oGetKey(sPrefix + "A"); + oJoypadConfig.m_uiB = m_poInputConfig->oGetKey(sPrefix + "B"); + oJoypadConfig.m_uiL = m_poInputConfig->oGetKey(sPrefix + "L"); + oJoypadConfig.m_uiR = m_poInputConfig->oGetKey(sPrefix + "R"); + oJoypadConfig.m_uiSelect = m_poInputConfig->oGetKey(sPrefix + "select"); + oJoypadConfig.m_uiStart = m_poInputConfig->oGetKey(sPrefix + "start"); + oJoypadConfig.m_uiSpeed = m_poInputConfig->oGetKey(sPrefix + "speed"); + oJoypadConfig.m_uiCapture = m_poInputConfig->oGetKey(sPrefix + "capture"); + + m_oJoypads.push_back(oJoypadConfig); + } +} + +void Window::vSaveJoypadsToConfig() +{ + for (int i = m_iJoypadMin; i <= m_iJoypadMax; i++) + { + char csPrefix[20]; + snprintf(csPrefix, sizeof(csPrefix), "joypad%d_", i); + std::string sPrefix(csPrefix); + + m_poInputConfig->vSetKey(sPrefix + "up", m_oJoypads[i - 1].m_uiUp ); + m_poInputConfig->vSetKey(sPrefix + "down", m_oJoypads[i - 1].m_uiDown ); + m_poInputConfig->vSetKey(sPrefix + "left", m_oJoypads[i - 1].m_uiLeft ); + m_poInputConfig->vSetKey(sPrefix + "right", m_oJoypads[i - 1].m_uiRight ); + m_poInputConfig->vSetKey(sPrefix + "A", m_oJoypads[i - 1].m_uiA ); + m_poInputConfig->vSetKey(sPrefix + "B", m_oJoypads[i - 1].m_uiB ); + m_poInputConfig->vSetKey(sPrefix + "L", m_oJoypads[i - 1].m_uiL ); + m_poInputConfig->vSetKey(sPrefix + "R", m_oJoypads[i - 1].m_uiR ); + m_poInputConfig->vSetKey(sPrefix + "select", m_oJoypads[i - 1].m_uiSelect ); + m_poInputConfig->vSetKey(sPrefix + "start", m_oJoypads[i - 1].m_uiStart ); + m_poInputConfig->vSetKey(sPrefix + "speed", m_oJoypads[i - 1].m_uiSpeed ); + m_poInputConfig->vSetKey(sPrefix + "capture", m_oJoypads[i - 1].m_uiCapture ); + } +} + +void Window::vUpdateScreen() +{ + if (m_eCartridge == CartridgeGB) + { + if (gbBorderOn) + { + m_iScreenWidth = m_iSGBScreenWidth; + m_iScreenHeight = m_iSGBScreenHeight; + gbBorderLineSkip = m_iSGBScreenWidth; + gbBorderColumnSkip = (m_iSGBScreenWidth - m_iGBScreenWidth) / 2; + gbBorderRowSkip = (m_iSGBScreenHeight - m_iGBScreenHeight) / 2; + } + else + { + m_iScreenWidth = m_iGBScreenWidth; + m_iScreenHeight = m_iGBScreenHeight; + gbBorderLineSkip = m_iGBScreenWidth; + gbBorderColumnSkip = 0; + gbBorderRowSkip = 0; + } + } + else if (m_eCartridge == CartridgeGBA) + { + m_iScreenWidth = m_iGBAScreenWidth; + m_iScreenHeight = m_iGBAScreenHeight; + } + + g_return_if_fail(m_iScreenWidth >= 1 && m_iScreenHeight >= 1); + + m_poScreenArea->vSetSize(m_iScreenWidth, m_iScreenHeight); + m_poScreenArea->vSetScale(m_poDisplayConfig->oGetKey("scale")); + + resize(1, 1); + + if (emulating) + { + vDrawScreen(); + } + else + { + vDrawDefaultScreen(); + } +} + +bool Window::bLoadROM(const std::string & _rsFile) +{ + vOnFileClose(); + + m_sRomFile = _rsFile; + const char * csFile = _rsFile.c_str(); + + IMAGE_TYPE eType = utilFindType(csFile); + if (eType == IMAGE_UNKNOWN) + { + vPopupError(_("Unknown file type %s"), csFile); + return false; + } + + bool bLoaded = false; + if (eType == IMAGE_GB) + { + bLoaded = gbLoadRom(csFile); + if (bLoaded) + { + m_eCartridge = CartridgeGB; + m_stEmulator = GBSystem; + } + } + else if (eType == IMAGE_GBA) + { + int iSize = CPULoadRom(csFile); + bLoaded = (iSize > 0); + if (bLoaded) + { + m_eCartridge = CartridgeGBA; + m_stEmulator = GBASystem; + + useBios = m_poCoreConfig->oGetKey("use_bios_file"); + CPUInit(m_poCoreConfig->sGetKey("bios_file").c_str(), useBios); + CPUReset(); + + // If the bios file was rejected by CPUInit + if (m_poCoreConfig->oGetKey("use_bios_file") && ! useBios) + { + m_poUseBiosItem->set_active(false); + m_poUseBiosItem->set_sensitive(false); + m_poCoreConfig->vSetKey("bios_file", ""); + } + } + } + + if (! bLoaded) + { + return false; + } + + vLoadBattery(); + vUpdateScreen(); + + debugger = false; // May cause conflicts + emulating = 1; + m_bWasEmulating = false; + m_uiThrottleDelay = Glib::TimeVal(0, 0); + + if (m_eCartridge == CartridgeGBA) + { + soundSetQuality(m_eSoundQuality); + } + else + { + gbSoundSetQuality(m_eSoundQuality); + } + + vUpdateGameSlots(); + vHistoryAdd(_rsFile); + + for (std::list::iterator it = m_listSensitiveWhenPlaying.begin(); + it != m_listSensitiveWhenPlaying.end(); + it++) + { + (*it)->set_sensitive(); + } + + if (m_poCoreConfig->oGetKey("load_game_auto")) + { + vOnLoadGameMostRecent(); + } + + vStartEmu(); + + return true; +} + +void Window::vPopupError(const char * _csFormat, ...) +{ + va_list args; + va_start(args, _csFormat); + char * csMsg = g_strdup_vprintf(_csFormat, args); + va_end(args); + + Gtk::MessageDialog oDialog(*this, + csMsg, + false, + Gtk::MESSAGE_ERROR, + Gtk::BUTTONS_OK); + oDialog.run(); + g_free(csMsg); +} + +void Window::vPopupErrorV(const char * _csFormat, va_list _args) +{ + char * csMsg = g_strdup_vprintf(_csFormat, _args); + + Gtk::MessageDialog oDialog(*this, + csMsg, + false, + Gtk::MESSAGE_ERROR, + Gtk::BUTTONS_OK); + oDialog.run(); + g_free(csMsg); +} + +void Window::vDrawScreen() +{ + m_poScreenArea->vDrawPixels(pix); +} + +void Window::vDrawDefaultScreen() +{ + m_poScreenArea->vDrawColor(0x000000); // Black +} + +void Window::vSetDefaultTitle() +{ + set_title("VBA"); +} + +void Window::vShowSpeed(int _iSpeed) +{ + char csTitle[50]; + + /*if (m_eShowSpeed == ShowPercentage) + { + snprintf(csTitle, 50, "VBA - %d%%", _iSpeed); + set_title(csTitle); + } + else if (m_eShowSpeed == ShowDetailed) + {*/ + snprintf(csTitle, 50, "VBA - %d%% (%d, %d fps)", + _iSpeed, systemFrameSkip, systemFPS); + set_title(csTitle); + //} +} + +void Window::vComputeFrameskip(int _iRate) +{ + static Glib::TimeVal uiLastTime; + static int iFrameskipAdjust = 0; + + Glib::TimeVal uiTime; + uiTime.assign_current_time(); + + if (m_bWasEmulating) + { + int iWantedSpeed = 100; + + if (systemThrottle > 0) + { + if (! speedup) + { + Glib::TimeVal uiDiff = uiTime - m_uiThrottleLastTime; + Glib::TimeVal iTarget = Glib::TimeVal(0, 1000 / (_iRate * systemThrottle)); + Glib::TimeVal iDelay = iTarget - uiDiff; + if (iDelay > Glib::TimeVal(0, 0)) + { + m_uiThrottleDelay = iDelay; + } + } + iWantedSpeed = systemThrottle; + } + + if (m_bAutoFrameskip) + { + Glib::TimeVal uiDiff = uiTime - uiLastTime; + int iSpeed = iWantedSpeed; + + if (uiDiff != Glib::TimeVal(0, 0)) + { + iSpeed = (1000000 / _iRate) / (uiDiff.as_double() * 1000); + } + + if (iSpeed >= iWantedSpeed - 2) + { + iFrameskipAdjust++; + if (iFrameskipAdjust >= 3) + { + iFrameskipAdjust = 0; + if (systemFrameSkip > 0) + { + systemFrameSkip--; + } + } + } + else + { + if (iSpeed < iWantedSpeed - 20) + { + iFrameskipAdjust -= ((iWantedSpeed - 10) - iSpeed) / 5; + } + else if (systemFrameSkip < 9) + { + iFrameskipAdjust--; + } + + if (iFrameskipAdjust <= -2) + { + iFrameskipAdjust += 2; + if (systemFrameSkip < 9) + { + systemFrameSkip++; + } + } + } + } + } + else + { + m_bWasEmulating = true; + } + + uiLastTime = uiTime; + m_uiThrottleLastTime = uiTime; +} + +void Window::vCaptureScreen(int _iNum) +{ + std::string sBaseName; + std::string sCaptureDir = m_poDirConfig->sGetKey("captures"); + if (sCaptureDir == "") + { + sBaseName = sCutSuffix(m_sRomFile); + } + else + { + sBaseName = sCaptureDir + "/" + sCutSuffix(Glib::path_get_basename(m_sRomFile)); + } + std::string sFormat = m_poCoreConfig->sGetKey("screenshot_format"); + + char * csFile = g_strdup_printf("%s_%02d.%s", + sBaseName.c_str(), + _iNum, + sFormat.c_str()); + if (sFormat == "png") + { + m_stEmulator.emuWritePNG(csFile); + } + else + { + m_stEmulator.emuWriteBMP(csFile); + } + g_free(csFile); +} + +u32 Window::uiReadJoypad() +{ + u32 uiJoypad = m_uiJoypadState; + + if (m_uiAutofireState != 0) + { + uiJoypad &= ~m_uiAutofireState; + if (m_bAutofireToggle) + { + uiJoypad |= m_uiAutofireState; + } + m_bAutofireToggle = ! m_bAutofireToggle; + } + + return uiJoypad; +} + +void Window::vCreateFileOpenDialog() +{ + if (m_poFileOpenDialog != NULL) + { + return; + } + + std::string sGBDir = m_poDirConfig->sGetKey("gb_roms"); + std::string sGBADir = m_poDirConfig->sGetKey("gba_roms"); + + Gtk::FileChooserDialog * poDialog = new Gtk::FileChooserDialog(*this, _("Open")); + poDialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + poDialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); + + if (sGBDir != "") + { + poDialog->add_shortcut_folder(sGBDir); + poDialog->set_current_folder(sGBDir); + } + + if (sGBADir != "" && sGBADir != sGBDir) + { + poDialog->add_shortcut_folder(sGBADir); + poDialog->set_current_folder(sGBADir); + } + + const char * acsPattern[] = + { + // GBA + "*.[bB][iI][nN]", "*.[aA][gG][bB]", "*.[gG][bB][aA]", + // GB + "*.[gG][bB]", "*.[sS][gG][bB]", "*.[cC][gG][bB]", "*.[gG][bB][cC]", + // Both + "*.[mM][bB]", "*.[eE][lL][fF]", "*.[zZ][iI][pP]", "*.[zZ]", "*.[gG][zZ]" + }; + + Gtk::FileFilter oAllGBAFilter; + oAllGBAFilter.set_name(_("All Gameboy Advance files")); + for (guint i = 0; i < G_N_ELEMENTS(acsPattern); i++) + { + oAllGBAFilter.add_pattern(acsPattern[i]); + } + + Gtk::FileFilter oGBAFilter; + oGBAFilter.set_name(_("Gameboy Advance files")); + for (int i = 0; i < 3; i++) + { + oGBAFilter.add_pattern(acsPattern[i]); + } + + Gtk::FileFilter oGBFilter; + oGBFilter.set_name(_("Gameboy files")); + for (int i = 3; i < 7; i++) + { + oGBFilter.add_pattern(acsPattern[i]); + } + + poDialog->add_filter(oAllGBAFilter); + poDialog->add_filter(oGBAFilter); + poDialog->add_filter(oGBFilter); + + m_poFileOpenDialog = poDialog; +} + +void Window::vLoadBattery() +{ + std::string sBattery; + std::string sDir = m_poDirConfig->sGetKey("batteries"); + if (sDir == "") + { + sBattery = sCutSuffix(m_sRomFile) + ".sav"; + } + else + { + sBattery = sDir + "/" + sCutSuffix(Glib::path_get_basename(m_sRomFile)) + ".sav"; + } + + if (m_stEmulator.emuReadBattery(sBattery.c_str())) + { + systemScreenMessage(_("Loaded battery")); + } +} + +void Window::vSaveBattery() +{ + std::string sBattery; + std::string sDir = m_poDirConfig->sGetKey("batteries"); + if (sDir == "") + { + sBattery = sCutSuffix(m_sRomFile) + ".sav"; + } + else + { + sBattery = sDir + "/" + sCutSuffix(Glib::path_get_basename(m_sRomFile)) + ".sav"; + } + + if (m_stEmulator.emuWriteBattery(sBattery.c_str())) + { + systemScreenMessage(_("Saved battery")); + } +} + +void Window::vStartEmu() +{ + if (m_oEmuSig.connected()) + { + return; + } + + m_oEmuSig = Glib::signal_idle().connect(sigc::mem_fun(*this, &Window::bOnEmuIdle), + Glib::PRIORITY_DEFAULT_IDLE); +} + +void Window::vStopEmu() +{ + m_oEmuSig.disconnect(); + m_bWasEmulating = false; +} + +void Window::vSetThrottle(int _iPercent) +{ + systemThrottle = _iPercent; + m_poCoreConfig->vSetKey("throttle", _iPercent); +} + +void Window::vSelectBestThrottleItem() +{ + struct + { + const char * m_csName; + const int m_iThrottle; + } + astThrottle[] = + { + { "ThrottleNoThrottle", 0 }, + { "Throttle25", 25 }, + { "Throttle50", 50 }, + { "Throttle100", 100 }, + { "Throttle150", 150 }, + { "Throttle200", 200 } + }; + for (guint i = 0; i < G_N_ELEMENTS(astThrottle); i++) + { + Gtk::CheckMenuItem * poCMI; + poCMI = dynamic_cast(m_poXml->get_widget(astThrottle[i].m_csName)); + if (astThrottle[i].m_iThrottle == systemThrottle) + { + poCMI->set_active(); + } + } +} + +void Window::vUpdateGameSlots() +{ + if (m_eCartridge == CartridgeNone) + { + std::string sDateTime = _("----/--/-- --:--:--"); + + for (int i = 0; i < 10; i++) + { + char csPrefix[10]; + snprintf(csPrefix, sizeof(csPrefix), "%2d ", i + 1); + + Gtk::Label * poLabel; + poLabel = dynamic_cast(m_apoLoadGameItem[i]->get_child()); + poLabel->set_text(csPrefix + sDateTime); + m_apoLoadGameItem[i]->set_sensitive(false); + + poLabel = dynamic_cast(m_apoSaveGameItem[i]->get_child()); + poLabel->set_text(csPrefix + sDateTime); + m_apoSaveGameItem[i]->set_sensitive(false); + + m_astGameSlot[i].m_bEmpty = true; + } + } + else + { + std::string sFileBase; + std::string sDir = m_poDirConfig->sGetKey("saves"); + if (sDir == "") + { + sFileBase = sCutSuffix(m_sRomFile); + } + else + { + sFileBase = sDir + "/" + sCutSuffix(Glib::path_get_basename(m_sRomFile)); + } + + const char * csDateFormat = _("%Y/%m/%d %H:%M:%S"); + + for (int i = 0; i < 10; i++) + { + char csPrefix[10]; + snprintf(csPrefix, sizeof(csPrefix), "%2d ", i + 1); + + char csSlot[10]; + snprintf(csSlot, sizeof(csSlot), "%d", i + 1); + m_astGameSlot[i].m_sFile = sFileBase + csSlot + ".sgm"; + + std::string sDateTime; + struct stat stStat; + if (stat(m_astGameSlot[i].m_sFile.c_str(), &stStat) == -1) + { + sDateTime = _("----/--/-- --:--:--"); + m_astGameSlot[i].m_bEmpty = true; + } + else + { + char csDateTime[30]; + strftime(csDateTime, sizeof(csDateTime), csDateFormat, + localtime(&stStat.st_mtime)); + sDateTime = csDateTime; + m_astGameSlot[i].m_bEmpty = false; + m_astGameSlot[i].m_uiTime = stStat.st_mtime; + } + + Gtk::Label * poLabel; + poLabel = dynamic_cast(m_apoLoadGameItem[i]->get_child()); + poLabel->set_text(csPrefix + sDateTime); + m_apoLoadGameItem[i]->set_sensitive(! m_astGameSlot[i].m_bEmpty); + + poLabel = dynamic_cast(m_apoSaveGameItem[i]->get_child()); + poLabel->set_text(csPrefix + sDateTime); + m_apoSaveGameItem[i]->set_sensitive(); + } + } +} + +} // VBA namespace diff --git a/src/gtk/window.h b/src/gtk/window.h new file mode 100644 index 00000000..25ec213b --- /dev/null +++ b/src/gtk/window.h @@ -0,0 +1,309 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_WINDOW_H__ +#define __VBA_WINDOW_H__ + +#include +#include + +#include +#include + +#include +#include +#include + +#include "../System.h" + +#include "configfile.h" +#include "screenarea.h" +#include "filters.h" +#include "input.h" +#include "joypadconfig.h" + +namespace VBA +{ + +class Window : public Gtk::Window +{ + friend class Gnome::Glade::Xml; + +public: + virtual ~Window(); + + inline static Window * poGetInstance() { return m_poInstance; } + + enum ECartridge + { + CartridgeNone, + CartridgeGB, + CartridgeGBA + }; + + // GB/GBA screen sizes + const int m_iGBScreenWidth; + const int m_iGBScreenHeight; + const int m_iSGBScreenWidth; + const int m_iSGBScreenHeight; + const int m_iGBAScreenWidth; + const int m_iGBAScreenHeight; + + bool bLoadROM(const std::string & _rsFile); + void vPopupError(const char * _csFormat, ...); + void vPopupErrorV(const char * _csFormat, va_list _args); + void vDrawScreen(); + void vComputeFrameskip(int _iRate); + void vShowSpeed(int _iSpeed); + void vCaptureScreen(int _iNum); + u32 uiReadJoypad(); + + inline ECartridge eGetCartridge() const { return m_eCartridge; } + +protected: + Window(GtkWindow * _pstWindow, + const Glib::RefPtr & _poXml); + + enum EShowSpeed + { + ShowNone, + ShowPercentage, + ShowDetailed + }; + + enum ESaveType + { + SaveAuto, + SaveEEPROM, + SaveSRAM, + SaveFlash, + SaveEEPROMSensor, + SaveNone + }; + + enum ESoundStatus + { + SoundOff, + SoundMute, + SoundOn + }; + + enum ESoundQuality + { + Sound44K = 1, + Sound22K = 2, + Sound11K = 4 + }; + + enum ESoundVolume + { + Sound100, + Sound200, + Sound300, + Sound400, + Sound25, + Sound50 + }; + + enum EEmulatorType + { + EmulatorAuto, + EmulatorCGB, + EmulatorSGB, + EmulatorGB, + EmulatorGBA, + EmulatorSGB2 + }; + + virtual void vOnFileOpen(); + virtual void vOnFileLoad(); + virtual void vOnFileSave(); + virtual void vOnLoadGameMostRecent(); + virtual void vOnLoadGameAutoToggled(Gtk::CheckMenuItem * _poCMI); + void vOnLoadGame(int _iSlot); + virtual void vOnSaveGameOldest(); + void vOnSaveGame(int _iSlot); + virtual void vOnFilePauseToggled(Gtk::CheckMenuItem * _poCMI); + virtual void vOnFileReset(); + virtual void vOnRecentReset(); + virtual void vOnRecentFreezeToggled(Gtk::CheckMenuItem * _poCMI); + virtual void vOnRecentFile(std::string _sFile); + virtual void vOnImportBatteryFile(); + virtual void vOnExportBatteryFile(); + virtual void vOnFileScreenCapture(); + virtual void vOnFileClose(); + virtual void vOnFileExit(); + virtual void vOnFrameskipToggled(Gtk::CheckMenuItem * _poCMI, int _iValue); + virtual void vOnThrottleToggled(Gtk::CheckMenuItem * _poCMI, int _iPercent); + virtual void vOnThrottleOther(Gtk::CheckMenuItem * _poCMI); + virtual void vOnVideoScaleToggled(Gtk::CheckMenuItem * _poCMI, int _iScale); + virtual void vOnLayerToggled(Gtk::CheckMenuItem * _poCMI, int _iLayer); + virtual void vOnDirectories(); + virtual void vOnDirectoryReset(Gtk::Entry * _poEntry); + virtual void vOnDirectorySelect(Gtk::Entry * _poEntry); + virtual void vOnPauseWhenInactiveToggled(Gtk::CheckMenuItem * _poCMI); + virtual void vOnSelectBios(); + virtual void vOnUseBiosToggled(Gtk::CheckMenuItem * _poCMI); + virtual void vOnShowSpeedToggled(Gtk::CheckMenuItem * _poCMI, int _iShowSpeed); + virtual void vOnSaveTypeToggled(Gtk::CheckMenuItem * _poCMI, int _iSaveType); + virtual void vOnFlashSizeToggled(Gtk::CheckMenuItem * _poCMI, int _iFlashSize); + virtual void vOnScreenshotFormatToggled(Gtk::CheckMenuItem * _poCMI, std::string _sFormat); + virtual void vOnSoundStatusToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundStatus); + virtual void vOnSoundEchoToggled(Gtk::CheckMenuItem * _poCMI); + virtual void vOnSoundLowPassToggled(Gtk::CheckMenuItem * _poCMI); + virtual void vOnSoundReverseToggled(Gtk::CheckMenuItem * _poCMI); + virtual void vOnSoundChannelToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundChannel); + virtual void vOnSoundQualityToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundQuality); + virtual void vOnSoundVolumeToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundVolume); + virtual void vOnGBBorderToggled(Gtk::CheckMenuItem * _poCMI); + virtual void vOnGBPrinterToggled(Gtk::CheckMenuItem * _poCMI); + virtual void vOnEmulatorTypeToggled(Gtk::CheckMenuItem * _poCMI, int _iEmulatorType); + virtual void vOnFilter2xToggled(Gtk::CheckMenuItem * _poCMI, int _iFilter2x); + virtual void vOnFilterIBToggled(Gtk::CheckMenuItem * _poCMI, int _iFilterIB); + virtual void vOnJoypadConfigure(int _iJoypad); + virtual void vOnJoypadToggled(Gtk::CheckMenuItem * _poCMI, int _iJoypad); + virtual void vOnAutofireToggled(Gtk::CheckMenuItem * _poCMI, u32 _uiKeyFlag); + virtual void vOnGDBWait(); + virtual void vOnGDBLoadAndWait(); + virtual void vOnGDBBreak(); + virtual void vOnGDBDisconnect(); + virtual void vOnHelpAbout(); + virtual bool bOnEmuIdle(); + + virtual bool on_focus_in_event(GdkEventFocus * _pstEvent); + virtual bool on_focus_out_event(GdkEventFocus * _pstEvent); + virtual bool on_key_press_event(GdkEventKey * _pstEvent); + virtual bool on_key_release_event(GdkEventKey * _pstEvent); + +private: + // Config limits + const int m_iFrameskipMin; + const int m_iFrameskipMax; + const int m_iThrottleMin; + const int m_iThrottleMax; + const int m_iScaleMin; + const int m_iScaleMax; + const int m_iShowSpeedMin; + const int m_iShowSpeedMax; + const int m_iSaveTypeMin; + const int m_iSaveTypeMax; + const int m_iSoundQualityMin; + const int m_iSoundQualityMax; + const int m_iSoundVolumeMin; + const int m_iSoundVolumeMax; + const int m_iEmulatorTypeMin; + const int m_iEmulatorTypeMax; + const int m_iFilter2xMin; + const int m_iFilter2xMax; + const int m_iFilterIBMin; + const int m_iFilterIBMax; + const int m_iJoypadMin; + const int m_iJoypadMax; + + static Window * m_poInstance; + + Glib::RefPtr m_poXml; + + std::string m_sUserDataDir; + std::string m_sConfigFile; + Config::File m_oConfig; + Config::Section * m_poHistoryConfig; + Config::Section * m_poDirConfig; + Config::Section * m_poCoreConfig; + Config::Section * m_poDisplayConfig; + Config::Section * m_poSoundConfig; + Config::Section * m_poInputConfig; + + Gtk::FileChooserDialog * m_poFileOpenDialog; + + ScreenArea * m_poScreenArea; + Gtk::Menu * m_poRecentMenu; + Gtk::MenuItem * m_poRecentResetItem; + Gtk::CheckMenuItem * m_poFilePauseItem; + Gtk::CheckMenuItem * m_poUseBiosItem; + Gtk::CheckMenuItem * m_poSoundOffItem; + + struct SGameSlot + { + bool m_bEmpty; + std::string m_sFile; + time_t m_uiTime; + }; + + Gtk::MenuItem * m_apoLoadGameItem[10]; + Gtk::MenuItem * m_apoSaveGameItem[10]; + SGameSlot m_astGameSlot[10]; + + std::list m_listHistory; + + std::list m_listSensitiveWhenPlaying; + + Gtk::Tooltips m_oTooltips; + + SigC::Connection m_oEmuSig; + + std::vector m_oJoypads; + Keymap * m_poKeymap; + + int m_iScreenWidth; + int m_iScreenHeight; + + std::string m_sRomFile; + ECartridge m_eCartridge; + EmulatedSystem m_stEmulator; + u32 m_uiJoypadState; + u32 m_uiAutofireState; + bool m_bAutofireToggle; + bool m_bPaused; + bool m_bWasEmulating; + bool m_bAutoFrameskip; + Glib::TimeVal m_uiThrottleLastTime; + Glib::TimeVal m_uiThrottleDelay; + EShowSpeed m_eShowSpeed; + ESoundQuality m_eSoundQuality; + + void vInitSystem(); + void vInitConfig(); + void vCheckConfig(); + void vLoadConfig(const std::string & _rsFile); + void vSaveConfig(const std::string & _rsFile); + void vLoadHistoryFromConfig(); + void vSaveHistoryToConfig(); + void vHistoryAdd(const std::string & _rsFile); + void vClearHistoryMenu(); + void vUpdateHistoryMenu(); + void vLoadJoypadsFromConfig(); + void vSaveJoypadsToConfig(); + void vUpdateScreen(); + void vDrawDefaultScreen(); + void vSetDefaultTitle(); + void vCreateFileOpenDialog(); + void vLoadBattery(); + void vSaveBattery(); + void vStartEmu(); + void vStopEmu(); + void vSetThrottle(int _iPercent); + void vSelectBestThrottleItem(); + void vUpdateGameSlots(); +}; + +} // namespace VBA + + +#endif // __VBA_WINDOW_H__ diff --git a/src/gtk/windowcallbacks.cpp b/src/gtk/windowcallbacks.cpp new file mode 100644 index 00000000..e12addeb --- /dev/null +++ b/src/gtk/windowcallbacks.cpp @@ -0,0 +1,1411 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "window.h" + +#include + +#include +#include + +#include "../agb/GBA.h" +#include "../dmg/gb.h" +#include "../dmg/gbGlobals.h" +#include "../dmg/gbPrinter.h" +#include "../Sound.h" +#include "../Util.h" + +#include "tools.h" +#include "intl.h" + +extern int systemRenderedFrames; +extern int systemFPS; +extern bool debugger; +extern int RGB_LOW_BITS_MASK; +extern void (*dbgMain)(); +extern void (*dbgSignal)(int, int); +extern void remoteInit(); +extern void remoteCleanUp(); +extern void remoteStubMain(); +extern void remoteStubSignal(int, int); +extern void remoteOutput(const char *, u32); +extern void remoteSetProtocol(int); +extern void remoteSetPort(int); + +namespace VBA +{ + +using Gnome::Glade::Xml; + +void Window::vOnFileOpen() +{ + while (m_poFileOpenDialog->run() == Gtk::RESPONSE_OK) + { + if (bLoadROM(m_poFileOpenDialog->get_filename())) + { + break; + } + } + m_poFileOpenDialog->hide(); +} + +void Window::vOnFileLoad() +{ + std::string sSaveDir = m_poDirConfig->sGetKey("saves"); + + Gtk::FileChooserDialog oDialog(*this, _("Load game")); + oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + oDialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); + + if (sSaveDir == "") + { + oDialog.set_current_folder(Glib::path_get_dirname(m_sRomFile)); + } + else + { + oDialog.set_current_folder(sSaveDir); + oDialog.add_shortcut_folder(sSaveDir); + } + + Gtk::FileFilter oSaveFilter; + oSaveFilter.set_name(_("VisualBoyAdvance save game")); + oSaveFilter.add_pattern("*.[sS][gG][mM]"); + + oDialog.add_filter(oSaveFilter); + + while (oDialog.run() == Gtk::RESPONSE_OK) + { + if (m_stEmulator.emuReadState(oDialog.get_filename().c_str())) + { + break; + } + } +} + +void Window::vOnFileSave() +{ + Glib::ustring sSaveDir = m_poDirConfig->sGetKey("saves"); + + Gtk::FileChooserDialog oDialog(*this, _("Save game"), + Gtk::FILE_CHOOSER_ACTION_SAVE); + oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + oDialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + + if (sSaveDir == "") + { + oDialog.set_current_folder(Glib::path_get_dirname(m_sRomFile)); + } + else + { + oDialog.set_current_folder(sSaveDir); + oDialog.add_shortcut_folder(sSaveDir); + } + oDialog.set_current_name(sCutSuffix(Glib::path_get_basename(m_sRomFile))); + + Gtk::FileFilter oSaveFilter; + oSaveFilter.set_name(_("VisualBoyAdvance save game")); + oSaveFilter.add_pattern("*.[sS][gG][mM]"); + + oDialog.add_filter(oSaveFilter); + + while (oDialog.run() == Gtk::RESPONSE_OK) + { + Glib::ustring sFile = oDialog.get_filename(); + if (! bHasSuffix(sFile, ".sgm", false)) + { + sFile += ".sgm"; + } + + if (Glib::file_test(sFile, Glib::FILE_TEST_EXISTS)) + { + Gtk::MessageDialog oConfirmDialog(*this, + _("File already exists. Overwrite it?"), + false, + Gtk::MESSAGE_QUESTION, + Gtk::BUTTONS_YES_NO); + if (oConfirmDialog.run() != Gtk::RESPONSE_YES) + { + continue; + } + } + + if (m_stEmulator.emuWriteState(sFile.c_str())) + { + break; + } + } +} + +void Window::vOnLoadGameMostRecent() +{ + int iMostRecent = -1; + time_t uiTimeMax; + + for (int i = 0; i < 10; i++) + { + if (! m_astGameSlot[i].m_bEmpty + && (iMostRecent < 0 || m_astGameSlot[i].m_uiTime > uiTimeMax)) + { + iMostRecent = i; + uiTimeMax = m_astGameSlot[i].m_uiTime; + } + } + + if (iMostRecent >= 0) + { + vOnLoadGame(iMostRecent + 1); + } +} + +void Window::vOnLoadGameAutoToggled(Gtk::CheckMenuItem * _poCMI) +{ + m_poCoreConfig->vSetKey("load_game_auto", _poCMI->get_active()); +} + +void Window::vOnLoadGame(int _iSlot) +{ + int i = _iSlot - 1; + if (! m_astGameSlot[i].m_bEmpty) + { + m_stEmulator.emuReadState(m_astGameSlot[i].m_sFile.c_str()); + m_poFilePauseItem->set_active(false); + } +} + +void Window::vOnSaveGameOldest() +{ + int iOldest = -1; + time_t uiTimeMin; + + for (int i = 0; i < 10; i++) + { + if (! m_astGameSlot[i].m_bEmpty + && (iOldest < 0 || m_astGameSlot[i].m_uiTime < uiTimeMin)) + { + iOldest = i; + uiTimeMin = m_astGameSlot[i].m_uiTime; + } + } + + if (iOldest >= 0) + { + vOnSaveGame(iOldest + 1); + } + else + { + vOnSaveGame(1); + } +} + +void Window::vOnSaveGame(int _iSlot) +{ + int i = _iSlot - 1; + m_stEmulator.emuWriteState(m_astGameSlot[i].m_sFile.c_str()); + vUpdateGameSlots(); +} + +void Window::vOnFilePauseToggled(Gtk::CheckMenuItem * _poCMI) +{ + m_bPaused = _poCMI->get_active(); + if (emulating) + { + if (m_bPaused) + { + vStopEmu(); + soundPause(); + } + else + { + vStartEmu(); + soundResume(); + } + } +} + +void Window::vOnFileReset() +{ + if (emulating) + { + m_stEmulator.emuReset(); + m_poFilePauseItem->set_active(false); + } +} + +void Window::vOnRecentReset() +{ + m_listHistory.clear(); + vClearHistoryMenu(); +} + +void Window::vOnRecentFreezeToggled(Gtk::CheckMenuItem * _poCMI) +{ + m_poRecentResetItem->set_sensitive(! _poCMI->get_active()); + m_poHistoryConfig->vSetKey("freeze", _poCMI->get_active()); +} + +void Window::vOnRecentFile(std::string _sFile) +{ + bLoadROM(_sFile); +} + +void Window::vOnImportBatteryFile() +{ + std::string BatteryDir = m_poDirConfig->sGetKey("batteries"); + + Gtk::FileChooserDialog oDialog(*this, _("Import battery file")); + oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + oDialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); + + if (BatteryDir == "") + { + oDialog.set_current_folder(Glib::path_get_dirname(m_sRomFile)); + } + else + { + oDialog.set_current_folder(BatteryDir); + oDialog.add_shortcut_folder(BatteryDir); + } + + Gtk::FileFilter oBatteryFilter; + oBatteryFilter.set_name(_("Battery file")); + oBatteryFilter.add_pattern("*.[sS][aA][vV]"); + + Gtk::FileFilter oFlashFilter; + oFlashFilter.set_name(_("Flash save")); + oFlashFilter.add_pattern("*.[dD][aA][tT]"); + + oDialog.add_filter(oBatteryFilter); + oDialog.add_filter(oFlashFilter); + + while (oDialog.run() == Gtk::RESPONSE_OK) + { + Gtk::MessageDialog oConfirmDialog(*this, + _("Importing a battery file will erase any saved games and reset the emulator. Do you want to continue?"), + false, + Gtk::MESSAGE_QUESTION, + Gtk::BUTTONS_YES_NO); + if (oConfirmDialog.run() != Gtk::RESPONSE_YES) + { + continue; + } + + if (m_stEmulator.emuReadBattery(oDialog.get_filename().c_str())) + { + m_stEmulator.emuReset(); + break; + } + else + { + vPopupError(_("Failed to import battery file %s."), + oDialog.get_filename().c_str()); + } + } +} + +void Window::vOnExportBatteryFile() +{ + std::string sBatteryDir = m_poDirConfig->sGetKey("batteries"); + + Gtk::FileChooserDialog oDialog(*this, _("Export battery file"), + Gtk::FILE_CHOOSER_ACTION_SAVE); + oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + oDialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + + if (sBatteryDir == "") + { + oDialog.set_current_folder(Glib::path_get_dirname(m_sRomFile)); + } + else + { + oDialog.set_current_folder(sBatteryDir); + oDialog.add_shortcut_folder(sBatteryDir); + } + oDialog.set_current_name(sCutSuffix(Glib::path_get_basename(m_sRomFile))); + + Gtk::FileFilter oBatteryFilter; + oBatteryFilter.set_name(_("Battery file")); + oBatteryFilter.add_pattern("*.[sS][aA][vV]"); + + Gtk::FileFilter oFlashFilter; + oFlashFilter.set_name(_("Flash save")); + oFlashFilter.add_pattern("*.[dD][aA][tT]"); + + oDialog.add_filter(oBatteryFilter); + oDialog.add_filter(oFlashFilter); + + while (oDialog.run() == Gtk::RESPONSE_OK) + { + Glib::ustring sFile = oDialog.get_filename(); + Glib::ustring sExt; + + if (oDialog.get_filter() == &oBatteryFilter) + { + sExt = ".sav"; + } + else + { + sExt = ".dat"; + } + + if (! bHasSuffix(sFile, sExt, false)) + { + sFile += sExt; + } + + if (Glib::file_test(sFile, Glib::FILE_TEST_EXISTS)) + { + Gtk::MessageDialog oConfirmDialog(*this, + _("File already exists. Overwrite it?"), + false, + Gtk::MESSAGE_QUESTION, + Gtk::BUTTONS_YES_NO); + if (oConfirmDialog.run() != Gtk::RESPONSE_YES) + { + continue; + } + } + + bool bResult; + if (m_eCartridge == CartridgeGB) + { + bResult = gbWriteBatteryFile(sFile.c_str(), false); + } + else + { + bResult = m_stEmulator.emuWriteBattery(sFile.c_str()); + } + + if (bResult) + { + break; + } + else + { + vPopupError(_("Failed to export battery file %s."), + sFile.c_str()); + } + } +} + +void Window::vOnFileScreenCapture() +{ + std::string sCaptureDir = m_poDirConfig->sGetKey("captures"); + + Gtk::FileChooserDialog oDialog(*this, _("Save screenshot"), + Gtk::FILE_CHOOSER_ACTION_SAVE); + oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + oDialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + + if (sCaptureDir == "") + { + oDialog.set_current_folder(Glib::path_get_dirname(m_sRomFile)); + } + else + { + oDialog.set_current_folder(sCaptureDir); + oDialog.add_shortcut_folder(sCaptureDir); + } + oDialog.set_current_name(sCutSuffix(Glib::path_get_basename(m_sRomFile))); + + Gtk::FileFilter oPngFilter; + oPngFilter.set_name(_("PNG image")); + oPngFilter.add_pattern("*.[pP][nN][gG]"); + + Gtk::FileFilter oBmpFilter; + oBmpFilter.set_name(_("BMP image")); + oBmpFilter.add_pattern("*.[bB][mM][pP]"); + + oDialog.add_filter(oPngFilter); + oDialog.add_filter(oBmpFilter); + + if (m_poCoreConfig->sGetKey("screenshot_format") == "bmp") + { + oDialog.set_filter(oBmpFilter); + } + + while (oDialog.run() == Gtk::RESPONSE_OK) + { + Glib::ustring sFile = oDialog.get_filename(); + Glib::ustring sExt; + + if (oDialog.get_filter() == &oPngFilter) + { + sExt = ".png"; + } + else + { + sExt = ".bmp"; + } + + if (! bHasSuffix(sFile, sExt, false)) + { + sFile += sExt; + } + + if (Glib::file_test(sFile, Glib::FILE_TEST_EXISTS)) + { + Gtk::MessageDialog oConfirmDialog(*this, + _("File already exists. Overwrite it?"), + false, + Gtk::MESSAGE_QUESTION, + Gtk::BUTTONS_YES_NO); + if (oConfirmDialog.run() != Gtk::RESPONSE_YES) + { + continue; + } + } + + bool bResult; + if (sExt == ".png") + { + bResult = m_stEmulator.emuWritePNG(sFile.c_str()); + } + else + { + bResult = m_stEmulator.emuWriteBMP(sFile.c_str()); + } + + if (bResult) + { + break; + } + } +} + +void Window::vOnFileClose() +{ + if (m_eCartridge != CartridgeNone) + { + soundPause(); + vStopEmu(); + vSetDefaultTitle(); + vDrawDefaultScreen(); + vSaveBattery(); + m_stEmulator.emuCleanUp(); + m_eCartridge = CartridgeNone; + emulating = 0; + + vUpdateGameSlots(); + + for (std::list::iterator it = m_listSensitiveWhenPlaying.begin(); + it != m_listSensitiveWhenPlaying.end(); + it++) + { + (*it)->set_sensitive(false); + } + + m_poFilePauseItem->set_active(false); + } +} + +void Window::vOnFileExit() +{ + hide(); +} + +void Window::vOnFrameskipToggled(Gtk::CheckMenuItem * _poCMI, int _iValue) +{ + if (! _poCMI->get_active()) + { + return; + } + + if (_iValue >= 0 && _iValue <= 9) + { + m_poCoreConfig->vSetKey("frameskip", _iValue); + gbFrameSkip = _iValue; + systemFrameSkip = _iValue; + m_bAutoFrameskip = false; + } + else + { + m_poCoreConfig->vSetKey("frameskip", "auto"); + gbFrameSkip = 0; + systemFrameSkip = 0; + m_bAutoFrameskip = true; + } +} + +void Window::vOnThrottleToggled(Gtk::CheckMenuItem * _poCMI, int _iPercent) +{ + if (! _poCMI->get_active()) + { + return; + } + + vSetThrottle(_iPercent); + + // Initialize the frameskip adjustment each time throttle is changed + if (m_bAutoFrameskip) + { + systemFrameSkip = 0; + } +} + +void Window::vOnThrottleOther(Gtk::CheckMenuItem * _poCMI) +{ + if (! _poCMI->get_active()) + { + return; + } + + Glib::RefPtr poXml; + poXml = Xml::create(PKGDATADIR "/vba.glade", "ThrottleDialog"); + + Gtk::Dialog * poDialog = dynamic_cast(poXml->get_widget("ThrottleDialog")); + Gtk::SpinButton * poSpin = dynamic_cast(poXml->get_widget("ThrottleSpin")); + + poDialog->set_transient_for(*this); + + if (systemThrottle != 0) + { + poSpin->set_value(systemThrottle); + } + else + { + poSpin->set_value(100); + } + + if (poDialog->run() == Gtk::RESPONSE_OK) + { + vSetThrottle(poSpin->get_value_as_int()); + } + + delete poDialog; + vSelectBestThrottleItem(); +} + +void Window::vOnVideoScaleToggled(Gtk::CheckMenuItem * _poCMI, int _iScale) +{ + if (! _poCMI->get_active()) + { + return; + } + + m_poDisplayConfig->vSetKey("scale", _iScale); + vUpdateScreen(); +} + +void Window::vOnLayerToggled(Gtk::CheckMenuItem * _poCMI, int _iLayer) +{ + int iMask = (0x0100 << _iLayer); + if (_poCMI->get_active()) + { + layerSettings |= iMask; + } + else + { + layerSettings &= ~iMask; + } + layerEnable = DISPCNT & layerSettings; + + const char * acsLayers[] = + { + "layer_bg0", + "layer_bg1", + "layer_bg2", + "layer_bg3", + "layer_obj", + "layer_win0", + "layer_win1", + "layer_objwin" + }; + m_poCoreConfig->vSetKey(acsLayers[_iLayer], _poCMI->get_active()); +} + +void Window::vOnDirectories() +{ + Glib::RefPtr poXml; + poXml = Xml::create(PKGDATADIR "/vba.glade", "DirectoriesDialog"); + + struct + { + const char * m_csKey; + const char * m_csEntry; + const char * m_csResetButton; + const char * m_csSelectButton; + } + astRow[] = + { + { "gba_roms", "GBARomsDirEntry", "GBARomsDirResetButton", "GBARomsDirSelectButton" }, + { "gb_roms", "GBRomsDirEntry", "GBRomsDirResetButton", "GBRomsDirSelectButton" }, + { "batteries", "BatteriesDirEntry", "BatteriesDirResetButton", "BatteriesDirSelectButton" }, + { "saves", "SavesDirEntry", "SavesDirResetButton", "SavesDirSelectButton" }, + { "captures", "CapturesDirEntry", "CapturesDirResetButton", "CapturesDirSelectButton" } + }; + + for (guint i = 0; i < G_N_ELEMENTS(astRow); i++) + { + Gtk::Entry * poEntry = dynamic_cast(poXml->get_widget(astRow[i].m_csEntry)); + Gtk::Button * poReset = dynamic_cast(poXml->get_widget(astRow[i].m_csResetButton)); + Gtk::Button * poSelect = dynamic_cast(poXml->get_widget(astRow[i].m_csSelectButton)); + + poEntry->set_text(m_poDirConfig->sGetKey(astRow[i].m_csKey)); + + poReset->signal_clicked().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnDirectoryReset), + poEntry)); + poSelect->signal_clicked().connect(sigc::bind( + sigc::mem_fun(*this, &Window::vOnDirectorySelect), + poEntry)); + } + + Gtk::Dialog * poDialog = dynamic_cast(poXml->get_widget("DirectoriesDialog")); + poDialog->set_transient_for(*this); + + if (poDialog->run() == Gtk::RESPONSE_OK) + { + for (guint i = 0; i < G_N_ELEMENTS(astRow); i++) + { + Gtk::Entry * poEntry = dynamic_cast(poXml->get_widget(astRow[i].m_csEntry)); + Glib::ustring sDir = poEntry->get_text(); + if (! Glib::file_test(sDir, Glib::FILE_TEST_IS_DIR)) + { + sDir = ""; + } + m_poDirConfig->vSetKey(astRow[i].m_csKey, sDir); + } + + // Needed if saves dir changed + vUpdateGameSlots(); + } + + delete poDialog; +} + +void Window::vOnDirectoryReset(Gtk::Entry * _poEntry) +{ + _poEntry->set_text(""); +} + +void Window::vOnDirectorySelect(Gtk::Entry * _poEntry) +{ + Gtk::FileChooserDialog oDialog(*this, _("Select directory"), + Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); + oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + oDialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); + + if (_poEntry->get_text() != "") + { + oDialog.add_shortcut_folder(_poEntry->get_text()); + oDialog.set_current_folder(_poEntry->get_text()); + } + + if (oDialog.run() == Gtk::RESPONSE_OK) + { + _poEntry->set_text(oDialog.get_filename()); + } +} + +void Window::vOnPauseWhenInactiveToggled(Gtk::CheckMenuItem * _poCMI) +{ + m_poDisplayConfig->vSetKey("pause_when_inactive", _poCMI->get_active()); +} + +void Window::vOnSelectBios() +{ + Gtk::FileChooserDialog oDialog(*this, _("Select BIOS file")); + oDialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + oDialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); + + if (m_poCoreConfig->sGetKey("bios_file") != "") + { + oDialog.set_filename(m_poCoreConfig->sGetKey("bios_file")); + } + + const char * acsPattern[] = + { + "*.[bB][iI][nN]", "*.[aA][gG][bB]", "*.[gG][bB][aA]", + "*.[bB][iI][oO][sS]", "*.[zZ][iI][pP]", "*.[zZ]", "*.[gG][zZ]" + }; + + Gtk::FileFilter oAllFilter; + oAllFilter.set_name(_("All files")); + oAllFilter.add_pattern("*"); + + Gtk::FileFilter oBiosFilter; + oBiosFilter.set_name(_("Gameboy Advance BIOS")); + for (guint i = 0; i < G_N_ELEMENTS(acsPattern); i++) + { + oBiosFilter.add_pattern(acsPattern[i]); + } + + oDialog.add_filter(oAllFilter); + oDialog.add_filter(oBiosFilter); + + oDialog.set_filter(oBiosFilter); + + while (oDialog.run() == Gtk::RESPONSE_OK) + { + if (Glib::file_test(oDialog.get_filename(), Glib::FILE_TEST_IS_REGULAR)) + { + m_poCoreConfig->vSetKey("bios_file", oDialog.get_filename()); + m_poUseBiosItem->set_sensitive(); + break; + } + } +} + +void Window::vOnUseBiosToggled(Gtk::CheckMenuItem * _poCMI) +{ + m_poCoreConfig->vSetKey("use_bios_file", _poCMI->get_active()); +} + +void Window::vOnShowSpeedToggled(Gtk::CheckMenuItem * _poCMI, int _iShowSpeed) +{ + if (! _poCMI->get_active()) + { + return; + } + + m_eShowSpeed = (EShowSpeed)_iShowSpeed; + if (m_eShowSpeed == ShowNone) + { + vSetDefaultTitle(); + } + m_poDisplayConfig->vSetKey("show_speed", _iShowSpeed); +} + +void Window::vOnSaveTypeToggled(Gtk::CheckMenuItem * _poCMI, int _iSaveType) +{ + if (! _poCMI->get_active()) + { + return; + } + + cpuSaveType = _iSaveType; + m_poCoreConfig->vSetKey("save_type", _iSaveType); +} + +void Window::vOnFlashSizeToggled(Gtk::CheckMenuItem * _poCMI, int _iFlashSize) +{ + if (! _poCMI->get_active()) + { + return; + } + + if (_iFlashSize == 64) + { + flashSetSize(0x10000); + } + else + { + flashSetSize(0x20000); + } + m_poCoreConfig->vSetKey("flash_size", _iFlashSize); +} + +void Window::vOnScreenshotFormatToggled(Gtk::CheckMenuItem * _poCMI, std::string _sFormat) +{ + if (! _poCMI->get_active()) + { + return; + } + + m_poCoreConfig->vSetKey("screenshot_format", _sFormat); +} + +void Window::vOnSoundStatusToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundStatus) +{ + if (! _poCMI->get_active()) + { + return; + } + + std::string sSoundStatus; + switch (_iSoundStatus) + { + case SoundOff: + soundOffFlag = true; + if (systemSoundOn) + { + soundShutdown(); + } + sSoundStatus = "off"; + break; + case SoundMute: + soundDisable(0x30f); + sSoundStatus = "mute"; + break; + case SoundOn: + if (soundOffFlag) + { + soundOffFlag = false; + if (! soundInit()) + { + m_poSoundOffItem->set_active(); + return; + } + } + soundEnable(0x30f); + sSoundStatus = "on"; + break; + } + m_poSoundConfig->vSetKey("status", sSoundStatus); +} + +void Window::vOnSoundEchoToggled(Gtk::CheckMenuItem * _poCMI) +{ + soundEcho = _poCMI->get_active(); + m_poSoundConfig->vSetKey("echo", soundEcho); +} + +void Window::vOnSoundLowPassToggled(Gtk::CheckMenuItem * _poCMI) +{ + soundLowPass = _poCMI->get_active(); + m_poSoundConfig->vSetKey("low_pass", soundLowPass); +} + +void Window::vOnSoundReverseToggled(Gtk::CheckMenuItem * _poCMI) +{ + soundReverse = _poCMI->get_active(); + m_poSoundConfig->vSetKey("reverse_stereo", soundReverse); +} + +void Window::vOnSoundChannelToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundChannel) +{ + int iShift = _iSoundChannel; + if (_iSoundChannel > 3) + { + iShift += 4; + } + int iFlag = 1 << iShift; + int iActive = soundGetEnable() & 0x30f; + if (_poCMI->get_active()) + { + iActive |= iFlag; + } + else + { + iActive &= ~iFlag; + } + soundEnable(iActive); + soundDisable(~iActive & 0x30f); + + const char * acsChannels[] = + { + "channel_1", + "channel_2", + "channel_3", + "channel_4", + "channel_A", + "channel_B" + }; + m_poSoundConfig->vSetKey(acsChannels[_iSoundChannel], _poCMI->get_active()); +} + +void Window::vOnSoundQualityToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundQuality) +{ + if (! _poCMI->get_active()) + { + return; + } + + m_eSoundQuality = (ESoundQuality)_iSoundQuality; + if (m_eCartridge == CartridgeGBA) + { + soundSetQuality(_iSoundQuality); + } + else if (m_eCartridge == CartridgeGB) + { + gbSoundSetQuality(_iSoundQuality); + } + m_poSoundConfig->vSetKey("quality", _iSoundQuality); +} + +void Window::vOnSoundVolumeToggled(Gtk::CheckMenuItem * _poCMI, int _iSoundVolume) +{ + if (! _poCMI->get_active()) + { + return; + } + + soundVolume = _iSoundVolume; + m_poSoundConfig->vSetKey("volume", _iSoundVolume); +} + +void Window::vOnGBBorderToggled(Gtk::CheckMenuItem * _poCMI) +{ + gbBorderOn = _poCMI->get_active(); + if (emulating && m_eCartridge == CartridgeGB && _poCMI->get_active()) + { + gbSgbRenderBorder(); + } + vUpdateScreen(); + m_poCoreConfig->vSetKey("gb_border", _poCMI->get_active()); +} + +void Window::vOnGBPrinterToggled(Gtk::CheckMenuItem * _poCMI) +{ + if (_poCMI->get_active()) + { + gbSerialFunction = gbPrinterSend; + } + else + { + gbSerialFunction = NULL; + } + m_poCoreConfig->vSetKey("gb_printer", _poCMI->get_active()); +} + +void Window::vOnEmulatorTypeToggled(Gtk::CheckMenuItem * _poCMI, int _iEmulatorType) +{ + gbEmulatorType = _iEmulatorType; + m_poCoreConfig->vSetKey("emulator_type", _iEmulatorType); +} + +void Window::vOnFilter2xToggled(Gtk::CheckMenuItem * _poCMI, int _iFilter2x) +{ + if (! _poCMI->get_active()) + { + return; + } + + m_poScreenArea->vSetFilter2x((EFilter2x)_iFilter2x); + if (emulating) + { + vDrawScreen(); + } + m_poDisplayConfig->vSetKey("filter2x", _iFilter2x); +} + +void Window::vOnFilterIBToggled(Gtk::CheckMenuItem * _poCMI, int _iFilterIB) +{ + if (! _poCMI->get_active()) + { + return; + } + + m_poScreenArea->vSetFilterIB((EFilterIB)_iFilterIB); + if (emulating) + { + vDrawScreen(); + } + m_poDisplayConfig->vSetKey("filterIB", _iFilterIB); +} + +void Window::vOnJoypadConfigure(int _iJoypad) +{ + Glib::RefPtr poXml; + poXml = Xml::create(PKGDATADIR "/vba.glade", "JoypadConfigDialog"); + + JoypadConfigDialog * poDialog = NULL; + poXml->get_widget_derived("JoypadConfigDialog", poDialog); + poDialog->set_transient_for(*this); + poDialog->vSetConfig(m_oJoypads[_iJoypad - 1]); + + if (poDialog->run() == Gtk::RESPONSE_OK) + { + m_oJoypads[_iJoypad - 1] = poDialog->stGetConfig(); + if (_iJoypad == m_poInputConfig->oGetKey("active_joypad")) + { + if (m_poKeymap != NULL) + { + delete m_poKeymap; + } + m_poKeymap = m_oJoypads[_iJoypad - 1].poCreateKeymap(); + } + } + + delete poDialog; +} + +void Window::vOnJoypadToggled(Gtk::CheckMenuItem * _poCMI, int _iJoypad) +{ + if (! _poCMI->get_active()) + { + return; + } + + if (m_poKeymap != NULL) + { + delete m_poKeymap; + } + m_poKeymap = m_oJoypads[_iJoypad - 1].poCreateKeymap(); + + m_poInputConfig->vSetKey("active_joypad", _iJoypad); +} + +void Window::vOnAutofireToggled(Gtk::CheckMenuItem * _poCMI, u32 _uiKeyFlag) +{ + if (_poCMI->get_active()) + { + m_uiAutofireState |= _uiKeyFlag; + } + else + { + m_uiAutofireState &= ~_uiKeyFlag; + } + + std::string sKey; + if (_uiKeyFlag == KeyFlagA) + { + sKey = "autofire_A"; + } + else if (_uiKeyFlag == KeyFlagB) + { + sKey = "autofire_B"; + } + else if (_uiKeyFlag == KeyFlagL) + { + sKey = "autofire_L"; + } + else if (_uiKeyFlag == KeyFlagR) + { + sKey = "autofire_R"; + } + m_poInputConfig->vSetKey(sKey, _poCMI->get_active()); +} + +void Window::vOnGDBWait() +{ + Glib::RefPtr poXml; + poXml = Xml::create(PKGDATADIR "/vba.glade", "TcpPortDialog"); + + Gtk::Dialog * poDialog = dynamic_cast(poXml->get_widget("TcpPortDialog")); + Gtk::SpinButton * poSpin = dynamic_cast(poXml->get_widget("TcpPortSpin")); + + poDialog->set_transient_for(*this); + + int iPort = 55555; + poSpin->set_value(iPort); + + bool bOk = false; + if (poDialog->run() == Gtk::RESPONSE_OK) + { + bOk = true; + iPort = poSpin->get_value_as_int(); + } + delete poDialog; + + if (! bOk) + { + return; + } + + m_eCartridge = CartridgeGBA; + m_sRomFile = "gnu_stub"; + m_stEmulator = GBASystem; + + rom = (u8 *) malloc(0x2000000); + workRAM = (u8 *) calloc(1, 0x40000); + bios = (u8 *) calloc(1, 0x4000); + internalRAM = (u8 *) calloc(1, 0x8000); + paletteRAM = (u8 *) calloc(1, 0x400); + vram = (u8 *) calloc(1, 0x20000); + oam = (u8 *) calloc(1, 0x400); + pix = (u8 *) calloc(1, 4 * m_iGBAScreenWidth * m_iGBAScreenHeight); + ioMem = (u8 *) calloc(1, 0x400); + + useBios = m_poCoreConfig->oGetKey("use_bios_file"); + CPUInit(m_poCoreConfig->sGetKey("bios_file").c_str(), useBios); + CPUReset(); + + for (std::list::iterator it = m_listSensitiveWhenPlaying.begin(); + it != m_listSensitiveWhenPlaying.end(); + it++) + { + (*it)->set_sensitive(); + } + + if (m_poCoreConfig->oGetKey("load_game_auto")) + { + vOnLoadGameMostRecent(); + } + + vStartEmu(); + + emulating = 1; + + dbgMain = remoteStubMain; + dbgSignal = remoteStubSignal; + dbgOutput = remoteOutput; + debugger = true; + + remoteSetProtocol(0); + remoteSetPort(iPort); + remoteInit(); +} + +void Window::vOnGDBLoadAndWait() +{ + bool bLoaded = false; + + while (m_poFileOpenDialog->run() == Gtk::RESPONSE_OK) + { + if (bLoadROM(m_poFileOpenDialog->get_filename())) + { + bLoaded = true; + break; + } + } + m_poFileOpenDialog->hide(); + + if (! bLoaded) + { + return; + } + + if (m_eCartridge != CartridgeGBA) + { + vPopupError(_("Only GBA images are supported.")); + vOnFileClose(); + return; + } + + Glib::RefPtr poXml; + poXml = Xml::create(PKGDATADIR "/vba.glade", "TcpPortDialog"); + + Gtk::Dialog * poDialog = dynamic_cast(poXml->get_widget("TcpPortDialog")); + Gtk::SpinButton * poSpin = dynamic_cast(poXml->get_widget("TcpPortSpin")); + + poDialog->set_transient_for(*this); + + int iPort = 55555; + poSpin->set_value(iPort); + + bool bOk = false; + if (poDialog->run() == Gtk::RESPONSE_OK) + { + bOk = true; + iPort = poSpin->get_value_as_int(); + } + delete poDialog; + + if (! bOk) + { + return; + } + + dbgMain = remoteStubMain; + dbgSignal = remoteStubSignal; + dbgOutput = remoteOutput; + debugger = true; + + remoteSetProtocol(0); + remoteSetPort(iPort); + remoteInit(); +} + +void Window::vOnGDBBreak() +{ + if (armState) + { + armNextPC -= 4; + reg[15].I -= 4; + } + else + { + armNextPC -= 2; + reg[15].I -= 2; + } + + debugger = true; +} + +void Window::vOnGDBDisconnect() +{ + remoteCleanUp(); + debugger = false; +} + +void Window::vOnHelpAbout() +{ + Glib::RefPtr poXml; + poXml = Xml::create(PKGDATADIR "/vba.glade", "AboutDialog"); + + Gtk::Dialog * poDialog = dynamic_cast(poXml->get_widget("AboutDialog")); + poDialog->set_transient_for(*this); + + Gtk::Image oIcon(PKGDATADIR "/vba-64.png"); + oIcon.show(); + Gtk::Container * poIconContainer = dynamic_cast(poXml->get_widget("AboutIconContainer")); + poIconContainer->add(oIcon); + + Gtk::Label * poLabel = dynamic_cast(poXml->get_widget("VersionLabel")); + poLabel->set_markup("" PACKAGE " " VERSION ""); + + poDialog->run(); + delete poDialog; +} + +bool Window::bOnEmuIdle() +{ + if (debugger && m_stEmulator.emuHasDebugger) + { + dbgMain(); + return true; + } + + if (m_uiThrottleDelay != Glib::TimeVal(0, 0)) + { + Glib::TimeVal uiTime; + uiTime.assign_current_time(); + + if (uiTime - m_uiThrottleLastTime >= m_uiThrottleDelay) + { + m_uiThrottleDelay = Glib::TimeVal(0, 0); + m_uiThrottleLastTime = uiTime; + } + else + { + return true; + } + } + + m_stEmulator.emuMain(m_stEmulator.emuCount); + return true; +} + +bool Window::on_focus_in_event(GdkEventFocus * _pstEvent) +{ + if (emulating + && ! m_bPaused + && m_poDisplayConfig->oGetKey("pause_when_inactive")) + { + vStartEmu(); + soundResume(); + } + return false; +} + +bool Window::on_focus_out_event(GdkEventFocus * _pstEvent) +{ + if (emulating + && ! m_bPaused + && m_poDisplayConfig->oGetKey("pause_when_inactive")) + { + vStopEmu(); + soundPause(); + } + return false; +} + +bool Window::on_key_press_event(GdkEventKey * _pstEvent) +{ + EKey eKey; + + if ((_pstEvent->state & Gtk::AccelGroup::get_default_mod_mask()) + || (eKey = m_poKeymap->eGetKey(_pstEvent->hardware_keycode)) == KeyNone) + { + return Gtk::Window::on_key_press_event(_pstEvent); + } + + switch (eKey) + { + case KeyA: + m_uiJoypadState |= KeyFlagA; + break; + case KeyB: + m_uiJoypadState |= KeyFlagB; + break; + case KeySelect: + m_uiJoypadState |= KeyFlagSelect; + break; + case KeyStart: + m_uiJoypadState |= KeyFlagStart; + break; + case KeyRight: + m_uiJoypadState |= KeyFlagRight; + m_uiJoypadState &= ~KeyFlagLeft; + break; + case KeyLeft: + m_uiJoypadState |= KeyFlagLeft; + m_uiJoypadState &= ~KeyFlagRight; + break; + case KeyUp: + m_uiJoypadState |= KeyFlagUp; + m_uiJoypadState &= ~KeyFlagDown; + break; + case KeyDown: + m_uiJoypadState |= KeyFlagDown; + m_uiJoypadState &= ~KeyFlagUp; + break; + case KeyR: + m_uiJoypadState |= KeyFlagR; + break; + case KeyL: + m_uiJoypadState |= KeyFlagL; + break; + case KeySpeed: + m_uiJoypadState |= KeyFlagSpeed; + break; + case KeyCapture: + m_uiJoypadState |= KeyFlagCapture; + break; + case KeyNone: + break; + } + return true; +} + +bool Window::on_key_release_event(GdkEventKey * _pstEvent) +{ + EKey eKey; + + if ((_pstEvent->state & Gtk::AccelGroup::get_default_mod_mask()) + || (eKey = m_poKeymap->eGetKey(_pstEvent->hardware_keycode)) == KeyNone) + { + return Gtk::Window::on_key_release_event(_pstEvent); + } + + switch (eKey) + { + case KeyA: + m_uiJoypadState &= ~KeyFlagA; + break; + case KeyB: + m_uiJoypadState &= ~KeyFlagB; + break; + case KeySelect: + m_uiJoypadState &= ~KeyFlagSelect; + break; + case KeyStart: + m_uiJoypadState &= ~KeyFlagStart; + break; + case KeyRight: + m_uiJoypadState &= ~KeyFlagRight; + break; + case KeyLeft: + m_uiJoypadState &= ~KeyFlagLeft; + break; + case KeyUp: + m_uiJoypadState &= ~KeyFlagUp; + break; + case KeyDown: + m_uiJoypadState &= ~KeyFlagDown; + break; + case KeyR: + m_uiJoypadState &= ~KeyFlagR; + break; + case KeyL: + m_uiJoypadState &= ~KeyFlagL; + break; + case KeySpeed: + m_uiJoypadState &= ~KeyFlagSpeed; + break; + case KeyCapture: + m_uiJoypadState &= ~KeyFlagCapture; + break; + case KeyNone: + break; + } + return true; +} + +} // namespace VBA