Crossfire Client, Trunk
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 
43 /* Configuration variables initialized to NULL, set by config_load() */
44 static char *theme;
46 
47 /*
48  * This should really be one of the CONFIG values, or perhaps a checkbox
49  * someplace that displays frame rate.
50  */
51 bool time_map_redraw = false;
52 
54 int predict_alpha = 10;
55 
56 static void on_config_close(GtkButton *button, gpointer user_data);
57 
58 static bool IS_DIFFERENT(int type) {
59  return want_config[type] != use_config[type];
60 }
61 
65 static char *ui_name() {
66  return g_path_get_basename(window_xml_file);
67 }
68 
91 static char **default_files = NULL;
92 void init_theme() {
93  char path[MAX_BUF];
94  char **tmp;
95  int i;
96 
97  /*
98  * The GTK man page says copy of this data should be made, so do that.
99  */
100  tmp = gtk_rc_get_default_files();
101  i = 0;
102  while (tmp && tmp[i]) {
103  i++;
104  }
105  /*
106  * Add two more GTK rc files that may be used by a player to customize
107  * the client appearance in general, or to customize the appearance
108  * of a specific layout. Allocate pointers to the local copy
109  * of the entire list.
110  */
111  i += 2;
112  default_files = g_malloc(sizeof(char *) * (i + 1));
113  /*
114  * Copy in GTK's default list which probably contains system paths
115  * like <SYSCONFDIR>/gtk-2.0/gtkrc and user-specific files like
116  * ${HOME}/.gtkrc, or even LANGuage-specific ones like
117  * ${HOME}/.gtkrc.en, etc.
118  */
119  i = 0;
120  while (tmp && tmp[i]) {
121  default_files[i] = g_strdup(tmp[i]);
122  i++;
123  }
124  /*
125  * Add a player-specific gtkrc to the list of default rc files. This
126  * file is probably reserved for player use, though in all liklihood
127  * will not get used that much. Still, it makes it easy for someone
128  * to make their own theme without having to have access to the
129  * system-wide theme folder. This is the lowest priority client rc
130  * file as either a <layout>.gtkrc file or a client-configured theme
131  * settings can over-ride it.
132  */
133  snprintf(path, sizeof(path), "%s/gtkrc", config_dir);
134  default_files[i] = g_strdup(path);
135  i++;
136  /*
137  * Add a UI layout-specific rc file to the list of default list. It
138  * seems reasonable to allow client code to have access to this file
139  * to make some basic changes to fonts, via a graphical interface.
140  * Truncate window_xml_file to remove a .extension if one exists, so
141  * that the window positions file can be created with a .gtkrc suffix.
142  * This is a mid-priority client rc file as its settings supersede the
143  * client gtkrc file, but are overridden by a client-configured theme.
144  */
145  snprintf(path, sizeof(path), "%s/%s.gtkrc", config_dir, ui_name());
146  default_files[i] = g_strdup(path);
147  i++;
148  /*
149  * Mark the end of the list of default rc files.
150  */
151  default_files[i] = NULL;
152 }
153 
154 void load_theme(int reload) {
155  /*
156  * Whether or not this is default and initial run, we want to register
157  * the modified rc search path list, so GTK needs to get the changes.
158  * It is necessary to reset the the list each time through here each
159  * theme change grows the list. Only one theme should be in the list
160  * at a time.
161  */
162  gtk_rc_set_default_files(default_files);
163 
164  /*
165  * If a client-configured theme has been selected (something other than
166  * "None"), then add it to the list of GTK rc files to process. Since
167  * this file is added last, it takes priority over both the gtkrc and
168  * <layout>.gtkrc files. Remember, strcmp returns zero on a match, and
169  * a theme file should not be registered if "None" is selected.
170  */
171  g_assert(theme != NULL); // ensured by config_load()
172  {
173  /*
174  * Check for existence of the client theme file. Unfortunately, at
175  * initial run time, the window may not be realized yet, so the
176  * message cannot be sent to the user directly. It doesn't hurt to
177  * add the path even if the file isn't there, but the player might
178  * still want to know something is wrong since they picked a theme.
179  */
180  if (access(theme, R_OK) == -1) {
181  LOG(LOG_ERROR, "load_theme", "Unable to find theme file %s", theme);
182  g_free(theme);
183  theme = g_strdup(THEME_DEFAULT);
184  }
185  gtk_rc_add_default_file(theme);
186  }
187 
188  /*
189  * Require GTK to reparse and rebind all the widget data.
190  */
191  gtk_rc_reparse_all_for_settings(
192  gtk_settings_get_for_screen(gdk_screen_get_default()), TRUE);
193  gtk_rc_reset_styles(
194  gtk_settings_get_for_screen(gdk_screen_get_default()));
195  /*
196  * Call client functions to reparse the custom widgets it controls.
197  */
198  info_get_styles();
203  /*
204  * Set inv_updated to force a redraw - otherwise it will not
205  * necessarily bind the lists with the new widgets.
206  */
207  cpl.below->inv_updated = 1;
208  cpl.ob->inv_updated = 1;
209  draw_lists();
210  draw_stats(TRUE);
211  draw_message_window(TRUE);
212 }
213 
217 static void config_load_legacy() {
218  char path[MAX_BUF], inbuf[MAX_BUF], *cp;
219  FILE *fp;
220  int i, val;
221 
222  LOG(LOG_INFO, "config_load_legacy",
223  "Configuration not found; trying old configuration files.");
224  LOG(LOG_INFO, "config_load_legacy",
225  "You will need to move your keybindings to the new location.");
226 
227  snprintf(path, sizeof(path), "%s/.crossfire/gdefaults2", g_getenv("HOME"));
228  if ((fp = fopen(path, "r")) == NULL) {
229  return;
230  }
231  while (fgets(inbuf, MAX_BUF - 1, fp)) {
232  inbuf[MAX_BUF - 1] = '\0';
233  inbuf[strlen(inbuf) - 1] = '\0'; /* kill newline */
234 
235  if (inbuf[0] == '#') {
236  continue;
237  }
238  /* Skip any setting line that does not contain a colon character */
239  if (!(cp = strchr(inbuf, ':'))) {
240  continue;
241  }
242  *cp = '\0';
243  cp += 2; /* colon, space, then value */
244 
245  val = -1;
246  if (isdigit(*cp)) {
247  val = atoi(cp);
248  } else if (!strcmp(cp, "True")) {
249  val = TRUE;
250  } else if (!strcmp(cp, "False")) {
251  val = FALSE;
252  }
253 
254  for (i = 1; i < CONFIG_NUMS; i++) {
255  if (!strcmp(config_names[i], inbuf)) {
256  if (val == -1) {
257  LOG(LOG_WARNING, "config.c::load_defaults",
258  "Invalid value/line: %s: %s", inbuf, cp);
259  } else {
260  want_config[i] = val;
261  }
262  break; /* Found a match - won't find another */
263  }
264  }
265  /* We found a match in the loop above, so do not do anything more */
266  if (i < CONFIG_NUMS) {
267  continue;
268  }
269 
270  /*
271  * Legacy - now use the map_width and map_height values Don't do sanity
272  * checking - that will be done below
273  */
274  if (!strcmp(inbuf, "mapsize")) {
275  if (sscanf(cp, "%hdx%hd", &want_config[CONFIG_MAPWIDTH],
276  &want_config[CONFIG_MAPHEIGHT]) != 2) {
277  LOG(LOG_WARNING, "config.c::load_defaults",
278  "Malformed mapsize option in gdefaults2. Ignoring");
279  }
280  } else if (!strcmp(inbuf, "theme")) {
281  if (theme != NULL) {
282  g_free(theme);
283  }
284  theme = g_strdup(cp);
285  continue;
286  } else if (!strcmp(inbuf, "window_layout")) {
287  strncpy(window_xml_file, cp, MAX_BUF - 1);
288  continue;
289  } else if (!strcmp(inbuf, "nopopups")) {
290  /* Changed name from nopopups to popups, so inverse value */
291  want_config[CONFIG_POPUPS] = !val;
292  continue;
293  } else if (!strcmp(inbuf, "nosplash")) {
294  want_config[CONFIG_SPLASH] = !val;
295  continue;
296  } else if (!strcmp(inbuf, "splash")) {
297  want_config[CONFIG_SPLASH] = val;
298  continue;
299  } else if (!strcmp(inbuf, "faceset")) {
300  face_info.want_faceset = g_strdup(cp); /* memory leak ! */
301  continue;
302  }
303  /* legacy, as this is now just saved as 'lighting' */
304  else if (!strcmp(inbuf, "per_tile_lighting")) {
305  if (val) {
307  }
308  } else if (!strcmp(inbuf, "per_pixel_lighting")) {
309  if (val) {
311  }
312  } else if (!strcmp(inbuf, "resists")) {
313  if (val) {
315  }
316  } else if (!strcmp(inbuf, "sdl")) {
317  if (val) {
319  }
320  } else LOG(LOG_WARNING, "config.c::load_defaults",
321  "Unknown line in gdefaults2: %s %s", inbuf, cp);
322  }
323  fclose(fp);
324 }
325 
331 void config_check() {
332  if (want_config[CONFIG_ICONSCALE] < 25 ||
333  want_config[CONFIG_ICONSCALE] > 200) {
334  LOG(LOG_WARNING, "config_check",
335  "Ignoring invalid 'iconscale' value '%d'; "
336  "must be between 25 and 200.\n",
339  }
340 
342  LOG(LOG_WARNING, "config_check",
343  "Ignoring invalid 'mapscale' value '%d'; "
344  "must be between 10 and 200.\n",
347  }
348 
350  LOG(LOG_WARNING, "config_check",
351  "No lighting mechanism selected - will not use darkness code");
352  want_config[CONFIG_DARKNESS] = FALSE;
353  }
354 
355  if (want_config[CONFIG_RESISTS] > 2) {
356  LOG(LOG_WARNING, "config_check",
357  "Ignoring invalid 'resists' value '%d'; "
358  "must be either 0, 1, or 2.\n",
361  }
362 
363  /* Make sure the map size os OK */
364  if (want_config[CONFIG_MAPWIDTH] < 9 ||
366  LOG(LOG_WARNING, "config_check", "Invalid map width (%d) "
367  "option in gdefaults2. Valid range is 9 to %d",
370  }
371 
372  if (want_config[CONFIG_MAPHEIGHT] < 9 ||
374  LOG(LOG_WARNING, "config_check", "Invalid map height (%d) "
375  "option in gdefaults2. Valid range is 9 to %d",
378  }
379 
380 #if !defined(HAVE_OPENGL)
383  LOG(LOG_ERROR, "config_check",
384  "Display mode is set to OpenGL, but client "
385  "is not compiled with OpenGL support. Reverting to pixmap mode.");
386  }
387 #endif
388 
389 #if !defined(HAVE_SDL)
392  LOG(LOG_ERROR, "config_check",
393  "Display mode is set to SDL, but client "
394  "is not compiled with SDL support. Reverting to pixmap mode.");
395  }
396 #endif
397 
398  if (want_config[CONFIG_CACHE]) {
399  LOG(LOG_ERROR, "config_check",
400  "Image caching is not currently supported in this client. Running without image caching.");
402  }
403 
404  // Enable darkness if lighting is not 'None'.
407  }
408 
411  } else {
413  }
414  if (csocket.fd) {
415  cs_print_string(csocket.fd, "setup sound %d", use_config[CONFIG_SOUND]);
416  }
417 
418 #ifdef TCP_NODELAY
419 #ifndef WIN32
420  // TODO: Merge with setsockopt code from client.c
421  int q = want_config[CONFIG_FASTTCP];
422 
423  if (csocket.fd && setsockopt(csocket.fd, SOL_TCP, TCP_NODELAY, &q, sizeof(q)) == -1) {
424  perror("TCP_NODELAY");
425  }
426 #endif
427 #endif
428 
429  /* Copy sanitized user settings to current settings. */
430  memcpy(use_config, want_config, sizeof(use_config));
431 
434  if (!use_config[CONFIG_CACHE]) {
435  use_config[CONFIG_DOWNLOAD] = FALSE;
436  }
437 }
438 
442 void config_load() {
443  GError *error = NULL;
444 
445  /* Copy initial desired settings from current settings. */
446  memcpy(want_config, use_config, sizeof(want_config));
447 
448  g_assert(g_file_test(config_dir, G_FILE_TEST_IS_DIR) == TRUE);
449 
450  /* Load existing or create new configuration file. */
451  config = g_key_file_new();
452  config_path = g_string_new(config_dir);
453  g_string_append(config_path, "/client.ini");
454 
455  g_key_file_load_from_file(config, config_path->str, G_KEY_FILE_NONE, &error);
456 
457  /* Load configuration values into settings array. */
458  if (error == NULL) {
459  LOG(LOG_DEBUG, "config_load", "config_path='%s'", config_path->str);
460  for (int i = 1; i < CONFIG_NUMS; i++) {
461  GError *error = NULL;
462  gint value = g_key_file_get_integer(config, "Client", config_names[i], &error);
463  if (error == NULL) {
464  want_config[i] = value;
465  }
466  }
467 
468  /* Load additional settings. */
469  if (theme != NULL) {
470  g_free(theme);
471  }
472  theme = g_key_file_get_string(config, "GTKv2", "theme", NULL);
473 
474  if (face_info.want_faceset != NULL) {
475  g_free(face_info.want_faceset);
476  }
477  face_info.want_faceset = g_key_file_get_string(config, "GTKv2", "faceset", NULL);
478 
479  predict_alpha = g_key_file_get_integer(config, "GTKv2", "predict_alpha", NULL);
480 
481  if (last_server != NULL) {
482  g_free(last_server);
483  }
484  last_server = g_key_file_get_string(config, "GTKv2", "last_server", NULL);
485 
486  char *layout = g_key_file_get_string(config, "GTKv2", "window_layout", NULL);
487  g_strlcpy(window_xml_file, layout, sizeof(window_xml_file));
488  free(layout);
489  } else {
490  g_error_free(error);
491 
492  /* Load legacy configuration file. */
494  }
495 
496  if (theme == NULL) {
497  theme = g_strdup(THEME_DEFAULT);
498  }
499 
500  if (face_info.want_faceset == NULL) {
501  face_info.want_faceset = g_strdup("");
502  }
503 
504  if (last_server == NULL) {
505  last_server = g_strdup("");
506  }
507 }
508 
514  GError *error = NULL;
515 
516  /* Save GTKv2 specific client settings. */
517  g_key_file_set_string(config, "GTKv2", "theme", theme);
518  g_key_file_set_string(config, "GTKv2", "faceset", face_info.want_faceset);
519  g_key_file_set_string(config, "GTKv2", "last_server", last_server);
520  g_key_file_set_integer(config, "GTKv2", "predict_alpha", predict_alpha);
521  g_key_file_set_string(config, "GTKv2", "window_layout", window_xml_file);
522 
523  /* Save the rest of the client settings. */
524  for (int i = 1; i < CONFIG_NUMS; i++) {
525  g_key_file_set_integer(config, "Client", config_names[i], want_config[i]);
526  }
527 
528  g_file_set_contents(config_path->str,
529  g_key_file_to_data(config, NULL, NULL), -1, &error);
530 
531  if (error != NULL) {
533  "Could not save settings!");
534  g_warning("Could not save settings: %s", error->message);
535  g_error_free(error);
536  }
537 }
538 
539 void config_init(GtkWidget *window_root) {
540  config_dialog =
541  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_dialog"));
542 
543  // Initialize file choosers and set filename filters.
545  GTK_FILE_CHOOSER(gtk_builder_get_object(dialog_xml, "ui_filechooser"));
546  theme_filechooser = GTK_FILE_CHOOSER(
547  gtk_builder_get_object(dialog_xml, "theme_filechooser"));
548 
549  GtkFileFilter *ui_filter = gtk_file_filter_new();
550  gtk_file_filter_add_pattern(ui_filter, "*.ui");
551  gtk_file_chooser_set_filter(ui_filechooser, ui_filter);
552 
554  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_echo"));
556  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_fasttcp"));
558  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_timestamp"));
560  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_grad_color"));
562  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_foodbeep"));
564  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_sound"));
566  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_cache"));
568  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_download"));
570  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_fog"));
572  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_smoothing"));
573 
574  config_combobox_displaymode = GTK_COMBO_BOX(
575  gtk_builder_get_object(dialog_xml, "config_combobox_displaymode"));
576  config_combobox_faceset = GTK_COMBO_BOX_TEXT(
577  gtk_builder_get_object(dialog_xml, "config_combobox_faceset"));
578  config_combobox_lighting = GTK_COMBO_BOX(
579  gtk_builder_get_object(dialog_xml, "config_combobox_lighting"));
580 
581  GtkWidget *config_button_close =
582  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "config_button_close"));
583  g_signal_connect(config_button_close, "clicked",
584  G_CALLBACK(on_config_close), NULL);
585  g_signal_connect(config_dialog, "delete_event", G_CALLBACK(on_config_close),
586  NULL);
587 
588  // Initialize available rendering modes.
589  GtkListStore *display_list =
590  GTK_LIST_STORE(gtk_combo_box_get_model(config_combobox_displaymode));
591  GtkTreeIter iter;
592 #ifdef HAVE_OPENGL
593  gtk_list_store_append(display_list, &iter);
594  gtk_list_store_set(display_list, &iter, 0, "OpenGL", 1, CFG_DM_OPENGL, -1);
595 #endif
596 #ifdef HAVE_SDL
597  gtk_list_store_append(display_list, &iter);
598  gtk_list_store_set(display_list, &iter, 0, "SDL", 1, CFG_DM_SDL, -1);
599 #endif
600  gtk_list_store_append(display_list, &iter);
601  gtk_list_store_set(display_list, &iter, 0, "Pixmap", 1, CFG_DM_PIXMAP, -1);
602 }
603 
608 static void combo_box_text_remove_all(GtkComboBoxText *combo_box) {
609  int count = gtk_tree_model_iter_n_children(
610  gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box)), NULL);
611  for (int i = 0; i < count; i++) {
612  gtk_combo_box_text_remove(combo_box, 0);
613  }
614 }
615 
616 /*
617  * Setup config_dialog sets the buttons, combos, etc, to the state that matches
618  * the want_config[] values.
619  */
620 static void setup_config_dialog() {
621  GtkTreeIter iter;
622 
623  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_echo),
625  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_fasttcp),
627  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_timestamp),
629  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_grad_color),
631  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_foodbeep),
633  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_sound),
635  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_cache),
637  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_download),
639  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_fog),
641  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_smoothing),
643 
644  // Fill face set combo box with available face sets from the server.
647  for (int i = 0; i < MAX_FACE_SETS; i++) {
648  const char *name = face_info.facesets[i].fullname;
649  if (name != NULL) {
650  gtk_combo_box_text_append_text(config_combobox_faceset, name);
651  // g_ascii_strcasecmp expects both arguments to be non-null.
652  // It appears to return 0 when one is null, confounding the result with
653  // that of an actual match.
654  if (face_info.want_faceset && !g_ascii_strcasecmp(face_info.want_faceset, name)) {
655  gtk_combo_box_set_active(GTK_COMBO_BOX(config_combobox_faceset), i);
656  }
657  } else {
658  break;
659  }
660  }
661  }
662 
663  // Set current display mode.
664  GtkTreeModel *model;
665  model = gtk_combo_box_get_model(config_combobox_displaymode);
666  bool next = gtk_tree_model_get_iter_first(model, &iter);
667  while (next) {
668  int current;
669  gtk_tree_model_get(model, &iter, 1, &current, -1);
670  if (current == want_config[CONFIG_DISPLAYMODE]) {
671  gtk_combo_box_set_active_iter(config_combobox_displaymode, &iter);
672  break;
673  }
674  next = gtk_tree_model_iter_next(model, &iter);
675  }
676 
677  // Lighting option indexes never change, so set option using index.
678  gtk_combo_box_set_active(config_combobox_lighting,
680 
681  gtk_file_chooser_set_filename(ui_filechooser, window_xml_file);
682  gtk_file_chooser_set_filename(theme_filechooser, theme);
683 }
684 
688 static int combobox_get_value(GtkComboBox *combobox, int column) {
689  GtkTreeModel *model = gtk_combo_box_get_model(combobox);
690  GtkTreeIter iter;
691  int result;
692 
693  gtk_combo_box_get_active_iter(combobox, &iter);
694  gtk_tree_model_get(model, &iter, column, &result, -1);
695  return result;
696 }
697 
703 static void read_config_dialog(void) {
705  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_echo));
707  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_fasttcp));
708  want_config[CONFIG_TIMESTAMP] = gtk_toggle_button_get_active(
709  GTK_TOGGLE_BUTTON(config_button_timestamp));
710  want_config[CONFIG_GRAD_COLOR] = gtk_toggle_button_get_active(
711  GTK_TOGGLE_BUTTON(config_button_grad_color));
713  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_foodbeep));
715  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_sound));
717  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_cache));
719  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_download));
721  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_fog));
722  want_config[CONFIG_SMOOTH] = gtk_toggle_button_get_active(
723  GTK_TOGGLE_BUTTON(config_button_smoothing));
724 
725  gchar *buf = 0;
726  GtkTreeIter iter;
737  if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(config_combobox_faceset), &iter)) {
738  // We have an active selection in our iterator. Now we get the string from the tree model.
739  GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(config_combobox_faceset));
740  gtk_tree_model_get(model, &iter, 0, &buf, -1);
741  if (buf) {
742  free(face_info.want_faceset);
743  face_info.want_faceset = g_strdup(buf);
744  g_free(buf);
745  }
746  else {
747  LOG(LOG_ERROR, "read_config_dialog", "Failed to get face set string from GTK Widget.");
748  }
749  }
750 
753 
754  // Lighting option indexes never change, so get option using index.
756  gtk_combo_box_get_active(config_combobox_lighting);
757 
758  // Set UI file.
759  buf = gtk_file_chooser_get_filename(ui_filechooser);
760  if (buf != NULL) {
761  g_strlcpy(window_xml_file, buf, sizeof(window_xml_file));
762  g_free(buf);
763  }
764 
765  // Set and load theme file.
766  buf = gtk_file_chooser_get_filename(theme_filechooser);
767  if (buf != NULL && g_ascii_strcasecmp(buf, theme) != 0) {
768  g_free(theme);
769  theme = buf;
770  load_theme(TRUE);
771  }
772 
774  draw_stats(TRUE);
775  }
776 }
777 
778 void on_configure_activate(GtkWidget *menuitem, gpointer user_data) {
779  gtk_widget_show(config_dialog);
781 }
782 
783 static void on_config_close(GtkButton *button, gpointer user_data) {
785  config_check();
786  save_defaults();
787  gtk_widget_hide(config_dialog);
788 }
789 
793 void save_winpos() {
794  GSList *pane_list, *list_loop;
795  int x, y, w, h, wx, wy;
796 
797  /* Save window position and size. */
798  get_window_coord(window_root, &x, &y, &wx, &wy, &w, &h);
799 
800  GString *window_root_info = g_string_new(NULL);
801  g_string_printf(window_root_info, "+%d+%dx%dx%d", wx, wy, w, h);
802 
803  g_key_file_set_string(config, ui_name(),
804  "window_root", window_root_info->str);
805  g_string_free(window_root_info, TRUE);
806 
807  /* Save the positions of all the HPANEDs and VPANEDs. */
808  pane_list = gtk_builder_get_objects(window_xml);
809 
810  for (list_loop = pane_list; list_loop != NULL; list_loop = list_loop->next) {
811  GType type = G_OBJECT_TYPE(list_loop->data);
812 
813  if (type == GTK_TYPE_HPANED || type == GTK_TYPE_VPANED) {
814  g_key_file_set_integer(config, ui_name(),
815  gtk_buildable_get_name(list_loop->data),
816  gtk_paned_get_position(GTK_PANED(list_loop->data)));
817  }
818  }
819 
820  g_slist_free(pane_list);
821  save_defaults();
822 
824  "Window positions saved!");
825 }
826 
834 void on_save_window_position_activate(GtkMenuItem *menuitem,
835  gpointer user_data) {
836  save_winpos();
837  /*
838  * The following prevents multiple saves per menu activation.
839  */
840  g_signal_stop_emission_by_name(GTK_WIDGET(menuitem), "activate");
841 }
842 
849  GSList *pane_list, *list;
850  pane_list = gtk_builder_get_objects(window_xml);
851 
852  // Load and set main window dimensions.
853  gchar *root_size = g_key_file_get_string(config, ui_name(),
854  "window_root", NULL);
855 
856  if (root_size != NULL) {
857  int w, h;
858 
859  if (sscanf(root_size, "+%*d+%*dx%dx%d", &w, &h) == 2) {
860  gtk_window_set_default_size(GTK_WINDOW(window_root), w, h);
861  }
862 
863  g_free(root_size);
864  }
865 
866  // Load and set panel positions.
867  for (list = pane_list; list != NULL; list = list->next) {
868  GType type = G_OBJECT_TYPE(list->data);
869 
870  if (type == GTK_TYPE_HPANED || type == GTK_TYPE_VPANED) {
871  int position = g_key_file_get_integer(config, ui_name(),
872  gtk_buildable_get_name(list->data), NULL);
873 
874  if (position != 0) {
875  gtk_paned_set_position(GTK_PANED(list->data), position);
876  }
877  }
878  }
879 
880  g_slist_free(pane_list);
881 }
CFG_LT_NONE
#define CFG_LT_NONE
Definition: client.h:226
config_button_download
GtkWidget * config_button_download
Definition: config.c:35
LOG_INFO
@ LOG_INFO
Minor, non-harmful issues.
Definition: client.h:434
MSG_TYPE_CLIENT
#define MSG_TYPE_CLIENT
Definition: newclient.h:387
init_theme
void init_theme()
Definition: config.c:92
LOG_WARNING
@ LOG_WARNING
Warning that something might not work.
Definition: client.h:435
time_map_redraw
bool time_map_redraw
Definition: config.c:51
config_combobox_displaymode
GtkComboBox * config_combobox_displaymode
Definition: config.c:39
config_button_cache
GtkWidget * config_button_cache
Definition: config.c:34
load_window_positions
void load_window_positions(GtkWidget *window_root)
Definition: config.c:848
CFG_LT_PIXEL
#define CFG_LT_PIXEL
Definition: client.h:228
ClientSocket::fd
GSocketConnection * fd
Definition: client.h:124
CFG_DM_OPENGL
#define CFG_DM_OPENGL
Definition: client.h:239
CONFIG_DOWNLOAD
#define CONFIG_DOWNLOAD
Definition: client.h:183
draw_stats
void draw_stats(int redraw)
Definition: stats.c:554
save_defaults
void save_defaults()
Definition: config.c:513
last_server
char * last_server
Definition: config.c:45
face_info
Face_Information face_info
Definition: image.c:169
CONFIG_FOGWAR
#define CONFIG_FOGWAR
Definition: client.h:188
CONFIG_MAPSCALE
#define CONFIG_MAPSCALE
Definition: client.h:190
config_combobox_lighting
GtkComboBox * config_combobox_lighting
Definition: config.c:39
CONFIG_GRAD_COLOR
#define CONFIG_GRAD_COLOR
Definition: client.h:206
NDI_RED
#define NDI_RED
Definition: newclient.h:224
map_check_resize
void map_check_resize(void)
Definition: map.c:49
CONFIG_LIGHTING
#define CONFIG_LIGHTING
Definition: client.h:199
NDI_BLUE
#define NDI_BLUE
Definition: newclient.h:226
config_names
const char *const config_names[CONFIG_NUMS]
Definition: init.c:30
IS_DIFFERENT
static bool IS_DIFFERENT(int type)
Definition: config.c:58
config_button_fasttcp
GtkWidget * config_button_fasttcp
Definition: config.c:32
CFG_LT_TILE
#define CFG_LT_TILE
Definition: client.h:227
config_combobox_faceset
GtkComboBoxText * config_combobox_faceset
Definition: config.c:38
mapdata.h
config_button_foodbeep
GtkWidget * config_button_foodbeep
Definition: config.c:34
CONFIG_FOODBEEP
#define CONFIG_FOODBEEP
Definition: client.h:203
CFG_DM_SDL
#define CFG_DM_SDL
Definition: client.h:238
CONFIG_CACHE
#define CONFIG_CACHE
Definition: client.h:187
CONFIG_NUMS
#define CONFIG_NUMS
Definition: client.h:217
Face_Information_struct::facesets
FaceSets facesets[MAX_FACE_SETS]
Definition: client.h:420
CFG_DM_PIXMAP
#define CFG_DM_PIXMAP
Definition: client.h:237
MAX_BUF
#define MAX_BUF
Definition: client.h:40
DEFAULT_IMAGE_SIZE
#define DEFAULT_IMAGE_SIZE
Definition: image.h:40
save_winpos
void save_winpos()
Definition: config.c:793
setup_config_dialog
static void setup_config_dialog()
Definition: config.c:620
default_files
static char ** default_files
Definition: config.c:91
CONFIG_TIMESTAMP
#define CONFIG_TIMESTAMP
Definition: client.h:214
Player_Struct::ob
item * ob
Definition: client.h:334
theme
static char * theme
Definition: config.c:44
ui_name
static char * ui_name()
Definition: config.c:65
spell_get_styles
void spell_get_styles(void)
Definition: spells.c:66
gtk2proto.h
on_config_close
static void on_config_close(GtkButton *button, gpointer user_data)
Definition: config.c:783
on_save_window_position_activate
void on_save_window_position_activate(GtkMenuItem *menuitem, gpointer user_data)
Definition: config.c:834
draw_lists
void draw_lists(void)
Definition: inventory.c:1165
Face_Information_struct::want_faceset
char * want_faceset
Definition: client.h:407
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:111
cs_print_string
int cs_print_string(GSocketConnection *fd, const char *str,...)
Definition: newsocket.c:252
config_dir
const char * config_dir
Definition: client.c:52
load_theme
void load_theme(int reload)
Definition: config.c:154
MAP_MAX_SIZE
#define MAP_MAX_SIZE
Definition: client.h:466
window_xml_file
char window_xml_file[MAX_BUF]
Definition: main.c:98
get_window_coord
void get_window_coord(GtkWidget *win, int *x, int *y, int *wx, int *wy, int *w, int *h)
Definition: main.c:579
want_config
gint16 want_config[CONFIG_NUMS]
Definition: init.c:41
draw_ext_info
void draw_ext_info(int orig_color, int type, int subtype, const char *message)
Definition: info.c:915
csocket
ClientSocket csocket
Definition: client.c:70
image.h
SOL_TCP
#define SOL_TCP
Definition: client.h:37
MAX_FACE_SETS
#define MAX_FACE_SETS
Definition: client.h:381
CONFIG_SPLASH
#define CONFIG_SPLASH
Definition: client.h:209
config_load_legacy
static void config_load_legacy()
Definition: config.c:217
config_button_echo
GtkWidget * config_button_echo
Definition: config.c:32
theme_filechooser
GtkFileChooser * theme_filechooser
Definition: config.c:37
config_button_fog
GtkWidget * config_button_fog
Definition: config.c:35
image_size
int image_size
Definition: image.c:30
ui_filechooser
GtkFileChooser * ui_filechooser
Definition: config.c:37
config_path
static GString * config_path
Definition: config.c:30
read_config_dialog
static void read_config_dialog(void)
Definition: config.c:703
config_button_sound
GtkWidget * config_button_sound
Definition: config.c:34
dialog_xml
GtkBuilder * dialog_xml
Definition: main.c:102
CONFIG_RESISTS
#define CONFIG_RESISTS
Definition: client.h:207
LOG_ERROR
@ LOG_ERROR
Warning that something definitely didn't work.
Definition: client.h:436
CONFIG_SOUND
#define CONFIG_SOUND
Definition: client.h:195
update_spell_information
void update_spell_information(void)
Definition: spells.c:190
main.h
FaceSets_struct::fullname
char * fullname
Definition: client.h:395
CONFIG_MAPWIDTH
#define CONFIG_MAPWIDTH
Definition: client.h:201
cpl
Client_Player cpl
Definition: client.c:69
predict_alpha
int predict_alpha
Definition: config.c:54
MSG_TYPE_CLIENT_CONFIG
#define MSG_TYPE_CLIENT_CONFIG
Definition: newclient.h:630
CONFIG_POPUPS
#define CONFIG_POPUPS
Definition: client.h:191
CONFIG_SMOOTH
#define CONFIG_SMOOTH
Definition: client.h:208
Player_Struct::below
item * below
Definition: client.h:335
inventory_get_styles
void inventory_get_styles(void)
Definition: inventory.c:501
THEME_DEFAULT
#define THEME_DEFAULT
Definition: config.c:41
config_init
void config_init(GtkWidget *window_root)
Definition: config.c:539
info_get_styles
void info_get_styles(void)
Definition: info.c:499
item_struct::inv_updated
guint16 inv_updated
Definition: item.h:77
use_config
gint16 use_config[CONFIG_NUMS]
Definition: client.h:242
Face_Information_struct::have_faceset_info
guint8 have_faceset_info
Definition: client.h:417
config_dialog
GtkWidget * config_dialog
Definition: config.c:32
stats_get_styles
void stats_get_styles(void)
Definition: stats.c:109
combo_box_text_remove_all
static void combo_box_text_remove_all(GtkComboBoxText *combo_box)
Definition: config.c:608
config_button_grad_color
GtkWidget * config_button_grad_color
Definition: config.c:33
CONFIG_ICONSCALE
#define CONFIG_ICONSCALE
Definition: client.h:189
draw_message_window
void draw_message_window(int redraw)
Definition: stats.c:459
CONFIG_ECHO
#define CONFIG_ECHO
Definition: client.h:184
window_root
GtkWidget * window_root
Definition: main.c:103
init_sounds
int init_sounds(void)
Definition: sound.c:26
CONFIG_MAPHEIGHT
#define CONFIG_MAPHEIGHT
Definition: client.h:202
CONFIG_FASTTCP
#define CONFIG_FASTTCP
Definition: client.h:185
CONFIG_DARKNESS
#define CONFIG_DARKNESS
Definition: client.h:204
combobox_get_value
static int combobox_get_value(GtkComboBox *combobox, int column)
Definition: config.c:688
LOG_DEBUG
@ LOG_DEBUG
Useful debugging information.
Definition: client.h:433
config_load
void config_load()
Definition: config.c:442
on_configure_activate
void on_configure_activate(GtkWidget *menuitem, gpointer user_data)
Definition: config.c:778
client.h
config_button_smoothing
GtkWidget * config_button_smoothing
Definition: config.c:35
config
static GKeyFile * config
Definition: config.c:29
config_button_timestamp
GtkWidget * config_button_timestamp
Definition: config.c:33
config_check
void config_check()
Definition: config.c:331
window_xml
GtkBuilder * window_xml
Definition: main.c:102
CONFIG_DISPLAYMODE
#define CONFIG_DISPLAYMODE
Definition: client.h:192