Crossfire Client, Branches  R11627
config.c
Go to the documentation of this file.
1 const char * const rcsid_gtk_config_c =
2  "$Id: config.c 9576 2008-07-19 23:42:35Z kbulgrien $";
3 /*
4  Crossfire client, a client program for the crossfire program.
5 
6  Copyright (C) 2001 Mark Wedel & Crossfire Development Team
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22  The author can be reached via e-mail to crossfire-devel@real-time.com
23 */
24 
25 /* This file handles the loading and saving of the configuration options,
26  * as well as presenting a nice gui to select the
27  * options
28  */
29 
30 #include <config.h>
31 
32 #ifdef __CYGWIN__
33 #include <errno.h>
34 #endif
35 
36 /* gtk */
37 #include <gtk/gtk.h>
38 #ifndef WIN32
39 #include <gdk/gdkx.h>
40 #else
41 #include <gdk/gdkwin32.h>
42 #endif
43 #include <gdk/gdkkeysyms.h>
44 
45 
46 /* always include our local headers after the system headers are included */
47 #include "client.h"
48 /*#include "clientbmap.h"*/
49 #include "item.h"
50 #include "gx11.h"
51 #include "gtkproto.h"
52 #include <ctype.h>
53 
54 
55 /* Abstract this out a bit - rather than have a whole bunch of
56  * duplicated code that generates these values, instead use
57  * pointers to functions that set and get the values - this
58  * makes adding new widgets a lot easier in most cases.
59  *
60  * button is the actual widget that is created.
61  *
62  * label is the label that is to be printed
63  *
64  * type if the type of widget. As long as the widget only
65  * needs to deal with numeric type values, this works
66  * fine - this means that dials can get just as easily
67  * added to this list
68  *
69  * config holds the corresponding CONFIG value from
70  * the common/client.h file. This allows
71  * use to use a fairly common function for most
72  * values.
73  *
74  * flags holds flags. Currently, the
75  * only flag is FLAG_UPDATE - if set,
76  * then we automatically the running total
77  * immediately. Otherwise, the want_config value
78  * only gets updated, and depending on the value,
79  * that value may get used/copied into the use_config
80  * at a later point. Many values which can change at
81  * runtime do not have this flag set simply so that it
82  * is easier to notice if it has changed and do the
83  * appropraite thing (eg, stop/start sound daemon, etc)
84  *
85  * Note on RBUTTON (radio button usage): Since a radio
86  * button is a collection of buttons of only which one can
87  * be pressed, the logic the program uses is this:
88  * 1) If the previous widget was a radio button, we add
89  * this one to the same group. This means if you want to
90  * have multiple sets of radio buttons, you should seperate
91  * them with something.
92  * 2) Since the radio button is several widgets, its not as simple
93  * as normal buttons to map them to a config value. Instead,
94  * use a range so that it is easy to tell what config value
95  * your button belongs to, eg, 100-199 is for the lighting
96  * options.
97  */
98 
99 #define MAX_BUTTONS 33
100 #define RBUTTON 1
101 #define CBUTTON 2
102 #define SEPERATOR 3 /* Seperator in the window */
103 
104 #define SPIN 0x100
105 #define SPIN_SCALE 0x101 /* Spin Button that is image scale */
106 #define SPIN_MAP 0x102 /* Spin button that is map size */
107 #define SPIN_CWINDOW 0x103 /* Spin command window */
108 
109 #define FLAG_UPDATE 0x1
110 #define FLAG_MAPPANE 0x2 /* Display on the map/image pane */
111 
112 typedef struct {
113  GtkWidget *widget;
114  int type;
115  int config;
116  int flags;
117  const char *label;
118 } CButtons;
119 
120 static GtkWidget *gtkwin_config = NULL, /* main window */
121  *faceset_combo; /* Combo box for faceset selection */
122 
123 
124 /* A dispatch table that can deal with the entire selection of
125  * config gui elements.
126  */
127 
130  "Beep When Food is Low"},
132  "Timestamp Messages"},
134  "Command Window"},
136  "Echo Bound Commands"},
137 {NULL, CBUTTON, CONFIG_FASTTCP, 0,
138  "Fast TCP Send (May improve performance at expense\n of outgoing bandwidth)"},
140  "Gradually change stat bar color based on value of the stat.\nThis option will result in some extra CPU usage."},
142  "Popup Windows"},
144  "Popup Sign Windows (need Popup Windows checked to be used)"},
146  "Splash Window"},
148  "Show Inventory Icon"},
149 {NULL, CBUTTON, CONFIG_TOOLTIPS, 0,
150  "Show Tooltips"},
151 {NULL, CBUTTON, CONFIG_SOUND, 0,
152  "Sound"},
153 {NULL, CBUTTON, CONFIG_SPLITINFO, 0,
154  "Split Information Window (Takes effect next run)"},
155 {NULL, CBUTTON, CONFIG_SPLITWIN, 0,
156  "Split Windows"},
158  "Trims text in the information window - "
159  "improves performance but bugs in\n gtk make the client unstable if this is used."
160  "This may work better with gtk 2.0"},
162  "Automatically re-applies a container when you use apply to close it. \nIf off, when you use apply to close the container, it stays unapplied"},
163 
164 {NULL, CBUTTON, CONFIG_RESISTS, 0,
165  "Display resistances in two columns rather than only one."},
166 
167 /* The following items are shown in the map tag.
168  * I grouped them together to make reading them a bit easier,
169  * but in fact, they could be intermixed with the other
170  * options.
171  */
172 
174  "Cache Images"},
176  "Download All Image Information (Takes effect on next server connection)"},
178  "Fog of War"},
180  "Icon Scale (Takes effect next run)"},
182  "Map Scale (Takes effect next run)"},
184  "Enable smoothing - Use additionnal CPU (Take effect on next connection)."},
186  "SDL Image Support (Take effect next run)"},
188  "Print Grid Overlay (SDL only, Slow, useful for debugging/development"},
189 
190 {NULL, SEPERATOR, 0, FLAG_MAPPANE,
191  "Lighting options, per pixel is prettier, per tile is faster.\nIf the darkness code is off, the pixel/tile options will be ignored."},
192 {NULL, RBUTTON, 100 + CFG_LT_PIXEL_BEST, FLAG_MAPPANE,
193  "Best Per Pixel Lighting (slowest)"},
194 {NULL, RBUTTON, 100 + CFG_LT_PIXEL, FLAG_MAPPANE,
195  "Fast Per Pixel Lighting"},
196 {NULL, RBUTTON, 100 + CFG_LT_TILE, FLAG_MAPPANE,
197  "Per Tile Lighting"},
199  "Enable darkness code - if off, all spaces will not be dimmed."},
200 
201 {NULL, SEPERATOR, 0, FLAG_MAPPANE,
202  "Map Size: Larger map lets you see more information, but takes more CPU\npower and bandwidth. Changing these will not take effect until the next time\nyou connect to a server"},
204  "Map Height"},
206  "Map Width"},
207 };
208 
209 
210 static void set_config_value(int cval, int value)
211 {
212  want_config[cbuttons[cval].config] = value;
213  if (cbuttons[cval].flags & FLAG_UPDATE)
214  use_config[cbuttons[cval].config] = value;
215 }
216 
218 
220  if (!splitwin_toggling) {
221  client_exit();
222  }
223 }
224 
225 static void toggle_splitwin(int newval)
226 {
228 
230  gtk_widget_destroy(gtkwin_root);
231 
232  if (newval) {
233  ; /* Currently don't have it, but want splitwindows */
234  } else {
235  /* opposite - do have it, but don't want it */
236  gtk_widget_destroy(gtkwin_info);
237  gtk_widget_destroy(gtkwin_stats);
238  gtk_widget_destroy(gtkwin_message);
239  gtk_widget_destroy(gtkwin_inv);
240  gtk_widget_destroy(gtkwin_look);
241  }
242 
243  create_windows();
245  draw_stats (1);
246  update_list_labels(&inv_list); /* After exploding or unexploding client, redraw weight labels. */
248 
250 }
251 
252 /* Ok, here it sets the config and saves it. This is sorta dangerous, and I'm not sure
253  * if it's actually possible to do dynamic reconfiguration of everything this way. Something may
254  * blow up in our faces.
255  */
256 
257 #define IS_DIFFERENT(TYPE) (want_config[TYPE] != use_config[TYPE])
258 
259 static void applyconfig(void) {
260 
261  int onbutton;
262  int lighting = 0;
263 
264  free(face_info.want_faceset);
265  face_info.want_faceset = strdup_local(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(faceset_combo)->entry)));
266  for (onbutton =0; onbutton < MAX_BUTTONS; onbutton++) {
267  if (cbuttons[onbutton].type == CBUTTON) {
268  set_config_value(onbutton, GTK_TOGGLE_BUTTON (cbuttons[onbutton].widget)->active);
269  } else if (cbuttons[onbutton].type & SPIN) {
270  set_config_value(onbutton, gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cbuttons[onbutton].widget)));
271  /*
272  * Nothing special for command window, icon_scale, map_scale,
273  * map width and height. It should be possible to dynamically
274  * change the width and height values, but that is for another day.
275  */
276 
277  } else if (cbuttons[onbutton].type == RBUTTON) {
278  /* We know that the only radio buttons currently in use are those for
279  * lighting. IF other radio buttons are added later, this should
280  * be changed.
281  */
282  if ( GTK_TOGGLE_BUTTON (cbuttons[onbutton].widget)->active) {
283  if ( cbuttons[onbutton].config >= 100 && cbuttons[onbutton].config < 200)
284  lighting = cbuttons[onbutton].config - 100;
285  }
286  }
287  } /* for onbutton ... loop */
288 
289 
290  /* User has toggled splitwindows - adjust accordingly */
294  }
295  if (IS_DIFFERENT(CONFIG_SOUND)) {
296  int tmp;
297  if (want_config[CONFIG_SOUND]) {
298  tmp = init_sounds();
299  if (csocket.fd)
300  cs_print_string(csocket.fd, "setup sound %d", tmp >= 0);
301  } else {
302  if (csocket.fd)
303  cs_print_string(csocket.fd, "setup sound 0");
304  }
306  }
308  if (want_config[CONFIG_TOOLTIPS]) gtk_tooltips_enable(tooltips);
309  else gtk_tooltips_disable(tooltips);
311  }
312  else if (IS_DIFFERENT(CONFIG_FASTTCP)) {
313 #ifdef TCP_NODELAY
314 #ifndef WIN32
315  int q = want_config[CONFIG_FASTTCP];
316 
317  if (csocket.fd && setsockopt(csocket.fd, SOL_TCP, TCP_NODELAY, &q, sizeof(q)) == -1)
318  perror("TCP_NODELAY");
319 #else
320  int q = want_config[CONFIG_FASTTCP];
321 
322  if (csocket.fd && setsockopt(csocket.fd, SOL_TCP, TCP_NODELAY, ( const char* )&q, sizeof(q)) == -1)
323  perror("TCP_NODELAY");
324 #endif
325 #endif
327  }
330  /* TODO What about the look list? And should showicon propogate back here? */
332  }
336  }
338  reset_stat_bars();
339  }
340 
341  if (lighting) {
342  if (want_config[CONFIG_LIGHTING] != lighting) {
343  want_config[CONFIG_LIGHTING] = lighting;
344  use_config[CONFIG_LIGHTING] = lighting;
345  }
346 #ifdef HAVE_SDL
348  /* This is done to make the 'lightmap' in the proper format */
349  init_SDL( NULL, 1);
350 #endif
351  }
353  resize_resistance_table(want_config[CONFIG_RESISTS]);
356  }
357 }
358 
359 
360 /* Ok, here it sets the config and saves it. This is sorta dangerous, and I'm not sure
361  * if it's actually possible to do dynamic reconfiguration of everything this way.
362  */
363 
364 static void saveconfig(void) {
365 
366  /* No idea why applyconfig was basically replicated - just call the
367  * function instead!
368  */
369  applyconfig();
370  save_defaults();
371 }
372 
373 /*
374  * GUI Config dialog.
375  *
376  *
377  */
378 
379 void configdialog(GtkWidget *widget) {
380  GtkWidget *vbox;
381  GtkWidget *tablabel;
382  GtkWidget *notebook;
383  GtkWidget *vbox1;
384  GtkWidget *vbox2;
385  GtkWidget *hbox1;
386  GtkWidget *applybutton;
387  GtkWidget *cancelbutton;
388  GtkWidget *savebutton;
389  GtkWidget *frame1;
390  GtkWidget *frame_map, *vbox_map; /* frame and vbox for map notebook */
391  GtkWidget *addwidget; /* Used in buildin the tab to point to the widget to add to */
392  GtkWidget *ehbox;
393  GtkWidget *clabel1, *clabel2, *clabel4, *clabel5, *cb1, *cb2, *cb3;
394  GtkWidget *cclists;
395  GtkWidget *extras[250];
396  GList *flist;
397  int i, num_extras=0;
398 
399  gchar *titles[] ={"#","Key","(#)","Mods","Command"};
400 
401  /* If the window isnt already up (in which case it's just raised) */
402  if(!gtkwin_config) {
403  int x, y, wx, wy, w, h;
404 
405 
406  gtkwin_config = gtk_window_new (GTK_WINDOW_DIALOG);
407  /* Pet peeve - center new window on top of parent, and not on the
408  * the center of the screen - the later is really annoying in
409  * xinerama mode. Thankfully, GTK 2.0 adds an option to
410  * center on parent - for now, just fake it by getting the parents
411  * geometry.
412  */
413  /*gtk_window_position (GTK_WINDOW (gtkwin_config), GTK_WIN_POS_CENTER);*/
414  get_window_coord(gtkwin_root, &x,&y, &wx,&wy,&w,&h);
415  gtk_widget_set_uposition(gtkwin_config, (wx + w - 450)/2, (wy + h-500) / 2);
416  gtk_widget_set_usize (gtkwin_config,450,600);
417  gtk_window_set_title (GTK_WINDOW (gtkwin_config), "Crossfire Configure");
418  gtk_window_set_policy (GTK_WINDOW (gtkwin_config), TRUE, TRUE, FALSE);
419 
420  gtk_signal_connect (GTK_OBJECT (gtkwin_config), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &gtkwin_config);
421 
422  gtk_container_border_width (GTK_CONTAINER (gtkwin_config), 0);
423 
424  /* vbox splits the window - top portion is the notebook, bottom
425  * portion is for the tabs for apply/save/config.
426  */
427  vbox = gtk_vbox_new(FALSE, 2);
428  gtk_container_add (GTK_CONTAINER(gtkwin_config),vbox);
429 
430  notebook = gtk_notebook_new ();
431  gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP );
432  gtk_box_pack_start (GTK_BOX(vbox),notebook, TRUE, TRUE, 0);
433 
434  tablabel = gtk_label_new ("General");
435  gtk_widget_show (tablabel);
436 
437  frame1 = gtk_frame_new("General options");
438  gtk_frame_set_shadow_type (GTK_FRAME(frame1), GTK_SHADOW_ETCHED_IN);
439  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame1, tablabel);
440 
441  vbox1 = gtk_vbox_new(FALSE, 0);
442  gtk_container_add (GTK_CONTAINER(frame1), vbox1);
443 
444  tablabel = gtk_label_new ("Map & Image");
445  gtk_widget_show (tablabel);
446 
447  frame_map = gtk_frame_new("Map and Image options");
448  gtk_frame_set_shadow_type (GTK_FRAME(frame_map), GTK_SHADOW_ETCHED_IN);
449  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame_map, tablabel);
450 
451  vbox_map = gtk_vbox_new(FALSE, 0);
452  gtk_container_add (GTK_CONTAINER(frame_map), vbox_map);
453 
454  for (i=0; i < MAX_BUTTONS; i++) {
455  if (cbuttons[i].flags & FLAG_MAPPANE)
456  addwidget = vbox_map;
457  else
458  addwidget = vbox1;
459 
460  if (cbuttons[i].type == CBUTTON) {
461  cbuttons[i].widget = gtk_check_button_new_with_label(cbuttons[i].label);
462  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(cbuttons[i].widget), want_config[cbuttons[i].config]);
463  }
464  else if (cbuttons[i].type == RBUTTON) {
465  if ((i>0) && (cbuttons[i-1].type == RBUTTON)) {
466  cbuttons[i].widget = gtk_radio_button_new_with_label_from_widget(
467  GTK_RADIO_BUTTON(cbuttons[i-1].widget), cbuttons[i].label);
468  } else {
469  cbuttons[i].widget = gtk_radio_button_new_with_label(NULL, cbuttons[i].label);
470  }
471  if ((want_config[CONFIG_LIGHTING]+100) == cbuttons[i].config)
472  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(cbuttons[i].widget), 1);
473  }
474  else if (cbuttons[i].type & SPIN) {
475  GtkAdjustment *adj=NULL;
476 
477  if (cbuttons[i].type == SPIN_SCALE)
478  adj = (GtkAdjustment *) gtk_adjustment_new(want_config[cbuttons[i].config], 25, 200, 1, 5, 5);
479  else if (cbuttons[i].type == SPIN_MAP)
480  adj = (GtkAdjustment *) gtk_adjustment_new(want_config[cbuttons[i].config], 9, MAP_MAX_SIZE, 1, 5, 5);
481  else if (cbuttons[i].type == SPIN_CWINDOW)
482  adj = (GtkAdjustment *) gtk_adjustment_new(want_config[cbuttons[i].config], 1, 127, 1, 5, 5);
483  cbuttons[i].widget = gtk_spin_button_new(adj, 1, 0);
484  extras[num_extras] = gtk_hbox_new(FALSE, 2);
485  gtk_box_pack_start(GTK_BOX(extras[num_extras]), cbuttons[i].widget, FALSE, FALSE, 0);
486  extras[++num_extras] = gtk_label_new(cbuttons[i].label);
487  gtk_box_pack_start(GTK_BOX(extras[num_extras-1]), extras[num_extras], FALSE, FALSE, 0);
488  gtk_box_pack_start(GTK_BOX(addwidget), extras[num_extras-1], FALSE, FALSE, 0);
489  num_extras++;
490  extras[num_extras++] = cbuttons[i].widget;
491  continue; /* What to skip the box_pack_start below */
492  }
493  else if (cbuttons[i].type == SEPERATOR) {
494  extras[num_extras] = (GtkWidget*)gtk_hseparator_new ();
495  gtk_box_pack_start (GTK_BOX (addwidget), extras[num_extras], FALSE, FALSE, 0);
496  cbuttons[i].widget = gtk_label_new(cbuttons[i].label);
497  gtk_label_set_justify(GTK_LABEL(cbuttons[i].widget), GTK_JUSTIFY_LEFT);
498  num_extras++;
499  }
500  else {
501  LOG(LOG_WARNING,"gtk::configdialog","Unknown cbutton type %d", cbuttons[i].type);
502  }
503  if (cbuttons[i].widget) {
504  extras[num_extras++] = cbuttons[i].widget;
505  gtk_box_pack_start(GTK_BOX(addwidget), cbuttons[i].widget, FALSE, FALSE, 0);
506  }
507  }
508 
509  for (i=0; i < num_extras; i++) {
510  gtk_widget_show(extras[i]);
511  }
512 
513  /* faceset is special because it is string data. */
514  faceset_combo = gtk_combo_new();
515  flist = NULL;
516  if (face_info.want_faceset) {
517  gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(faceset_combo)->entry), face_info.want_faceset);
518  flist = g_list_append(flist, face_info.want_faceset);
519  }
520 
521  /* If we have real faceset info from the server, use it */
523  for (i=0; i<MAX_FACE_SETS; i++)
524  if (face_info.facesets[i].fullname)
525  flist = g_list_append(flist, face_info.facesets[i].fullname);
526  } else {
527  flist = g_list_append(flist, "standard");
528  flist = g_list_append(flist, "classic");
529  }
530  if (flist) gtk_combo_set_popdown_strings(GTK_COMBO(faceset_combo), flist);
531  addwidget = gtk_hbox_new(FALSE, 0);
532  gtk_box_pack_start(GTK_BOX(addwidget), faceset_combo, FALSE, FALSE, 0);
533  tablabel = gtk_label_new("Faceset to use. Only takes effect for new\n face information from server. Not supported on\n all servers.");
534  gtk_label_set_justify(GTK_LABEL(tablabel), GTK_JUSTIFY_LEFT);
535  gtk_box_pack_start(GTK_BOX(addwidget), tablabel, FALSE, FALSE, 0);
536 
537  gtk_box_pack_start(GTK_BOX(vbox_map), addwidget, FALSE, FALSE, 0);
538  gtk_widget_show(tablabel);
539  gtk_widget_show(faceset_combo);
540  gtk_widget_show(addwidget);
541 
542  gtk_widget_show (vbox1);
543  gtk_widget_show (frame1);
544  gtk_widget_show(vbox_map);
545  gtk_widget_show(frame_map);
546 
547 
548  /*
549  * This block deals with drawing the keybindings
550  * block.
551  */
552 
553  tablabel = gtk_label_new ("Keybindings");
554  gtk_widget_show (tablabel);
555  vbox2 = gtk_vbox_new(FALSE, 0);
556  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox2, tablabel);
557  frame1 = gtk_frame_new("Keybindings");
558  gtk_frame_set_shadow_type (GTK_FRAME(frame1), GTK_SHADOW_ETCHED_IN);
559  gtk_box_pack_start (GTK_BOX (vbox2), frame1, TRUE, TRUE, 0);
560  vbox1 = gtk_vbox_new(FALSE, 0);
561  gtk_container_add (GTK_CONTAINER(frame1), vbox1);
562  cclists = gtk_scrolled_window_new (0,0);
563  cclist = gtk_clist_new_with_titles (5, titles);
564 
565  gtk_clist_set_column_width (GTK_CLIST(cclist), 0, 20);
566  gtk_clist_set_column_width (GTK_CLIST(cclist), 1, 50);
567  gtk_clist_set_column_width (GTK_CLIST(cclist), 2, 20);
568  gtk_clist_set_column_width (GTK_CLIST(cclist), 3, 40);
569  gtk_clist_set_column_width (GTK_CLIST(cclist), 4, 245);
570  gtk_clist_set_selection_mode (GTK_CLIST(cclist) , GTK_SELECTION_SINGLE);
571 
572  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(cclists),
573  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
574  gtk_container_add (GTK_CONTAINER (cclists), cclist);
575  gtk_box_pack_start (GTK_BOX(vbox1),cclists, TRUE, TRUE, 0);
577 
578  gtk_signal_connect_after (GTK_OBJECT(cclist),
579  "select_row",
580  GTK_SIGNAL_FUNC(cclist_button_event),
581  NULL);
582 
583  gtk_widget_show(cclist);
584  gtk_widget_show(cclists);
585 
586  ehbox=gtk_hbox_new(FALSE, 0);
587 
588 
589  clabel1 = gtk_label_new ("Binding #:");
590  gtk_box_pack_start (GTK_BOX (ehbox),clabel1, FALSE, TRUE, 2);
591  gtk_widget_show (clabel1);
592 
593  cnumentrytext = gtk_label_new ("0");
594  gtk_box_pack_start (GTK_BOX (ehbox),cnumentrytext, FALSE, TRUE, 2);
595  gtk_widget_set_usize (cnumentrytext, 25, 0);
596  gtk_widget_show (cnumentrytext);
597 
598  clabel2 = gtk_label_new ("Key:");
599  gtk_box_pack_start (GTK_BOX (ehbox),clabel2, FALSE, TRUE, 2);
600  gtk_widget_show (clabel2);
601 
602  ckeyentrytext = gtk_entry_new ();
603  gtk_box_pack_start (GTK_BOX (ehbox),ckeyentrytext, TRUE, TRUE, 2);
604  gtk_widget_set_usize (ckeyentrytext, 110, 0);
605  gtk_signal_connect(GTK_OBJECT(ckeyentrytext), "key_press_event",
606  GTK_SIGNAL_FUNC(ckeyentry_callback),
607  ckeyentrytext);
608  gtk_widget_show (ckeyentrytext);
609  gtk_entry_set_text (GTK_ENTRY(ckeyentrytext), "Press key to bind here");
610 
611  clabel4 = gtk_label_new ("Mods:");
612  gtk_box_pack_start (GTK_BOX (ehbox),clabel4, FALSE, TRUE, 2);
613  gtk_widget_show (clabel4);
614 
615  cmodentrytext = gtk_entry_new ();
616  gtk_box_pack_start (GTK_BOX (ehbox),cmodentrytext, FALSE, TRUE, 2);
617  gtk_widget_set_usize (cmodentrytext, 45, 0);
618  gtk_widget_show (cmodentrytext);
619 
620  gtk_box_pack_start (GTK_BOX (vbox1),ehbox, FALSE, TRUE, 2);
621 
622  gtk_widget_show (ehbox);
623 
624  ehbox=gtk_hbox_new(FALSE, 0);
625 
626  clabel5 = gtk_label_new ("Command:");
627  gtk_box_pack_start (GTK_BOX (ehbox),clabel5, FALSE, TRUE, 2);
628  gtk_widget_show (clabel5);
629 
630  ckentrytext = gtk_entry_new ();
631  gtk_box_pack_start (GTK_BOX (ehbox),ckentrytext, TRUE, TRUE, 2);
632  gtk_widget_show (ckentrytext);
633 
634  gtk_box_pack_start (GTK_BOX (vbox1),ehbox, FALSE, TRUE, 2);
635 
636  gtk_widget_show (ehbox);
637 
638  ehbox=gtk_hbox_new(TRUE, 0);
639 
640 
641  cb1 = gtk_button_new_with_label ("Unbind");
642  gtk_box_pack_start (GTK_BOX (ehbox),cb1, FALSE, TRUE, 4);
643  /*gtk_widget_set_usize (cb1, 45, 0);*/
644  gtk_signal_connect_object (GTK_OBJECT (cb1), "clicked",
645  GTK_SIGNAL_FUNC(ckeyunbind),
646  NULL);
647  gtk_widget_show (cb1);
648 
649  cb2 = gtk_button_new_with_label ("Bind");
650  gtk_box_pack_start (GTK_BOX (ehbox),cb2, FALSE, TRUE, 4);
651  gtk_signal_connect_object (GTK_OBJECT (cb2), "clicked",
652  GTK_SIGNAL_FUNC(bind_callback),
653  NULL);
654  /* gtk_widget_set_usize (cb2, 45, 0);*/
655  gtk_widget_show (cb2);
656 
657  cb3 = gtk_button_new_with_label ("Clear");
658  gtk_box_pack_start (GTK_BOX (ehbox),cb3, FALSE, TRUE, 4);
659  /* gtk_widget_set_usize (cb2, 45, 0);*/
660  gtk_signal_connect_object (GTK_OBJECT (cb3), "clicked",
661  GTK_SIGNAL_FUNC(ckeyclear),
662  NULL);
663  gtk_widget_show (cb3);
664  gtk_box_pack_start (GTK_BOX (vbox1),ehbox, FALSE, TRUE, 2);
665 
666  gtk_widget_show (ehbox);
667 
668  gtk_widget_show (vbox1);
669  gtk_widget_show (frame1);
670  gtk_widget_show (vbox2);
671 
672  gtk_widget_show (notebook);
673 
674  /* And give some options to actually do something with our new nifty configuration */
675 
676  hbox1 = gtk_hbox_new(TRUE, 0);
677  gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 6);
678  savebutton = gtk_button_new_with_label("Save");
679  gtk_signal_connect_object (GTK_OBJECT (savebutton), "clicked",
680  GTK_SIGNAL_FUNC(saveconfig),
681  NULL);
682  gtk_box_pack_start(GTK_BOX(hbox1), savebutton, FALSE, TRUE, 4);
683 
684  applybutton = gtk_button_new_with_label("Apply");
685  gtk_signal_connect_object (GTK_OBJECT (applybutton), "clicked",
686  GTK_SIGNAL_FUNC(applyconfig),
687  NULL);
688  gtk_box_pack_start(GTK_BOX(hbox1), applybutton, FALSE, TRUE, 4);
689 
690  cancelbutton = gtk_button_new_with_label("Close");
691  gtk_signal_connect_object (GTK_OBJECT (cancelbutton), "clicked",
692  GTK_SIGNAL_FUNC(gtk_widget_destroy),
693  GTK_OBJECT (gtkwin_config));
694 
695  gtk_box_pack_start(GTK_BOX(hbox1), cancelbutton, FALSE, TRUE, 4);
696  gtk_widget_show(savebutton);
697  gtk_widget_show(applybutton);
698  gtk_widget_show(cancelbutton);
699 
700  gtk_widget_show (hbox1);
701  gtk_widget_show (vbox);
702  gtk_widget_show (gtkwin_config);
703  }
704  else {
705  gdk_window_raise (gtkwin_config->window);
706  }
707 }
708 
709 
710 void load_defaults(void)
711 {
712  char path[MAX_BUF],inbuf[MAX_BUF],*cp;
713  FILE *fp;
714  int i, val;
715 
716  /* Copy over the want values to use values now */
717  for (i=0; i<CONFIG_NUMS; i++) {
718  use_config[i] = want_config[i];
719  }
720 
721  sprintf(path,"%s/.crossfire/gdefaults", getenv("HOME"));
722  if ((fp=fopen(path,"r"))==NULL) return;
723  while (fgets(inbuf, MAX_BUF-1, fp)) {
724  inbuf[MAX_BUF-1]='\0';
725  inbuf[strlen(inbuf)-1]='\0'; /* kill newline */
726 
727  if (inbuf[0]=='#') continue;
728  /* IF no colon, then we certainly don't have a real value, so just skip */
729  if (!(cp=strchr(inbuf,':'))) continue;
730  *cp='\0';
731  cp+=2; /* colon, space, then value */
732 
733  val = -1;
734  if (isdigit(*cp)) val=atoi(cp);
735  else if (!strcmp(cp,"True")) val = TRUE;
736  else if (!strcmp(cp,"False")) val = FALSE;
737 
738  for (i=1; i<CONFIG_NUMS; i++) {
739  if (!strcmp(config_names[i], inbuf)) {
740  if (val == -1) {
741  LOG(LOG_WARNING,"gtk::load_defaults","Invalid value/line: %s: %s", inbuf, cp);
742  } else {
743  want_config[i] = val;
744  }
745  break; /* Found a match - won't find another */
746  }
747  }
748  /* We found a match in the loop above, so no need to do anything more */
749  if (i < CONFIG_NUMS) continue;
750 
751  /* Legacy - now use the map_width and map_height values
752  * Don't do sanity checking - that will be done below
753  */
754  if (!strcmp(inbuf,"mapsize")) {
755  if (sscanf(cp,"%hdx%hd", &want_config[CONFIG_MAPWIDTH], &want_config[CONFIG_MAPHEIGHT])!=2) {
756  LOG(LOG_WARNING,"gtk::load_defaults","Malformed mapsize option in gdefaults. Ignoring");
757  }
758  }
759  else if (!strcmp(inbuf, "server")) {
760  server = strdup_local(cp); /* memory leak ! */
761  continue;
762  }
763  else if (!strcmp(inbuf, "sound_server")) {
764  sound_server = strdup_local(cp); /* memory leak ! */
765  continue;
766  }
767  else if (!strcmp(inbuf, "nopopups")) {
768  /* Changed name from nopopups to popups, so inverse value */
769  want_config[CONFIG_POPUPS] = !val;
770  continue;
771  }
772  else if (!strcmp(inbuf, "nosplash")) {
773  want_config[CONFIG_SPLASH] = !val;
774  continue;
775  }
776  else if (!strcmp(inbuf, "splash")) {
777  want_config[CONFIG_SPLASH] = val;
778  continue;
779  }
780  else if (!strcmp(inbuf, "faceset")) {
781  face_info.want_faceset = strdup_local(cp); /* memory leak ! */
782  continue;
783  }
784  /* legacy support for the old resistances values, we need to adjust the values to the new form */
785  else if (!strcmp(inbuf, "resists")) {
786  if (val) want_config[CONFIG_RESISTS] = val-1;
787  }
788  else if (!strcmp(inbuf, "sdl")) {
790  }
791 
792 
793  else LOG(LOG_WARNING,"gtk::load_defaults","Unknown line in gdefaults: %s %s", inbuf, cp);
794  }
795  fclose(fp);
796  /* Make sure some of the values entered are sane - since a user can
797  * edit the defaults file directly, they could put bogus values
798  * in
799  */
801  LOG(LOG_WARNING,"gtk::load_defaults","Ignoring iconscale value read for gdefaults file.\n"
802  "Invalid iconscale range (%d), valid range for -iconscale is 25 through 200",
805  }
807  LOG(LOG_WARNING,"gtk::load_defaults","ignoring mapscale value read for gdefaults file.\n"
808  "Invalid mapscale range (%d), valid range for -iconscale is 25 through 200",
811  }
813  LOG(LOG_WARNING,"gtk::load_defaults","No lighting mechanism selected - will not use darkness code");
815  }
816 
817  /* Make sure the map size os OK */
819  LOG(LOG_WARNING,"gtk::load_defaults",
820  "Invalid map width (%d) option in gdefaults. Valid range is 9 to %d",
823  }
825  LOG(LOG_WARNING,"gtk::load_defaults",
826  "Invalid map height (%d) option in gdefaults. Valid range is 9 to %d",
829  }
830 
831 #ifndef HAVE_SDL
832  /* If SDL is not built in, having SDL mode turned on causes many issues. */
834 #endif
835 
836  /* Now copy over the values just loaded */
837  for (i=0; i<CONFIG_NUMS; i++) {
838  use_config[i] = want_config[i];
839  }
840 
845 
846 }
847 
848 void save_defaults(void)
849 {
850  char path[MAX_BUF],buf[MAX_BUF];
851  FILE *fp;
852  int i;
853 
854  sprintf(path,"%s/.crossfire/gdefaults", getenv("HOME"));
855  if (make_path_to_file(path)==-1) {
856  LOG(LOG_ERROR,"gtk::save_defaults","Could not create %s", path);
857  return;
858  }
859  if ((fp=fopen(path,"w"))==NULL) {
860  LOG(LOG_ERROR,"gtk::save_defaults","Could not open %s", path);
861  return;
862  }
863  fprintf(fp,"# This file is generated automatically by crossfire-client-gtk.\n");
864  fprintf(fp,"# Manual editing is allowed, but the client may be finicky about\n");
865  fprintf(fp,"# some of the matching it does. All comparisons are case sensitive.\n");
866  fprintf(fp,"# 'True' and 'False' are the proper cases for those two values\n");
867  fprintf(fp,"# 'True' and 'False' have been replaced with 1 and 0 respectively\n");
868  fprintf(fp,"server: %s\n", server);
869  fprintf(fp,"sound_server: %s\n", sound_server);
870  fprintf(fp,"faceset: %s\n", face_info.want_faceset);
871 
872  /* This isn't quite as good as before, as instead of saving things as 'True'
873  * or 'False', it is just 1 or 0. However, for the most part, the user isn't
874  * going to be editing the file directly.
875  */
876  for (i=1; i < CONFIG_NUMS; i++) {
877  fprintf(fp,"%s: %d\n", config_names[i], want_config[i]);
878  }
879 
880  fclose(fp);
881  sprintf(buf,"Defaults saved to %s",path);
882  draw_info(buf,NDI_BLUE);
883 }
void inventory_splitwin_toggling(void)
Definition: inventory.c:790
int flags
Definition: config.c:116
#define SOL_TCP
Definition: client-types.h:124
static void set_config_value(int cval, int value)
Definition: config.c:210
void init_SDL(GtkWidget *sdl_window, int just_lightmap)
GtkTooltips * tooltips
Definition: gx11.c:252
#define DEFAULT_IMAGE_SIZE
Definition: gx11.c:114
GtkWidget * gtkwin_info
Definition: gx11.c:278
#define CONFIG_POPUPS
Definition: client.h:160
static void toggle_splitwin(int newval)
Definition: config.c:225
void configdialog(GtkWidget *widget)
Definition: config.c:379
#define SPIN
Definition: config.c:104
#define CONFIG_ECHO
Definition: client.h:153
void ckeyclear(void)
Definition: keys.c:1251
#define MAP_MAX_SIZE
Definition: client.h:447
#define CONFIG_TIMESTAMP
Definition: client.h:182
#define CONFIG_APPLY_CONTAINER
Definition: client.h:179
#define FLAG_UPDATE
Definition: config.c:109
ClientSocket csocket
Definition: client.c:78
FaceSets facesets[MAX_FACE_SETS]
Definition: client.h:355
int make_path_to_file(char *filename)
Definition: misc.c:94
Face_Information face_info
Definition: image.c:167
void get_window_coord(GtkWidget *win, int *x, int *y, int *wx, int *wy, int *w, int *h)
Definition: gx11.c:4789
int map_image_half_size
Definition: gx11.c:117
#define CONFIG_SIGNPOPUP
Definition: client.h:181
#define CONFIG_SPLASH
Definition: client.h:178
#define CONFIG_FOGWAR
Definition: client.h:157
sint16 want_config[CONFIG_NUMS]
Definition: init.c:50
GtkWidget * ckeyentrytext
Definition: gx11.c:235
#define CONFIG_MAPSCALE
Definition: client.h:159
void bind_callback(GtkWidget *gtklist, GdkEventButton *event)
Definition: keys.c:1181
void draw_keybindings(GtkWidget *keylist)
Definition: keys.c:1129
GtkWidget * widget
Definition: config.c:113
#define CONFIG_SPLITINFO
Definition: client.h:165
char * server
Definition: client.c:56
#define CFG_LT_PIXEL_BEST
Definition: client.h:189
int init_sounds(void)
Definition: sound.c:60
#define SPIN_MAP
Definition: config.c:106
#define CFG_DM_SDL
Definition: client.h:195
void draw_stats(int redraw)
Definition: gx11.c:2015
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:178
#define TRUE
Definition: client-types.h:71
#define CONFIG_CWINDOW
Definition: client.h:155
static GtkWidget * gtkwin_config
Definition: config.c:120
#define CONFIG_FOODBEEP
Definition: client.h:172
int map_image_size
Definition: gx11.c:117
void display_map_doneupdate(int redraw, int notice)
Definition: gx11.c:5300
#define CONFIG_NUMS
Definition: client.h:183
itemlist look_list
Definition: inventory.c:1013
int cs_print_string(int fd, const char *str,...)
Definition: newsocket.c:259
GtkWidget * cclist
Definition: gx11.c:260
#define SPIN_CWINDOW
Definition: config.c:107
void draw_message_window(int redraw)
Definition: gx11.c:2458
#define RBUTTON
Definition: config.c:100
sint16 use_config[CONFIG_NUMS]
Definition: init.c:50
void create_windows(void)
Definition: gx11.c:4032
#define CFG_LT_TILE
Definition: client.h:187
#define CFG_LT_PIXEL
Definition: client.h:188
#define FLAG_MAPPANE
Definition: config.c:110
#define CONFIG_GRAD_COLOR
Definition: client.h:175
#define SPIN_SCALE
Definition: config.c:105
GtkWidget * gtkwin_root
Definition: gx11.c:278
#define CONFIG_CACHE
Definition: client.h:156
void ckeyentry_callback(GtkWidget *widget, GdkEventKey *event, GtkWidget *window)
Definition: keys.c:1233
#define CONFIG_FASTTCP
Definition: client.h:154
int fd
Definition: client.h:97
GtkWidget * cnumentrytext
Definition: gx11.c:235
GtkWidget * gtkwin_look
Definition: gx11.c:281
GtkWidget * ckentrytext
Definition: gx11.c:235
static void applyconfig(void)
Definition: config.c:259
static void saveconfig(void)
Definition: config.c:364
void save_defaults(void)
Definition: config.c:848
#define CONFIG_SMOOTH
Definition: client.h:177
void main_window_destroyed(void)
Definition: config.c:219
int config
Definition: config.c:115
#define MAX_BUF
Definition: client-types.h:128
#define CFG_DM_PIXMAP
Definition: client.h:194
void ckeyunbind(GtkWidget *gtklist, GdkEventButton *event)
Definition: keys.c:1214
GtkWidget * gtkwin_message
Definition: gx11.c:281
#define IS_DIFFERENT(TYPE)
Definition: config.c:257
void client_exit(void)
Definition: gx11.c:3269
#define CONFIG_MAPWIDTH
Definition: client.h:170
#define CONFIG_SHOWICON
Definition: client.h:162
#define MAX_FACE_SETS
Definition: client.h:315
#define CONFIG_SHOWGRID
Definition: client.h:167
#define CONFIG_TRIMINFO
Definition: client.h:169
const char *const rcsid_gtk_config_c
Definition: config.c:1
char * sound_server
Definition: client.c:62
#define CONFIG_ICONSCALE
Definition: client.h:158
#define SEPERATOR
Definition: config.c:102
GtkWidget * gtkwin_stats
Definition: gx11.c:281
char * strdup_local(const char *str)
Definition: misc.c:125
#define CONFIG_MAPHEIGHT
Definition: client.h:171
#define CONFIG_DOWNLOAD
Definition: client.h:152
itemlist inv_list
Definition: inventory.c:1013
#define CONFIG_RESISTS
Definition: client.h:176
char * fullname
Definition: client.h:333
int type
Definition: config.c:114
static int splitwin_toggling
Definition: config.c:217
void cclist_button_event(GtkWidget *gtklist, gint row, gint column, GdkEventButton *event)
Definition: gx11.c:2758
void draw_info(const char *str, int color)
Definition: gx11.c:1773
void load_defaults(void)
Definition: config.c:710
static CButtons cbuttons[MAX_BUTTONS]
Definition: config.c:128
#define CONFIG_DISPLAYMODE
Definition: client.h:161
#define CONFIG_LIGHTING
Definition: client.h:168
GtkWidget * cmodentrytext
Definition: gx11.c:235
#define FALSE
Definition: client-types.h:68
const char * label
Definition: config.c:117
int image_size
Definition: gx11.c:116
#define CONFIG_SPLITWIN
Definition: client.h:166
void reset_stat_bars(void)
Definition: gx11.c:2264
#define MAX_BUTTONS
Definition: config.c:99
static GtkWidget * faceset_combo
Definition: config.c:120
const char *const config_names[CONFIG_NUMS]
Definition: init.c:40
#define CONFIG_DARKNESS
Definition: client.h:173
void itemlist_set_show_icon(itemlist *l, int new_setting)
Definition: inventory.c:1288
#define CONFIG_TOOLTIPS
Definition: client.h:163
void resize_resistance_table(int resists_show)
Definition: gx11.c:2350
GtkWidget * gtkwin_inv
Definition: gx11.c:281
#define NDI_BLUE
Definition: newclient.h:206
#define CONFIG_SOUND
Definition: client.h:164
void update_list_labels(itemlist *l)
Definition: inventory.c:1182
#define CBUTTON
Definition: config.c:101