automake upgrade
[gdash.git] / src / settings.cpp
blob0cc30cc6a497fc408b5f146c6e40b15837df656b
1 /*
2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
19 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #include "config.h"
26 #include <glib/gi18n.h>
27 #include <glib.h>
28 #include <map>
30 #include "misc/logger.hpp"
31 #include "misc/printf.hpp"
32 #include "misc/autogfreeptr.hpp"
33 #include "cave/colors.hpp"
34 #include "misc/util.hpp"
35 #include "cave/gamerender.hpp"
36 #include "gfx/pixbuffactory.hpp"
37 #include "input/gameinputhandler.hpp"
38 #include "mainwindow.hpp"
40 #include "settings.hpp"
42 #ifdef HAVE_SDL
43 #include <SDL.h>
44 #endif
46 #ifdef HAVE_GTK
47 #include <gdk/gdkkeysyms.h>
48 #endif
51 #define SETTINGS_INI_FILE "gdash.ini"
52 #define SETTINGS_GDASH_GROUP "GDash"
54 /* possible languages. */
55 /* they are not translated, so every language name is show in that language itself. */
56 const char *gd_languages_names[] = {N_("System default"), "English", "Deutsch", "Magyar", NULL};
57 /* this should correspond to the above one. */
58 static const char *languages_for_env[] = { NULL, "en", "de", "hu" };
60 #ifdef G_OS_WIN32
61 /* locale names used in windows. */
62 static const char *language_locale_default[] = { "", NULL, };
63 static const char *language_locale_en[] = { "English", NULL, };
64 static const char *language_locale_de[] = { "German", NULL, };
65 static const char *language_locale_hu[] = { "Hungarian", NULL, };
66 #else
67 /* locale names used in unix. */
68 /* anyone, a better solution for this? */
69 static const char *language_locale_default[] =
70 { "", NULL, };
71 static const char *language_locale_en[] =
72 { "en_US.UTF-8", "en_US.UTF8", "en_US.ISO8859-15", "en_US.ISO8859-1", "en_US.US-ASCII", "en_US", "en", NULL, };
73 static const char *language_locale_de[] = {
74 "de_DE.UTF-8", "de_DE.UTF8", "de_DE.ISO8859-15", "de_DE.ISO8859-1", "de_DE",
75 "de_AT.UTF-8", "de_AT.UTF8", "de_AT.ISO8859-15", "de_AT.ISO8859-1", "de_AT",
76 "de_CH.UTF-8", "de_CH.UTF8", "de_CH.ISO8859-15", "de_CH.ISO8859-1", "de_CH",
77 "de", NULL,
79 static const char *language_locale_hu[] =
80 { "hu_HU.UTF-8", "hu_HU.UTF8", "hu_HU.ISO8859-2", "hu_HU", "hu", NULL, };
81 #endif /* ifdef g_os_win32 else */
83 /* put the locales to be tried in an array - same for windows and unix */
84 static const char **language_locale[] = {
85 language_locale_default,
86 language_locale_en,
87 language_locale_de,
88 language_locale_hu,
92 static std::map<char const *, int *> settings_integers;
93 static std::map<char const *, bool *> settings_bools;
94 static std::map<char const *, std::string *> settings_strings;
97 /* universal settings */
98 std::string gd_username;
99 std::string gd_theme;
100 bool gd_no_invisible_outbox = false;
101 bool gd_all_caves_selectable = false;
102 bool gd_import_as_all_caves_selectable = false;
103 bool gd_use_bdcff_highscore = false;
104 int gd_pal_emu_scanline_shade = 80;
105 bool gd_fine_scroll = true;
106 bool gd_particle_effects = true;
107 bool gd_show_story = true;
108 bool gd_show_name_of_game = true;
109 int gd_status_bar_colors = GD_STATUS_BAR_ORIGINAL;
111 /* palette settings */
112 int gd_c64_palette = 0;
113 int gd_c64dtv_palette = 0;
114 int gd_atari_palette = 0;
115 int gd_preferred_palette = GdColor::TypeRGB;
116 /* editor settings */
117 bool gd_game_view = true; /* show animated cells instead of arrows & ... */
118 bool gd_colored_objects = true; /* show objects with different color */
119 bool gd_show_object_list = true; /* show object list */
120 int gd_editor_window_width = 800; /* window size */
121 int gd_editor_window_height = 520; /* window size */
122 bool gd_fast_uncover_in_test = true;
124 /* preferences */
125 int gd_language = 0;
126 bool gd_show_preview = true;
128 /* graphics */
129 int gd_graphics_engine = 0; /* whichever is the first one supported */
130 bool gd_fullscreen = false;
131 int gd_cell_scale_factor_game = 2;
132 int gd_cell_scale_type_game = GD_SCALING_NEAREST;
133 bool gd_pal_emulation_game = false;
134 int gd_cell_scale_factor_editor = 1;
135 int gd_cell_scale_type_editor = GD_SCALING_NEAREST;
136 bool gd_pal_emulation_editor = false;
138 /* html output option */
139 /* CURRENTLY ONLY FROM THE COMMAND LINE */
140 char *gd_html_stylesheet_filename = NULL;
141 char *gd_html_favicon_filename = NULL;
143 /* GTK keyboard settings */
144 #ifdef HAVE_GTK /* only if having gtk */
145 int gd_gtk_key_left = GDK_Left;
146 int gd_gtk_key_right = GDK_Right;
147 int gd_gtk_key_up = GDK_Up;
148 int gd_gtk_key_down = GDK_Down;
149 int gd_gtk_key_fire_1 = GDK_Control_L;
150 int gd_gtk_key_fire_2 = GDK_Control_R;
151 int gd_gtk_key_suicide = GDK_s;
152 int gd_gtk_key_fast_forward = GDK_f;
153 int gd_gtk_key_status_bar = GDK_Shift_L;
154 int gd_gtk_key_restart_level = GDK_Escape;
155 #endif /* only if having gtk */
157 /* SDL settings */
158 #ifdef HAVE_SDL
159 int gd_sdl_key_left = SDLK_LEFT;
160 int gd_sdl_key_right = SDLK_RIGHT;
161 int gd_sdl_key_up = SDLK_UP;
162 int gd_sdl_key_down = SDLK_DOWN;
163 int gd_sdl_key_fire_1 = SDLK_LCTRL;
164 int gd_sdl_key_fire_2 = SDLK_RCTRL;
165 int gd_sdl_key_suicide = SDLK_s;
166 int gd_sdl_key_fast_forward = SDLK_f;
167 int gd_sdl_key_status_bar = SDLK_LSHIFT;
168 int gd_sdl_key_restart_level = SDLK_ESCAPE;
169 std::string gd_shader;
170 int shader_pal_radial_distortion = 10;
171 int shader_pal_random_scanline_displace = 50;
172 int shader_pal_luma_x_blur = 50;
173 int shader_pal_chroma_x_blur = 75;
174 int shader_pal_chroma_y_blur = 75;
175 int shader_pal_chroma_to_luma_strength = 25;
176 int shader_pal_luma_to_chroma_strength = 15;
177 int shader_pal_random_y = 5;
178 int shader_pal_random_uv = 10;
179 int shader_pal_scanline_shade_luma = 90;
180 int shader_pal_phosphor_shade = 85;
181 #endif /* use_sdl */
183 /* sound settings */
184 #ifdef HAVE_SDL
185 bool gd_sound_enabled = true;
186 bool gd_sound_16bit_mixing = true;
187 bool gd_sound_44khz_mixing = true;
188 bool gd_sound_stereo = true;
189 bool gd_classic_sound = false;
190 int gd_sound_chunks_volume_percent = 50;
191 int gd_sound_music_volume_percent = 50;
192 #endif /* if gd_sound */
195 /* some directories the game uses */
196 std::string gd_user_config_dir;
197 std::string gd_system_data_dir;
198 std::string gd_system_caves_dir;
199 std::string gd_system_music_dir;
201 std::vector<std::string> gd_sound_dirs, gd_themes_dirs, gd_fonts_dirs, gd_shaders_dirs;
203 /* command line parameters */
204 int gd_param_license = 0;
205 char **gd_param_cavenames = NULL;
206 gboolean gd_param_debug = FALSE;
207 gboolean gd_param_load_default_settings = FALSE;
211 static void set_page_numbers(Setting *settings) {
212 int page = -1;
213 for (size_t i = 0; settings[i].name != NULL; ++i) {
214 if (settings[i].type == TypePage)
215 page++;
216 settings[i].page = page;
221 Setting *gd_get_game_settings_array() {
222 static Setting settings_static[] = {
223 { TypePage, N_("Game") },
224 { TypeStringv, N_("Language"), &gd_language, false, gd_languages_names, N_("The language of the application. Changing this setting requires a restart!") },
225 { TypeBoolean, N_("All caves selectable"), &gd_all_caves_selectable, false, NULL, N_("All caves and intermissions can be selected at game start.") },
226 { TypeBoolean, N_("Import as all selectable"), &gd_import_as_all_caves_selectable, false, NULL, N_("Original, C64 games are imported not with A, E, I, M caves selectable, but all caves (ABCD, EFGH... excluding intermissions). This does not affect BDCFF caves.") },
227 { TypeBoolean, N_("Use BDCFF highscore"), &gd_use_bdcff_highscore, false, NULL, N_("Use BDCFF highscores. GDash saves highscores in its own configuration directory and also in the *.bd files. However, it prefers loading them from the configuration directory; as the *.bd files might be read-only. You can enable this setting to let GDash load them from the *.bd files.") },
228 { TypeBoolean, N_("Show story"), &gd_show_story, false, NULL, N_("If the cave has a story, it will be shown when the cave is first started.") },
229 { TypeBoolean, N_("Game name at uncover"), &gd_show_name_of_game, false, NULL, N_("Show the name of the game when uncovering a cave.") },
230 { TypeBoolean, N_("No invisible outbox"), &gd_no_invisible_outbox, false, NULL, N_("Show invisible outboxes as visible (blinking) ones.") },
232 { TypePage, N_("Theme and colors") },
233 { TypeTheme, N_("Theme"), NULL, false, NULL, N_("Graphics theme used inside the game."), 0, 0, NULL },
234 { TypeStringv, N_("Status bar colors"), &gd_status_bar_colors, false, gd_status_bar_colors_get_names(), N_("Preferred status bar color scheme. Only affects the colors, not the status bar layout.") },
235 { TypeStringv, N_(" C64 palette"), &gd_c64_palette, false, GdColor::get_c64_palette_names(), N_("The color palette for games imported from C64 files.") },
236 { TypeStringv, N_(" C64DTV palette"), &gd_c64dtv_palette, false, GdColor::get_c64dtv_palette_names(), N_("The color palette for imported C64 DTV games.") },
237 { TypeStringv, N_(" Atari palette"), &gd_atari_palette, false, GdColor::get_atari_palette_names(), N_("The color palette for imported Atari games.") },
238 { TypeStringv, N_(" Preferred palette"), &gd_preferred_palette, false, GdColor::get_palette_types_names(), N_("New caves and random colored caves use this palette.") },
240 { TypePage, N_("Game graphics") },
241 // TRANSLATORS: here "engine" = "graphics engine"
242 { TypeStringv, N_("Engine"), &gd_graphics_engine, true, gd_graphics_engine_names, N_("Graphics engine which used for drawing.") },
243 { TypeInteger, N_("Scaling factor"), &gd_cell_scale_factor_game, true, NULL, N_("Scaling size."), 1, 4 },
244 { TypeStringv, N_(" Scaling type"), &gd_cell_scale_type_game, true, gd_scaling_names, N_("Software scaling method used. This setting is only effective for the GTK+ and the SDL engines. If you use the OpenGL engine, you can configure its scaling method by selecting a shader.") },
245 { TypeBoolean, N_(" Software PAL emu"), &gd_pal_emulation_game, true, NULL, N_("Use PAL emulated graphics, i.e. lines are striped, and colors are distorted like on a TV. Only effective for the GTK+ and the SDL engines.") },
246 { TypePercent, N_(" PAL scanline shade"), &gd_pal_emu_scanline_shade, true, NULL, N_("Darker rows for PAL emulation. Only effective for the GTK+ and the SDL engines.") },
247 { TypeBoolean, N_("Fine scrolling"), &gd_fine_scroll, true, NULL, N_("If fine scrolling is turned off, scrolling and cave animation is limited to a lower frame rate, and consumes much less CPU. On some hardware, it might actually look better than fine scrolling. Not all graphics engines support fine scrolling.") },
248 { TypeBoolean, N_("Particle effects"), &gd_particle_effects, true, NULL, N_("Particle effects during play. This requires a lot of CPU power.") },
250 #ifdef HAVE_SDL
251 { TypePage, N_("OpenGL settings") },
252 { TypeShader, N_("Shader"), NULL, true, NULL, N_("The shader which adds a graphical effect to the screen. Only effective if the OpenGL engine is used. If your video card is older, it might not support shaders. The GDash TV shader can be configured with the settings below."), 0, 0, &gd_shader },
253 { TypePercent, N_("Radial distortion"), &shader_pal_radial_distortion, false, NULL, N_("With radial distortion, the screen won't be flat, but it will look like as if it's projected on a sphere.") },
254 { TypePercent, N_("Random scanline displacement"), &shader_pal_random_scanline_displace, false, NULL, N_("Increasing this setting causes the the image to be unstable horizontally.") },
255 { TypePercent, N_("Luma X blur"), &shader_pal_luma_x_blur, false, NULL, N_("Horizontal blur of luminosity.") },
256 { TypePercent, N_("Chroma X blur"), &shader_pal_chroma_x_blur, false, NULL, N_("Slight horizontal blur of colors.") },
257 { TypePercent, N_("Chroma Y blur"), &shader_pal_chroma_y_blur, false, NULL, N_("Vertical blur of colors, to imitate a PAL TV signal.") },
258 { TypePercent, N_("Chroma to luma"), &shader_pal_chroma_to_luma_strength, false, NULL, N_("Sudden changes in colors can cause patterns to appear on the image.") },
259 { TypePercent, N_("Luma to chroma"), &shader_pal_luma_to_chroma_strength, false, NULL, N_("Sudden changes in luminosity can cause false colors to appear on the image.") },
260 { TypePercent, N_("Random Y"), &shader_pal_random_y, false, NULL, N_("Noise level of luminosity.") },
261 { TypePercent, N_("Random UV"), &shader_pal_random_uv, false, NULL, N_("Noise level of colors.") },
262 { TypePercent, N_("Scanline shade"), &shader_pal_scanline_shade_luma, false, NULL, N_("Darkened horizontal rows to emulate a TV screen.") },
263 { TypePercent, N_("Phosphor shade"), &shader_pal_phosphor_shade, false, NULL, N_("Red, green and blue subpixels of a TV screen can be emulated.") },
264 #endif
266 #ifdef HAVE_GTK
267 { TypePage, N_("Editor settings") },
268 { TypeInteger, N_("Scaling factor"), &gd_cell_scale_factor_editor, true, NULL, N_("Scaling size."), 1, 4 },
269 { TypeStringv, N_(" Scaling type"), &gd_cell_scale_type_editor, true, gd_scaling_names, N_("Scaling method.") },
270 { TypeBoolean, N_(" Software PAL emu"), &gd_pal_emulation_editor, true, NULL, N_("Use PAL emulated graphics, i.e. lines are striped, and colors are distorted like on a TV.") },
271 { TypeBoolean, N_("Animated view"), &gd_game_view, true, NULL, N_("Show simplified view of cave in the editor.") },
272 { TypeBoolean, N_("Colored objects"), &gd_colored_objects, true, NULL, N_("Cave objects are colored, to make them different from random cave elements.") },
273 { TypeBoolean, N_("Object list"), &gd_show_object_list, true, NULL, N_("Show objects list sidebar in the editor.") },
274 { TypeBoolean, N_("Fast uncover in test"), &gd_fast_uncover_in_test, false, NULL, N_("Fast uncovering and covering of cave in editor cave test, to reduce waiting time.") },
275 #endif
277 #ifdef HAVE_SDL
278 { TypePage, N_("Sound") },
279 { TypeBoolean, N_("Sound"), &gd_sound_enabled, true, NULL, N_("Play sounds and music in the program.") },
280 { TypeBoolean, N_("Classic sounds only"), &gd_classic_sound, true, NULL, N_("Play only classic sounds taken from the original game.") },
281 { TypeBoolean, N_("Stereo sounds"), &gd_sound_stereo, true, NULL, N_("If you enable stereo sounds, you will hear the direction of sounds in the caves.") },
282 { TypeBoolean, N_("16-bit mixing"), &gd_sound_16bit_mixing, true, NULL, N_("Use 16-bit mixing of sounds. Try changing this setting if sound is clicky.") },
283 { TypeBoolean, N_("44kHz mixing"), &gd_sound_44khz_mixing, true, NULL, N_("Use 44kHz mixing of sounds. Try changing this setting if sound is clicky.") },
284 #endif
286 /* end */
287 { TypeBoolean, NULL },
290 set_page_numbers(settings_static);
292 return settings_static;
297 Setting *gd_get_keyboard_settings_array(GameInputHandler *gih) {
298 static Setting settings_static[] = {
299 { TypePage, N_("Keyboard") },
300 { TypeKey, N_("Key left"), &gih->get_key_variable(GameInputHandler::KeyLeft), false },
301 { TypeKey, N_("Key right"), &gih->get_key_variable(GameInputHandler::KeyRight), false },
302 { TypeKey, N_("Key up"), &gih->get_key_variable(GameInputHandler::KeyUp), false },
303 { TypeKey, N_("Key down"), &gih->get_key_variable(GameInputHandler::KeyDown), false },
304 { TypeKey, N_("Key snap"), &gih->get_key_variable(GameInputHandler::KeyFire1), false },
305 { TypeKey, N_("Key snap (alt.)"), &gih->get_key_variable(GameInputHandler::KeyFire2), false },
306 { TypeKey, N_("Key suicide"), &gih->get_key_variable(GameInputHandler::KeySuicide), false },
307 { TypeKey, N_("Key fast forward"), &gih->get_key_variable(GameInputHandler::KeyFastForward), false },
308 { TypeKey, N_("Key status bar"), &gih->get_key_variable(GameInputHandler::KeyStatusBar), false },
309 { TypeKey, N_("Key restart level"), &gih->get_key_variable(GameInputHandler::KeyRestartLevel), false },
310 /* end */
311 { TypeBoolean, NULL },
314 set_page_numbers(settings_static);
316 return settings_static;
320 static char *displayname(char const *filename) {
321 if (g_str_equal(filename, "")) {
322 // TRANSLATORS: Default (builtin) theme, shader, etc.
323 return g_strdup(_("[Default]"));
325 char *disp = g_filename_display_basename(filename);
326 if (strrchr(disp, '.')) /* remove extension */
327 *strrchr(disp, '.') = '\0';
328 return disp;
332 void gd_settings_array_prepare(Setting *settings, SettingType which,
333 std::vector<std::string> const & strings, int *var) {
334 for (unsigned i = 0; settings[i].name != NULL; ++i) {
335 if (settings[i].type == which) {
336 settings[i].var = var;
337 char **stringv = g_new(char *, strings.size()+1);
338 for (unsigned j = 0; j != strings.size(); ++j)
339 stringv[j] = displayname(strings[j].c_str());
340 stringv[strings.size()] = NULL;
341 settings[i].stringv = (char const **) stringv;
347 void gd_settings_array_unprepare(Setting *settings, SettingType which) {
348 for (unsigned i = 0; settings[i].name != NULL; ++i) {
349 if (settings[i].type == which) {
350 settings[i].var = NULL;
351 g_strfreev((char **) settings[i].stringv);
352 settings[i].stringv = NULL;
358 /* gets boolean value from key file; returns def if not found or unreadable */
359 static bool keyfile_get_bool_with_default(GKeyFile *keyfile, const char *group, const char *key, bool def) {
360 GError *error = NULL;
361 gboolean result = g_key_file_get_boolean(keyfile, group, key, &error);
362 if (!error)
363 return result != FALSE;
364 gd_debug(error->message);
365 g_error_free(error);
366 return def;
369 /* gets integer value from key file; returns def if not found or unreadable */
370 static int keyfile_get_integer_with_default(GKeyFile *keyfile, const char *group, const char *key, int def) {
371 GError *error = NULL;
372 int result = g_key_file_get_integer(keyfile, group, key, &error);
373 if (!error)
374 return result;
375 gd_debug(error->message);
376 g_error_free(error);
377 return def;
380 static std::string keyfile_get_string(GKeyFile *keyfile, const char *group, const char *key) {
381 if (!g_key_file_has_key(keyfile, group, key, NULL))
382 return "";
384 GError *error = NULL;
385 AutoGFreePtr<char> result(g_key_file_get_string(keyfile, group, key, &error));
386 if (result != NULL)
387 return std::string(result);
388 gd_debug(error->message);
389 g_error_free(error);
390 return "";
394 void gd_settings_init() {
395 gd_username = g_get_real_name();
396 settings_bools["no_invisible_outbox"] = &gd_no_invisible_outbox;
397 settings_bools["all_caves_selectable"] = &gd_all_caves_selectable;
398 settings_bools["import_as_all_caves_selectable"] = &gd_import_as_all_caves_selectable;
399 settings_bools["use_bdcff_highscore"] = &gd_use_bdcff_highscore;
400 settings_bools["fine_scroll"] = &gd_fine_scroll;
401 settings_bools["particle_effects"] = &gd_particle_effects;
402 settings_bools["show_story"] = &gd_show_story;
403 settings_bools["show_name_of_game"] = &gd_show_name_of_game;
404 settings_integers["pal_emu_scanline_shade"] = &gd_pal_emu_scanline_shade;
405 settings_integers["status_bar_colors"] = &gd_status_bar_colors;
406 settings_integers["c64_palette"] = &gd_c64_palette;
407 settings_integers["c64dtv_palette"] = &gd_c64dtv_palette;
408 settings_integers["atari_palette"] = &gd_atari_palette;
409 settings_integers["preferred_palette"] = &gd_preferred_palette;
410 settings_strings["username"] = &gd_username;
411 settings_strings["theme"] = &gd_theme;
413 settings_bools["game_view"] = &gd_game_view;
414 settings_bools["colored_objects"] = &gd_colored_objects;
415 settings_bools["show_object_list"] = &gd_show_object_list;
416 settings_bools["show_preview"] = &gd_show_preview;
417 settings_bools["pal_emulation_game"] = &gd_pal_emulation_game;
418 settings_bools["pal_emulation_editor"] = &gd_pal_emulation_editor;
419 settings_bools["fast_uncover_in_test"] = &gd_fast_uncover_in_test;
420 settings_integers["editor_window_width"] = &gd_editor_window_width;
421 settings_integers["editor_window_height"] = &gd_editor_window_height;
422 settings_integers["language"] = &gd_language;
423 settings_bools["fullscreen"] = &gd_fullscreen;
424 settings_integers["graphics_engine"] = &gd_graphics_engine;
425 settings_integers["cell_scale_factor_game"] = &gd_cell_scale_factor_game;
426 settings_integers["cell_scale_type_game"] = &gd_cell_scale_type_game;
427 settings_integers["cell_scale_factor_editor"] = &gd_cell_scale_factor_editor;
428 settings_integers["cell_scale_type_editor"] = &gd_cell_scale_type_editor;
430 #ifdef HAVE_GTK
431 settings_integers["gtk_key_left"] = &gd_gtk_key_left;
432 settings_integers["gtk_key_right"] = &gd_gtk_key_right;
433 settings_integers["gtk_key_up"] = &gd_gtk_key_up;
434 settings_integers["gtk_key_down"] = &gd_gtk_key_down;
435 settings_integers["gtk_key_fire_1"] = &gd_gtk_key_fire_1;
436 settings_integers["gtk_key_fire_2"] = &gd_gtk_key_fire_2;
437 settings_integers["gtk_key_suicide"] = &gd_gtk_key_suicide;
438 settings_integers["gtk_key_fast_forward"] = &gd_gtk_key_fast_forward;
439 settings_integers["gtk_key_status_bar"] = &gd_gtk_key_status_bar;
440 settings_integers["gtk_key_restart_level"] = &gd_gtk_key_restart_level;
441 #endif
443 #ifdef HAVE_SDL /* only if having sdl */
444 settings_integers["sdl_key_left"] = &gd_sdl_key_left;
445 settings_integers["sdl_key_right"] = &gd_sdl_key_right;
446 settings_integers["sdl_key_up"] = &gd_sdl_key_up;
447 settings_integers["sdl_key_down"] = &gd_sdl_key_down;
448 settings_integers["sdl_key_fire_1"] = &gd_sdl_key_fire_1;
449 settings_integers["sdl_key_fire_2"] = &gd_sdl_key_fire_2;
450 settings_integers["sdl_key_suicide"] = &gd_sdl_key_suicide;
451 settings_integers["sdl_key_fast_forward"] = &gd_sdl_key_fast_forward;
452 settings_integers["sdl_key_status_bar"] = &gd_sdl_key_status_bar;
453 settings_integers["sdl_key_restart_level"] = &gd_sdl_key_restart_level;
454 settings_strings["shader"] = &gd_shader;
456 settings_integers["shader_pal_radial_distortion"] = &shader_pal_radial_distortion;
457 settings_integers["shader_pal_random_scanline_displace"] = &shader_pal_random_scanline_displace;
458 settings_integers["shader_pal_luma_x_blur"] = &shader_pal_luma_x_blur;
459 settings_integers["shader_pal_chroma_x_blur"] = &shader_pal_chroma_x_blur;
460 settings_integers["shader_pal_chroma_y_blur"] = &shader_pal_chroma_y_blur;
461 settings_integers["shader_pal_chroma_to_luma_strength"] = &shader_pal_chroma_to_luma_strength;
462 settings_integers["shader_pal_luma_to_chroma_strength"] = &shader_pal_luma_to_chroma_strength;
463 settings_integers["shader_pal_random_y"] = &shader_pal_random_y;
464 settings_integers["shader_pal_random_uv"] = &shader_pal_random_uv;
465 settings_integers["shader_pal_scanline_shade_luma"] = &shader_pal_scanline_shade_luma;
466 settings_integers["shader_pal_phosphor_shade"] = &shader_pal_phosphor_shade;
467 #endif /* use_sdl */
469 #ifdef HAVE_SDL
470 settings_bools["sound"] = &gd_sound_enabled;
471 settings_bools["sound_16bit_mixing"] = &gd_sound_16bit_mixing;
472 settings_bools["sound_44khz_mixing"] = &gd_sound_44khz_mixing;
473 settings_bools["sound_stereo"] = &gd_sound_stereo;
474 settings_bools["classic_sound"] = &gd_classic_sound;
475 settings_integers["sound_chunks_volume_percent"] = &gd_sound_chunks_volume_percent;
476 settings_integers["sound_music_volume_percent"] = &gd_sound_music_volume_percent;
477 #endif
481 static void add_dirs(std::vector<std::string>& dirs, const char *specific) {
482 // user's own config
483 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, gd_user_config_dir.c_str(), specific, NULL)));
484 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, gd_user_config_dir.c_str(), NULL)));
485 // system-wide gdash config
486 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, gd_system_data_dir.c_str(), specific, NULL)));
487 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, gd_system_data_dir.c_str(), NULL)));
488 // for testing: actual directory
489 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, ".", specific, NULL)));
490 dirs.push_back(gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, ".", NULL)));
493 /* sets up directiories and loads translations */
494 void gd_settings_init_dirs() {
495 #ifdef G_OS_WIN32
496 /* on win32, use the glib function. */
497 gd_system_data_dir = g_win32_get_package_installation_directory(NULL, NULL);
498 #else
499 /* on linux, this is a defined, built-in string, $perfix/share/locale */
500 gd_system_data_dir = PKGDATADIR;
501 #endif
502 gd_system_caves_dir = gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, gd_system_data_dir.c_str(), "caves", NULL));
503 gd_system_music_dir = gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, gd_system_data_dir.c_str(), "music", NULL));
504 gd_user_config_dir = gd_tostring_free(g_build_path(G_DIR_SEPARATOR_S, g_get_user_config_dir(), PACKAGE, NULL));
506 add_dirs(gd_sound_dirs, "sound");
507 add_dirs(gd_themes_dirs, "themes");
508 add_dirs(gd_fonts_dirs, "fonts");
509 add_dirs(gd_shaders_dirs, "shaders");
512 /* set locale from the gdash setting variable. */
513 /* only bother setting the locale cleverly when we are in the gtk version. */
514 /* for sdl version, not really matters. */
515 /* if no gtk, just set the system default locale. */
516 void gd_settings_set_locale() {
517 if (gd_language < 0 || gd_language >= int(G_N_ELEMENTS(language_locale)))
518 gd_language = 0; /* switch to default, if out of bounds. */
520 /* we set the language environment variable, as gtk and other stuff will use it. */
521 g_assert(G_N_ELEMENTS(language_locale) == G_N_ELEMENTS(languages_for_env));
522 if (languages_for_env[gd_language] != NULL) {
523 g_setenv("LANG", languages_for_env[gd_language], TRUE);
524 g_setenv("LANGUAGE", languages_for_env[gd_language], TRUE);
527 /* try to set the locale. */
528 int i = 0;
529 char *result = NULL;
530 while (result == NULL && language_locale[gd_language][i] != NULL) {
531 result = setlocale(LC_ALL, language_locale[gd_language][i]);
532 i++;
534 if (result == NULL) {
535 /* failed to set. switch to system default */
536 if (gd_language != 0)
537 gd_message(CPrintf("Failed to set language to '%s'. Switching to system default locale.") % gd_languages_names[gd_language]);
538 setlocale(LC_ALL, "");
542 /* sets up directiories and loads translations */
543 /* also instructs gettext to give all strings as utf8, as gtk uses that */
544 void gd_settings_init_translation() {
545 /* different directories storing the translation files on unix and win32. */
546 /* gdash (and gtk) always uses utf8, so convert translated strings to utf8 if needed. */
547 #ifdef G_OS_WIN32
548 bindtextdomain("gtk20-properties", gd_system_data_dir.c_str());
549 bind_textdomain_codeset("gtk20-properties", "UTF-8");
550 bindtextdomain("gtk20", gd_system_data_dir.c_str());
551 bind_textdomain_codeset("gtk20", "UTF-8");
552 bindtextdomain("glib20", gd_system_data_dir.c_str());
553 bind_textdomain_codeset("glib20", "UTF-8");
554 bindtextdomain(PACKAGE, gd_system_data_dir.c_str()); /* gdash */
555 bind_textdomain_codeset(PACKAGE, "UTF-8");
556 #else
557 bindtextdomain(PACKAGE, LOCALEDIR); /* gdash */
558 bind_textdomain_codeset(PACKAGE, "UTF-8");
559 #endif
560 textdomain(PACKAGE); /* set default textdomain to gdash */
564 /* load settings from .config/gdash/gdash.ini */
565 void gd_load_settings() {
566 GError *error = NULL;
567 gchar *data;
568 gsize length;
570 AutoGFreePtr<char> filename(g_build_path(G_DIR_SEPARATOR_S, gd_user_config_dir.c_str(), SETTINGS_INI_FILE, NULL));
571 if (!g_file_get_contents(filename, &data, &length, &error)) {
572 /* no ini file found */
573 gd_debug(error->message);
574 g_error_free(error);
575 return;
577 /* if zero length file, also return */
578 if (length == 0)
579 return;
581 GKeyFile *ini = g_key_file_new();
582 gboolean success = g_key_file_load_from_data(ini, data, length, G_KEY_FILE_NONE, &error);
583 g_free(data);
584 if (!success) {
585 gd_message(CPrintf("INI file contents error: %s") % error->message);
586 g_error_free(error);
587 return;
590 /* load the settings */
591 for (std::map<char const *, int *>::const_iterator it = settings_integers.begin(); it != settings_integers.end(); ++it) {
592 char const *key = it->first;
593 int &var = *it->second;
594 var = keyfile_get_integer_with_default(ini, SETTINGS_GDASH_GROUP, key, var);
596 for (std::map<char const *, bool *>::const_iterator it = settings_bools.begin(); it != settings_bools.end(); ++it) {
597 char const *key = it->first;
598 bool &var = *it->second;
599 var = keyfile_get_bool_with_default(ini, SETTINGS_GDASH_GROUP, key, var);
601 for (std::map<char const *, std::string *>::const_iterator it = settings_strings.begin(); it != settings_strings.end(); ++it) {
602 char const *key = it->first;
603 std::string &var = *it->second;
604 var = keyfile_get_string(ini, SETTINGS_GDASH_GROUP, key);
607 g_key_file_free(ini);
609 /* check settings */
610 gd_cell_scale_factor_game = gd_clamp(gd_cell_scale_factor_game, 1, 4);
611 gd_cell_scale_factor_editor = gd_clamp(gd_cell_scale_factor_editor, 1, 4);
612 gd_cell_scale_type_game = gd_clamp(gd_cell_scale_type_game, 0, GD_SCALING_MAX-1);
613 gd_cell_scale_type_editor = gd_clamp(gd_cell_scale_type_editor, 0, GD_SCALING_MAX-1);
614 if (gd_preferred_palette < 0 || gd_preferred_palette >= int(GdColor::TypeInvalid))
615 gd_preferred_palette = GdColor::TypeRGB;
616 if (gd_status_bar_colors < 0 || gd_status_bar_colors > int(GD_STATUS_BAR_MAX))
617 gd_status_bar_colors = GD_STATUS_BAR_ORIGINAL;
621 /* save settings to .config/gdash.ini */
622 void gd_save_settings() {
623 GKeyFile *ini = g_key_file_new();
625 /* save them */
626 for (std::map<char const *, int *>::const_iterator it = settings_integers.begin(); it != settings_integers.end(); ++it) {
627 char const *key = it->first;
628 int &var = *it->second;
629 g_key_file_set_integer(ini, SETTINGS_GDASH_GROUP, key, var);
631 for (std::map<char const *, bool *>::const_iterator it = settings_bools.begin(); it != settings_bools.end(); ++it) {
632 char const *key = it->first;
633 bool &var = *it->second;
634 g_key_file_set_boolean(ini, SETTINGS_GDASH_GROUP, key, (gboolean) var);
636 for (std::map<char const *, std::string *>::const_iterator it = settings_strings.begin(); it != settings_strings.end(); ++it) {
637 char const *key = it->first;
638 std::string &var = *it->second;
639 g_key_file_set_string(ini, SETTINGS_GDASH_GROUP, key, var.c_str());
642 GError *error = NULL;
643 /* convert to string and free */
644 AutoGFreePtr<gchar> data(g_key_file_to_data(ini, NULL, &error));
645 g_key_file_free(ini);
646 if (error) {
647 /* this is highly unlikely - why would g_key_file_to_data report error? docs do not mention. */
648 gd_warning(CPrintf("Unable to save settings: %s") % error->message);
649 g_error_free(error);
650 return;
653 AutoGFreePtr<gchar> filename(g_build_path(G_DIR_SEPARATOR_S, gd_user_config_dir.c_str(), SETTINGS_INI_FILE, NULL));
654 g_mkdir_with_parents(gd_user_config_dir.c_str(), 0700);
655 g_file_set_contents(filename, data, -1, &error);
656 if (error) {
657 /* error saving the file */
658 gd_warning(CPrintf("Unable to save settings: %s") % error->message);
659 g_error_free(error);
660 return;
664 GOptionContext *gd_option_context_new() {
665 GOptionEntry const entries[] = {
666 {"license", 'L', 0, G_OPTION_ARG_NONE, &gd_param_license, N_("Show license and quit")},
667 {"debug", 'v', 0, G_OPTION_ARG_NONE, &gd_param_debug, N_("Show some debug messages")},
668 {"default-settings", 0, 0, G_OPTION_ARG_NONE, &gd_param_load_default_settings, N_("Load default settings")},
669 {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &gd_param_cavenames, N_("Cave names")},
670 {NULL}
672 GOptionContext *context = g_option_context_new(_("[FILE NAME]"));
673 g_option_context_set_help_enabled(context, TRUE);
674 g_option_context_add_main_entries(context, entries, PACKAGE); /* gdash parameters */
676 return context;