Crossfire Client, Trunk  R20612
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  mapdata_init();
390 }
391 
395 void config_load() {
396  GError *error = NULL;
397 
398  /* Copy initial desired settings from current settings. */
399  memcpy(want_config, use_config, sizeof(want_config));
400 
401  g_assert(g_file_test(config_dir, G_FILE_TEST_IS_DIR) == TRUE);
402 
403  /* Load existing or create new configuration file. */
404  config = g_key_file_new();
405  config_path = g_string_new(config_dir);
406  g_string_append(config_path, "/client.ini");
407 
408  g_key_file_load_from_file(config, config_path->str, G_KEY_FILE_NONE, &error);
409 
410  /* Load configuration values into settings array. */
411  if (error == NULL) {
412  for (int i = 1; i < CONFIG_NUMS; i++) {
413  want_config[i] = g_key_file_get_integer(config, "Client",
414  config_names[i], NULL);
415  }
416 
417  /* Load additional settings. */
418  /* TODO: Both of these below are one-time memory leaks. */
419  theme = g_key_file_get_string(config, "GTKv2",
420  "theme", NULL);
421  face_info.want_faceset = g_key_file_get_string(config, "GTKv2",
422  "faceset", NULL);
423 
424  char *layout =
425  g_key_file_get_string(config, "GTKv2", "window_layout", NULL);
426  g_strlcpy(window_xml_file, layout, sizeof(window_xml_file));
427  free(layout);
428  } else {
429  g_error_free(error);
430 
431  /* Load legacy configuration file. */
433  }
434 }
435 
441  GError *error = NULL;
442 
443  /* Save GTKv2 specific client settings. */
444  g_key_file_set_string(config, "GTKv2", "theme", theme);
445  g_key_file_set_string(config, "GTKv2", "faceset", face_info.want_faceset);
446  g_key_file_set_string(config, "GTKv2", "window_layout", window_xml_file);
447 
448  /* Save the rest of the client settings. */
449  for (int i = 1; i < CONFIG_NUMS; i++) {
450  g_key_file_set_integer(config, "Client", config_names[i], want_config[i]);
451  }
452 
453  g_file_set_contents(config_path->str,
454  g_key_file_to_data(config, NULL, NULL), -1, &error);
455 
456  if (error != NULL) {
458  "Could not save settings!");
459  g_warning("Could not save settings: %s", error->message);
460  g_error_free(error);
461  }
462 }
463 
464 void config_init(GtkWidget *window_root) {
465  config_dialog =
466  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_dialog"));
467 
468  // Initialize file choosers and set filename filters.
470  GTK_FILE_CHOOSER(gtk_builder_get_object(dialog_xml, "ui_filechooser"));
471  theme_filechooser = GTK_FILE_CHOOSER(
472  gtk_builder_get_object(dialog_xml, "theme_filechooser"));
473 
474  GtkFileFilter *ui_filter = gtk_file_filter_new();
475  gtk_file_filter_add_pattern(ui_filter, "*.ui");
476  gtk_file_chooser_set_filter(ui_filechooser, ui_filter);
477 
479  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_echo"));
481  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_fasttcp"));
483  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_timestamp"));
485  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_grad_color"));
487  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_foodbeep"));
489  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_sound"));
491  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_cache"));
493  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_download"));
495  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_fog"));
497  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_smoothing"));
498 
499  config_combobox_displaymode = GTK_COMBO_BOX(
500  gtk_builder_get_object(dialog_xml, "config_combobox_displaymode"));
501  config_combobox_faceset = GTK_COMBO_BOX_TEXT(
502  gtk_builder_get_object(dialog_xml, "config_combobox_faceset"));
503  config_combobox_lighting = GTK_COMBO_BOX(
504  gtk_builder_get_object(dialog_xml, "config_combobox_lighting"));
505 
506  GtkWidget *config_button_close =
507  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_close"));
508  g_signal_connect(config_button_close, "clicked",
509  G_CALLBACK(on_config_close), NULL);
510  g_signal_connect(config_dialog, "delete_event", G_CALLBACK(on_config_close),
511  NULL);
512 
513  // Initialize available rendering modes.
514  GtkListStore *display_list =
515  GTK_LIST_STORE(gtk_combo_box_get_model(config_combobox_displaymode));
516  GtkTreeIter iter;
517 #ifdef HAVE_OPENGL
518  gtk_list_store_append(display_list, &iter);
519  gtk_list_store_set(display_list, &iter, 0, "OpenGL", 1, CFG_DM_OPENGL, -1);
520 #endif
521 #ifdef HAVE_SDL
522  gtk_list_store_append(display_list, &iter);
523  gtk_list_store_set(display_list, &iter, 0, "SDL", 1, CFG_DM_SDL, -1);
524 #endif
525  gtk_list_store_append(display_list, &iter);
526  gtk_list_store_set(display_list, &iter, 0, "Pixmap", 1, CFG_DM_PIXMAP, -1);
527 }
528 
533 static void combo_box_text_remove_all(GtkComboBoxText *combo_box) {
534  int count = gtk_tree_model_iter_n_children(
535  gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box)), NULL);
536  for (int i = 0; i < count; i++) {
537  gtk_combo_box_text_remove(combo_box, 0);
538  }
539 }
540 
541 /*
542  * Setup config_dialog sets the buttons, combos, etc, to the state that matches
543  * the want_config[] values.
544  */
545 static void setup_config_dialog() {
546  GtkTreeIter iter;
547  gchar *buf;
548  int count;
549 
550  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_echo),
552  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_fasttcp),
554  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_timestamp),
556  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_grad_color),
558  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_foodbeep),
560  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_sound),
562  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_cache),
564  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_download),
566  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_fog),
568  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_smoothing),
570 
571  // Fill face set combo box with available face sets from the server.
573 
574  /* If we have real faceset info from the server, use it */
576  for (int i = 0; i < MAX_FACE_SETS; i++)
577  if (face_info.facesets[i].fullname)
578  gtk_combo_box_text_append_text(config_combobox_faceset,
580  }
581 
582  GtkTreeModel *model =
583  gtk_combo_box_get_model(GTK_COMBO_BOX(config_combobox_faceset));
584  count = gtk_tree_model_iter_n_children(model, NULL);
585  for (int i = 0; i < count; i++) {
586  if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, i)) {
587  LOG(LOG_ERROR, "setup_config_dialog", "Cannot iterate facesets\n");
588  break;
589  }
590  gtk_tree_model_get(model, &iter, 0, &buf, -1);
591 
592  if (face_info.want_faceset &&
593  !g_ascii_strcasecmp(face_info.want_faceset, buf)) {
594  gtk_combo_box_set_active(GTK_COMBO_BOX(config_combobox_faceset), i);
595  g_free(buf);
596  break;
597  }
598  g_free(buf);
599  }
600 
601  // Set current display mode.
602  model = gtk_combo_box_get_model(config_combobox_displaymode);
603  bool next = gtk_tree_model_get_iter_first(model, &iter);
604  while (next) {
605  int current;
606  gtk_tree_model_get(model, &iter, 1, &current, -1);
607  if (current == want_config[CONFIG_DISPLAYMODE]) {
608  gtk_combo_box_set_active_iter(config_combobox_displaymode, &iter);
609  break;
610  }
611  next = gtk_tree_model_iter_next(model, &iter);
612  }
613 
614  // Lighting option indexes never change, so set option using index.
615  gtk_combo_box_set_active(config_combobox_lighting,
617 
618  gtk_file_chooser_set_filename(ui_filechooser, window_xml_file);
619  gtk_file_chooser_set_filename(theme_filechooser, theme);
620 }
621 
622 #define IS_DIFFERENT(TYPE) (want_config[TYPE] != use_config[TYPE])
623 
627 static int combobox_get_value(GtkComboBox *combobox, int column) {
628  GtkTreeModel *model = gtk_combo_box_get_model(combobox);
629  GtkTreeIter iter;
630  int result;
631 
632  gtk_combo_box_get_active_iter(combobox, &iter);
633  gtk_tree_model_get(model, &iter, column, &result, -1);
634  return result;
635 }
636 
642 static void read_config_dialog(void) {
644  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_echo));
646  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_fasttcp));
647  want_config[CONFIG_TIMESTAMP] = gtk_toggle_button_get_active(
648  GTK_TOGGLE_BUTTON(config_button_timestamp));
649  want_config[CONFIG_GRAD_COLOR] = gtk_toggle_button_get_active(
650  GTK_TOGGLE_BUTTON(config_button_grad_color));
652  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_foodbeep));
654  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_sound));
656  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_cache));
658  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_download));
660  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_fog));
661  want_config[CONFIG_SMOOTH] = gtk_toggle_button_get_active(
662  GTK_TOGGLE_BUTTON(config_button_smoothing));
663 
664  gchar *buf;
665 
666  buf = gtk_combo_box_text_get_active_text(config_combobox_faceset);
667  if (buf) {
668  free(face_info.want_faceset);
669  face_info.want_faceset = g_strdup(buf);
670  g_free(buf);
671  }
672 
675 
676  // Lighting option indexes never change, so get option using index.
678  gtk_combo_box_get_active(config_combobox_lighting);
679 
680  // Enable darkness if lighting is not 'None'.
684  }
685 
686  // Set UI file.
687  buf = gtk_file_chooser_get_filename(ui_filechooser);
688  if (buf != NULL) {
689  g_strlcpy(window_xml_file, buf, sizeof(window_xml_file));
690  g_free(buf);
691  }
692 
693  // Set and load theme file.
694  buf = gtk_file_chooser_get_filename(theme_filechooser);
695  if (buf != NULL && g_ascii_strcasecmp(buf, theme) != 0) {
696  g_free(theme);
697  theme = buf;
698  load_theme(TRUE);
699  }
700 
701  /*
702  * Some values can take effect right now, others not. Code below handles
703  * these cases - largely grabbed from gtk/config.c
704  */
705  if (IS_DIFFERENT(CONFIG_SOUND)) {
706  int tmp;
707  if (want_config[CONFIG_SOUND]) {
708  tmp = init_sounds();
709  if (csocket.fd) {
710  cs_print_string(csocket.fd, "setup sound %d", tmp >= 0);
711  }
712  } else {
713  if (csocket.fd) {
714  cs_print_string(csocket.fd, "setup sound 0");
715  }
716  }
718  }
720 #ifdef TCP_NODELAY
721 #ifndef WIN32
722  // TODO: Merge with setsockopt code from client.c
723  int q = want_config[CONFIG_FASTTCP];
724 
725  if (csocket.fd &&
726  setsockopt(csocket.fd, SOL_TCP, TCP_NODELAY, &q, sizeof(q)) == -1) {
727  perror("TCP_NODELAY");
728  }
729 #endif
730 #endif
732  }
733 
735 #ifdef HAVE_SDL
737  /* This is done to make the 'lightmap' in the proper format */
738  {
739  init_SDL(NULL, 1);
740  }
741 #endif
742  }
743  /*
744  * Nothing to do, but we can switch immediately without problems. do force
745  * a redraw
746  */
749  draw_stats(TRUE);
750  }
751 }
752 
753 void on_configure_activate(GtkWidget *menuitem, gpointer user_data) {
754  gtk_widget_show(config_dialog);
756 }
757 
758 static void on_config_close(GtkButton *button, gpointer user_data) {
760  save_defaults();
761  gtk_widget_hide(config_dialog);
762 }
763 
767 void save_winpos() {
768  GSList *pane_list, *list_loop;
769  int x, y, w, h, wx, wy;
770 
771  /* Save window position and size. */
772  get_window_coord(window_root, &x, &y, &wx, &wy, &w, &h);
773 
774  GString *window_root_info = g_string_new(NULL);
775  g_string_printf(window_root_info, "+%d+%dx%dx%d", wx, wy, w, h);
776 
777  g_key_file_set_string(config, ui_name(),
778  "window_root", window_root_info->str);
779  g_string_free(window_root_info, TRUE);
780 
781  /* Save the positions of all the HPANEDs and VPANEDs. */
782  pane_list = gtk_builder_get_objects(window_xml);
783 
784  for (list_loop = pane_list; list_loop != NULL; list_loop = list_loop->next) {
785  GType type = G_OBJECT_TYPE(list_loop->data);
786 
787  if (type == GTK_TYPE_HPANED || type == GTK_TYPE_VPANED) {
788  g_key_file_set_integer(config, ui_name(),
789  gtk_buildable_get_name(list_loop->data),
790  gtk_paned_get_position(GTK_PANED(list_loop->data)));
791  }
792  }
793 
794  g_slist_free(pane_list);
795  save_defaults();
796 
798  "Window positions saved!");
799 }
800 
808 void on_save_window_position_activate(GtkMenuItem *menuitem,
809  gpointer user_data) {
810  save_winpos();
811  /*
812  * The following prevents multiple saves per menu activation.
813  */
814  g_signal_stop_emission_by_name(GTK_OBJECT(menuitem), "activate");
815 }
816 
823  GSList *pane_list, *list;
824  pane_list = gtk_builder_get_objects(window_xml);
825 
826  // Load and set main window dimensions.
827  gchar *root_size = g_key_file_get_string(config, ui_name(),
828  "window_root", NULL);
829 
830  if (root_size != NULL) {
831  int w, h;
832 
833  if (sscanf(root_size, "+%*d+%*dx%dx%d", &w, &h) == 2) {
834  gtk_window_set_default_size(GTK_WINDOW(window_root), w, h);
835  }
836 
837  g_free(root_size);
838  }
839 
840  // Load and set panel positions.
841  for (list = pane_list; list != NULL; list = list->next) {
842  GType type = G_OBJECT_TYPE(list->data);
843 
844  if (type == GTK_TYPE_HPANED || type == GTK_TYPE_VPANED) {
845  int position = g_key_file_get_integer(config, ui_name(),
846  gtk_buildable_get_name(list->data), NULL);
847 
848  if (position != 0) {
849  gtk_paned_set_position(GTK_PANED(list->data), position);
850  }
851  }
852  }
853 
854  g_slist_free(pane_list);
855 }
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:642
#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:484
GtkBuilder * window_xml
Definition: main.c:86
void config_check()
Definition: config.c:311
void info_get_styles(void)
Definition: info.c:516
int image_size
Definition: image.c:36
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:808
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:475
static void combo_box_text_remove_all(GtkComboBoxText *combo_box)
Definition: config.c:533
void config_load()
Definition: config.c:395
GtkWidget * config_button_grad_color
Definition: config.c:32
char window_xml_file[MAX_BUF]
Definition: main.c:82
static char * theme
Definition: config.c:42
ClientSocket csocket
Definition: client.c:69
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:758
GtkWidget * config_button_timestamp
Definition: config.c:32
static int combobox_get_value(GtkComboBox *combobox, int column)
Definition: config.c:627
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:109
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:87
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:1075
Client_Player cpl
Definition: client.c:68
#define CONFIG_GRAD_COLOR
Definition: client.h:208
void save_defaults()
Definition: config.c:440
#define CONFIG_DARKNESS
Definition: client.h:206
#define CONFIG_MAPHEIGHT
Definition: client.h:204
void mapdata_init(void)
Definition: mapdata.c:556
#define THEME_DEFAULT
Definition: config.c:41
#define MAX_BUF
Definition: client.h:40
void config_init(GtkWidget *window_root)
Definition: config.c:464
#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:753
#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't work.
Definition: client.h:444
#define IS_DIFFERENT(TYPE)
Definition: config.c:622
static void setup_config_dialog()
Definition: config.c:545
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:822
#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:767
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:245
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:86
#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