diff --git a/desmume/src/gtk/Makefile.am b/desmume/src/gtk/Makefile.am
index 09a8cead0..59cb1f2be 100644
--- a/desmume/src/gtk/Makefile.am
+++ b/desmume/src/gtk/Makefile.am
@@ -14,6 +14,7 @@ desmume_SOURCES = \
avout_pipe_base.cpp avout_pipe_base.h \
avout_x264.cpp avout_x264.h \
avout_flac.cpp avout_flac.h \
+ config.cpp config.h config_opts.h \
desmume.h desmume.cpp \
dTool.h dToolsList.cpp \
tools/ioregsView.cpp tools/ioregsView.h \
diff --git a/desmume/src/gtk/config.cpp b/desmume/src/gtk/config.cpp
new file mode 100644
index 000000000..eceb2f06b
--- /dev/null
+++ b/desmume/src/gtk/config.cpp
@@ -0,0 +1,166 @@
+/*
+ Copyright (C) 2014 DeSmuME team
+ Copyright (C) 2014 Alvin Wong
+
+ This file 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 of the License, or
+ (at your option) any later version.
+
+ This file 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 the this software. If not, see .
+*/
+
+#include
+#include
+
+#include "config.h"
+
+using std::string;
+using std::vector;
+
+namespace desmume {
+namespace config {
+
+/* class value */
+
+template<>
+void value::load() {
+ GError* err = NULL;
+ bool val = g_key_file_get_boolean(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), &err);
+ if (err != NULL) {
+ g_error_free(err);
+ } else {
+ this->mData = val;
+ }
+}
+
+template<>
+void value::save() {
+ g_key_file_set_boolean(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData ? TRUE : FALSE);
+}
+
+/* class value */
+
+template<>
+void value::load() {
+ GError* err = NULL;
+ int val = g_key_file_get_integer(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), &err);
+ if (err != NULL) {
+ g_error_free(err);
+ } else {
+ this->mData = val;
+ }
+}
+
+template<>
+void value::save() {
+ g_key_file_set_integer(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData);
+}
+
+/* class value */
+
+template<>
+void value::load() {
+ char* val = g_key_file_get_string(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), NULL);
+ if (val != NULL) {
+ this->mData = val;
+ g_free(val);
+ }
+}
+
+template<>
+void value::save() {
+ g_key_file_set_string(this->mKeyFile, this->mSection.c_str(), this->mKey.c_str(), this->mData.c_str());
+}
+
+/* class Config */
+
+Config::Config()
+ : mKeyFile(g_key_file_new())
+# define OPT(name, type, default, section, key) \
+ , name(default, #section, #key)
+# include "config_opts.h"
+# undef OPT
+{
+# define OPT(name, type, default, section, key) \
+ this->name.mKeyFile = this->mKeyFile;
+# include "config_opts.h"
+# undef OPT
+}
+
+Config::~Config() {
+ g_key_file_free(this->mKeyFile);
+}
+
+void Config::load() {
+ char* config_dir = g_build_filename(g_get_user_config_dir(), "desmume", NULL);
+ g_mkdir_with_parents(config_dir, 0755);
+ char* config_file = g_build_filename(config_dir, "config.cfg", NULL);
+ g_key_file_load_from_file(this->mKeyFile, config_file, G_KEY_FILE_KEEP_COMMENTS, NULL);
+ g_free(config_file);
+ g_free(config_dir);
+# define OPT(name, type, default, section, key) \
+ this->name.load();
+# include "config_opts.h"
+# undef OPT
+}
+
+void Config::save() {
+# define OPT(name, type, default, section, key) \
+ this->name.save();
+# include "config_opts.h"
+# undef OPT
+ gsize length;
+ char* data = g_key_file_to_data(this->mKeyFile, &length, NULL);
+ char* config_dir = g_build_filename(g_get_user_config_dir(), "desmume", NULL);
+ g_mkdir_with_parents(config_dir, 0755);
+ char* config_file = g_build_filename(config_dir, "config.cfg", NULL);
+ g_file_set_contents(config_file, data, length, NULL);
+ g_free(config_file);
+ g_free(config_dir);
+ g_free(data);
+}
+
+#if 0
+/* class Config::Input */
+
+Config::Input::Input()
+ : keys(NB_KEYS)
+ , joykeys(NB_KEYS)
+{
+static const u16 gtk_kb_cfg[NB_KEYS] = {
+ GDK_x, // A
+ GDK_z, // B
+ GDK_Shift_R, // select
+ GDK_Return, // start
+ GDK_Right, // Right
+ GDK_Left, // Left
+ GDK_Up, // Up
+ GDK_Down, // Down
+ GDK_w, // R
+ GDK_q, // L
+ GDK_s, // X
+ GDK_a, // Y
+ GDK_p, // DEBUG
+ GDK_o, // BOOST
+ GDK_BackSpace, // Lid
+};
+ for (size_t i = 0; i < NB_KEYS; i++) {
+ this->keys[i] = new value(gtk_kb_cfg[i], "Keys", ...);
+ }
+}
+
+void Config::Input::load();
+
+void Config::Input::save();
+#endif
+
+} /* namespace config */
+} /* namespace desmume */
+
diff --git a/desmume/src/gtk/config.h b/desmume/src/gtk/config.h
new file mode 100644
index 000000000..9ebd99b9b
--- /dev/null
+++ b/desmume/src/gtk/config.h
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2014 DeSmuME team
+ Copyright (C) 2014 Alvin Wong
+
+ This file 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 of the License, or
+ (at your option) any later version.
+
+ This file 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 the this software. If not, see .
+*/
+
+#ifndef DESMUME_CONFIG_CLASS_H_
+#define DESMUME_CONFIG_CLASS_H_
+
+#include
+#include
+
+#include
+
+namespace desmume {
+namespace config {
+
+template
+class value {
+ friend class Config;
+
+ std::string mSection;
+ std::string mKey;
+ GKeyFile* mKeyFile;
+
+ T mDefaultVal;
+ T mData;
+
+ value(const value&); // DO NOT IMPLEMENT
+ value operator=(const value&); // DO NOT IMPLEMENT
+ void load();
+ void save();
+public:
+ value(const T& defaultVal, const std::string& section, const std::string& key)
+ : mSection(section)
+ , mKey(key)
+ , mDefaultVal(defaultVal)
+ , mData(defaultVal) {}
+ inline T defaultVal() {
+ return this->mDefaultVal;
+ }
+ inline T get() {
+ return this->mData;
+ }
+ inline operator T() {
+ return this->mData;
+ }
+ inline void set(const T& value) {
+ this->mData = value;
+ //this->save();
+ }
+ inline T operator=(const T& value) {
+ this->mData = value;
+ return this->mData;
+ }
+}; /* class value */
+
+#ifdef OPT
+# undef OPT
+#endif
+
+class Config {
+protected:
+ GKeyFile* mKeyFile;
+
+ Config(const Config&); // DO NOT IMPLEMENT
+ Config operator=(const Config&); // DO NOT IMPLEMENT
+public:
+ // member fields
+# define OPT(name, type, default, section, key) \
+ value name;
+# include "config_opts.h"
+# undef OPT
+#if 0
+ // Special case: input config
+ class Input {
+ friend class Config;
+ std::vector*> keys;
+ std::vector*> joykeys;
+ Input();
+ void load();
+ void save();
+ } inputs;
+#endif
+
+ // constructor
+ Config();
+
+ // methods
+ virtual ~Config();
+ void load();
+ void save();
+}; /* class Config */
+
+#undef DESMUME_CONFIG_CONFIG
+
+} /* namespace config */
+} /* namespace desmume */
+
+#endif /* DESMUME_CONFIG_CLASS_H_ */
+
diff --git a/desmume/src/gtk/config_opts.h b/desmume/src/gtk/config_opts.h
new file mode 100644
index 000000000..b57736dde
--- /dev/null
+++ b/desmume/src/gtk/config_opts.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2014 DeSmuME team
+ Copyright (C) 2014 Alvin Wong
+
+ This file 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 of the License, or
+ (at your option) any later version.
+
+ This file 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 the this software. If not, see .
+*/
+/*
+ This file contains a list of config options.
+
+ #define OPT(name, type, default, section, key)
+*/
+
+/* View */
+OPT(view_orient, int, 0, View, ScreenLayout)
+OPT(view_swap, bool, false, View, SwapScreens)
+OPT(view_rot, int, 0, View, Rotation)
+OPT(view_gap, bool, false, View, ScreenGap)
+OPT(view_filter, int, 0, View, Filter)
+OPT(view_cairoFilter, int, 3, View, SecondaryFilter) /* default: nearest-neighbour */
+OPT(view_menu, bool, true, View, ShowMenu)
+OPT(view_toolbar, bool, true, View, ShowToolbar)
+OPT(view_statusbar, bool, true, View, ShowStatusbar)
+
+/* Window */
+OPT(window_scale, int, 0, Window, Scale2x)
+/*OPT(window_x, int, -1, Window, X)*/
+/*OPT(window_y, int, -1, Window, Y)*/
+/*OPT(window_w, int, 0, Window, Width)*/
+/*OPT(window_h, int, 0, Window, Height)*/
+OPT(window_maximized, bool, false, Window, Maximized)
+OPT(window_fullscreen, bool, false, Window, Fullscreen)
+
+/* HUD display */
+OPT(hud_fps, bool, false, HudDisplay, Fps)
+OPT(hud_frameCounter, bool, false, HudDisplay, FrameCounter)
+OPT(hud_lagCounter, bool, false, HudDisplay, LagCounter)
+OPT(hud_input, bool, false, HudDisplay, Input)
+OPT(hud_graphicalInput, bool, false, HudDisplay, GraphicalInput)
+OPT(hud_rtc, bool, false, HudDisplay, RTC)
+OPT(hud_mic, bool, false, HudDisplay, Mic)
+
+/* Config */
+OPT(fpslimiter, bool, true, Config, FpsLimiter)
+OPT(autoframeskip, bool, true, Config, AudoFrameskip)
+OPT(frameskip, int, 0, Config, Frameskip)
+
+/* Audio */
+OPT(audio_enabled, bool, true, Audio, Enabled)
+OPT(audio_sync, int, 0, Audio, Synchronization)
+OPT(audio_interpolation, int, 1, Audio, Interpolation)
+
diff --git a/desmume/src/gtk/main.cpp b/desmume/src/gtk/main.cpp
index e402e1437..1af7aaa51 100644
--- a/desmume/src/gtk/main.cpp
+++ b/desmume/src/gtk/main.cpp
@@ -74,6 +74,8 @@
#include "glx_3Demu.h"
#endif
+#include "config.h"
+
#include "DeSmuME.xpm"
#undef GPOINTER_TO_INT
@@ -86,11 +88,12 @@
#define GAP_SIZE 64
-static int gtk_fps_limiter_disabled;
static int draw_count;
extern int _scanline_filter_a, _scanline_filter_b, _scanline_filter_c, _scanline_filter_d;
VideoFilter* video;
+desmume::config::Config config;
+
enum {
MAIN_BG_0 = 0,
MAIN_BG_1,
@@ -400,8 +403,8 @@ static const GtkActionEntry action_entries[] = {
#endif
{ "ConfigMenu", NULL, "_Config" },
- { "SPUModeMenu", NULL, "_SPU Mode" },
- { "SPUInterpolationMenu", NULL, "Sound _Interpolation" },
+ { "SPUModeMenu", NULL, "Audio _Synchronization" },
+ { "SPUInterpolationMenu", NULL, "Audio _Interpolation" },
{ "FrameskipMenu", NULL, "_Frameskip" },
{ "CheatMenu", NULL, "_Cheat" },
{ "cheatsearch", NULL, "_Search", NULL, NULL, CheatSearch },
@@ -820,7 +823,8 @@ static void ToggleMenuVisible(GtkToggleAction *action)
{
GtkWidget *pMenuBar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
- if (gtk_toggle_action_get_active(action) == TRUE)
+ config.view_menu = gtk_toggle_action_get_active(action);
+ if (config.view_menu)
gtk_widget_show(pMenuBar);
else
gtk_widget_hide(pMenuBar);
@@ -830,7 +834,8 @@ static void ToggleToolbarVisible(GtkToggleAction *action)
{
GtkWidget *pToolBar = gtk_ui_manager_get_widget (ui_manager, "/ToolBar");
- if (gtk_toggle_action_get_active(action) == TRUE)
+ config.view_toolbar = gtk_toggle_action_get_active(action);
+ if (config.view_toolbar)
gtk_widget_show(pToolBar);
else
gtk_widget_hide(pToolBar);
@@ -838,7 +843,8 @@ static void ToggleToolbarVisible(GtkToggleAction *action)
static void ToggleStatusbarVisible(GtkToggleAction *action)
{
- if (gtk_toggle_action_get_active(action) == TRUE)
+ config.view_statusbar = gtk_toggle_action_get_active(action);
+ if (config.view_statusbar)
gtk_widget_show(pStatusBar);
else
gtk_widget_hide(pStatusBar);
@@ -848,24 +854,31 @@ static void ToggleFullscreen(GtkToggleAction *action)
{
GtkWidget *pMenuBar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
GtkWidget *pToolBar = gtk_ui_manager_get_widget (ui_manager, "/ToolBar");
- if (gtk_toggle_action_get_active(action) == TRUE)
+ config.window_fullscreen = gtk_toggle_action_get_active(action);
+ if (config.window_fullscreen)
{
gtk_widget_hide(pMenuBar);
gtk_widget_hide(pToolBar);
gtk_widget_hide(pStatusBar);
- gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "view_menu"), FALSE);
- gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "view_toolbar"), FALSE);
- gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "view_statusbar"), FALSE);
+ gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "view_menu"), FALSE);
+ gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "view_toolbar"), FALSE);
+ gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "view_statusbar"), FALSE);
gtk_window_fullscreen(GTK_WINDOW(pWindow));
}
else
{
- gtk_widget_show(pMenuBar);
- gtk_widget_show(pToolBar);
- gtk_widget_show(pStatusBar);
- gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "view_menu"), TRUE);
- gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "view_toolbar"), TRUE);
- gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "view_statusbar"), TRUE);
+ if (config.view_menu) {
+ gtk_widget_show(pMenuBar);
+ }
+ if (config.view_toolbar) {
+ gtk_widget_show(pToolBar);
+ }
+ if (config.view_statusbar) {
+ gtk_widget_show(pStatusBar);
+ }
+ gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "view_menu"), TRUE);
+ gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "view_toolbar"), TRUE);
+ gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "view_statusbar"), TRUE);
gtk_window_unfullscreen(GTK_WINDOW(pWindow));
}
}
@@ -1436,19 +1449,25 @@ static void UpdateDrawingAreaAspect()
static void ToggleGap(GtkToggleAction* action)
{
- nds_screen.gap_size = gtk_toggle_action_get_active(action) ? GAP_SIZE : 0;
+ config.view_gap = gtk_toggle_action_get_active(action);
+ nds_screen.gap_size = config.view_gap ? GAP_SIZE : 0;
UpdateDrawingAreaAspect();
}
static void SetRotation(GtkAction *action, GtkRadioAction *current)
{
nds_screen.rotation_angle = gtk_radio_action_get_current_value(current);
+ config.view_rot = nds_screen.rotation_angle;
UpdateDrawingAreaAspect();
}
static void SetWinsize(GtkAction *action, GtkRadioAction *current)
{
winsize_current = (winsize_enum) gtk_radio_action_get_current_value(current);
+ config.window_scale = winsize_current;
+ if (config.window_fullscreen) {
+ gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "fullscreen"), FALSE);
+ }
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "fullscreen"), winsize_current == WINSIZE_SCALE);
UpdateDrawingAreaAspect();
}
@@ -1457,12 +1476,14 @@ static void SetOrientation(GtkAction *action, GtkRadioAction *current)
{
nds_screen.orientation = (orientation_enum)gtk_radio_action_get_current_value(current);
osd->singleScreen = nds_screen.orientation == ORIENT_SINGLE;
+ config.view_orient = nds_screen.orientation;
UpdateDrawingAreaAspect();
}
static void ToggleSwapScreens(GtkToggleAction *action) {
nds_screen.swap = gtk_toggle_action_get_active(action);
osd->swapScreens = nds_screen.swap;
+ config.view_swap = nds_screen.swap;
RedrawScreen();
}
@@ -2213,12 +2234,14 @@ static void Modify_PriInterpolation(GtkAction *action, GtkRadioAction *current)
{
uint filter = gtk_radio_action_get_current_value(current) ;
video->ChangeFilterByID((VideoFilterTypeID)filter);
+ config.view_filter = filter;
RedrawScreen();
}
static void Modify_Interpolation(GtkAction *action, GtkRadioAction *current)
{
Interpolation = (cairo_filter_t)gtk_radio_action_get_current_value(current);
+ config.view_cairoFilter = Interpolation;
RedrawScreen();
}
@@ -2242,6 +2265,7 @@ static void Modify_SPUMode(GtkAction *action, GtkRadioAction *current)
SPU_SetSynchMode(0, 0);
break;
}
+ config.audio_sync = SPUMode;
}
static void Modify_SPUInterpolation(GtkAction *action, GtkRadioAction *current)
@@ -2252,6 +2276,7 @@ static void Modify_SPUInterpolation(GtkAction *action, GtkRadioAction *current)
static void Modify_Frameskip(GtkAction *action, GtkRadioAction *current)
{
autoFrameskipMax = gtk_radio_action_get_current_value(current) ;
+ config.frameskip = autoFrameskipMax;
if (!autoframeskip) {
Frameskip = autoFrameskipMax;
}
@@ -2423,7 +2448,7 @@ gboolean EmuLoop(gpointer data)
avout_x264.updateVideo((u16*)GPU_screen);
RedrawScreen();
- if (gtk_fps_limiter_disabled || keys_latch & KEYMASK_(KEY_BOOST - 1)) {
+ if (!config.fpslimiter || keys_latch & KEYMASK_(KEY_BOOST - 1)) {
if (autoframeskip) {
Frameskip = 0;
} else {
@@ -2627,24 +2652,31 @@ static void ToggleHudDisplay(GtkToggleAction* action, gpointer data)
switch (hudId) {
case HUD_DISPLAY_FPS:
CommonSettings.hud.FpsDisplay = active;
+ config.hud_fps = active;
break;
case HUD_DISPLAY_INPUT:
CommonSettings.hud.ShowInputDisplay = active;
+ config.hud_input = active;
break;
case HUD_DISPLAY_GINPUT:
CommonSettings.hud.ShowGraphicalInputDisplay = active;
+ config.hud_graphicalInput = active;
break;
case HUD_DISPLAY_FCOUNTER:
CommonSettings.hud.FrameCounterDisplay = active;
+ config.hud_frameCounter = active;
break;
case HUD_DISPLAY_LCOUNTER:
CommonSettings.hud.ShowLagFrameCounter = active;
+ config.hud_lagCounter = active;
break;
case HUD_DISPLAY_RTC:
CommonSettings.hud.ShowRTC = active;
+ config.hud_rtc = active;
break;
case HUD_DISPLAY_MIC:
CommonSettings.hud.ShowMicrophone = active;
+ config.hud_mic = active;
break;
case HUD_DISPLAY_EDITOR:
HudEditorMode = active;
@@ -2662,22 +2694,25 @@ static void desmume_gtk_menu_view_hud (GtkActionGroup *ag)
const gchar* name;
const gchar* label;
guint id;
+ bool active;
+ bool& setting;
} hud_menu[] = {
- { "hud_fps","Display _fps", HUD_DISPLAY_FPS },
- { "hud_input","Display _Input", HUD_DISPLAY_INPUT },
- { "hud_graphicalinput","Display _Graphical Input", HUD_DISPLAY_GINPUT },
- { "hud_framecounter","Display Frame _Counter", HUD_DISPLAY_FCOUNTER },
- { "hud_lagcounter","Display _Lag Counter", HUD_DISPLAY_LCOUNTER },
- { "hud_rtc","Display _RTC", HUD_DISPLAY_RTC },
- { "hud_mic","Display _Mic", HUD_DISPLAY_MIC },
- { "hud_editor","_Editor Mode", HUD_DISPLAY_EDITOR },
+ { "hud_fps","Display _fps", HUD_DISPLAY_FPS, config.hud_fps, CommonSettings.hud.FpsDisplay },
+ { "hud_input","Display _Input", HUD_DISPLAY_INPUT, config.hud_input, CommonSettings.hud.ShowInputDisplay },
+ { "hud_graphicalinput","Display _Graphical Input", HUD_DISPLAY_GINPUT, config.hud_graphicalInput, CommonSettings.hud.ShowGraphicalInputDisplay },
+ { "hud_framecounter","Display Frame _Counter", HUD_DISPLAY_FCOUNTER, config.hud_frameCounter, CommonSettings.hud.FrameCounterDisplay },
+ { "hud_lagcounter","Display _Lag Counter", HUD_DISPLAY_LCOUNTER, config.hud_lagCounter, CommonSettings.hud.ShowLagFrameCounter },
+ { "hud_rtc","Display _RTC", HUD_DISPLAY_RTC, config.hud_rtc, CommonSettings.hud.ShowRTC },
+ { "hud_mic","Display _Mic", HUD_DISPLAY_MIC, config.hud_mic, CommonSettings.hud.ShowMicrophone },
+ { "hud_editor","_Editor Mode", HUD_DISPLAY_EDITOR, false, HudEditorMode },
};
guint i;
GtkToggleAction *act;
for(i = 0; i < sizeof(hud_menu) / sizeof(hud_menu[0]); i++){
act = gtk_toggle_action_new(hud_menu[i].name, hud_menu[i].label, NULL, NULL);
- gtk_toggle_action_set_active(act, FALSE);
+ gtk_toggle_action_set_active(act, hud_menu[i].active ? TRUE : FALSE);
+ hud_menu[i].setting = hud_menu[i].active;
g_signal_connect(G_OBJECT(act), "activate", G_CALLBACK(ToggleHudDisplay), GUINT_TO_POINTER(hud_menu[i].id));
gtk_action_group_add_action_with_accel(ag, GTK_ACTION(act), NULL);
}
@@ -2686,7 +2721,8 @@ static void desmume_gtk_menu_view_hud (GtkActionGroup *ag)
static void ToggleAudio (GtkToggleAction *action)
{
- if (gtk_toggle_action_get_active(action) == TRUE) {
+ config.audio_enabled = gtk_toggle_action_get_active(action);
+ if (config.audio_enabled) {
SPU_ChangeSoundCore(SNDCORE_SDL, 735 * 4);
osd->addLine("Audio enabled");
} else {
@@ -2712,10 +2748,9 @@ static void ToggleMicNoise (GtkToggleAction *action)
static void ToggleFpsLimiter (GtkToggleAction *action)
{
- BOOL limiterEnable = (BOOL)gtk_toggle_action_get_active(action);
+ config.fpslimiter = (BOOL)gtk_toggle_action_get_active(action);
- gtk_fps_limiter_disabled = !limiterEnable;
- if (limiterEnable)
+ if (config.fpslimiter)
osd->addLine("Fps limiter enabled");
else
osd->addLine("Fps limiter disabled");
@@ -2724,9 +2759,9 @@ static void ToggleFpsLimiter (GtkToggleAction *action)
static void ToggleAutoFrameskip (GtkToggleAction *action)
{
- BOOL autoSet = (BOOL)gtk_toggle_action_get_active(action);
+ config.autoframeskip = (BOOL)gtk_toggle_action_get_active(action);
- if ((BOOL)gtk_toggle_action_get_active(action)) {
+ if (config.autoframeskip) {
autoframeskip = true;
Frameskip = 0;
osd->addLine("Auto frameskip enabled");
@@ -2760,6 +2795,8 @@ static gboolean timeout_exit_cb(gpointer data)
static int
common_gtk_main( class configured_features *my_config)
{
+ config.load();
+
driver = new GtkDriver();
SDL_TimerID limiter_timer = NULL;
@@ -2880,7 +2917,7 @@ common_gtk_main( class configured_features *my_config)
}
desmume_init( arm9_memio, &arm9_ctrl_iface,
arm7_memio, &arm7_ctrl_iface,
- my_config->disable_sound);
+ my_config->disable_sound || !config.audio_enabled);
/* Init the hud / osd stuff */
#ifdef HAVE_LIBAGG
@@ -2941,7 +2978,7 @@ common_gtk_main( class configured_features *my_config)
gtk_action_group_add_actions(action_group, action_entries, G_N_ELEMENTS(action_entries), NULL);
gtk_action_group_add_toggle_actions(action_group, toggle_entries, G_N_ELEMENTS(toggle_entries), NULL);
/* Update audio toggle status */
- if (my_config->disable_sound) {
+ if (my_config->disable_sound || !config.audio_enabled) {
GtkAction *action = gtk_action_group_get_action(action_group, "enableaudio");
if (action)
gtk_toggle_action_set_active((GtkToggleAction *)action, FALSE);
@@ -2956,22 +2993,84 @@ common_gtk_main( class configured_features *my_config)
desmume_gtk_menu_tools(action_group);
gtk_action_group_add_radio_actions(action_group, savet_entries, G_N_ELEMENTS(savet_entries),
my_config->savetype, G_CALLBACK(changesavetype), NULL);
+
+ if (config.view_cairoFilter < CAIRO_FILTER_FAST || config.view_cairoFilter > CAIRO_FILTER_BILINEAR) {
+ config.view_cairoFilter = CAIRO_FILTER_NEAREST;
+ }
+ Interpolation = (cairo_filter_t)config.view_cairoFilter.get();
gtk_action_group_add_radio_actions(action_group, interpolation_entries, G_N_ELEMENTS(interpolation_entries),
Interpolation, G_CALLBACK(Modify_Interpolation), NULL);
+
+ if (config.view_filter < VideoFilterTypeID_None || config.view_filter >= VideoFilterTypeIDCount) {
+ config.view_filter = VideoFilterTypeID_None;
+ }
gtk_action_group_add_radio_actions(action_group, pri_interpolation_entries, G_N_ELEMENTS(pri_interpolation_entries),
- VideoFilterTypeID_None, G_CALLBACK(Modify_PriInterpolation), NULL);
+ config.view_filter, G_CALLBACK(Modify_PriInterpolation), NULL);
+
+ switch (config.audio_sync) {
+ case SPUMODE_SYNCN:
+ case SPUMODE_SYNCZ:
+#ifdef HAVE_LIBSOUNDTOUCH
+ case SPUMODE_SYNCP:
+#endif
+ SPUMode = config.audio_sync;
+ SPU_SetSynchMode(1, config.audio_sync-1);
+ break;
+
+ case SPUMODE_DUALASYNC:
+ default:
+ config.audio_sync = SPUMODE_DUALASYNC;
+ SPUMode = SPUMODE_DUALASYNC;
+ SPU_SetSynchMode(0, 0);
+ break;
+ }
gtk_action_group_add_radio_actions(action_group, spumode_entries, G_N_ELEMENTS(spumode_entries),
- 0, G_CALLBACK(Modify_SPUMode), NULL);
+ config.audio_sync, G_CALLBACK(Modify_SPUMode), NULL);
+
gtk_action_group_add_radio_actions(action_group, spuinterpolation_entries, G_N_ELEMENTS(spuinterpolation_entries),
CommonSettings.spuInterpolationMode, G_CALLBACK(Modify_SPUInterpolation), NULL);
+
gtk_action_group_add_radio_actions(action_group, frameskip_entries, G_N_ELEMENTS(frameskip_entries),
- 0, G_CALLBACK(Modify_Frameskip), NULL);
+ config.frameskip, G_CALLBACK(Modify_Frameskip), NULL);
+ autoFrameskipMax = config.frameskip;
+ gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "frameskipA"), config.autoframeskip);
+ if (config.autoframeskip) {
+ autoframeskip = true;
+ Frameskip = 0;
+ } else {
+ autoframeskip = false;
+ Frameskip = autoFrameskipMax;
+ }
+
+ switch (config.view_rot) {
+ case 0:
+ case 90:
+ case 180:
+ case 270:
+ break;
+ default:
+ config.view_rot = 0;
+ break;
+ }
+ nds_screen.rotation_angle = config.view_rot;
gtk_action_group_add_radio_actions(action_group, rotation_entries, G_N_ELEMENTS(rotation_entries),
- 0, G_CALLBACK(SetRotation), NULL);
+ nds_screen.rotation_angle, G_CALLBACK(SetRotation), NULL);
+
+
+ if (config.window_scale < WINSIZE_SCALE || config.window_scale > WINSIZE_5) {
+ config.window_scale = WINSIZE_SCALE;
+ }
+ winsize_current = (winsize_enum)config.window_scale.get();
gtk_action_group_add_radio_actions(action_group, winsize_entries, G_N_ELEMENTS(winsize_entries),
- WINSIZE_SCALE, G_CALLBACK(SetWinsize), NULL);
+ winsize_current, G_CALLBACK(SetWinsize), NULL);
+
+ if (config.view_orient < ORIENT_VERTICAL || config.view_orient > ORIENT_SINGLE) {
+ config.view_orient = ORIENT_VERTICAL;
+ }
+ nds_screen.orientation = (orientation_enum)config.view_orient.get();
gtk_action_group_add_radio_actions(action_group, orientation_entries, G_N_ELEMENTS(orientation_entries),
- 0, G_CALLBACK(SetOrientation), NULL);
+ nds_screen.orientation, G_CALLBACK(SetOrientation), NULL);
+
{
GList * list = gtk_action_group_list_actions(action_group);
g_list_foreach(list, dui_set_accel_group, accel_group);
@@ -2984,6 +3083,12 @@ common_gtk_main( class configured_features *my_config)
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "cheatlist"), FALSE);
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "cheatsearch"), FALSE);
+ nds_screen.gap_size = config.view_gap ? GAP_SIZE : 0;
+ gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "gap"), config.view_gap);
+
+ nds_screen.swap = config.view_swap;
+ gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "orient_swapscreens"), config.view_swap);
+
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
accel_group = gtk_ui_manager_get_accel_group (ui_manager);
@@ -3010,9 +3115,6 @@ common_gtk_main( class configured_features *my_config)
pDrawingArea = gtk_drawing_area_new();
gtk_container_add (GTK_CONTAINER (pVBox), pDrawingArea);
- winsize_current = WINSIZE_SCALE;
- UpdateDrawingAreaAspect();
-
gtk_widget_set_events(pDrawingArea,
GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
@@ -3036,8 +3138,36 @@ common_gtk_main( class configured_features *my_config)
gtk_widget_show_all(pWindow);
- gtk_fps_limiter_disabled = my_config->disable_limiter;
- if (gtk_fps_limiter_disabled) {
+ if (winsize_current == WINSIZE_SCALE) {
+ if (config.window_fullscreen) {
+ gtk_widget_hide(pMenuBar);
+ gtk_widget_hide(pToolBar);
+ gtk_widget_hide(pStatusBar);
+ gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "view_menu"), FALSE);
+ gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "view_toolbar"), FALSE);
+ gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "view_statusbar"), FALSE);
+ gtk_window_fullscreen(GTK_WINDOW(pWindow));
+ }
+ } else {
+ config.window_fullscreen = false;
+ gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "fullscreen"), FALSE);
+ }
+ if (!config.view_menu) {
+ gtk_widget_hide(pMenuBar);
+ gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "view_menu"), FALSE);
+ }
+ if (!config.view_toolbar) {
+ gtk_widget_hide(pToolBar);
+ gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "view_toolbar"), FALSE);
+ }
+ if (!config.view_statusbar) {
+ gtk_widget_hide(pStatusBar);
+ gtk_toggle_action_set_active((GtkToggleAction*)gtk_action_group_get_action(action_group, "view_statusbar"), FALSE);
+ }
+ UpdateDrawingAreaAspect();
+
+ if (my_config->disable_limiter || !config.fpslimiter) {
+ config.fpslimiter = false;
GtkAction *action = gtk_action_group_get_action(action_group, "enablefpslimiter");
if (action)
gtk_toggle_action_set_active((GtkToggleAction *)action, FALSE);
@@ -3099,11 +3229,13 @@ common_gtk_main( class configured_features *my_config)
video->SetFilterParameteri(VF_PARAM_SCANLINE_C, _scanline_filter_c);
video->SetFilterParameteri(VF_PARAM_SCANLINE_D, _scanline_filter_d);
+ RedrawScreen();
/* Main loop */
gtk_main();
delete video;
+ config.save();
avout_x264.end();
avout_flac.end();