Crossfire Client, Trunk  R20996
config.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #include "client.h"
20 
21 #include <ctype.h>
22 #include <gtk/gtk.h>
23 
24 #include "image.h"
25 #include "main.h"
26 #include "mapdata.h"
27 #include "gtk2proto.h"
28 
29 static GKeyFile *config;
30 static GString *config_path;
31 
36 
38 GtkComboBoxText *config_combobox_faceset;
40 
41 #define THEME_DEFAULT CF_DATADIR "/themes/Standard"
42 static char *theme = THEME_DEFAULT;
43 
44 static void on_config_close(GtkButton *button, gpointer user_data);
45 
49 static char *ui_name() {
50  return g_path_get_basename(window_xml_file);
51 }
52 
75 static char **default_files = NULL;
76 void init_theme() {
77  char path[MAX_BUF];
78  char **tmp;
79  int i;
80 
81  /*
82  * The GTK man page says copy of this data should be made, so do that.
83  */
84  tmp = gtk_rc_get_default_files();
85  i = 0;
86  while (tmp[i]) {
87  i++;
88  }
89  /*
90  * Add two more GTK rc files that may be used by a player to customize
91  * the client appearance in general, or to customize the appearance
92  * of a specific layout. Allocate pointers to the local copy
93  * of the entire list.
94  */
95  i += 2;
96  default_files = g_malloc(sizeof(char *) * (i + 1));
97  /*
98  * Copy in GTK's default list which probably contains system paths
99  * like <SYSCONFDIR>/gtk-2.0/gtkrc and user-specific files like
100  * ${HOME}/.gtkrc, or even LANGuage-specific ones like
101  * ${HOME}/.gtkrc.en, etc.
102  */
103  i = 0;
104  while (tmp[i]) {
105  default_files[i] = g_strdup(tmp[i]);
106  i++;
107  }
108  /*
109  * Add a player-specific gtkrc to the list of default rc files. This
110  * file is probably reserved for player use, though in all liklihood
111  * will not get used that much. Still, it makes it easy for someone
112  * to make their own theme without having to have access to the
113  * system-wide theme folder. This is the lowest priority client rc
114  * file as either a <layout>.gtkrc file or a client-configured theme
115  * settings can over-ride it.
116  */
117  snprintf(path, sizeof(path), "%s/gtkrc", config_dir);
118  default_files[i] = g_strdup(path);
119  i++;
120  /*
121  * Add a UI layout-specific rc file to the list of default list. It
122  * seems reasonable to allow client code to have access to this file
123  * to make some basic changes to fonts, via a graphical interface.
124  * Truncate window_xml_file to remove a .extension if one exists, so
125  * that the window positions file can be created with a .gtkrc suffix.
126  * This is a mid-priority client rc file as its settings supersede the
127  * client gtkrc file, but are overridden by a client-configured theme.
128  */
129  snprintf(path, sizeof(path), "%s/%s.gtkrc", config_dir, ui_name());
130  default_files[i] = g_strdup(path);
131  i++;
132  /*
133  * Mark the end of the list of default rc files.
134  */
135  default_files[i] = NULL;
136 }
137 
138 void load_theme(int reload) {
139  /*
140  * Whether or not this is default and initial run, we want to register
141  * the modified rc search path list, so GTK needs to get the changes.
142  * It is necessary to reset the the list each time through here each
143  * theme change grows the list. Only one theme should be in the list
144  * at a time.
145  */
146  gtk_rc_set_default_files(default_files);
147 
148  /*
149  * If a client-configured theme has been selected (something other than
150  * "None"), then add it to the list of GTK rc files to process. Since
151  * this file is added last, it takes priority over both the gtkrc and
152  * <layout>.gtkrc files. Remember, strcmp returns zero on a match, and
153  * a theme file should not be registered if "None" is selected.
154  */
155  if (theme != NULL) {
156  /*
157  * Check for existence of the client theme file. Unfortunately, at
158  * initial run time, the window may not be realized yet, so the
159  * message cannot be sent to the user directly. It doesn't hurt to
160  * add the path even if the file isn't there, but the player might
161  * still want to know something is wrong since they picked a theme.
162  */
163  if (access(theme, R_OK) == -1) {
164  LOG(LOG_ERROR, "load_theme", "Unable to find theme file %s", theme);
166  }
167  gtk_rc_add_default_file(theme);
168  }
169 
170  /*
171  * Require GTK to reparse and rebind all the widget data.
172  */
173  gtk_rc_reparse_all_for_settings(
174  gtk_settings_get_for_screen(gdk_screen_get_default()), TRUE);
175  gtk_rc_reset_styles(
176  gtk_settings_get_for_screen(gdk_screen_get_default()));
177  /*
178  * Call client functions to reparse the custom widgets it controls.
179  */
180  info_get_styles();
185  /*
186  * Set inv_updated to force a redraw - otherwise it will not
187  * necessarily bind the lists with the new widgets.
188  */
189  cpl.below->inv_updated = 1;
190  cpl.ob->inv_updated = 1;
191  draw_lists();
192  draw_stats(TRUE);
193  draw_message_window(TRUE);
194 }
195 
199 static void config_load_legacy() {
200  char path[MAX_BUF], inbuf[MAX_BUF], *cp;
201  FILE *fp;
202  int i, val;
203 
204  LOG(LOG_INFO, "config_load_legacy",
205  "Configuration not found; trying old configuration files.");
206  LOG(LOG_INFO, "config_load_legacy",
207  "You will need to move your keybindings to the new location.");
208 
209  snprintf(path, sizeof(path), "%s/.crossfire/gdefaults2", g_getenv("HOME"));
210  if ((fp = fopen(path, "r")) == NULL) {
211  return;
212  }
213  while (fgets(inbuf, MAX_BUF - 1, fp)) {
214  inbuf[MAX_BUF - 1] = '\0';
215  inbuf[strlen(inbuf) - 1] = '\0'; /* kill newline */
216 
217  if (inbuf[0] == '#') {
218  continue;
219  }
220  /* Skip any setting line that does not contain a colon character */
221  if (!(cp = strchr(inbuf, ':'))) {
222  continue;
223  }
224  *cp = '\0';
225  cp += 2; /* colon, space, then value */
226 
227  val = -1;
228  if (isdigit(*cp)) {
229  val = atoi(cp);
230  } else if (!strcmp(cp, "True")) {
231  val = TRUE;
232  } else if (!strcmp(cp, "False")) {
233  val = FALSE;
234  }
235 
236  for (i = 1; i < CONFIG_NUMS; i++) {
237  if (!strcmp(config_names[i], inbuf)) {
238  if (val == -1) {
239  LOG(LOG_WARNING, "config.c::load_defaults",
240  "Invalid value/line: %s: %s", inbuf, cp);
241  } else {
242  want_config[i] = val;
243  }
244  break; /* Found a match - won't find another */
245  }
246  }
247  /* We found a match in the loop above, so do not do anything more */
248  if (i < CONFIG_NUMS) {
249  continue;
250  }
251 
252  /*
253  * Legacy - now use the map_width and map_height values Don't do sanity
254  * checking - that will be done below
255  */
256  if (!strcmp(inbuf, "mapsize")) {
257  if (sscanf(cp, "%hdx%hd", &want_config[CONFIG_MAPWIDTH],
258  &want_config[CONFIG_MAPHEIGHT]) != 2) {
259  LOG(LOG_WARNING, "config.c::load_defaults",
260  "Malformed mapsize option in gdefaults2. Ignoring");
261  }
262  } else if (!strcmp(inbuf, "theme")) {
263  theme = g_strdup(cp); /* memory leak ! */
264  continue;
265  } else if (!strcmp(inbuf, "window_layout")) {
266  strncpy(window_xml_file, cp, MAX_BUF - 1);
267  continue;
268  } else if (!strcmp(inbuf, "nopopups")) {
269  /* Changed name from nopopups to popups, so inverse value */
270  want_config[CONFIG_POPUPS] = !val;
271  continue;
272  } else if (!strcmp(inbuf, "nosplash")) {
273  want_config[CONFIG_SPLASH] = !val;
274  continue;
275  } else if (!strcmp(inbuf, "splash")) {
276  want_config[CONFIG_SPLASH] = val;
277  continue;
278  } else if (!strcmp(inbuf, "faceset")) {
279  face_info.want_faceset = g_strdup(cp); /* memory leak ! */
280  continue;
281  }
282  /* legacy, as this is now just saved as 'lighting' */
283  else if (!strcmp(inbuf, "per_tile_lighting")) {
284  if (val) {
286  }
287  } else if (!strcmp(inbuf, "per_pixel_lighting")) {
288  if (val) {
290  }
291  } else if (!strcmp(inbuf, "resists")) {
292  if (val) {
294  }
295  } else if (!strcmp(inbuf, "sdl")) {
296  if (val) {
298  }
299  } else LOG(LOG_WARNING, "config.c::load_defaults",
300  "Unknown line in gdefaults2: %s %s", inbuf, cp);
301  }
302  fclose(fp);
303 }
304 
311 void config_check() {
312  if (want_config[CONFIG_ICONSCALE] < 25 ||
313  want_config[CONFIG_ICONSCALE] > 200) {
314  LOG(LOG_WARNING, "config_check",
315  "Ignoring invalid 'iconscale' value '%d'; "
316  "must be between 25 and 200.\n",
319  }
320 
321  if (want_config[CONFIG_MAPSCALE] < 25 ||
322  want_config[CONFIG_MAPSCALE] > 200) {
323  LOG(LOG_WARNING, "config_check",
324  "Ignoring invalid 'mapscale' value '%d'; "
325  "must be between 25 and 200.\n",
328  }
329 
331  LOG(LOG_WARNING, "config_check",
332  "No lighting mechanism selected - will not use darkness code");
333  want_config[CONFIG_DARKNESS] = FALSE;
334  }
335 
336  if (want_config[CONFIG_RESISTS] > 2) {
337  LOG(LOG_WARNING, "config_check",
338  "Ignoring invalid 'resists' value '%d'; "
339  "must be either 0, 1, or 2.\n",
342  }
343 
344  /* Make sure the map size os OK */
345  if (want_config[CONFIG_MAPWIDTH] < 9 ||
347  LOG(LOG_WARNING, "config_check", "Invalid map width (%d) "
348  "option in gdefaults2. Valid range is 9 to %d",
351  }
352 
353  if (want_config[CONFIG_MAPHEIGHT] < 9 ||
355  LOG(LOG_WARNING, "config_check", "Invalid map height (%d) "
356  "option in gdefaults2. Valid range is 9 to %d",
359  }
360 
361 #if !defined(HAVE_OPENGL)
364  LOG(LOG_ERROR, "config_check",
365  "Display mode is set to OpenGL, but client "
366  "is not compiled with OpenGL support. Reverting to pixmap mode.");
367  }
368 #endif
369 
370 #if !defined(HAVE_SDL)
373  LOG(LOG_ERROR, "config_check",
374  "Display mode is set to SDL, but client "
375  "is not compiled with SDL support. Reverting to pixmap mode.");
376  }
377 #endif
378 
379  /* Copy sanitized user settings to current settings. */
380  memcpy(use_config, want_config, sizeof(use_config));
381 
385  if (!use_config[CONFIG_CACHE]) {
386  use_config[CONFIG_DOWNLOAD] = FALSE;
387  }
388 }
389 
393 void config_load() {
394  GError *error = NULL;
395 
396  /* Copy initial desired settings from current settings. */
397  memcpy(want_config, use_config, sizeof(want_config));
398 
399  g_assert(g_file_test(config_dir, G_FILE_TEST_IS_DIR) == TRUE);
400 
401  /* Load existing or create new configuration file. */
402  config = g_key_file_new();
403  config_path = g_string_new(config_dir);
404  g_string_append(config_path, "/client.ini");
405 
406  g_key_file_load_from_file(config, config_path->str, G_KEY_FILE_NONE, &error);
407 
408  /* Load configuration values into settings array. */
409  if (error == NULL) {
410  for (int i = 1; i < CONFIG_NUMS; i++) {
411  want_config[i] = g_key_file_get_integer(config, "Client",
412  config_names[i], NULL);
413  }
414 
415  /* Load additional settings. */
416  /* TODO: Both of these below are one-time memory leaks. */
417  theme = g_key_file_get_string(config, "GTKv2",
418  "theme", NULL);
419  face_info.want_faceset = g_key_file_get_string(config, "GTKv2",
420  "faceset", NULL);
421 
422  char *layout =
423  g_key_file_get_string(config, "GTKv2", "window_layout", NULL);
424  g_strlcpy(window_xml_file, layout, sizeof(window_xml_file));
425  free(layout);
426  } else {
427  g_error_free(error);
428 
429  /* Load legacy configuration file. */
431  }
432 }
433 
439  GError *error = NULL;
440 
441  /* Save GTKv2 specific client settings. */
442  g_key_file_set_string(config, "GTKv2", "theme", theme);
443  g_key_file_set_string(config, "GTKv2", "faceset", face_info.want_faceset);
444  g_key_file_set_string(config, "GTKv2", "window_layout", window_xml_file);
445 
446  /* Save the rest of the client settings. */
447  for (int i = 1; i < CONFIG_NUMS; i++) {
448  g_key_file_set_integer(config, "Client", config_names[i], want_config[i]);
449  }
450 
451  g_file_set_contents(config_path->str,
452  g_key_file_to_data(config, NULL, NULL), -1, &error);
453 
454  if (error != NULL) {
456  "Could not save settings!");
457  g_warning("Could not save settings: %s", error->message);
458  g_error_free(error);
459  }
460 }
461 
462 void config_init(GtkWidget *window_root) {
463  config_dialog =
464  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_dialog"));
465 
466  // Initialize file choosers and set filename filters.
468  GTK_FILE_CHOOSER(gtk_builder_get_object(dialog_xml, "ui_filechooser"));
469  theme_filechooser = GTK_FILE_CHOOSER(
470  gtk_builder_get_object(dialog_xml, "theme_filechooser"));
471 
472  GtkFileFilter *ui_filter = gtk_file_filter_new();
473  gtk_file_filter_add_pattern(ui_filter, "*.ui");
474  gtk_file_chooser_set_filter(ui_filechooser, ui_filter);
475 
477  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_echo"));
479  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_fasttcp"));
481  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_timestamp"));
483  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_grad_color"));
485  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_foodbeep"));
487  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_sound"));
489  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_cache"));
491  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_download"));
493  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_fog"));
495  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_smoothing"));
496 
497  config_combobox_displaymode = GTK_COMBO_BOX(
498  gtk_builder_get_object(dialog_xml, "config_combobox_displaymode"));
499  config_combobox_faceset = GTK_COMBO_BOX_TEXT(
500  gtk_builder_get_object(dialog_xml, "config_combobox_faceset"));
501  config_combobox_lighting = GTK_COMBO_BOX(
502  gtk_builder_get_object(dialog_xml, "config_combobox_lighting"));
503 
504  GtkWidget *config_button_close =
505  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_close"));
506  g_signal_connect(config_button_close, "clicked",
507  G_CALLBACK(on_config_close), NULL);
508  g_signal_connect(config_dialog, "delete_event", G_CALLBACK(on_config_close),
509  NULL);
510 
511  // Initialize available rendering modes.
512  GtkListStore *display_list =
513  GTK_LIST_STORE(gtk_combo_box_get_model(config_combobox_displaymode));
514  GtkTreeIter iter;
515 #ifdef HAVE_OPENGL
516  gtk_list_store_append(display_list, &iter);
517  gtk_list_store_set(display_list, &iter, 0, "OpenGL", 1, CFG_DM_OPENGL, -1);
518 #endif
519 #ifdef HAVE_SDL
520  gtk_list_store_append(display_list, &iter);
521  gtk_list_store_set(display_list, &iter, 0, "SDL", 1, CFG_DM_SDL, -1);
522 #endif
523  gtk_list_store_append(display_list, &iter);
524  gtk_list_store_set(display_list, &iter, 0, "Pixmap", 1, CFG_DM_PIXMAP, -1);
525 }
526 
531 static void combo_box_text_remove_all(GtkComboBoxText *combo_box) {
532  int count = gtk_tree_model_iter_n_children(
533  gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box)), NULL);
534  for (int i = 0; i < count; i++) {
535  gtk_combo_box_text_remove(combo_box, 0);
536  }
537 }
538 
539 /*
540  * Setup config_dialog sets the buttons, combos, etc, to the state that matches
541  * the want_config[] values.
542  */
543 static void setup_config_dialog() {
544  GtkTreeIter iter;
545  gchar *buf;
546  int count;
547 
548  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_echo),
550  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_fasttcp),
552  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_timestamp),
554  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_grad_color),
556  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_foodbeep),
558  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_sound),
560  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_cache),
562  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_download),
564  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_fog),
566  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_smoothing),
568 
569  // Fill face set combo box with available face sets from the server.
571 
572  /* If we have real faceset info from the server, use it */
574  for (int i = 0; i < MAX_FACE_SETS; i++)
575  if (face_info.facesets[i].fullname)
576  gtk_combo_box_text_append_text(config_combobox_faceset,
578  }
579 
580  GtkTreeModel *model =
581  gtk_combo_box_get_model(GTK_COMBO_BOX(config_combobox_faceset));
582  count = gtk_tree_model_iter_n_children(model, NULL);
583  for (int i = 0; i < count; i++) {
584  if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, i)) {
585  LOG(LOG_ERROR, "setup_config_dialog", "Cannot iterate facesets\n");
586  break;
587  }
588  gtk_tree_model_get(model, &iter, 0, &buf, -1);
589 
590  if (face_info.want_faceset &&
591  !g_ascii_strcasecmp(face_info.want_faceset, buf)) {
592  gtk_combo_box_set_active(GTK_COMBO_BOX(config_combobox_faceset), i);
593  g_free(buf);
594  break;
595  }
596  g_free(buf);
597  }
598 
599  // Set current display mode.
600  model = gtk_combo_box_get_model(config_combobox_displaymode);
601  bool next = gtk_tree_model_get_iter_first(model, &iter);
602  while (next) {
603  int current;
604  gtk_tree_model_get(model, &iter, 1, &current, -1);
605  if (current == want_config[CONFIG_DISPLAYMODE]) {
606  gtk_combo_box_set_active_iter(config_combobox_displaymode, &iter);
607  break;
608  }
609  next = gtk_tree_model_iter_next(model, &iter);
610  }
611 
612  // Lighting option indexes never change, so set option using index.
613  gtk_combo_box_set_active(config_combobox_lighting,
615 
616  gtk_file_chooser_set_filename(ui_filechooser, window_xml_file);
617  gtk_file_chooser_set_filename(theme_filechooser, theme);
618 }
619 
620 #define IS_DIFFERENT(TYPE) (want_config[TYPE] != use_config[TYPE])
621 
625 static int combobox_get_value(GtkComboBox *combobox, int column) {
626  GtkTreeModel *model = gtk_combo_box_get_model(combobox);
627  GtkTreeIter iter;
628  int result;
629 
630  gtk_combo_box_get_active_iter(combobox, &iter);
631  gtk_tree_model_get(model, &iter, column, &result, -1);
632  return result;
633 }
634 
640 static void read_config_dialog(void) {
642  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_echo));
644  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_fasttcp));
645  want_config[CONFIG_TIMESTAMP] = gtk_toggle_button_get_active(
646  GTK_TOGGLE_BUTTON(config_button_timestamp));
647  want_config[CONFIG_GRAD_COLOR] = gtk_toggle_button_get_active(
648  GTK_TOGGLE_BUTTON(config_button_grad_color));
650  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_foodbeep));
652  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_sound));
654  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_cache));
656  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_download));
658  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_fog));
659  want_config[CONFIG_SMOOTH] = gtk_toggle_button_get_active(
660  GTK_TOGGLE_BUTTON(config_button_smoothing));
661 
662  gchar *buf;
663 
664  buf = gtk_combo_box_text_get_active_text(config_combobox_faceset);
665  if (buf) {
666  free(face_info.want_faceset);
667  face_info.want_faceset = g_strdup(buf);
668  g_free(buf);
669  }
670 
673 
674  // Lighting option indexes never change, so get option using index.
676  gtk_combo_box_get_active(config_combobox_lighting);
677 
678  // Enable darkness if lighting is not 'None'.
682  }
683 
684  // Set UI file.
685  buf = gtk_file_chooser_get_filename(ui_filechooser);
686  if (buf != NULL) {
687  g_strlcpy(window_xml_file, buf, sizeof(window_xml_file));
688  g_free(buf);
689  }
690 
691  // Set and load theme file.
692  buf = gtk_file_chooser_get_filename(theme_filechooser);
693  if (buf != NULL && g_ascii_strcasecmp(buf, theme) != 0) {
694  g_free(theme);
695  theme = buf;
696  load_theme(TRUE);
697  }
698 
699  /*
700  * Some values can take effect right now, others not. Code below handles
701  * these cases - largely grabbed from gtk/config.c
702  */
703  if (IS_DIFFERENT(CONFIG_SOUND)) {
704  int tmp;
705  if (want_config[CONFIG_SOUND]) {
706  tmp = init_sounds();
707  if (csocket.fd) {
708  cs_print_string(csocket.fd, "setup sound %d", tmp >= 0);
709  }
710  } else {
711  if (csocket.fd) {
712  cs_print_string(csocket.fd, "setup sound 0");
713  }
714  }
716  }
718 #ifdef TCP_NODELAY
719 #ifndef WIN32
720  // TODO: Merge with setsockopt code from client.c
721  int q = want_config[CONFIG_FASTTCP];
722 
723  if (csocket.fd &&
724  setsockopt(csocket.fd, SOL_TCP, TCP_NODELAY, &q, sizeof(q)) == -1) {
725  perror("TCP_NODELAY");
726  }
727 #endif
728 #endif
730  }
731 
733 #ifdef HAVE_SDL
735  /* This is done to make the 'lightmap' in the proper format */
736  {
737  init_SDL(NULL, 1);
738  }
739 #endif
740  }
741  /*
742  * Nothing to do, but we can switch immediately without problems. do force
743  * a redraw
744  */
747  draw_stats(TRUE);
748  }
749 }
750 
751 void on_configure_activate(GtkWidget *menuitem, gpointer user_data) {
752  gtk_widget_show(config_dialog);
754 }
755 
756 static void on_config_close(GtkButton *button, gpointer user_data) {
758  save_defaults();
759  gtk_widget_hide(config_dialog);
760 }
761 
765 void save_winpos() {
766  GSList *pane_list, *list_loop;
767  int x, y, w, h, wx, wy;
768 
769  /* Save window position and size. */
770  get_window_coord(window_root, &x, &y, &wx, &wy, &w, &h);
771 
772  GString *window_root_info = g_string_new(NULL);
773  g_string_printf(window_root_info, "+%d+%dx%dx%d", wx, wy, w, h);
774 
775  g_key_file_set_string(config, ui_name(),
776  "window_root", window_root_info->str);
777  g_string_free(window_root_info, TRUE);
778 
779  /* Save the positions of all the HPANEDs and VPANEDs. */
780  pane_list = gtk_builder_get_objects(window_xml);
781 
782  for (list_loop = pane_list; list_loop != NULL; list_loop = list_loop->next) {
783  GType type = G_OBJECT_TYPE(list_loop->data);
784 
785  if (type == GTK_TYPE_HPANED || type == GTK_TYPE_VPANED) {
786  g_key_file_set_integer(config, ui_name(),
787  gtk_buildable_get_name(list_loop->data),
788  gtk_paned_get_position(GTK_PANED(list_loop->data)));
789  }
790  }
791 
792  g_slist_free(pane_list);
793  save_defaults();
794 
796  "Window positions saved!");
797 }
798 
806 void on_save_window_position_activate(GtkMenuItem *menuitem,
807  gpointer user_data) {
808  save_winpos();
809  /*
810  * The following prevents multiple saves per menu activation.
811  */
812  g_signal_stop_emission_by_name(GTK_OBJECT(menuitem), "activate");
813 }
814 
821  GSList *pane_list, *list;
822  pane_list = gtk_builder_get_objects(window_xml);
823 
824  // Load and set main window dimensions.
825  gchar *root_size = g_key_file_get_string(config, ui_name(),
826  "window_root", NULL);
827 
828  if (root_size != NULL) {
829  int w, h;
830 
831  if (sscanf(root_size, "+%*d+%*dx%dx%d", &w, &h) == 2) {
832  gtk_window_set_default_size(GTK_WINDOW(window_root), w, h);
833  }
834 
835  g_free(root_size);
836  }
837 
838  // Load and set panel positions.
839  for (list = pane_list; list != NULL; list = list->next) {
840  GType type = G_OBJECT_TYPE(list->data);
841 
842  if (type == GTK_TYPE_HPANED || type == GTK_TYPE_VPANED) {
843  int position = g_key_file_get_integer(config, ui_name(),
844  gtk_buildable_get_name(list->data), NULL);
845 
846  if (position != 0) {
847  gtk_paned_set_position(GTK_PANED(list->data), position);
848  }
849  }
850  }
851 
852  g_slist_free(pane_list);
853 }
static GString * config_path
Definition: config.c:30
void update_spell_information(void)
Definition: spells.c:190
GtkWidget * config_button_foodbeep
Definition: config.c:32
static void read_config_dialog(void)
Definition: config.c:640
#define CONFIG_FASTTCP
Definition: client.h:187
void get_window_coord(GtkWidget *win, int *x, int *y, int *wx, int *wy, int *w, int *h)
Definition: main.c:527
GtkBuilder * window_xml
Definition: main.c:96
void config_check()
Definition: config.c:311
void info_get_styles(void)
Definition: info.c:516
int image_size
Definition: image.c:35
void spell_get_styles(void)
Definition: spells.c:66
GSocketConnection * fd
Definition: client.h:120
gint16 use_config[CONFIG_NUMS]
Definition: init.c:40
#define CONFIG_RESISTS
Definition: client.h:209
#define DEFAULT_IMAGE_SIZE
Definition: image.h:40
static char * ui_name()
Definition: config.c:49
void on_save_window_position_activate(GtkMenuItem *menuitem, gpointer user_data)
Definition: config.c:806
int map_image_size
Definition: map.c:39
guint8 have_faceset_info
Definition: client.h:425
guint16 inv_updated
Definition: item.h:76
#define CONFIG_LIGHTING
Definition: client.h:201
#define CONFIG_POPUPS
Definition: client.h:193
item * ob
Definition: client.h:336
#define CONFIG_DISPLAYMODE
Definition: client.h:194
static char ** default_files
Definition: config.c:75
void load_theme(int reload)
Definition: config.c:138
Warning that something might not work.
Definition: client.h:443
#define NDI_BLUE
Definition: newclient.h:226
#define MAP_MAX_SIZE
Definition: client.h:474
static void combo_box_text_remove_all(GtkComboBoxText *combo_box)
Definition: config.c:531
void config_load()
Definition: config.c:393
GtkWidget * config_button_grad_color
Definition: config.c:32
char window_xml_file[MAX_BUF]
Definition: main.c:92
static char * theme
Definition: config.c:42
ClientSocket csocket
Definition: client.c:67
GtkWidget * config_button_smoothing
Definition: config.c:32
FaceSets facesets[MAX_FACE_SETS]
Definition: client.h:428
#define CONFIG_FOODBEEP
Definition: client.h:205
Face_Information face_info
Definition: image.c:169
#define SOL_TCP
Definition: client.h:37
static void config_load_legacy()
Definition: config.c:199
#define MSG_TYPE_CLIENT
Definition: newclient.h:395
static GKeyFile * config
Definition: config.c:29
static void on_config_close(GtkButton *button, gpointer user_data)
Definition: config.c:756
GtkWidget * config_button_timestamp
Definition: config.c:32
static int combobox_get_value(GtkComboBox *combobox, int column)
Definition: config.c:625
void init_theme()
Definition: config.c:76
GtkWidget * config_button_cache
Definition: config.c:32
void draw_stats(int redraw)
Definition: stats.c:554
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:111
GtkFileChooser * theme_filechooser
Definition: config.c:37
GtkFileChooser * ui_filechooser
Definition: config.c:37
#define NDI_RED
Definition: newclient.h:224
#define CONFIG_SPLASH
Definition: client.h:211
#define CFG_DM_PIXMAP
Definition: client.h:239
GtkWidget * window_root
Definition: main.c:97
void draw_message_window(int redraw)
Definition: stats.c:459
GtkComboBox * config_combobox_lighting
Definition: config.c:39
item * below
Definition: client.h:337
void draw_lists(void)
Definition: inventory.c:1051
Client_Player cpl
Definition: client.c:66
#define CONFIG_GRAD_COLOR
Definition: client.h:208
void save_defaults()
Definition: config.c:438
#define CONFIG_DARKNESS
Definition: client.h:206
#define CONFIG_MAPHEIGHT
Definition: client.h:204
#define THEME_DEFAULT
Definition: config.c:41
#define MAX_BUF
Definition: client.h:40
void config_init(GtkWidget *window_root)
Definition: config.c:462
#define CONFIG_CACHE
Definition: client.h:189
const char * config_dir
Definition: client.c:52
#define CONFIG_NUMS
Definition: client.h:218
void on_configure_activate(GtkWidget *menuitem, gpointer user_data)
Definition: config.c:751
#define MAX_FACE_SETS
Definition: client.h:383
gint16 want_config[CONFIG_NUMS]
Definition: init.c:40
GtkWidget * config_dialog
Definition: config.c:32
GtkWidget * config_button_fasttcp
Definition: config.c:32
#define CFG_LT_NONE
Definition: client.h:228
#define CONFIG_DOWNLOAD
Definition: client.h:185
void stats_get_styles(void)
Definition: stats.c:109
GtkWidget * config_button_download
Definition: config.c:32
int init_sounds(void)
Definition: sound.c:27
#define CFG_LT_TILE
Definition: client.h:229
Warning that something definitely didn&#39;t work.
Definition: client.h:444
#define IS_DIFFERENT(TYPE)
Definition: config.c:620
static void setup_config_dialog()
Definition: config.c:543
GtkComboBoxText * config_combobox_faceset
Definition: config.c:38
GtkComboBox * config_combobox_displaymode
Definition: config.c:39
#define CONFIG_ICONSCALE
Definition: client.h:191
void load_window_positions(GtkWidget *window_root)
Definition: config.c:820
#define CONFIG_TIMESTAMP
Definition: client.h:217
#define CFG_DM_SDL
Definition: client.h:240
void draw_ext_info(int orig_color, int type, int subtype, const char *message)
Definition: info.c:932
#define CONFIG_SMOOTH
Definition: client.h:210
void save_winpos()
Definition: config.c:765
char * fullname
Definition: client.h:403
#define CFG_LT_PIXEL
Definition: client.h:230
#define CONFIG_SOUND
Definition: client.h:197
void init_SDL(GtkWidget *sdl_window, int just_lightmap)
int cs_print_string(GSocketConnection *fd, const char *str,...)
Definition: newsocket.c:248
void inventory_get_styles(void)
Definition: inventory.c:425
#define CONFIG_ECHO
Definition: client.h:186
#define CFG_DM_OPENGL
Definition: client.h:241
GtkBuilder * dialog_xml
Definition: main.c:96
#define CONFIG_FOGWAR
Definition: client.h:190
GtkWidget * config_button_sound
Definition: config.c:32
const char *const config_names[CONFIG_NUMS]
Definition: init.c:30
Minor, non-harmful issues.
Definition: client.h:442
#define CONFIG_MAPSCALE
Definition: client.h:192
GtkWidget * config_button_echo
Definition: config.c:32
GtkWidget * config_button_fog
Definition: config.c:32
int map_image_half_size
Definition: map.c:40
#define CONFIG_MAPWIDTH
Definition: client.h:203
#define MSG_TYPE_CLIENT_CONFIG
Definition: newclient.h:659