Crossfire Client, Branch
R11627
|
00001 const char * const rcsid_gtk2_config_c = 00002 "$Id: config.c 11627 2009-04-04 16:55:25Z lalo $"; 00003 /* 00004 Crossfire client, a client program for the crossfire program. 00005 00006 Copyright (C) 2005,2007 Mark Wedel & Crossfire Development Team 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 00022 The author can be reached via e-mail to crossfire@metalforge.org 00023 */ 00024 00030 #ifdef HAVE_CONFIG_H 00031 # include <config.h> 00032 #endif 00033 00034 #include <gtk/gtk.h> 00035 #include <glade/glade.h> 00036 #include <ctype.h> 00037 00038 #include "client.h" 00039 00040 #include "main.h" 00041 #include "image.h" 00042 #include "gtk2proto.h" 00043 00044 #include <dirent.h> 00045 00046 #ifdef MINGW 00047 int alphasort(const struct dirent **a, const struct dirent **b) 00048 { 00049 return strcoll((*a)->d_name, (*b)->d_name); 00050 } 00051 00052 int scandir(const char *dir, struct dirent ***namelist, 00053 int (*select)(const struct dirent *), 00054 int (*compar)(const struct dirent **, const struct dirent **)) { 00055 DIR *d; 00056 struct dirent *entry; 00057 register int i=0; 00058 size_t entrysize; 00059 00060 if((d = opendir(dir)) == NULL) 00061 return -1; 00062 00063 *namelist = NULL; 00064 while ((entry = readdir(d)) != NULL) 00065 { 00066 if (select == NULL || (select != NULL && (*select)(entry))) 00067 { 00068 *namelist = (struct dirent **)realloc((void *)(*namelist), 00069 (size_t)((i + 1) * sizeof(struct dirent *))); 00070 if (*namelist == NULL) return -1; 00071 entrysize = sizeof(struct dirent) - sizeof(entry->d_name) + strlen(entry->d_name) + 1; 00072 (*namelist)[i] = (struct dirent *)malloc(entrysize); 00073 if ((*namelist)[i] == NULL) return -1; 00074 memcpy((*namelist)[i], entry, entrysize); 00075 i++; 00076 } 00077 } 00078 if (closedir(d)) return -1; 00079 if (i == 0) return -1; 00080 if (compar != NULL) 00081 qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), 00082 (int(*)(const void*, const void*))compar); 00083 00084 return i; 00085 } 00086 #endif 00087 00088 GtkWidget *config_window, *config_spinbutton_cwindow, *config_button_echo, 00089 *config_button_fasttcp, *config_button_grad_color, *config_button_foodbeep, 00090 *config_button_sound, *config_button_cache, *config_button_download, 00091 *config_button_fog, *config_spinbutton_iconscale, *config_spinbutton_mapscale, 00092 *config_spinbutton_mapwidth, *config_spinbutton_mapheight, 00093 *config_button_smoothing, *config_combobox_displaymode, 00094 *config_combobox_faceset, *config_combobox_lighting, 00095 *config_combobox_theme, *config_combobox_glade; 00096 00097 /* This is the string names that correspond to the numberic id's in client.h */ 00098 00099 static char *theme = "Standard"; 00100 static char *themedir = "themes"; 00101 static char *gladedir = "glade-gtk2"; 00102 00103 static const char * const display_modes[] = {"Pixmap", "SDL", "OpenGL"}; 00104 00116 void load_theme(int reload) 00117 { 00118 char path[MAX_BUF]; 00119 int i; 00120 static char **default_files=NULL; 00121 00122 /* 00123 * We should only be called with reload once at startup. at that time, 00124 * store away the default rc files so we can restore them later. 00125 */ 00126 if (!reload) { 00127 char **tmp; 00128 00129 /* 00130 * GTK man page says copy of this data should be made, so lets go and 00131 * do that. 00132 */ 00133 tmp = gtk_rc_get_default_files(); 00134 i=0; 00135 while (tmp[i]) { 00136 i++; 00137 } 00138 default_files = malloc(sizeof(char*) * (i+1)); 00139 i=0; 00140 while (tmp[i]) { 00141 default_files[i] = strdup(tmp[i]); 00142 i++; 00143 } 00144 default_files[i] = NULL; 00145 } 00146 00147 if (!strcmp(theme,"None")) { 00148 /* 00149 * If this is default and initial run, nothing to do. If it not 00150 * initial run, we need to reset the search path. 00151 */ 00152 if (reload) { 00153 gtk_rc_set_default_files(default_files); 00154 } 00155 } else { 00156 snprintf(path, MAX_BUF, "%s/%s/%s", CF_DATADIR, themedir, theme); 00157 /* 00158 * Check for existence of file. Unfortunately, at initial run time, 00159 * the window may not be realized, so we can't print this error to the 00160 * user directly. 00161 */ 00162 if (access(path, R_OK) == -1) { 00163 LOG(LOG_ERROR, "config.c::load_theme", 00164 "Unable to find theme file %s", path); 00165 return; 00166 } 00167 /* 00168 * We need to reset the search path, otherwise the effects are 00169 * additive. In practice, we could manipulate pointer so it is just 00170 * one call to gtk_rc_set_default_files(), but that is probably more 00171 * complicated than just doing these two calls here. 00172 */ 00173 gtk_rc_set_default_files(default_files); 00174 gtk_rc_add_default_file(path); 00175 } 00176 00177 if (reload) { 00178 /* 00179 * Reload data - so we need to force GTK to reparse and rebind all the 00180 * widget data. Then, we need to call our own functions to reparse the 00181 * custom widget handling we do. 00182 */ 00183 gtk_rc_reparse_all_for_settings(gtk_settings_get_for_screen(gdk_screen_get_default()), TRUE); 00184 gtk_rc_reset_styles(gtk_settings_get_for_screen(gdk_screen_get_default())); 00185 info_get_styles(); 00186 inventory_get_styles(); 00187 stats_get_styles(); 00188 spell_get_styles(); 00189 update_spell_information(); 00190 /* 00191 * Set the inv_updated to force a redraw - otherwise it will not 00192 * necessarily bind the lists with the new widgets. 00193 */ 00194 cpl.ob->inv_updated = 1; 00195 cpl.below->inv_updated = 1; 00196 draw_lists(); 00197 00198 draw_stats(TRUE); 00199 draw_message_window(TRUE); 00200 } 00201 } 00202 00207 void load_defaults(void) 00208 { 00209 char path[MAX_BUF],inbuf[MAX_BUF],*cp; 00210 FILE *fp; 00211 int i, val; 00212 00213 /* Copy over the want values to use values now */ 00214 for (i=0; i<CONFIG_NUMS; i++) { 00215 use_config[i] = want_config[i]; 00216 } 00217 00218 snprintf(path, sizeof(path), "%s/.crossfire/gdefaults2", getenv("HOME")); 00219 if ((fp=fopen(path,"r"))==NULL) return; 00220 while (fgets(inbuf, MAX_BUF-1, fp)) { 00221 inbuf[MAX_BUF-1]='\0'; 00222 inbuf[strlen(inbuf)-1]='\0'; /* kill newline */ 00223 00224 if (inbuf[0]=='#') continue; 00225 /* Skip any setting line that does not contain a colon character */ 00226 if (!(cp=strchr(inbuf,':'))) continue; 00227 *cp='\0'; 00228 cp+=2; /* colon, space, then value */ 00229 00230 val = -1; 00231 if (isdigit(*cp)) val=atoi(cp); 00232 else if (!strcmp(cp,"True")) val = TRUE; 00233 else if (!strcmp(cp,"False")) val = FALSE; 00234 00235 for (i=1; i<CONFIG_NUMS; i++) { 00236 if (!strcmp(config_names[i], inbuf)) { 00237 if (val == -1) { 00238 LOG(LOG_WARNING, "config.c::load_defaults", 00239 "Invalid value/line: %s: %s", inbuf, cp); 00240 } else { 00241 want_config[i] = val; 00242 } 00243 break; /* Found a match - won't find another */ 00244 } 00245 } 00246 /* We found a match in the loop above, so do not do anything more */ 00247 if (i < CONFIG_NUMS) continue; 00248 00249 /* 00250 * Legacy - now use the map_width and map_height values Don't do sanity 00251 * checking - that will be done below 00252 */ 00253 if (!strcmp(inbuf,"mapsize")) { 00254 if (sscanf(cp,"%hdx%hd", &want_config[CONFIG_MAPWIDTH], &want_config[CONFIG_MAPHEIGHT])!=2) { 00255 LOG(LOG_WARNING, "config.c::load_defaults", 00256 "Malformed mapsize option in gdefaults2. Ignoring"); 00257 } 00258 } 00259 else if (!strcmp(inbuf, "server")) { 00260 server = strdup_local(cp); /* memory leak ! */ 00261 continue; 00262 } 00263 else if (!strcmp(inbuf, "theme")) { 00264 theme = strdup_local(cp); /* memory leak ! */ 00265 continue; 00266 } 00267 else if (!strcmp(inbuf, "window_layout")) { 00268 strncpy(window_xml_file, cp, MAX_BUF-1); 00269 continue; 00270 } 00271 else if (!strcmp(inbuf, "nopopups")) { 00272 /* Changed name from nopopups to popups, so inverse value */ 00273 want_config[CONFIG_POPUPS] = !val; 00274 continue; 00275 } 00276 else if (!strcmp(inbuf, "nosplash")) { 00277 want_config[CONFIG_SPLASH] = !val; 00278 continue; 00279 } 00280 else if (!strcmp(inbuf, "splash")) { 00281 want_config[CONFIG_SPLASH] = val; 00282 continue; 00283 } 00284 else if (!strcmp(inbuf, "faceset")) { 00285 face_info.want_faceset = strdup_local(cp); /* memory leak ! */ 00286 continue; 00287 } 00288 /* legacy, as this is now just saved as 'lighting' */ 00289 else if (!strcmp(inbuf, "per_tile_lighting")) { 00290 if (val) want_config[CONFIG_LIGHTING] = CFG_LT_TILE; 00291 } 00292 else if (!strcmp(inbuf, "per_pixel_lighting")) { 00293 if (val) want_config[CONFIG_LIGHTING] = CFG_LT_PIXEL; 00294 } 00295 else if (!strcmp(inbuf, "resists")) { 00296 if (val) want_config[CONFIG_RESISTS] = val; 00297 } 00298 else if (!strcmp(inbuf, "sdl")) { 00299 if (val) want_config[CONFIG_DISPLAYMODE] = CFG_DM_SDL; 00300 } 00301 else LOG(LOG_WARNING, "config.c::load_defaults", 00302 "Unknown line in gdefaults2: %s %s", inbuf, cp); 00303 } 00304 fclose(fp); 00305 /* 00306 * Make sure some of the values entered are sane - since a user can edit 00307 * the defaults file directly, they could put bogus values in 00308 */ 00309 if (want_config[CONFIG_ICONSCALE]< 25 || want_config[CONFIG_ICONSCALE]>200) { 00310 LOG(LOG_WARNING, "config.c::load_defaults", 00311 "Ignoring iconscale value read from gdefaults2 file.\n" 00312 "Invalid iconscale range (%d), valid range for -iconscale " 00313 "is 25 through 200", want_config[CONFIG_ICONSCALE]); 00314 want_config[CONFIG_ICONSCALE] = use_config[CONFIG_ICONSCALE]; 00315 } 00316 if (want_config[CONFIG_MAPSCALE]< 25 || want_config[CONFIG_MAPSCALE]>200) { 00317 LOG(LOG_WARNING, "config.c::load_defaults", 00318 "ignoring mapscale value read for gdefaults2 file.\n" 00319 "Invalid mapscale range (%d), valid range for -iconscale " 00320 "is 25 through 200", want_config[CONFIG_MAPSCALE]); 00321 want_config[CONFIG_MAPSCALE] = use_config[CONFIG_MAPSCALE]; 00322 } 00323 if (!want_config[CONFIG_LIGHTING]) { 00324 LOG(LOG_WARNING, "config.c::load_defaults", 00325 "No lighting mechanism selected - will not use darkness code"); 00326 want_config[CONFIG_DARKNESS] = FALSE; 00327 } 00328 if (want_config[CONFIG_RESISTS] > 2) { 00329 LOG(LOG_WARNING, "config.c::load_defaults", 00330 "ignoring resists display value read for gdafaults file.\n" 00331 "Invalid value (%d), must be one value of 0, 1 or 2.", 00332 want_config[CONFIG_RESISTS]); 00333 want_config[CONFIG_RESISTS] = 0; 00334 } 00335 00336 /* Make sure the map size os OK */ 00337 if (want_config[CONFIG_MAPWIDTH] < 9 || want_config[CONFIG_MAPWIDTH] > MAP_MAX_SIZE) { 00338 LOG(LOG_WARNING, "config.c::load_defaults", "Invalid map width (%d) " 00339 "option in gdefaults2. Valid range is 9 to %d", 00340 want_config[CONFIG_MAPWIDTH], MAP_MAX_SIZE); 00341 want_config[CONFIG_MAPWIDTH] = use_config[CONFIG_MAPWIDTH]; 00342 } 00343 if (want_config[CONFIG_MAPHEIGHT] < 9 || want_config[CONFIG_MAPHEIGHT] > MAP_MAX_SIZE) { 00344 LOG(LOG_WARNING, "config.c::load_defaults", "Invalid map height (%d) " 00345 "option in gdefaults2. Valid range is 9 to %d", 00346 want_config[CONFIG_MAPHEIGHT], MAP_MAX_SIZE); 00347 want_config[CONFIG_MAPHEIGHT] = use_config[CONFIG_MAPHEIGHT]; 00348 } 00349 00350 /* Now copy over the values just loaded */ 00351 for (i=0; i<CONFIG_NUMS; i++) { 00352 use_config[i] = want_config[i]; 00353 } 00354 00355 image_size = DEFAULT_IMAGE_SIZE * use_config[CONFIG_ICONSCALE] / 100; 00356 map_image_size = DEFAULT_IMAGE_SIZE * use_config[CONFIG_MAPSCALE] / 100; 00357 map_image_half_size = DEFAULT_IMAGE_SIZE * use_config[CONFIG_MAPSCALE] / 200; 00358 /*inv_list.show_icon = use_config[CONFIG_SHOWICON];*/ 00359 } 00360 00365 void save_defaults(void) 00366 { 00367 char path[MAX_BUF],buf[MAX_BUF]; 00368 FILE *fp; 00369 int i; 00370 00371 snprintf(path, sizeof(path), "%s/.crossfire/gdefaults2", getenv("HOME")); 00372 if (make_path_to_file(path)==-1) { 00373 LOG(LOG_ERROR, "config.c::save_defaults","Could not create %s", path); 00374 return; 00375 } 00376 if ((fp=fopen(path,"w"))==NULL) { 00377 LOG(LOG_ERROR, "config.c::save_defaults", "Could not open %s", path); 00378 return; 00379 } 00380 fprintf(fp,"# crossfire-client-gtk2 automatically generates this file.\n"); 00381 fprintf(fp,"# Manual editing is allowed, but the client may be a bit\n"); 00382 fprintf(fp,"# finicky about the keys and values. Comparisons are case\n"); 00383 fprintf(fp,"# sensitive. 'True' and 'False' are the proper case, but\n"); 00384 fprintf(fp,"# have been replaced with 1 and 0 respectively.\n#\n"); 00385 fprintf(fp,"server: %s\n", server); 00386 fprintf(fp,"theme: %s\n", theme); 00387 fprintf(fp,"faceset: %s\n", face_info.want_faceset); 00388 fprintf(fp,"window_layout: %s\n", window_xml_file); 00389 /* 00390 * This isn't quite as good as before, as instead of saving things as 00391 * 'True' or 'False', it is just 1 or 0. However, for the most part, the 00392 * user isn't going to be editing the file directly. 00393 */ 00394 for (i=1; i < CONFIG_NUMS; i++) { 00395 fprintf(fp,"%s: %d\n", config_names[i], want_config[i]); 00396 } 00397 00398 fclose(fp); 00399 snprintf(buf, sizeof(buf), "Defaults saved to %s",path); 00400 draw_info(buf,NDI_BLUE); 00401 } 00402 00407 void config_init(GtkWidget *window_root) 00408 { 00409 static int has_init=0; 00410 GladeXML *xml_tree; 00411 GtkWidget *widget; 00412 int count, i; 00413 00414 has_init=1; 00415 00416 config_window = glade_xml_get_widget(dialog_xml, "config_window"); 00417 xml_tree = glade_get_widget_tree(GTK_WIDGET(config_window)); 00418 00419 config_spinbutton_cwindow = 00420 glade_xml_get_widget(xml_tree, "config_spinbutton_cwindow"); 00421 config_button_echo = 00422 glade_xml_get_widget(xml_tree, "config_button_echo"); 00423 config_button_fasttcp = 00424 glade_xml_get_widget(xml_tree, "config_button_fasttcp"); 00425 config_button_grad_color = 00426 glade_xml_get_widget(xml_tree, "config_button_grad_color"); 00427 config_button_foodbeep = 00428 glade_xml_get_widget(xml_tree, "config_button_foodbeep"); 00429 config_button_sound = 00430 glade_xml_get_widget(xml_tree, "config_button_sound"); 00431 config_button_cache = 00432 glade_xml_get_widget(xml_tree, "config_button_cache"); 00433 config_button_download = 00434 glade_xml_get_widget(xml_tree, "config_button_download"); 00435 config_button_fog = 00436 glade_xml_get_widget(xml_tree, "config_button_fog"); 00437 config_button_smoothing = 00438 glade_xml_get_widget(xml_tree, "config_button_smoothing"); 00439 config_spinbutton_iconscale = 00440 glade_xml_get_widget(xml_tree, "config_spinbutton_iconscale"); 00441 config_spinbutton_mapscale = 00442 glade_xml_get_widget(xml_tree, "config_spinbutton_mapscale"); 00443 config_spinbutton_mapwidth = 00444 glade_xml_get_widget(xml_tree, "config_spinbutton_mapwidth"); 00445 config_spinbutton_mapheight = 00446 glade_xml_get_widget(xml_tree, "config_spinbutton_mapheight"); 00447 config_combobox_displaymode = 00448 glade_xml_get_widget(xml_tree, "config_combobox_displaymode"); 00449 config_combobox_faceset = 00450 glade_xml_get_widget(xml_tree, "config_combobox_faceset"); 00451 config_combobox_lighting = 00452 glade_xml_get_widget(xml_tree, "config_combobox_lighting"); 00453 config_combobox_theme = 00454 glade_xml_get_widget(xml_tree, "config_combobox_theme"); 00455 config_combobox_glade = 00456 glade_xml_get_widget(xml_tree, "config_combobox_glade"); 00457 00458 widget = glade_xml_get_widget(xml_tree, "config_button_save"); 00459 g_signal_connect ((gpointer) widget, "clicked", 00460 G_CALLBACK (on_config_button_save_clicked), NULL); 00461 00462 widget = glade_xml_get_widget(xml_tree, "config_button_apply"); 00463 g_signal_connect ((gpointer) widget, "clicked", 00464 G_CALLBACK (on_config_button_apply_clicked), NULL); 00465 00466 widget = glade_xml_get_widget(xml_tree, "config_button_close"); 00467 g_signal_connect ((gpointer) widget, "clicked", 00468 G_CALLBACK (on_config_button_close_clicked), NULL); 00469 00470 /* 00471 * Display mode combo box setup. First, remove all entries, then populate 00472 * with what options are available based on what was compiled in. 00473 */ 00474 count = gtk_tree_model_iter_n_children( 00475 gtk_combo_box_get_model(GTK_COMBO_BOX(config_combobox_displaymode)), NULL); 00476 for (i=0; i < count; i++) 00477 gtk_combo_box_remove_text(GTK_COMBO_BOX(config_combobox_displaymode), 0); 00478 00479 #ifdef HAVE_OPENGL 00480 gtk_combo_box_append_text(GTK_COMBO_BOX(config_combobox_displaymode), "OpenGL"); 00481 #endif 00482 00483 #ifdef HAVE_SDL 00484 gtk_combo_box_append_text(GTK_COMBO_BOX(config_combobox_displaymode), "SDL"); 00485 #endif 00486 gtk_combo_box_append_text(GTK_COMBO_BOX(config_combobox_displaymode), "Pixmap"); 00487 00488 } 00489 00500 static int scandir_theme_filter(const struct dirent *d) 00501 { 00502 if (d->d_name[0] == '.') return 0; 00503 return 1; 00504 } 00505 00517 static int scandir_glade_filter(const struct dirent *d) 00518 { 00519 char *token = NULL; 00520 char *extok = NULL; 00521 char delim[] = "."; 00522 char exten[] = "glade"; 00523 char parse[MAX_BUF] = ""; 00524 00525 strncpy(parse, d->d_name, MAX_BUF); 00526 token = strtok(parse, delim); 00527 while (token) { 00528 extok = token; 00529 token = strtok(NULL, delim); 00530 } 00531 if (extok && strncmp(exten, extok, strlen(exten)) == 0) { 00532 if (strncmp(parse, DIALOG_XML_FILENAME, strlen(parse)) == 0) 00533 return 0; 00534 return 1; 00535 } 00536 return 0; 00537 } 00538 00565 static void fill_combobox_from_datadir(GtkWidget *combobox, char *active, 00566 uint64 want_none, char *subdir, int (*scandir_filter) ()) 00567 { 00568 int count, i; 00569 GtkTreeModel *model; 00570 gchar *buf; 00571 GtkTreeIter iter; 00572 00573 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combobox)); 00574 count = gtk_tree_model_iter_n_children(model, NULL); 00575 /* 00576 * If count is 0, the combo box control has not been initialized yet, so 00577 * fill it with the appropriate selections now. 00578 */ 00579 if (count == 0) { 00580 char path[MAX_BUF]; 00581 struct dirent **files; 00582 int done_none=0; 00583 00584 snprintf(path, MAX_BUF, "%s/%s", CF_DATADIR, subdir); 00585 00586 count = scandir(path, &files, *scandir_filter, alphasort); 00587 LOG(LOG_DEBUG, "config.c::fill_combobox_from_datadir", 00588 "found %d files in %s\n", count, path); 00589 00590 for (i=0; i<count; i++) { 00591 /* 00592 * If a 'None' entry is desired, and if an entry that falls after 00593 * 'None' is found, and, if 'None' has not already been added, 00594 * insert it now. 00595 */ 00596 if (!done_none && want_none && 00597 strcmp(files[i]->d_name, "None") > 0) { 00598 gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), "None"); 00599 done_none=1; 00600 } 00601 00602 gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), files[i]->d_name); 00603 } 00604 /* Set this for below */ 00605 count = gtk_tree_model_iter_n_children(model, NULL); 00606 } 00607 /* 00608 * The block belows causes the matching combobox item to be selected. Set 00609 * it irregardless of whether this is the first time this is run or not. 00610 */ 00611 for (i=0; i < count; i++) { 00612 if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, i)) { 00613 LOG(LOG_ERROR, "config.c::fill_combobox_from_datadir", 00614 "Unable to get combo box iter\n"); 00615 break; 00616 } 00617 gtk_tree_model_get(model, &iter, 0, &buf, -1); 00618 if (!strcasecmp(active, buf)) { 00619 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), i); 00620 g_free(buf); 00621 break; 00622 } 00623 g_free(buf); 00624 } 00625 } 00626 00627 /* 00628 * Setup_config_window sets the buttons, combos, etc, to the state that matches 00629 * the want_config[] values. 00630 */ 00631 static void setup_config_window(void) 00632 { 00633 int count, i; 00634 GtkTreeModel *model; 00635 gchar *buf; 00636 GtkTreeIter iter; 00637 00638 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_echo), 00639 want_config[CONFIG_ECHO]); 00640 00641 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_fasttcp), 00642 want_config[CONFIG_FASTTCP]); 00643 00644 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_grad_color), 00645 want_config[CONFIG_GRAD_COLOR]); 00646 00647 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_foodbeep), 00648 want_config[CONFIG_FOODBEEP]); 00649 00650 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_sound), 00651 want_config[CONFIG_SOUND]); 00652 00653 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_cache), 00654 want_config[CONFIG_CACHE]); 00655 00656 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_download), 00657 want_config[CONFIG_DOWNLOAD]); 00658 00659 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_fog), 00660 want_config[CONFIG_FOGWAR]); 00661 00662 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_button_smoothing), 00663 want_config[CONFIG_SMOOTH]); 00664 00665 gtk_spin_button_set_value(GTK_SPIN_BUTTON(config_spinbutton_cwindow), 00666 (float)want_config[CONFIG_CWINDOW]); 00667 00668 gtk_spin_button_set_value(GTK_SPIN_BUTTON(config_spinbutton_iconscale), 00669 (float)want_config[CONFIG_ICONSCALE]); 00670 00671 gtk_spin_button_set_value(GTK_SPIN_BUTTON(config_spinbutton_mapscale), 00672 (float)want_config[CONFIG_MAPSCALE]); 00673 00674 gtk_spin_button_set_value(GTK_SPIN_BUTTON(config_spinbutton_mapwidth), 00675 (float)want_config[CONFIG_MAPWIDTH]); 00676 00677 gtk_spin_button_set_value(GTK_SPIN_BUTTON(config_spinbutton_mapheight), 00678 (float)want_config[CONFIG_MAPHEIGHT]); 00679 /* 00680 * Face set combo box setup. 00681 * Remove all the entries currently in the combo box 00682 */ 00683 model = gtk_combo_box_get_model(GTK_COMBO_BOX(config_combobox_faceset)); 00684 count = gtk_tree_model_iter_n_children(model, NULL); 00685 00686 for (i=0; i < count; i++) 00687 gtk_combo_box_remove_text(GTK_COMBO_BOX(config_combobox_faceset), 0); 00688 00689 /* If we have real faceset info from the server, use it */ 00690 if (face_info.have_faceset_info) { 00691 for (i=0; i<MAX_FACE_SETS; i++) 00692 if (face_info.facesets[i].fullname) 00693 gtk_combo_box_append_text(GTK_COMBO_BOX(config_combobox_faceset), 00694 face_info.facesets[i].fullname); 00695 } else { 00696 gtk_combo_box_append_text(GTK_COMBO_BOX(config_combobox_faceset), "Standard"); 00697 gtk_combo_box_append_text(GTK_COMBO_BOX(config_combobox_faceset), "Classic"); 00698 } 00699 count = gtk_tree_model_iter_n_children(model, NULL); 00700 00701 for (i=0; i < count; i++) { 00702 if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, i)) { 00703 LOG(LOG_ERROR, "config.c::setup_config_window", 00704 "Unable to get faceset iter\n"); 00705 break; 00706 } 00707 gtk_tree_model_get(model, &iter, 0, &buf, -1); 00708 00709 if (face_info.want_faceset && !strcasecmp(face_info.want_faceset, buf)) { 00710 gtk_combo_box_set_active(GTK_COMBO_BOX(config_combobox_faceset), i); 00711 g_free(buf); 00712 break; 00713 } 00714 g_free(buf); 00715 } 00716 00717 if (sizeof(display_modes) < want_config[CONFIG_DISPLAYMODE]) { 00718 LOG(LOG_ERROR, "config.c::setup_config_window", 00719 "Player display mode not in display_modes range\n"); 00720 } else { 00721 /* 00722 * We want to set up the boxes to match current settings for things 00723 * like displaymode. 00724 */ 00725 model = gtk_combo_box_get_model(GTK_COMBO_BOX(config_combobox_displaymode)); 00726 count = gtk_tree_model_iter_n_children(model, NULL); 00727 for (i=0; i < count; i++) { 00728 if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, i)) { 00729 LOG(LOG_ERROR, "config.c::setup_config_window", 00730 "Unable to get faceset iter\n"); 00731 break; 00732 } 00733 gtk_tree_model_get(model, &iter, 0, &buf, -1); 00734 if (!strcasecmp(display_modes[want_config[CONFIG_DISPLAYMODE]], buf)) { 00735 gtk_combo_box_set_active(GTK_COMBO_BOX(config_combobox_displaymode), i); 00736 g_free(buf); 00737 break; 00738 } 00739 g_free(buf); 00740 } 00741 } 00742 00743 /* 00744 * We want to set up the boxes to match current settings for things like 00745 * lighting. A bit of a hack to hardcode the strings below. 00746 */ 00747 model = gtk_combo_box_get_model(GTK_COMBO_BOX(config_combobox_lighting)); 00748 count = gtk_tree_model_iter_n_children(model, NULL); 00749 for (i=0; i < count; i++) { 00750 if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, i)) { 00751 LOG(LOG_ERROR, "config.c::setup_config_window", 00752 "Unable to get lighting iter\n"); 00753 break; 00754 } 00755 gtk_tree_model_get(model, &iter, 0, &buf, -1); 00756 if ((want_config[CONFIG_LIGHTING] == CFG_LT_TILE && !strcasecmp(buf, "Per Tile")) || 00757 (want_config[CONFIG_LIGHTING] == CFG_LT_PIXEL && !strcasecmp(buf, "Fast Per Pixel")) || 00758 (want_config[CONFIG_LIGHTING] == CFG_LT_PIXEL_BEST && !strcasecmp(buf, "Best Per Pixel")) || 00759 (want_config[CONFIG_LIGHTING] == CFG_LT_NONE && !strcasecmp(buf, "None"))) { 00760 gtk_combo_box_set_active(GTK_COMBO_BOX(config_combobox_lighting), i); 00761 g_free(buf); 00762 break; 00763 } 00764 g_free(buf); 00765 } 00766 /* 00767 * Use the filenames of files found in the themes subdirectory of the 00768 * crossfire-client data directory as the selectable items in a combo box 00769 * selector control. Specify the current default, and that a "None" entry 00770 * needs to be added also. 00771 */ 00772 fill_combobox_from_datadir(config_combobox_theme, theme, 1, themedir, 00773 &scandir_theme_filter); 00774 /* 00775 * Use the filenames of files found in the glade-gtk subdirectory of the 00776 * crossfire-client data directory as the selectable items in a combo box 00777 * selector control. Specify the current default, and that no "None" entry 00778 * is desired. 00779 */ 00780 fill_combobox_from_datadir(config_combobox_glade, window_xml_file, 0, 00781 gladedir, &scandir_glade_filter); 00782 } 00783 00784 #define IS_DIFFERENT(TYPE) (want_config[TYPE] != use_config[TYPE]) 00785 00791 static void read_config_window(void) 00792 { 00793 gchar *buf; 00794 00795 want_config[CONFIG_ECHO] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_echo)); 00796 want_config[CONFIG_FASTTCP] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_fasttcp)); 00797 want_config[CONFIG_GRAD_COLOR] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_grad_color)); 00798 want_config[CONFIG_FOODBEEP] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_foodbeep)); 00799 want_config[CONFIG_SOUND] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_sound)); 00800 want_config[CONFIG_CACHE] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_cache)); 00801 want_config[CONFIG_DOWNLOAD] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_download)); 00802 want_config[CONFIG_FOGWAR] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_fog)); 00803 want_config[CONFIG_SMOOTH] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_button_smoothing)); 00804 want_config[CONFIG_CWINDOW] = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(config_spinbutton_cwindow)); 00805 want_config[CONFIG_ICONSCALE] = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(config_spinbutton_iconscale)); 00806 want_config[CONFIG_MAPSCALE] = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(config_spinbutton_mapscale)); 00807 want_config[CONFIG_MAPWIDTH] = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(config_spinbutton_mapwidth)); 00808 want_config[CONFIG_MAPHEIGHT] = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(config_spinbutton_mapheight)); 00809 00810 buf = gtk_combo_box_get_active_text(GTK_COMBO_BOX(config_combobox_faceset)); 00811 00812 /* 00813 * We may be able to eliminate the extra strdup/free, but I'm not 100% sure 00814 * that we are guaranteed that glib won't implement them through its 00815 * own/different malloc library. 00816 */ 00817 if (buf) { 00818 free(face_info.want_faceset); 00819 face_info.want_faceset = strdup_local(buf); 00820 g_free(buf); 00821 } 00822 00823 buf = gtk_combo_box_get_active_text(GTK_COMBO_BOX(config_combobox_displaymode)); 00824 if (buf) { 00825 if (!strcasecmp(buf,"OpenGL")) want_config[CONFIG_DISPLAYMODE] = CFG_DM_OPENGL; 00826 else if (!strcasecmp(buf,"SDL")) want_config[CONFIG_DISPLAYMODE] = CFG_DM_SDL; 00827 else if (!strcasecmp(buf,"Pixmap")) want_config[CONFIG_DISPLAYMODE] = CFG_DM_PIXMAP; 00828 g_free(buf); 00829 } 00830 00831 buf = gtk_combo_box_get_active_text(GTK_COMBO_BOX(config_combobox_lighting)); 00832 if (buf) { 00833 if (!strcasecmp(buf, "Per Tile")) want_config[CONFIG_LIGHTING] = CFG_LT_TILE; 00834 else if (!strcasecmp(buf, "Fast Per Pixel")) want_config[CONFIG_LIGHTING] = CFG_LT_PIXEL; 00835 else if (!strcasecmp(buf, "Best Per Pixel")) want_config[CONFIG_LIGHTING] = CFG_LT_PIXEL_BEST; 00836 else if (!strcasecmp(buf, "None")) want_config[CONFIG_LIGHTING] = CFG_LT_NONE; 00837 if (want_config[CONFIG_LIGHTING] != CFG_LT_NONE) { 00838 want_config[CONFIG_DARKNESS] = 1; 00839 use_config[CONFIG_DARKNESS] = 1; 00840 } 00841 00842 g_free(buf); 00843 } 00844 /* 00845 * Load up the theme. A problem is we don't really know if theme has been 00846 * allocated or is just pointing as a static string. So we lose a few 00847 * bytes and just don't free the data. 00848 */ 00849 buf = gtk_combo_box_get_active_text(GTK_COMBO_BOX(config_combobox_theme)); 00850 if (buf) { 00851 if (strcmp(buf, theme)) { 00852 theme = buf; 00853 load_theme(TRUE); 00854 } else { 00855 g_free(buf); 00856 } 00857 } else { 00858 theme = "None"; 00859 } 00860 /* 00861 * Load up the layout and set the combobox control to point to the loaded 00862 * default value. 00863 */ 00864 buf = gtk_combo_box_get_active_text(GTK_COMBO_BOX(config_combobox_glade)); 00865 if (buf && strcmp(buf, window_xml_file)) { 00866 strncpy(window_xml_file, buf, MAX_BUF); 00867 } 00868 /* 00869 * Some values can take effect right now, others not. Code below handles 00870 * these cases - largely grabbed from gtk/config.c 00871 */ 00872 if (IS_DIFFERENT(CONFIG_SOUND)) { 00873 int tmp; 00874 if (want_config[CONFIG_SOUND]) { 00875 tmp = init_sounds(); 00876 if (csocket.fd) 00877 cs_print_string(csocket.fd, "setup sound %d", tmp >= 0); 00878 } else { 00879 if (csocket.fd) 00880 cs_print_string(csocket.fd, "setup sound 0"); 00881 } 00882 use_config[CONFIG_SOUND] = want_config[CONFIG_SOUND]; 00883 } 00884 if (IS_DIFFERENT(CONFIG_FASTTCP)) { 00885 #ifdef TCP_NODELAY 00886 #ifndef WIN32 00887 int q = want_config[CONFIG_FASTTCP]; 00888 00889 if (csocket.fd && setsockopt(csocket.fd, SOL_TCP, TCP_NODELAY, &q, sizeof(q)) == -1) 00890 perror("TCP_NODELAY"); 00891 #else 00892 int q = want_config[CONFIG_FASTTCP]; 00893 00894 if (csocket.fd && setsockopt(csocket.fd, SOL_TCP, TCP_NODELAY, ( const char* )&q, sizeof(q)) == -1) 00895 perror("TCP_NODELAY"); 00896 #endif 00897 #endif 00898 use_config[CONFIG_FASTTCP] = want_config[CONFIG_FASTTCP]; 00899 } 00900 00901 if (IS_DIFFERENT(CONFIG_LIGHTING)) { 00902 #ifdef HAVE_SDL 00903 if (use_config[CONFIG_DISPLAYMODE]==CFG_DM_SDL) 00904 /* This is done to make the 'lightmap' in the proper format */ 00905 init_SDL( NULL, 1); 00906 #endif 00907 } 00908 /* 00909 * Nothing to do, but we can switch immediately without problems. do force 00910 * a redraw 00911 */ 00912 if (IS_DIFFERENT(CONFIG_GRAD_COLOR)) { 00913 use_config[CONFIG_GRAD_COLOR] = want_config[CONFIG_GRAD_COLOR]; 00914 draw_stats(TRUE); 00915 } 00916 } 00917 00925 void 00926 on_config_button_save_clicked (GtkButton *button, 00927 gpointer user_data) 00928 { 00929 read_config_window(); 00930 save_defaults(); 00931 } 00932 00940 void 00941 on_config_button_apply_clicked (GtkButton *button, 00942 gpointer user_data) 00943 { 00944 read_config_window(); 00945 } 00946 00954 void 00955 on_config_button_close_clicked (GtkButton *button, 00956 gpointer user_data) 00957 { 00958 gtk_widget_hide(config_window); 00959 } 00960 00967 void 00968 on_configure_activate (GtkMenuItem *menuitem, 00969 gpointer user_data) 00970 { 00971 gtk_widget_show(config_window); 00972 setup_config_window(); 00973 } 00974 00981 void save_winpos(void) 00982 { 00983 char savename[MAX_BUF]; 00984 char buf[MAX_BUF]; 00985 char *cp; 00986 FILE *save; 00987 int x,y,w,h,wx,wy; 00988 extern GtkWidget *window_root; 00989 GList *pane_list, *list_loop; 00990 GladeXML *xml_tree; 00991 GtkWidget *widget; 00992 00993 /* 00994 * Truncate window_xml_file to remove a .extension if one exists, so that 00995 * the window positions file can be created with a different .extension. 00996 * this helps keep the length of the file name more reasonable. 00997 */ 00998 strncpy(buf, window_xml_file, MAX_BUF); 00999 cp = strrchr(buf, '.'); 01000 if (cp) 01001 cp[0] = 0; 01002 01003 snprintf(savename, sizeof(savename), "%s/.crossfire/%s.pos", getenv("HOME"), buf); 01004 if (!(save = fopen(savename, "w"))) { 01005 snprintf(buf, sizeof(buf), "Cannot open %s - window positions not saved!", savename); 01006 draw_info(buf, NDI_RED); 01007 return; 01008 } 01009 get_window_coord(window_root, &x,&y, &wx,&wy,&w,&h); 01010 fprintf(save,"window_root: +%d+%dx%dx%d\n", wx, wy, w, h); 01011 01012 xml_tree = glade_get_widget_tree(GTK_WIDGET(window_root)); 01013 /* 01014 * Iterate through all widgets whose names begin with hpaned_* and vpaned_* 01015 * to save the widget name and the position of the pane divider. Widgets 01016 * are dynamically found and processed so long as the .glade file designer 01017 * adheres to the naming conventions that Glade Designer uses. 01018 */ 01019 pane_list = glade_xml_get_widget_prefix(xml_tree, "hpaned_"); 01020 for (list_loop = pane_list; list_loop; list_loop = g_list_next(list_loop)) { 01021 widget = list_loop->data; 01022 fprintf(save, "%s: %d\n", glade_get_widget_name(widget), 01023 gtk_paned_get_position(GTK_PANED(widget))); 01024 } 01025 g_list_free(pane_list); 01026 01027 pane_list = glade_xml_get_widget_prefix(xml_tree, "vpaned_"); 01028 for (list_loop = pane_list; list_loop; list_loop = g_list_next(list_loop)) { 01029 widget = list_loop->data; 01030 fprintf(save, "%s: %d\n", glade_get_widget_name(widget), 01031 gtk_paned_get_position(GTK_PANED(widget))); 01032 } 01033 g_list_free(pane_list); 01034 01035 fclose(save); 01036 snprintf(buf, sizeof(buf), "Window positions saved to %s", savename); 01037 draw_info(buf, NDI_BLUE); 01038 } 01039 01047 void 01048 on_save_window_position_activate (GtkMenuItem *menuitem, 01049 gpointer user_data) 01050 { 01051 save_winpos(); 01052 /* 01053 * The following prevents multiple saves per menu activation. 01054 */ 01055 g_signal_stop_emission_by_name(GTK_OBJECT(menuitem), "activate"); 01056 } 01057 01064 void load_window_positions(GtkWidget *window_root) 01065 { 01066 char loadname[MAX_BUF]; 01067 char buf[MAX_BUF]; 01068 char *cp; 01069 GladeXML *xml_tree; 01070 GtkWidget *widget; 01071 FILE *load; 01072 01073 /* 01074 * Truncate window_xml_file to remove a .extension if one exists, so that 01075 * the window positions file can be created with a different .extension. 01076 * this helps keep the length of the file name more reasonable. 01077 */ 01078 strncpy(buf, window_xml_file, MAX_BUF); 01079 cp = strrchr(buf, '.'); 01080 if (cp) 01081 cp[0] = 0; 01082 01083 snprintf(loadname, sizeof(loadname), "%s/.crossfire/%s.pos", getenv("HOME"), buf); 01084 if (!(load = fopen(loadname, "r"))) { 01085 snprintf(buf, sizeof(buf), 01086 "Cannot open %s: Using default window positions.", loadname); 01087 draw_info(buf, NDI_RED); 01088 return; 01089 } 01090 else { 01091 snprintf(buf, sizeof(buf), "Loading window positions from %s", loadname); 01092 draw_info(buf, NDI_RED); 01093 } 01094 01095 xml_tree = glade_get_widget_tree(GTK_WIDGET (window_root)); 01096 01097 while(fgets(buf, MAX_BUF-1, load)!=NULL) { 01098 if ((cp=strchr(buf,':'))!=NULL) { 01099 *cp=0; 01100 cp++; 01101 while(isspace(*cp)) cp++; 01102 01103 if (!strcmp(buf,"window_root")) { 01104 int x,y,w,h; 01105 01106 if (sscanf(cp,"+%d+%dx%dx%d", &x, &y, &w, &h) == 4) { 01107 gtk_window_set_default_size (GTK_WINDOW(window_root), w, h); 01108 gtk_window_move(GTK_WINDOW(window_root), x, y); 01109 01110 } else { 01111 LOG(LOG_ERROR, "config.c::load_window_positions", 01112 "Window size %s corrupt\n", cp); 01113 } 01114 } else if (strstr(buf,"paned_")) { 01115 /* 01116 * The save names are a re-sizeable pane, but check to be sure 01117 * it is a valid widget name if only to prevent sending a 01118 * generic error to stderr if it does not exist in the current 01119 * layout. 01120 */ 01121 widget = glade_xml_get_widget(xml_tree, buf); 01122 if (widget) { 01123 gtk_paned_set_position(GTK_PANED(widget), atoi(cp)); 01124 } else { 01125 LOG(LOG_INFO, "config.c::load_window_positions", "%s in " 01126 "%s not found in this UI layout.\n", buf, loadname); 01127 } 01128 } else { 01129 LOG(LOG_ERROR, "config.c::load_window_positions", 01130 "Found unknown line %s in %s\n", buf, loadname); 01131 } 01132 } 01133 } 01134 fclose(load); 01135 }