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