1 /***********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <stdarg.h>
19 #include <string.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 
23 /* utility */
24 #include "capability.h"
25 #include "fcintl.h"
26 #include "ioz.h"
27 #include "log.h"
28 #include "mem.h"
29 #include "registry.h"
30 #include "shared.h"
31 #include "string_vector.h"
32 #include "support.h"
33 
34 /* common */
35 #include "events.h"
36 #include "version.h"
37 
38 /* client/agents */
39 #include "cma_fec.h"
40 
41 /* client/include */
42 #include "chatline_g.h"
43 #include "dialogs_g.h"
44 #include "gui_main_g.h"
45 #include "menu_g.h"
46 #include "optiondlg_g.h"
47 #include "repodlgs_g.h"
48 #include "voteinfo_bar_g.h"
49 
50 /* client */
51 #include "audio.h"
52 #include "cityrepdata.h"
53 #include "client_main.h"
54 #include "climisc.h"
55 #include "connectdlg_common.h"
56 #include "global_worklist.h"
57 #include "mapctrl_common.h"
58 #include "mapview_common.h"
59 #include "music.h"
60 #include "overview_common.h"
61 #include "packhand_gen.h"
62 #include "plrdlg_common.h"
63 #include "repodlgs_common.h"
64 #include "servers.h"
65 #include "themes_common.h"
66 #include "tilespec.h"
67 
68 #include "options.h"
69 
70 
71 struct client_options gui_options = {
72 /** Defaults for options normally on command line **/
73 
74   .default_user_name = "\0",
75   .default_server_host = "localhost",
76   .default_server_port = DEFAULT_SOCK_PORT,
77   .default_metaserver = DEFAULT_METASERVER_OPTION,
78   .default_tileset_overhead_name = "\0",
79   .default_tileset_iso_name = "\0",
80   .default_tileset_hex_name = "\0",
81   .default_tileset_isohex_name = "\0",
82   .default_sound_set_name = "stdsounds",
83   .default_music_set_name = "stdmusic",
84   .default_sound_plugin_name = "\0",
85   .default_chat_logfile = GUI_DEFAULT_CHAT_LOGFILE,
86 
87   .save_options_on_exit = TRUE,
88 
89   .use_prev_server = FALSE,
90   .heartbeat_enabled = FALSE,
91 
92 /** Migrations **/
93   .first_boot = FALSE,
94   .default_tileset_name = "\0",
95   .gui_gtk3_22_migrated_from_gtk3 = FALSE,
96   .gui_gtk3_migrated_from_gtk2 = FALSE,
97   .gui_sdl2_migrated_from_sdl = FALSE,
98   .gui_gtk2_migrated_from_2_5 = FALSE,
99   .gui_gtk3_migrated_from_2_5 = FALSE,
100   .gui_qt_migrated_from_2_5 = FALSE,
101 
102   .migrate_fullscreen = FALSE,
103 
104 /** Local Options: **/
105 
106   .solid_color_behind_units = FALSE,
107   .sound_bell_at_new_turn = FALSE,
108   .smooth_move_unit_msec = 30,
109   .smooth_center_slide_msec = 200,
110   .smooth_combat_step_msec = 10,
111   .ai_manual_turn_done = TRUE,
112   .auto_center_on_unit = TRUE,
113   .auto_center_on_automated = TRUE,
114   .auto_center_on_combat = FALSE,
115   .auto_center_each_turn = TRUE,
116   .wakeup_focus = TRUE,
117   .goto_into_unknown = TRUE,
118   .center_when_popup_city = TRUE,
119   .concise_city_production = FALSE,
120   .auto_turn_done = FALSE,
121   .meta_accelerators = TRUE,
122   .ask_city_name = TRUE,
123   .popup_new_cities = TRUE,
124   .popup_actor_arrival = TRUE,
125   .keyboardless_goto = TRUE,
126   .enable_cursor_changes = TRUE,
127   .separate_unit_selection = FALSE,
128   .unit_selection_clears_orders = TRUE,
129   .highlight_our_names = FT_COLOR("#000000", "#FFFF00"),
130 
131   .voteinfo_bar_use = TRUE,
132   .voteinfo_bar_always_show = FALSE,
133   .voteinfo_bar_hide_when_not_player = FALSE,
134   .voteinfo_bar_new_at_front = FALSE,
135 
136   .autoaccept_tileset_suggestion = FALSE,
137   .autoaccept_soundset_suggestion = FALSE,
138   .autoaccept_musicset_suggestion = FALSE,
139 
140   .sound_enable_effects = TRUE,
141   .sound_enable_menu_music = TRUE,
142   .sound_enable_game_music = TRUE,
143 
144 /* This option is currently set by the client - not by the user. */
145   .update_city_text_in_refresh_tile = TRUE,
146 
147   .draw_city_outlines = TRUE,
148   .draw_city_output = FALSE,
149   .draw_map_grid = FALSE,
150   .draw_city_names = TRUE,
151   .draw_city_growth = TRUE,
152   .draw_city_productions = TRUE,
153   .draw_city_buycost = FALSE,
154   .draw_city_trade_routes = FALSE,
155   .draw_terrain = TRUE,
156   .draw_coastline = FALSE,
157   .draw_roads_rails = TRUE,
158   .draw_irrigation = TRUE,
159   .draw_mines = TRUE,
160   .draw_fortress_airbase = TRUE,
161   .draw_specials = TRUE,
162   .draw_huts = TRUE,
163   .draw_pollution = TRUE,
164   .draw_cities = TRUE,
165   .draw_units = TRUE,
166   .draw_focus_unit = FALSE,
167   .draw_fog_of_war = TRUE,
168   .draw_borders = TRUE,
169   .draw_native = FALSE,
170   .draw_full_citybar = TRUE,
171   .draw_unit_shields = TRUE,
172   .player_dlg_show_dead_players = TRUE,
173   .reqtree_show_icons = TRUE,
174   .reqtree_curved_lines = FALSE,
175 
176 /* options for map images */
177 /*  .mapimg_format, */
178   .mapimg_zoom = 2,
179 /* See the definition of MAPIMG_LAYER in mapimg.h. */
180   .mapimg_layer = {
181     FALSE, /* a - MAPIMG_LAYER_AREA */
182     TRUE,  /* b - MAPIMG_LAYER_BORDERS */
183     TRUE,  /* c - MAPIMG_LAYER_CITIES */
184     TRUE,  /* f - MAPIMG_LAYER_FOGOFWAR */
185     TRUE,  /* k - MAPIMG_LAYER_KNOWLEDGE */
186     TRUE,  /* t - MAPIMG_LAYER_TERRAIN */
187     TRUE   /* u - MAPIMG_LAYER_UNITS */
188   },
189 /*  .mapimg_filename, */
190 
191   .zoom_set = FALSE,
192   .zoom_default_level = 1.0,
193 
194 /* gui-gtk-2.0 client specific options. */
195   .gui_gtk2_default_theme_name = FC_GTK2_DEFAULT_THEME_NAME,
196   .gui_gtk2_fullscreen = FALSE,
197   .gui_gtk2_map_scrollbars = FALSE,
198   .gui_gtk2_dialogs_on_top = TRUE,
199   .gui_gtk2_show_task_icons = TRUE,
200   .gui_gtk2_enable_tabs = TRUE,
201   .gui_gtk2_better_fog = TRUE,
202   .gui_gtk2_show_chat_message_time = FALSE,
203   .gui_gtk2_new_messages_go_to_top = FALSE,
204   .gui_gtk2_show_message_window_buttons = TRUE,
205   .gui_gtk2_metaserver_tab_first = FALSE,
206   .gui_gtk2_allied_chat_only = FALSE,
207   .gui_gtk2_message_chat_location = GUI_GTK_MSGCHAT_SEPARATE,
208   .gui_gtk2_small_display_layout = FALSE,
209   .gui_gtk2_mouse_over_map_focus = FALSE,
210   .gui_gtk2_chatline_autocompletion = TRUE,
211   .gui_gtk2_citydlg_xsize = GUI_GTK2_CITYDLG_DEFAULT_XSIZE,
212   .gui_gtk2_citydlg_ysize = GUI_GTK2_CITYDLG_DEFAULT_YSIZE,
213   .gui_gtk2_popup_tech_help = GUI_POPUP_TECH_HELP_RULESET,
214   .gui_gtk2_font_city_label = "Monospace 8",
215   .gui_gtk2_font_notify_label = "Monospace Bold 9",
216   .gui_gtk2_font_spaceship_label = "Monospace 8",
217   .gui_gtk2_font_help_label = "Sans Bold 10",
218   .gui_gtk2_font_help_link = "Sans 9",
219   .gui_gtk2_font_help_text = "Monospace 8",
220   .gui_gtk2_font_chatline = "Monospace 8",
221   .gui_gtk2_font_beta_label = "Sans Italic 10",
222   .gui_gtk2_font_small = "Sans 9",
223   .gui_gtk2_font_comment_label = "Sans Italic 9",
224   .gui_gtk2_font_city_names = "Sans Bold 10",
225   .gui_gtk2_font_city_productions = "Serif 10",
226   .gui_gtk2_font_reqtree_text = "Serif 10",
227 
228 /* gui-gtk-3.0 client specific options. */
229   .gui_gtk3_default_theme_name = FC_GTK3_DEFAULT_THEME_NAME,
230   .gui_gtk3_fullscreen = FALSE,
231   .gui_gtk3_map_scrollbars = FALSE,
232   .gui_gtk3_dialogs_on_top = TRUE,
233   .gui_gtk3_show_task_icons = TRUE,
234   .gui_gtk3_enable_tabs = TRUE,
235   .gui_gtk3_show_chat_message_time = FALSE,
236   .gui_gtk3_new_messages_go_to_top = FALSE,
237   .gui_gtk3_show_message_window_buttons = TRUE,
238   .gui_gtk3_metaserver_tab_first = FALSE,
239   .gui_gtk3_allied_chat_only = FALSE,
240   .gui_gtk3_message_chat_location = GUI_GTK_MSGCHAT_SEPARATE,
241   .gui_gtk3_small_display_layout = FALSE,
242   .gui_gtk3_mouse_over_map_focus = FALSE,
243   .gui_gtk3_chatline_autocompletion = TRUE,
244   .gui_gtk3_citydlg_xsize = GUI_GTK3_CITYDLG_DEFAULT_XSIZE,
245   .gui_gtk3_citydlg_ysize = GUI_GTK3_CITYDLG_DEFAULT_YSIZE,
246   .gui_gtk3_popup_tech_help = GUI_POPUP_TECH_HELP_RULESET,
247   .gui_gtk3_governor_range_min = -20,
248   .gui_gtk3_governor_range_max = 20,
249   .gui_gtk3_font_city_label = "Monospace 8",
250   .gui_gtk3_font_notify_label = "Monospace Bold 9",
251   .gui_gtk3_font_spaceship_label = "Monospace 8",
252   .gui_gtk3_font_help_label = "Sans Bold 10",
253   .gui_gtk3_font_help_link = "Sans 9",
254   .gui_gtk3_font_help_text = "Monospace 8",
255   .gui_gtk3_font_chatline = "Monospace 8",
256   .gui_gtk3_font_beta_label = "Sans Italic 10",
257   .gui_gtk3_font_small = "Sans 9",
258   .gui_gtk3_font_comment_label = "Sans Italic 9",
259   .gui_gtk3_font_city_names = "Sans Bold 10",
260   .gui_gtk3_font_city_productions = "Serif 10",
261   .gui_gtk3_font_reqtree_text = "Serif 10",
262 
263 /* gui-gtk-3.22 client specific options. */
264   .gui_gtk3_22_default_theme_name = FC_GTK3_DEFAULT_THEME_NAME,
265   .gui_gtk3_22_fullscreen = FALSE,
266   .gui_gtk3_22_map_scrollbars = FALSE,
267   .gui_gtk3_22_dialogs_on_top = TRUE,
268   .gui_gtk3_22_show_task_icons = TRUE,
269   .gui_gtk3_22_enable_tabs = TRUE,
270   .gui_gtk3_22_show_chat_message_time = FALSE,
271   .gui_gtk3_22_new_messages_go_to_top = FALSE,
272   .gui_gtk3_22_show_message_window_buttons = TRUE,
273   .gui_gtk3_22_metaserver_tab_first = FALSE,
274   .gui_gtk3_22_allied_chat_only = FALSE,
275   .gui_gtk3_22_message_chat_location = GUI_GTK_MSGCHAT_SEPARATE,
276   .gui_gtk3_22_small_display_layout = FALSE,
277   .gui_gtk3_22_mouse_over_map_focus = FALSE,
278   .gui_gtk3_22_chatline_autocompletion = TRUE,
279   .gui_gtk3_22_citydlg_xsize = GUI_GTK3_CITYDLG_DEFAULT_XSIZE,
280   .gui_gtk3_22_citydlg_ysize = GUI_GTK3_CITYDLG_DEFAULT_YSIZE,
281   .gui_gtk3_22_popup_tech_help = GUI_POPUP_TECH_HELP_RULESET,
282   .gui_gtk3_22_governor_range_min = -20,
283   .gui_gtk3_22_governor_range_max = 20,
284   .gui_gtk3_22_font_city_label = "Monospace 8",
285   .gui_gtk3_22_font_notify_label = "Monospace Bold 9",
286   .gui_gtk3_22_font_spaceship_label = "Monospace 8",
287   .gui_gtk3_22_font_help_label = "Sans Bold 10",
288   .gui_gtk3_22_font_help_link = "Sans 9",
289   .gui_gtk3_22_font_help_text = "Monospace 8",
290   .gui_gtk3_22_font_chatline = "Monospace 8",
291   .gui_gtk3_22_font_beta_label = "Sans Italic 10",
292   .gui_gtk3_22_font_small = "Sans 9",
293   .gui_gtk3_22_font_comment_label = "Sans Italic 9",
294   .gui_gtk3_22_font_city_names = "Sans Bold 10",
295   .gui_gtk3_22_font_city_productions = "Serif 10",
296   .gui_gtk3_22_font_reqtree_text = "Serif 10",
297 
298 /* gui-sdl client specific options. */
299   .gui_sdl_default_theme_name = FC_SDL_DEFAULT_THEME_NAME,
300   .gui_sdl_fullscreen = FALSE,
301   .gui_sdl_screen = VIDEO_MODE(640, 480),
302   .gui_sdl_do_cursor_animation = TRUE,
303   .gui_sdl_use_color_cursors = TRUE,
304 
305 /* gui-sdl2 client specific options. */
306   .gui_sdl2_default_theme_name = FC_SDL2_DEFAULT_THEME_NAME,
307   .gui_sdl2_fullscreen = FALSE,
308   .gui_sdl2_screen = VIDEO_MODE(640, 480),
309   .gui_sdl2_swrenderer = FALSE,
310   .gui_sdl2_do_cursor_animation = TRUE,
311   .gui_sdl2_use_color_cursors = TRUE,
312 
313 /* gui-qt client specific options. */
314   .gui_qt_fullscreen = FALSE,
315   .gui_qt_show_preview = TRUE,
316   .gui_qt_sidebar_left = TRUE,
317   .gui_qt_default_theme_name = FC_QT_DEFAULT_THEME_NAME,
318   .gui_qt_font_city_label = "Monospace,8,-1,5,50,0,0,0,0,0",
319   .gui_qt_font_default = "Sans Serif,10,-1,5,75,0,0,0,0,0",
320   .gui_qt_font_notify_label = "Monospace,8,-1,5,75,0,0,0,0,0",
321   .gui_qt_font_spaceship_label = "Monospace,8,-1,5,50,0,0,0,0,0",
322   .gui_qt_font_help_label = "Sans Serif,9,-1,5,50,0,0,0,0,0",
323   .gui_qt_font_help_link = "Sans Serif,9,-1,5,50,0,0,0,0,0",
324   .gui_qt_font_help_text = "Monospace,8,-1,5,50,0,0,0,0,0",
325   .gui_qt_font_help_title = "Sans Serif,10,-1,5,75,0,0,0,0,0",
326   .gui_qt_font_chatline = "Monospace,8,-1,5,50,0,0,0,0,0",
327   .gui_qt_font_beta_label = "Sans Serif,10,-1,5,50,1,0,0,0,0",
328   .gui_qt_font_small = "Sans Serif,9,-1,5,50,0,0,0,0,0",
329   .gui_qt_font_comment_label = "Sans Serif,9,-1,5,50,1,0,0,0,0",
330   .gui_qt_font_city_names = "Sans Serif,10,-1,5,75,0,0,0,0,0",
331   .gui_qt_font_city_productions = "Sans Serif,10,-1,5,50,1,0,0,0,0",
332   .gui_qt_font_reqtree_text = "Sans Serif,10,-1,5,50,1,0,0,0,0",
333   .gui_qt_show_titlebar = TRUE,
334   .gui_qt_wakeup_text = "Wake up %1"
335 };
336 
337 /* Set to TRUE after the first call to options_init(), to avoid the usage
338  * of non-initialized datas when calling the changed callback. */
339 static bool options_fully_initialized = FALSE;
340 
341 static const struct strvec *get_mapimg_format_list(const struct option *poption);
342 
343 /****************************************************************************
344   Option set structure.
345 ****************************************************************************/
346 struct option_set {
347   struct option * (*option_by_number) (int);
348   struct option * (*option_first) (void);
349 
350   int (*category_number) (void);
351   const char * (*category_name) (int);
352 };
353 
354 /****************************************************************************
355   Returns the option corresponding of the number in this option set.
356 ****************************************************************************/
optset_option_by_number(const struct option_set * poptset,int id)357 struct option *optset_option_by_number(const struct option_set *poptset,
358                                        int id)
359 {
360   fc_assert_ret_val(NULL != poptset, NULL);
361 
362   return poptset->option_by_number(id);
363 }
364 
365 /****************************************************************************
366   Returns the option corresponding of the name in this option set.
367 ****************************************************************************/
optset_option_by_name(const struct option_set * poptset,const char * name)368 struct option *optset_option_by_name(const struct option_set *poptset,
369                                      const char *name)
370 {
371   fc_assert_ret_val(NULL != poptset, NULL);
372 
373   options_iterate(poptset, poption) {
374     if (0 == strcmp(option_name(poption), name)) {
375       return poption;
376     }
377   } options_iterate_end;
378   return NULL;
379 }
380 
381 /****************************************************************************
382   Returns the first option of this option set.
383 ****************************************************************************/
optset_option_first(const struct option_set * poptset)384 struct option *optset_option_first(const struct option_set *poptset)
385 {
386   fc_assert_ret_val(NULL != poptset, NULL);
387 
388   return poptset->option_first();
389 }
390 
391 /****************************************************************************
392   Returns the number of categories of this option set.
393 ****************************************************************************/
optset_category_number(const struct option_set * poptset)394 int optset_category_number(const struct option_set *poptset)
395 {
396   fc_assert_ret_val(NULL != poptset, 0);
397 
398   return poptset->category_number();
399 }
400 
401 /****************************************************************************
402   Returns the name (translated) of the category of this option set.
403 ****************************************************************************/
optset_category_name(const struct option_set * poptset,int category)404 const char *optset_category_name(const struct option_set *poptset,
405                                  int category)
406 {
407   fc_assert_ret_val(NULL != poptset, NULL);
408 
409   return poptset->category_name(category);
410 }
411 
412 
413 /****************************************************************************
414   The base class for options.
415 ****************************************************************************/
416 struct option {
417   /* A link to the option set. */
418   const struct option_set *poptset;
419   /* Type of the option. */
420   enum option_type type;
421 
422   /* Common accessors. */
423   const struct option_common_vtable {
424     int (*number) (const struct option *);
425     const char * (*name) (const struct option *);
426     const char * (*description) (const struct option *);
427     const char * (*help_text) (const struct option *);
428     int (*category) (const struct option *);
429     bool (*is_changeable) (const struct option *);
430     struct option * (*next) (const struct option *);
431   } *common_vtable;
432   /* Specific typed accessors. */
433   union {
434     /* Specific boolean accessors (OT_BOOLEAN == type). */
435     const struct option_bool_vtable {
436       bool (*get) (const struct option *);
437       bool (*def) (const struct option *);
438       bool (*set) (struct option *, bool);
439     } *bool_vtable;
440     /* Specific integer accessors (OT_INTEGER == type). */
441     const struct option_int_vtable {
442       int (*get) (const struct option *);
443       int (*def) (const struct option *);
444       int (*minimum) (const struct option *);
445       int (*maximum) (const struct option *);
446       bool (*set) (struct option *, int);
447     } *int_vtable;
448     /* Specific string accessors (OT_STRING == type). */
449     const struct option_str_vtable {
450       const char * (*get) (const struct option *);
451       const char * (*def) (const struct option *);
452       const struct strvec * (*values) (const struct option *);
453       bool (*set) (struct option *, const char *);
454     } *str_vtable;
455     /* Specific enum accessors (OT_ENUM == type). */
456     const struct option_enum_vtable {
457       int (*get) (const struct option *);
458       int (*def) (const struct option *);
459       const struct strvec * (*values) (const struct option *);
460       bool (*set) (struct option *, int);
461       int (*cmp) (const char *, const char *);
462     } *enum_vtable;
463     /* Specific bitwise accessors (OT_BITWISE == type). */
464     const struct option_bitwise_vtable {
465       unsigned (*get) (const struct option *);
466       unsigned (*def) (const struct option *);
467       const struct strvec * (*values) (const struct option *);
468       bool (*set) (struct option *, unsigned);
469     } *bitwise_vtable;
470     /* Specific font accessors (OT_FONT == type). */
471     const struct option_font_vtable {
472       const char * (*get) (const struct option *);
473       const char * (*def) (const struct option *);
474       const char * (*target) (const struct option *);
475       bool (*set) (struct option *, const char *);
476     } *font_vtable;
477     /* Specific color accessors (OT_COLOR == type). */
478     const struct option_color_vtable {
479       struct ft_color (*get) (const struct option *);
480       struct ft_color (*def) (const struct option *);
481       bool (*set) (struct option *, struct ft_color);
482     } *color_vtable;
483     /* Specific video mode accessors (OT_VIDEO_MODE == type). */
484     const struct option_video_mode_vtable {
485       struct video_mode (*get) (const struct option *);
486       struct video_mode (*def) (const struct option *);
487       bool (*set) (struct option *, struct video_mode);
488     } *video_mode_vtable;
489   };
490 
491   /* Called after the value changed. */
492   void (*changed_callback) (struct option *option);
493 
494   int callback_data;
495 
496   /* Volatile. */
497   void *gui_data;
498 };
499 
500 #define OPTION(poption) ((struct option *) (poption))
501 
502 #define OPTION_INIT(optset, spec_type, spec_table_var, common_table,        \
503                     spec_table, changed_cb, cb_data) {                      \
504   .poptset = optset,                                                        \
505   .type = spec_type,                                                        \
506   .common_vtable = &common_table,                                           \
507   INIT_BRACE_BEGIN                                                          \
508     .spec_table_var = &spec_table                                           \
509   INIT_BRACE_END,                                                           \
510   .changed_callback = changed_cb,                                           \
511   .callback_data = cb_data,                                                 \
512   .gui_data = NULL                                                          \
513 }
514 #define OPTION_BOOL_INIT(optset, common_table, bool_table, changed_cb)      \
515   OPTION_INIT(optset, OT_BOOLEAN, bool_vtable, common_table, bool_table,    \
516               changed_cb, 0)
517 #define OPTION_INT_INIT(optset, common_table, int_table, changed_cb)        \
518   OPTION_INIT(optset, OT_INTEGER, int_vtable, common_table, int_table,      \
519               changed_cb, 0)
520 #define OPTION_STR_INIT(optset, common_table, str_table, changed_cb, cb_data) \
521   OPTION_INIT(optset, OT_STRING, str_vtable, common_table, str_table,       \
522               changed_cb, cb_data)
523 #define OPTION_ENUM_INIT(optset, common_table, enum_table, changed_cb)      \
524   OPTION_INIT(optset, OT_ENUM, enum_vtable, common_table, enum_table,       \
525               changed_cb, 0)
526 #define OPTION_BITWISE_INIT(optset, common_table, bitwise_table,            \
527                             changed_cb)                                     \
528   OPTION_INIT(optset, OT_BITWISE, bitwise_vtable, common_table,             \
529               bitwise_table, changed_cb, 0)
530 #define OPTION_FONT_INIT(optset, common_table, font_table, changed_cb)      \
531   OPTION_INIT(optset, OT_FONT, font_vtable, common_table, font_table,       \
532               changed_cb, 0)
533 #define OPTION_COLOR_INIT(optset, common_table, color_table, changed_cb)    \
534   OPTION_INIT(optset, OT_COLOR, color_vtable, common_table, color_table,    \
535               changed_cb, 0)
536 #define OPTION_VIDEO_MODE_INIT(optset, common_table, video_mode_table,      \
537                                changed_cb)                                  \
538   OPTION_INIT(optset, OT_VIDEO_MODE, video_mode_vtable, common_table,       \
539               video_mode_table, changed_cb, 0)
540 
541 
542 /****************************************************************************
543   Returns the option set owner of this option.
544 ****************************************************************************/
option_optset(const struct option * poption)545 const struct option_set *option_optset(const struct option *poption)
546 {
547   fc_assert_ret_val(NULL != poption, NULL);
548 
549   return poption->poptset;
550 }
551 
552 /****************************************************************************
553   Returns the number of the option.
554 ****************************************************************************/
option_number(const struct option * poption)555 int option_number(const struct option *poption)
556 {
557   fc_assert_ret_val(NULL != poption, -1);
558 
559   return poption->common_vtable->number(poption);
560 }
561 
562 /****************************************************************************
563   Returns the name of the option.
564 ****************************************************************************/
option_name(const struct option * poption)565 const char *option_name(const struct option *poption)
566 {
567   fc_assert_ret_val(NULL != poption, NULL);
568 
569   return poption->common_vtable->name(poption);
570 }
571 
572 /****************************************************************************
573   Returns the description (translated) of the option.
574 ****************************************************************************/
option_description(const struct option * poption)575 const char *option_description(const struct option *poption)
576 {
577   fc_assert_ret_val(NULL != poption, NULL);
578 
579   return poption->common_vtable->description(poption);
580 }
581 
582 /****************************************************************************
583   Returns the help text (translated) of the option.
584 ****************************************************************************/
option_help_text(const struct option * poption)585 const char *option_help_text(const struct option *poption)
586 {
587   fc_assert_ret_val(NULL != poption, NULL);
588 
589   return poption->common_vtable->help_text(poption);
590 }
591 
592 /****************************************************************************
593   Returns the type of the option.
594 ****************************************************************************/
option_type(const struct option * poption)595 enum option_type option_type(const struct option *poption)
596 {
597   fc_assert_ret_val(NULL != poption, -1);
598 
599   return poption->type;
600 }
601 
602 /****************************************************************************
603   Returns the category of the option.
604 ****************************************************************************/
option_category(const struct option * poption)605 int option_category(const struct option *poption)
606 {
607   fc_assert_ret_val(NULL != poption, -1);
608 
609   return poption->common_vtable->category(poption);
610 }
611 
612 /****************************************************************************
613   Returns the name (tranlated) of the category of the option.
614 ****************************************************************************/
option_category_name(const struct option * poption)615 const char *option_category_name(const struct option *poption)
616 {
617   fc_assert_ret_val(NULL != poption, NULL);
618 
619   return optset_category_name(poption->poptset,
620                               poption->common_vtable->category(poption));
621 }
622 
623 /****************************************************************************
624   Returns TRUE if this option can be modified.
625 ****************************************************************************/
option_is_changeable(const struct option * poption)626 bool option_is_changeable(const struct option *poption)
627 {
628   fc_assert_ret_val(NULL != poption, FALSE);
629 
630   return poption->common_vtable->is_changeable(poption);
631 }
632 
633 /****************************************************************************
634   Returns the next option or NULL if this is the last.
635 ****************************************************************************/
option_next(const struct option * poption)636 struct option *option_next(const struct option *poption)
637 {
638   fc_assert_ret_val(NULL != poption, NULL);
639 
640   return poption->common_vtable->next(poption);
641 }
642 
643 /****************************************************************************
644   Set the option to its default value.  Returns TRUE if the option changed.
645 ****************************************************************************/
option_reset(struct option * poption)646 bool option_reset(struct option *poption)
647 {
648   fc_assert_ret_val(NULL != poption, FALSE);
649 
650   switch (option_type(poption)) {
651   case OT_BOOLEAN:
652     return option_bool_set(poption, option_bool_def(poption));
653   case OT_INTEGER:
654     return option_int_set(poption, option_int_def(poption));
655   case OT_STRING:
656     return option_str_set(poption, option_str_def(poption));
657   case OT_ENUM:
658     return option_enum_set_int(poption, option_enum_def_int(poption));
659   case OT_BITWISE:
660     return option_bitwise_set(poption, option_bitwise_def(poption));
661   case OT_FONT:
662     return option_font_set(poption, option_font_def(poption));
663   case OT_COLOR:
664     return option_color_set(poption, option_color_def(poption));
665   case OT_VIDEO_MODE:
666     return option_video_mode_set(poption, option_video_mode_def(poption));
667   }
668   return FALSE;
669 }
670 
671 /****************************************************************************
672   Set the function to call every time this option changes.  Can be NULL.
673 ****************************************************************************/
option_set_changed_callback(struct option * poption,void (* callback)(struct option *))674 void option_set_changed_callback(struct option *poption,
675                                  void (*callback) (struct option *))
676 {
677   fc_assert_ret(NULL != poption);
678 
679   poption->changed_callback = callback;
680 }
681 
682 /****************************************************************************
683   Force to use the option changed callback.
684 ****************************************************************************/
option_changed(struct option * poption)685 void option_changed(struct option *poption)
686 {
687   fc_assert_ret(NULL != poption);
688 
689   if (!options_fully_initialized) {
690     /* Prevent to use non-initialized datas. */
691     return;
692   }
693 
694   if (poption->changed_callback) {
695     poption->changed_callback(poption);
696   }
697 
698   option_gui_update(poption);
699 }
700 
701 /****************************************************************************
702   Set the gui data for this option.
703 ****************************************************************************/
option_set_gui_data(struct option * poption,void * data)704 void option_set_gui_data(struct option *poption, void *data)
705 {
706   fc_assert_ret(NULL != poption);
707 
708   poption->gui_data = data;
709 }
710 
711 /****************************************************************************
712   Returns the gui data of this option.
713 ****************************************************************************/
option_get_gui_data(const struct option * poption)714 void *option_get_gui_data(const struct option *poption)
715 {
716   fc_assert_ret_val(NULL != poption, NULL);
717 
718   return poption->gui_data;
719 }
720 
721 /****************************************************************************
722   Returns the callback data of this option.
723 ****************************************************************************/
option_get_cb_data(const struct option * poption)724 int option_get_cb_data(const struct option *poption)
725 {
726   fc_assert_ret_val(NULL != poption, 0);
727 
728   return poption->callback_data;
729 }
730 
731 /****************************************************************************
732   Returns the current value of this boolean option.
733 ****************************************************************************/
option_bool_get(const struct option * poption)734 bool option_bool_get(const struct option *poption)
735 {
736   fc_assert_ret_val(NULL != poption, FALSE);
737   fc_assert_ret_val(OT_BOOLEAN == poption->type, FALSE);
738 
739   return poption->bool_vtable->get(poption);
740 }
741 
742 /****************************************************************************
743   Returns the default value of this boolean option.
744 ****************************************************************************/
option_bool_def(const struct option * poption)745 bool option_bool_def(const struct option *poption)
746 {
747   fc_assert_ret_val(NULL != poption, FALSE);
748   fc_assert_ret_val(OT_BOOLEAN == poption->type, FALSE);
749 
750   return poption->bool_vtable->def(poption);
751 }
752 
753 /****************************************************************************
754   Sets the value of this boolean option. Returns TRUE if the value changed.
755 ****************************************************************************/
option_bool_set(struct option * poption,bool val)756 bool option_bool_set(struct option *poption, bool val)
757 {
758   fc_assert_ret_val(NULL != poption, FALSE);
759   fc_assert_ret_val(OT_BOOLEAN == poption->type, FALSE);
760 
761   if (poption->bool_vtable->set(poption, val)) {
762     option_changed(poption);
763     return TRUE;
764   }
765   return FALSE;
766 }
767 
768 /****************************************************************************
769   Returns the current value of this integer option.
770 ****************************************************************************/
option_int_get(const struct option * poption)771 int option_int_get(const struct option *poption)
772 {
773   fc_assert_ret_val(NULL != poption, 0);
774   fc_assert_ret_val(OT_INTEGER == poption->type, 0);
775 
776   return poption->int_vtable->get(poption);
777 }
778 
779 /****************************************************************************
780   Returns the default value of this integer option.
781 ****************************************************************************/
option_int_def(const struct option * poption)782 int option_int_def(const struct option *poption)
783 {
784   fc_assert_ret_val(NULL != poption, 0);
785   fc_assert_ret_val(OT_INTEGER == poption->type, 0);
786 
787   return poption->int_vtable->def(poption);
788 }
789 
790 /****************************************************************************
791   Returns the minimal value of this integer option.
792 ****************************************************************************/
option_int_min(const struct option * poption)793 int option_int_min(const struct option *poption)
794 {
795   fc_assert_ret_val(NULL != poption, 0);
796   fc_assert_ret_val(OT_INTEGER == poption->type, 0);
797 
798   return poption->int_vtable->minimum(poption);
799 }
800 
801 /****************************************************************************
802   Returns the maximal value of this integer option.
803 ****************************************************************************/
option_int_max(const struct option * poption)804 int option_int_max(const struct option *poption)
805 {
806   fc_assert_ret_val(NULL != poption, 0);
807   fc_assert_ret_val(OT_INTEGER == poption->type, 0);
808 
809   return poption->int_vtable->maximum(poption);
810 }
811 
812 /****************************************************************************
813   Sets the value of this integer option. Returns TRUE if the value changed.
814 ****************************************************************************/
option_int_set(struct option * poption,int val)815 bool option_int_set(struct option *poption, int val)
816 {
817   fc_assert_ret_val(NULL != poption, FALSE);
818   fc_assert_ret_val(OT_INTEGER == poption->type, FALSE);
819 
820   if (poption->int_vtable->set(poption, val)) {
821     option_changed(poption);
822     return TRUE;
823   }
824   return FALSE;
825 }
826 
827 /****************************************************************************
828   Returns the current value of this string option.
829 ****************************************************************************/
option_str_get(const struct option * poption)830 const char *option_str_get(const struct option *poption)
831 {
832   fc_assert_ret_val(NULL != poption, NULL);
833   fc_assert_ret_val(OT_STRING == poption->type, NULL);
834 
835   return poption->str_vtable->get(poption);
836 }
837 
838 /****************************************************************************
839   Returns the default value of this string option.
840 ****************************************************************************/
option_str_def(const struct option * poption)841 const char *option_str_def(const struct option *poption)
842 {
843   fc_assert_ret_val(NULL != poption, NULL);
844   fc_assert_ret_val(OT_STRING == poption->type, NULL);
845 
846   return poption->str_vtable->def(poption);
847 }
848 
849 /****************************************************************************
850   Returns the possible string values of this string option.
851 ****************************************************************************/
option_str_values(const struct option * poption)852 const struct strvec *option_str_values(const struct option *poption)
853 {
854   fc_assert_ret_val(NULL != poption, NULL);
855   fc_assert_ret_val(OT_STRING == poption->type, NULL);
856 
857   return poption->str_vtable->values(poption);
858 }
859 
860 /****************************************************************************
861   Sets the value of this string option. Returns TRUE if the value changed.
862 ****************************************************************************/
option_str_set(struct option * poption,const char * str)863 bool option_str_set(struct option *poption, const char *str)
864 {
865   fc_assert_ret_val(NULL != poption, FALSE);
866   fc_assert_ret_val(OT_STRING == poption->type, FALSE);
867   fc_assert_ret_val(NULL != str, FALSE);
868 
869   if (poption->str_vtable->set(poption, str)) {
870     option_changed(poption);
871     return TRUE;
872   }
873   return FALSE;
874 }
875 
876 /****************************************************************************
877   Returns the value corresponding to the user-visible (translatable but not
878   translated) string. Returns -1 if not matched.
879 ****************************************************************************/
option_enum_str_to_int(const struct option * poption,const char * str)880 int option_enum_str_to_int(const struct option *poption, const char *str)
881 {
882   const struct strvec *values;
883   int val;
884 
885   fc_assert_ret_val(NULL != poption, -1);
886   fc_assert_ret_val(OT_ENUM == poption->type, -1);
887   values = poption->enum_vtable->values(poption);
888   fc_assert_ret_val(NULL != values, -1);
889 
890   for (val = 0; val < strvec_size(values); val++) {
891     if (0 == poption->enum_vtable->cmp(strvec_get(values, val), str)) {
892       return val;
893     }
894   }
895   return -1;
896 }
897 
898 /****************************************************************************
899   Returns the user-visible (translatable but not translated) string
900   corresponding to the value. Returns NULL on error.
901 ****************************************************************************/
option_enum_int_to_str(const struct option * poption,int val)902 const char *option_enum_int_to_str(const struct option *poption, int val)
903 {
904   const struct strvec *values;
905 
906   fc_assert_ret_val(NULL != poption, NULL);
907   fc_assert_ret_val(OT_ENUM == poption->type, NULL);
908   values = poption->enum_vtable->values(poption);
909   fc_assert_ret_val(NULL != values, NULL);
910 
911   return strvec_get(values, val);
912 }
913 
914 /****************************************************************************
915   Returns the current value of this enum option (as an integer).
916 ****************************************************************************/
option_enum_get_int(const struct option * poption)917 int option_enum_get_int(const struct option *poption)
918 {
919   fc_assert_ret_val(NULL != poption, -1);
920   fc_assert_ret_val(OT_ENUM == poption->type, -1);
921 
922   return poption->enum_vtable->get(poption);
923 }
924 
925 /****************************************************************************
926   Returns the current value of this enum option as a user-visible
927   (translatable but not translated) string.
928 ****************************************************************************/
option_enum_get_str(const struct option * poption)929 const char *option_enum_get_str(const struct option *poption)
930 {
931   fc_assert_ret_val(NULL != poption, NULL);
932   fc_assert_ret_val(OT_ENUM == poption->type, NULL);
933 
934   return strvec_get(poption->enum_vtable->values(poption),
935                     poption->enum_vtable->get(poption));
936 }
937 
938 /****************************************************************************
939   Returns the default value of this enum option (as an integer).
940 ****************************************************************************/
option_enum_def_int(const struct option * poption)941 int option_enum_def_int(const struct option *poption)
942 {
943   fc_assert_ret_val(NULL != poption, -1);
944   fc_assert_ret_val(OT_ENUM == poption->type, -1);
945 
946   return poption->enum_vtable->def(poption);
947 }
948 
949 /****************************************************************************
950   Returns the default value of this enum option as a user-visible
951   (translatable but not translated) string.
952 ****************************************************************************/
option_enum_def_str(const struct option * poption)953 const char *option_enum_def_str(const struct option *poption)
954 {
955   fc_assert_ret_val(NULL != poption, NULL);
956   fc_assert_ret_val(OT_ENUM == poption->type, NULL);
957 
958   return strvec_get(poption->enum_vtable->values(poption),
959                     poption->enum_vtable->def(poption));
960 }
961 
962 /****************************************************************************
963   Returns the possible string values of this enum option, as user-visible
964   (translatable but not translated) strings.
965 ****************************************************************************/
option_enum_values(const struct option * poption)966 const struct strvec *option_enum_values(const struct option *poption)
967 {
968   fc_assert_ret_val(NULL != poption, NULL);
969   fc_assert_ret_val(OT_ENUM == poption->type, NULL);
970 
971   return poption->enum_vtable->values(poption);
972 }
973 
974 /****************************************************************************
975   Sets the value of this enum option. Returns TRUE if the value changed.
976 ****************************************************************************/
option_enum_set_int(struct option * poption,int val)977 bool option_enum_set_int(struct option *poption, int val)
978 {
979   fc_assert_ret_val(NULL != poption, FALSE);
980   fc_assert_ret_val(OT_ENUM == poption->type, FALSE);
981 
982   if (poption->enum_vtable->set(poption, val)) {
983     option_changed(poption);
984     return TRUE;
985   }
986   return FALSE;
987 }
988 
989 /****************************************************************************
990   Sets the value of this enum option from a string, which is matched as a
991   user-visible (translatable but not translated) string. Returns TRUE if the
992   value changed.
993 ****************************************************************************/
option_enum_set_str(struct option * poption,const char * str)994 bool option_enum_set_str(struct option *poption, const char *str)
995 {
996   fc_assert_ret_val(NULL != poption, FALSE);
997   fc_assert_ret_val(OT_ENUM == poption->type, FALSE);
998   fc_assert_ret_val(NULL != str, FALSE);
999 
1000   if (poption->enum_vtable->set(poption,
1001                                 option_enum_str_to_int(poption, str))) {
1002     option_changed(poption);
1003     return TRUE;
1004   }
1005   return FALSE;
1006 }
1007 
1008 /****************************************************************************
1009   Returns the current value of this bitwise option.
1010 ****************************************************************************/
option_bitwise_get(const struct option * poption)1011 unsigned option_bitwise_get(const struct option *poption)
1012 {
1013   fc_assert_ret_val(NULL != poption, 0);
1014   fc_assert_ret_val(OT_BITWISE == poption->type, 0);
1015 
1016   return poption->bitwise_vtable->get(poption);
1017 }
1018 
1019 /****************************************************************************
1020   Returns the default value of this bitwise option.
1021 ****************************************************************************/
option_bitwise_def(const struct option * poption)1022 unsigned option_bitwise_def(const struct option *poption)
1023 {
1024   fc_assert_ret_val(NULL != poption, 0);
1025   fc_assert_ret_val(OT_BITWISE == poption->type, 0);
1026 
1027   return poption->bitwise_vtable->def(poption);
1028 }
1029 
1030 /****************************************************************************
1031   Returns the mask of this bitwise option.
1032 ****************************************************************************/
option_bitwise_mask(const struct option * poption)1033 unsigned option_bitwise_mask(const struct option *poption)
1034 {
1035   const struct strvec *values;
1036 
1037   fc_assert_ret_val(NULL != poption, 0);
1038   fc_assert_ret_val(OT_BITWISE == poption->type, 0);
1039 
1040   values = poption->bitwise_vtable->values(poption);
1041   fc_assert_ret_val(NULL != values, 0);
1042 
1043   return (1 << strvec_size(values)) - 1;
1044 }
1045 
1046 /****************************************************************************
1047   Returns a vector of strings describing every bit of this option, as
1048   user-visible (translatable but not translated) strings.
1049 ****************************************************************************/
option_bitwise_values(const struct option * poption)1050 const struct strvec *option_bitwise_values(const struct option *poption)
1051 {
1052   fc_assert_ret_val(NULL != poption, NULL);
1053   fc_assert_ret_val(OT_BITWISE == poption->type, NULL);
1054 
1055   return poption->bitwise_vtable->values(poption);
1056 }
1057 
1058 /****************************************************************************
1059   Sets the value of this bitwise option. Returns TRUE if the value changed.
1060 ****************************************************************************/
option_bitwise_set(struct option * poption,unsigned val)1061 bool option_bitwise_set(struct option *poption, unsigned val)
1062 {
1063   fc_assert_ret_val(NULL != poption, FALSE);
1064   fc_assert_ret_val(OT_BITWISE == poption->type, FALSE);
1065 
1066   if (0 != (val & ~option_bitwise_mask(poption))
1067       || !poption->bitwise_vtable->set(poption, val)) {
1068     return FALSE;
1069   }
1070 
1071   option_changed(poption);
1072   return TRUE;
1073 }
1074 
1075 /****************************************************************************
1076   Returns the current value of this font option.
1077 ****************************************************************************/
option_font_get(const struct option * poption)1078 const char *option_font_get(const struct option *poption)
1079 {
1080   fc_assert_ret_val(NULL != poption, NULL);
1081   fc_assert_ret_val(OT_FONT == poption->type, NULL);
1082 
1083   return poption->font_vtable->get(poption);
1084 }
1085 
1086 /****************************************************************************
1087   Returns the default value of this font option.
1088 ****************************************************************************/
option_font_def(const struct option * poption)1089 const char *option_font_def(const struct option *poption)
1090 {
1091   fc_assert_ret_val(NULL != poption, NULL);
1092   fc_assert_ret_val(OT_FONT == poption->type, NULL);
1093 
1094   return poption->font_vtable->def(poption);
1095 }
1096 
1097 /****************************************************************************
1098   Returns the target style name of this font option.
1099 ****************************************************************************/
option_font_target(const struct option * poption)1100 const char *option_font_target(const struct option *poption)
1101 {
1102   fc_assert_ret_val(NULL != poption, NULL);
1103   fc_assert_ret_val(OT_FONT == poption->type, NULL);
1104 
1105   return poption->font_vtable->target(poption);
1106 }
1107 
1108 /****************************************************************************
1109   Sets the value of this font option. Returns TRUE if the value changed.
1110 ****************************************************************************/
option_font_set(struct option * poption,const char * font)1111 bool option_font_set(struct option *poption, const char *font)
1112 {
1113   fc_assert_ret_val(NULL != poption, FALSE);
1114   fc_assert_ret_val(OT_FONT == poption->type, FALSE);
1115   fc_assert_ret_val(NULL != font, FALSE);
1116 
1117   if (poption->font_vtable->set(poption, font)) {
1118     option_changed(poption);
1119     return TRUE;
1120   }
1121   return FALSE;
1122 }
1123 
1124 /****************************************************************************
1125   Returns the current value of this color option.
1126 ****************************************************************************/
option_color_get(const struct option * poption)1127 struct ft_color option_color_get(const struct option *poption)
1128 {
1129   fc_assert_ret_val(NULL != poption, ft_color_construct(NULL, NULL));
1130   fc_assert_ret_val(OT_COLOR == poption->type, ft_color_construct(NULL, NULL));
1131 
1132   return poption->color_vtable->get(poption);
1133 }
1134 
1135 /****************************************************************************
1136   Returns the default value of this color option.
1137 ****************************************************************************/
option_color_def(const struct option * poption)1138 struct ft_color option_color_def(const struct option *poption)
1139 {
1140   fc_assert_ret_val(NULL != poption, ft_color_construct(NULL, NULL));
1141   fc_assert_ret_val(OT_COLOR == poption->type, ft_color_construct(NULL, NULL));
1142 
1143   return poption->color_vtable->def(poption);
1144 }
1145 
1146 /****************************************************************************
1147   Sets the value of this color option. Returns TRUE if the value
1148   changed.
1149 ****************************************************************************/
option_color_set(struct option * poption,struct ft_color color)1150 bool option_color_set(struct option *poption, struct ft_color color)
1151 {
1152   fc_assert_ret_val(NULL != poption, FALSE);
1153   fc_assert_ret_val(OT_COLOR == poption->type, FALSE);
1154 
1155   if (poption->color_vtable->set(poption, color)) {
1156     option_changed(poption);
1157     return TRUE;
1158   }
1159   return FALSE;
1160 }
1161 
1162 /****************************************************************************
1163   Returns the current value of this video mode option.
1164 ****************************************************************************/
option_video_mode_get(const struct option * poption)1165 struct video_mode option_video_mode_get(const struct option *poption)
1166 {
1167   fc_assert_ret_val(NULL != poption, video_mode_construct(-1, -1));
1168   fc_assert_ret_val(OT_VIDEO_MODE == poption->type,
1169                     video_mode_construct(-1, -1));
1170 
1171   return poption->video_mode_vtable->get(poption);
1172 }
1173 
1174 /****************************************************************************
1175   Returns the default value of this video mode option.
1176 ****************************************************************************/
option_video_mode_def(const struct option * poption)1177 struct video_mode option_video_mode_def(const struct option *poption)
1178 {
1179   fc_assert_ret_val(NULL != poption, video_mode_construct(-1, -1));
1180   fc_assert_ret_val(OT_VIDEO_MODE == poption->type,
1181                     video_mode_construct(-1, -1));
1182 
1183   return poption->video_mode_vtable->def(poption);
1184 }
1185 
1186 /****************************************************************************
1187   Sets the value of this video mode option. Returns TRUE if the value
1188   changed.
1189 ****************************************************************************/
option_video_mode_set(struct option * poption,struct video_mode mode)1190 bool option_video_mode_set(struct option *poption, struct video_mode mode)
1191 {
1192   fc_assert_ret_val(NULL != poption, FALSE);
1193   fc_assert_ret_val(OT_VIDEO_MODE == poption->type, FALSE);
1194 
1195   if (poption->video_mode_vtable->set(poption, mode)) {
1196     option_changed(poption);
1197     return TRUE;
1198   }
1199   return FALSE;
1200 }
1201 
1202 
1203 /****************************************************************************
1204   Client option set.
1205 ****************************************************************************/
1206 static struct option *client_optset_option_by_number(int id);
1207 static struct option *client_optset_option_first(void);
1208 static int client_optset_category_number(void);
1209 static const char *client_optset_category_name(int category);
1210 
1211 static struct option_set client_optset_static = {
1212   .option_by_number = client_optset_option_by_number,
1213   .option_first = client_optset_option_first,
1214   .category_number = client_optset_category_number,
1215   .category_name = client_optset_category_name
1216 };
1217 const struct option_set *client_optset = &client_optset_static;
1218 
1219 struct copt_val_name {
1220   const char *support;          /* Untranslated long support name, used
1221                                  * for saving. */
1222   const char *pretty;           /* Translated, used to display to the
1223                                  * users. */
1224 };
1225 
1226 /****************************************************************************
1227   Virtuals tables for the client options.
1228 ****************************************************************************/
1229 static int client_option_number(const struct option *poption);
1230 static const char *client_option_name(const struct option *poption);
1231 static const char *client_option_description(const struct option *poption);
1232 static const char *client_option_help_text(const struct option *poption);
1233 static int client_option_category(const struct option *poption);
1234 static bool client_option_is_changeable(const struct option *poption);
1235 static struct option *client_option_next(const struct option *poption);
1236 
1237 static const struct option_common_vtable client_option_common_vtable = {
1238   .number = client_option_number,
1239   .name = client_option_name,
1240   .description = client_option_description,
1241   .help_text = client_option_help_text,
1242   .category = client_option_category,
1243   .is_changeable = client_option_is_changeable,
1244   .next = client_option_next
1245 };
1246 
1247 static bool client_option_bool_get(const struct option *poption);
1248 static bool client_option_bool_def(const struct option *poption);
1249 static bool client_option_bool_set(struct option *poption, bool val);
1250 
1251 static const struct option_bool_vtable client_option_bool_vtable = {
1252   .get = client_option_bool_get,
1253   .def = client_option_bool_def,
1254   .set = client_option_bool_set
1255 };
1256 
1257 static int client_option_int_get(const struct option *poption);
1258 static int client_option_int_def(const struct option *poption);
1259 static int client_option_int_min(const struct option *poption);
1260 static int client_option_int_max(const struct option *poption);
1261 static bool client_option_int_set(struct option *poption, int val);
1262 
1263 static const struct option_int_vtable client_option_int_vtable = {
1264   .get = client_option_int_get,
1265   .def = client_option_int_def,
1266   .minimum = client_option_int_min,
1267   .maximum = client_option_int_max,
1268   .set = client_option_int_set
1269 };
1270 
1271 static const char *client_option_str_get(const struct option *poption);
1272 static const char *client_option_str_def(const struct option *poption);
1273 static const struct strvec *
1274     client_option_str_values(const struct option *poption);
1275 static bool client_option_str_set(struct option *poption, const char *str);
1276 
1277 static const struct option_str_vtable client_option_str_vtable = {
1278   .get = client_option_str_get,
1279   .def = client_option_str_def,
1280   .values = client_option_str_values,
1281   .set = client_option_str_set
1282 };
1283 
1284 static int client_option_enum_get(const struct option *poption);
1285 static int client_option_enum_def(const struct option *poption);
1286 static const struct strvec *
1287     client_option_enum_pretty_names(const struct option *poption);
1288 static bool client_option_enum_set(struct option *poption, int val);
1289 
1290 static const struct option_enum_vtable client_option_enum_vtable = {
1291   .get = client_option_enum_get,
1292   .def = client_option_enum_def,
1293   .values = client_option_enum_pretty_names,
1294   .set = client_option_enum_set,
1295   .cmp = fc_strcasecmp
1296 };
1297 
1298 #if 0 /* There's no bitwise options currently */
1299 static unsigned client_option_bitwise_get(const struct option *poption);
1300 static unsigned client_option_bitwise_def(const struct option *poption);
1301 static const struct strvec *
1302     client_option_bitwise_pretty_names(const struct option *poption);
1303 static bool client_option_bitwise_set(struct option *poption, unsigned val);
1304 
1305 static const struct option_bitwise_vtable client_option_bitwise_vtable = {
1306   .get = client_option_bitwise_get,
1307   .def = client_option_bitwise_def,
1308   .values = client_option_bitwise_pretty_names,
1309   .set = client_option_bitwise_set
1310 };
1311 #endif /* 0 */
1312 
1313 static const char *client_option_font_get(const struct option *poption);
1314 static const char *client_option_font_def(const struct option *poption);
1315 static const char *client_option_font_target(const struct option *poption);
1316 static bool client_option_font_set(struct option *poption, const char *font);
1317 
1318 static const struct option_font_vtable client_option_font_vtable = {
1319   .get = client_option_font_get,
1320   .def = client_option_font_def,
1321   .target = client_option_font_target,
1322   .set = client_option_font_set
1323 };
1324 
1325 static struct ft_color client_option_color_get(const struct option *poption);
1326 static struct ft_color client_option_color_def(const struct option *poption);
1327 static bool client_option_color_set(struct option *poption,
1328                                     struct ft_color color);
1329 
1330 static const struct option_color_vtable client_option_color_vtable = {
1331   .get = client_option_color_get,
1332   .def = client_option_color_def,
1333   .set = client_option_color_set
1334 };
1335 
1336 static struct video_mode
1337 client_option_video_mode_get(const struct option *poption);
1338 static struct video_mode
1339 client_option_video_mode_def(const struct option *poption);
1340 static bool client_option_video_mode_set(struct option *poption,
1341                                          struct video_mode mode);
1342 
1343 static const struct option_video_mode_vtable client_option_video_mode_vtable = {
1344   .get = client_option_video_mode_get,
1345   .def = client_option_video_mode_def,
1346   .set = client_option_video_mode_set
1347 };
1348 
1349 enum client_option_category {
1350   COC_GRAPHICS,
1351   COC_OVERVIEW,
1352   COC_SOUND,
1353   COC_INTERFACE,
1354   COC_MAPIMG,
1355   COC_NETWORK,
1356   COC_FONT,
1357   COC_MAX
1358 };
1359 
1360 /****************************************************************************
1361   Derived class client option, inherinting of base class option.
1362 ****************************************************************************/
1363 struct client_option {
1364   struct option base_option;    /* Base structure, must be the first! */
1365 
1366   const char *name;             /* Short name - used as an identifier */
1367   const char *description;      /* One-line description */
1368   const char *help_text;        /* Paragraph-length help text */
1369   enum client_option_category category;
1370   enum gui_type specific;       /* GUI_STUB for common options. */
1371 
1372   union {
1373     /* OT_BOOLEAN type option. */
1374     struct {
1375       bool *const pvalue;
1376       const bool def;
1377     } boolean;
1378     /* OT_INTEGER type option. */
1379     struct {
1380       int *const pvalue;
1381       const int def, min, max;
1382     } integer;
1383     /* OT_STRING type option. */
1384     struct {
1385       char *const pvalue;
1386       const size_t size;
1387       const char *const def;
1388       /*
1389        * A function to return a string vector of possible string values,
1390        * or NULL for none.
1391        */
1392       const struct strvec *(*const val_accessor) (const struct option *);
1393     } string;
1394     /* OT_ENUM type option. */
1395     struct {
1396       int *const pvalue;
1397       const int def;
1398       struct strvec *support_names, *pretty_names; /* untranslated */
1399       const struct copt_val_name * (*const name_accessor) (int value);
1400     } enumerator;
1401     /* OT_BITWISE type option. */
1402     struct {
1403       unsigned *const pvalue;
1404       const unsigned def;
1405       struct strvec *support_names, *pretty_names; /* untranslated */
1406       const struct copt_val_name * (*const name_accessor) (int value);
1407     } bitwise;
1408     /* OT_FONT type option. */
1409     struct {
1410       char *const pvalue;
1411       const size_t size;
1412       const char *const def;
1413       const char *const target;
1414     } font;
1415     /* OT_COLOR type option. */
1416     struct {
1417       struct ft_color *const pvalue;
1418       const struct ft_color def;
1419     } color;
1420     /* OT_VIDEO_MODE type option. */
1421     struct {
1422       struct video_mode *const pvalue;
1423       const struct video_mode def;
1424     } video_mode;
1425   };
1426 };
1427 
1428 #define CLIENT_OPTION(poption) ((struct client_option *) (poption))
1429 
1430 /*
1431  * Generate a client option of type OT_BOOLEAN.
1432  *
1433  * oname: The option data.  Note it is used as name to be loaded or saved.
1434  *        So, you shouldn't change the name of this variable in any case.
1435  * odesc: A short description of the client option.  Should be used with the
1436  *        N_() macro.
1437  * ohelp: The help text for the client option.  Should be used with the N_()
1438  *        macro.
1439  * ocat:  The client_option_class of this client option.
1440  * ospec: A gui_type enumerator which determin for what particular client
1441  *        gui this option is for. Sets to GUI_STUB for common options.
1442  * odef:  The default value of this client option (FALSE or TRUE).
1443  * ocb:   A callback function of type void (*)(struct option *) called when
1444  *        the option changed.
1445  */
1446 #define GEN_BOOL_OPTION(oname, odesc, ohelp, ocat, ospec, odef, ocb)        \
1447 {                                                                           \
1448   .base_option = OPTION_BOOL_INIT(&client_optset_static,                    \
1449                                   client_option_common_vtable,              \
1450                                   client_option_bool_vtable, ocb),          \
1451   .name = #oname,                                                           \
1452   .description = odesc,                                                     \
1453   .help_text = ohelp,                                                       \
1454   .category = ocat,                                                         \
1455   .specific = ospec,                                                        \
1456   INIT_BRACE_BEGIN                                                          \
1457     .boolean = {                                                            \
1458       .pvalue = &gui_options.oname,                                         \
1459       .def = odef,                                                          \
1460     }                                                                       \
1461   INIT_BRACE_END                                                            \
1462 }
1463 
1464 /*
1465  * Generate a client option of type OT_INTEGER.
1466  *
1467  * oname: The option data.  Note it is used as name to be loaded or saved.
1468  *        So, you shouldn't change the name of this variable in any case.
1469  * odesc: A short description of the client option.  Should be used with the
1470  *        N_() macro.
1471  * ohelp: The help text for the client option.  Should be used with the N_()
1472  *        macro.
1473  * ocat:  The client_option_class of this client option.
1474  * ospec: A gui_type enumerator which determin for what particular client
1475  *        gui this option is for. Sets to GUI_STUB for common options.
1476  * odef:  The default value of this client option.
1477  * omin:  The minimal value of this client option.
1478  * omax:  The maximal value of this client option.
1479  * ocb:   A callback function of type void (*)(struct option *) called when
1480  *        the option changed.
1481  */
1482 #define GEN_INT_OPTION(oname, odesc, ohelp, ocat, ospec, odef, omin, omax, ocb) \
1483 {                                                                           \
1484   .base_option = OPTION_INT_INIT(&client_optset_static,                     \
1485                                  client_option_common_vtable,               \
1486                                  client_option_int_vtable, ocb),            \
1487   .name = #oname,                                                           \
1488   .description = odesc,                                                     \
1489   .help_text = ohelp,                                                       \
1490   .category = ocat,                                                         \
1491   .specific = ospec,                                                        \
1492   INIT_BRACE_BEGIN                                                          \
1493     .integer = {                                                            \
1494       .pvalue = &gui_options.oname,                                         \
1495       .def = odef,                                                          \
1496       .min = omin,                                                          \
1497       .max = omax                                                           \
1498     }                                                                       \
1499   INIT_BRACE_END                                                            \
1500 }
1501 
1502 /*
1503  * Generate a client option of type OT_STRING.
1504  *
1505  * oname: The option data.  Note it is used as name to be loaded or saved.
1506  *        So, you shouldn't change the name of this variable in any case.
1507  *        Be sure to pass the array variable and not a pointer to it because
1508  *        the size is calculated with sizeof().
1509  * odesc: A short description of the client option.  Should be used with the
1510  *        N_() macro.
1511  * ohelp: The help text for the client option.  Should be used with the N_()
1512  *        macro.
1513  * ocat:  The client_option_class of this client option.
1514  * ospec: A gui_type enumerator which determines for what particular client
1515  *        gui this option is for. Set to GUI_STUB for common options.
1516  * odef:  The default string for this client option.
1517  * ocb:   A callback function of type void (*)(struct option *) called when
1518  *        the option changed.
1519  */
1520 #define GEN_STR_OPTION(oname, odesc, ohelp, ocat, ospec, odef, ocb, cbd)    \
1521 {                                                                           \
1522   .base_option = OPTION_STR_INIT(&client_optset_static,                     \
1523                                  client_option_common_vtable,               \
1524                                  client_option_str_vtable, ocb, cbd),       \
1525   .name = #oname,                                                           \
1526   .description = odesc,                                                     \
1527   .help_text = ohelp,                                                       \
1528   .category = ocat,                                                         \
1529   .specific = ospec,                                                        \
1530   INIT_BRACE_BEGIN                                                          \
1531     .string = {                                                             \
1532       .pvalue = gui_options.oname,                                          \
1533       .size = sizeof(gui_options.oname),                                    \
1534       .def = odef,                                                          \
1535       .val_accessor = NULL                                                  \
1536     }                                                                       \
1537   INIT_BRACE_END                                                            \
1538 }
1539 
1540 /*
1541  * Generate a client option of type OT_STRING with a string accessor
1542  * function.
1543  *
1544  * oname: The option data.  Note it is used as name to be loaded or saved.
1545  *        So, you shouldn't change the name of this variable in any case.
1546  *        Be sure to pass the array variable and not a pointer to it because
1547  *        the size is calculated with sizeof().
1548  * odesc: A short description of the client option.  Should be used with the
1549  *        N_() macro.
1550  * ohelp: The help text for the client option.  Should be used with the N_()
1551  *        macro.
1552  * ocat:  The client_option_class of this client option.
1553  * ospec: A gui_type enumerator which determin for what particular client
1554  *        gui this option is for. Sets to GUI_STUB for common options.
1555  * odef:  The default string for this client option.
1556  * oacc:  The string accessor where to find the allowed values of type
1557  *        'const struct strvec * (*) (void)'.
1558  * ocb:   A callback function of type void (*)(struct option *) called when
1559  *        the option changed.
1560  */
1561 #define GEN_STR_LIST_OPTION(oname, odesc, ohelp, ocat, ospec, odef, oacc, ocb, cbd) \
1562 {                                                                           \
1563   .base_option = OPTION_STR_INIT(&client_optset_static,                     \
1564                                  client_option_common_vtable,               \
1565                                  client_option_str_vtable, ocb, cbd),       \
1566   .name = #oname,                                                           \
1567   .description = odesc,                                                     \
1568   .help_text = ohelp,                                                       \
1569   .category = ocat,                                                         \
1570   .specific = ospec,                                                        \
1571   INIT_BRACE_BEGIN                                                          \
1572     .string = {                                                             \
1573       .pvalue = gui_options.oname,                                          \
1574       .size = sizeof(gui_options.oname),                                    \
1575       .def = odef,                                                          \
1576       .val_accessor = oacc                                                  \
1577     }                                                                       \
1578   INIT_BRACE_END                                                            \
1579 }
1580 
1581 /*
1582  * Generate a client option of type OT_ENUM.
1583  *
1584  * oname: The option data.  Note it is used as name to be loaded or saved.
1585  *        So, you shouldn't change the name of this variable in any case.
1586  * odesc: A short description of the client option.  Should be used with the
1587  *        N_() macro.
1588  * ohelp: The help text for the client option.  Should be used with the N_()
1589  *        macro.
1590  * ocat:  The client_option_class of this client option.
1591  * ospec: A gui_type enumerator which determin for what particular client
1592  *        gui this option is for. Sets to GUI_STUB for common options.
1593  * odef:  The default value for this client option.
1594  * oacc:  The name accessor of type 'const struct copt_val_name * (*) (int)'.
1595  * ocb:   A callback function of type void (*) (struct option *) called when
1596  *        the option changed.
1597  */
1598 #define GEN_ENUM_OPTION(oname, odesc, ohelp, ocat, ospec, odef, oacc, ocb)  \
1599 {                                                                           \
1600   .base_option = OPTION_ENUM_INIT(&client_optset_static,                    \
1601                                   client_option_common_vtable,              \
1602                                   client_option_enum_vtable, ocb),          \
1603   .name = #oname,                                                           \
1604   .description = odesc,                                                     \
1605   .help_text = ohelp,                                                       \
1606   .category = ocat,                                                         \
1607   .specific = ospec,                                                        \
1608   INIT_BRACE_BEGIN                                                          \
1609     .enumerator = {                                                         \
1610       .pvalue = (int *) &gui_options.oname,                                 \
1611       .def = odef,                                                          \
1612       .support_names = NULL, /* Set in options_init(). */                   \
1613       .pretty_names  = NULL,                                                \
1614       .name_accessor = oacc                                                 \
1615     }                                                                       \
1616   INIT_BRACE_END                                                            \
1617 }
1618 
1619 /*
1620  * Generate a client option of type OT_BITWISE.
1621  *
1622  * oname: The option data.  Note it is used as name to be loaded or saved.
1623  *        So, you shouldn't change the name of this variable in any case.
1624  * odesc: A short description of the client option.  Should be used with the
1625  *        N_() macro.
1626  * ohelp: The help text for the client option.  Should be used with the N_()
1627  *        macro.
1628  * ocat:  The client_option_class of this client option.
1629  * ospec: A gui_type enumerator which determin for what particular client
1630  *        gui this option is for. Sets to GUI_STUB for common options.
1631  * odef:  The default value for this client option.
1632  * oacc:  The name accessor of type 'const struct copt_val_name * (*) (int)'.
1633  * ocb:   A callback function of type void (*) (struct option *) called when
1634  *        the option changed.
1635  */
1636 #define GEN_BITWISE_OPTION(oname, odesc, ohelp, ocat, ospec, odef, oacc,    \
1637                            ocb)                                             \
1638 {                                                                           \
1639   .base_option = OPTION_BITWISE_INIT(&client_optset_static,                 \
1640                                      client_option_common_vtable,           \
1641                                      client_option_bitwise_vtable, ocb),    \
1642   .name = #oname,                                                           \
1643   .description = odesc,                                                     \
1644   .help_text = ohelp,                                                       \
1645   .category = ocat,                                                         \
1646   .specific = ospec,                                                        \
1647   INIT_BRACE_BEGIN                                                          \
1648     .bitwise = {                                                            \
1649       .pvalue = &gui_options.oname,                                         \
1650       .def = odef,                                                          \
1651       .support_names = NULL, /* Set in options_init(). */                   \
1652       .pretty_names  = NULL,                                                \
1653       .name_accessor = oacc                                                 \
1654     }                                                                       \
1655   INIT_BRACE_END                                                            \
1656 }
1657 
1658 /*
1659  * Generate a client option of type OT_FONT.
1660  *
1661  * oname: The option data.  Note it is used as name to be loaded or saved.
1662  *        So, you shouldn't change the name of this variable in any case.
1663  *        Be sure to pass the array variable and not a pointer to it because
1664  *        the size is calculated with sizeof().
1665  * otgt:  The target widget style.
1666  * odesc: A short description of the client option.  Should be used with the
1667  *        N_() macro.
1668  * ohelp: The help text for the client option.  Should be used with the N_()
1669  *        macro.
1670  * ocat:  The client_option_class of this client option.
1671  * ospec: A gui_type enumerator which determin for what particular client
1672  *        gui this option is for. Sets to GUI_STUB for common options.
1673  * odef:  The default string for this client option.
1674  * ocb:   A callback function of type void (*)(struct option *) called when
1675  *        the option changed.
1676  */
1677 #define GEN_FONT_OPTION(oname, otgt, odesc, ohelp, ocat, ospec, odef, ocb)  \
1678 {                                                                           \
1679   .base_option = OPTION_FONT_INIT(&client_optset_static,                    \
1680                                   client_option_common_vtable,              \
1681                                   client_option_font_vtable, ocb),          \
1682   .name = #oname,                                                           \
1683   .description = odesc,                                                     \
1684   .help_text = ohelp,                                                       \
1685   .category = ocat,                                                         \
1686   .specific = ospec,                                                        \
1687   INIT_BRACE_BEGIN                                                          \
1688     .font = {                                                               \
1689       .pvalue = gui_options.oname,                                          \
1690       .size = sizeof(gui_options.oname),                                    \
1691       .def = odef,                                                          \
1692       .target = otgt,                                                       \
1693     }                                                                       \
1694   INIT_BRACE_END                                                            \
1695 }
1696 
1697 /*
1698  * Generate a client option of type OT_COLOR.
1699  *
1700  * oname: The option data.  Note it is used as name to be loaded or saved.
1701  *        So, you shouldn't change the name of this variable in any case.
1702  * odesc: A short description of the client option.  Should be used with the
1703  *        N_() macro.
1704  * ohelp: The help text for the client option.  Should be used with the N_()
1705  *        macro.
1706  * ocat:  The client_option_class of this client option.
1707  * ospec: A gui_type enumerator which determin for what particular client
1708  *        gui this option is for. Sets to GUI_STUB for common options.
1709  * odef_fg, odef_bg:  The default values for this client option.
1710  * ocb:   A callback function of type void (*)(struct option *) called when
1711  *        the option changed.
1712  */
1713 #define GEN_COLOR_OPTION(oname, odesc, ohelp, ocat, ospec, odef_fg,         \
1714                          odef_bg, ocb)                                      \
1715 {                                                                           \
1716   .base_option = OPTION_COLOR_INIT(&client_optset_static,                   \
1717                                    client_option_common_vtable,             \
1718                                    client_option_color_vtable, ocb),        \
1719   .name = #oname,                                                           \
1720   .description = odesc,                                                     \
1721   .help_text = ohelp,                                                       \
1722   .category = ocat,                                                         \
1723   .specific = ospec,                                                        \
1724   INIT_BRACE_BEGIN                                                          \
1725     .color = {                                                              \
1726       .pvalue = &gui_options.oname,                                         \
1727       .def = FT_COLOR(odef_fg, odef_bg)                                     \
1728     }                                                                       \
1729   INIT_BRACE_END                                                            \
1730 }
1731 
1732 /*
1733  * Generate a client option of type OT_VIDEO_MODE.
1734  *
1735  * oname: The option data.  Note it is used as name to be loaded or saved.
1736  *        So, you shouldn't change the name of this variable in any case.
1737  * odesc: A short description of the client option.  Should be used with the
1738  *        N_() macro.
1739  * ohelp: The help text for the client option.  Should be used with the N_()
1740  *        macro.
1741  * ocat:  The client_option_class of this client option.
1742  * ospec: A gui_type enumerator which determin for what particular client
1743  *        gui this option is for. Sets to GUI_STUB for common options.
1744  * odef_width, odef_height:  The default values for this client option.
1745  * ocb:   A callback function of type void (*)(struct option *) called when
1746  *        the option changed.
1747  */
1748 #define GEN_VIDEO_OPTION(oname, odesc, ohelp, ocat, ospec, odef_width,      \
1749                          odef_height, ocb)                                  \
1750 {                                                                           \
1751   .base_option = OPTION_VIDEO_MODE_INIT(&client_optset_static,              \
1752                                         client_option_common_vtable,        \
1753                                         client_option_video_mode_vtable,    \
1754                                         ocb),                               \
1755   .name = #oname,                                                           \
1756   .description = odesc,                                                     \
1757   .help_text = ohelp,                                                       \
1758   .category = ocat,                                                         \
1759   .specific = ospec,                                                        \
1760   INIT_BRACE_BEGIN                                                          \
1761     .video_mode = {                                                         \
1762       .pvalue = &gui_options.oname,                                         \
1763       .def = VIDEO_MODE(odef_width, odef_height)                            \
1764     }                                                                       \
1765   INIT_BRACE_END                                                            \
1766 }
1767 
1768 /****************************************************************************
1769   Enumerator name accessors.
1770 ****************************************************************************/
1771 
1772 /****************************************************************************
1773   GTK message/chat layout setting names accessor.
1774 ****************************************************************************/
1775 static const struct copt_val_name
gui_gtk_message_chat_location_name(int value)1776   *gui_gtk_message_chat_location_name(int value)
1777 {
1778   /* Order must match enum GUI_GTK_MSGCHAT_* */
1779   static const struct copt_val_name names[] = {
1780     /* TRANS: enum value for 'gui_gtk2/gtk3_message_chat_location' */
1781     { "SPLIT",    N_("Split") },
1782     /* TRANS: enum value for 'gui_gtk2/gtk3_message_chat_location' */
1783     { "SEPARATE", N_("Separate") },
1784     /* TRANS: enum value for 'gui_gtk2/gtk3_message_chat_location' */
1785     { "MERGED",   N_("Merged") }
1786   };
1787 
1788   return (0 <= value && value < ARRAY_SIZE(names)
1789           ? names + value : NULL);
1790 }
1791 
1792 /****************************************************************************
1793   Popup tech help setting names accessor.
1794 ****************************************************************************/
1795 static const struct copt_val_name
gui_popup_tech_help_name(int value)1796   *gui_popup_tech_help_name(int value)
1797 {
1798   /* Order must match enum GUI_POPUP_TECH_HELP_* */
1799   static const struct copt_val_name names[] = {
1800     /* TRANS: enum value for 'gui_popup_tech_help' */
1801     { "ENABLED",   N_("Enabled") },
1802     /* TRANS: enum value for 'gui_popup_tech_help' */
1803     { "DISABLED",  N_("Disabled") },
1804     /* TRANS: enum value for 'gui_popup_tech_help' */
1805     { "RULESET",   N_("Ruleset") }
1806   };
1807 
1808   return (0 <= value && value < ARRAY_SIZE(names)
1809           ? names + value : NULL);
1810 }
1811 
1812 /* Some changed callbacks. */
1813 static void reqtree_show_icons_callback(struct option *poption);
1814 static void view_option_changed_callback(struct option *poption);
1815 static void manual_turn_done_callback(struct option *poption);
1816 static void voteinfo_bar_callback(struct option *poption);
1817 static void font_changed_callback(struct option *poption);
1818 static void mapimg_changed_callback(struct option *poption);
1819 static void game_music_enable_callback(struct option *poption);
1820 static void menu_music_enable_callback(struct option *poption);
1821 
1822 static struct client_option client_options[] = {
1823   GEN_STR_OPTION(default_user_name,
1824                  N_("Login name"),
1825                  N_("This is the default login username that will be used "
1826                     "in the connection dialogs or with the -a command-line "
1827                     "parameter."),
1828                  COC_NETWORK, GUI_STUB, NULL, NULL, 0),
1829   GEN_BOOL_OPTION(use_prev_server, N_("Default to previously used server"),
1830                   N_("Automatically update \"Server\" and \"Server port\" "
1831                      "options to match your latest connection, so by "
1832                      "default you connect to the same server you used "
1833                      "on the previous run. You should enable "
1834                      "saving options on exit too, so that the automatic "
1835                      "updates to the options get saved too."),
1836                   COC_NETWORK, GUI_STUB, FALSE, NULL),
1837   GEN_STR_OPTION(default_server_host,
1838                  N_("Server"),
1839                  N_("This is the default server hostname that will be used "
1840                     "in the connection dialogs or with the -a command-line "
1841                     "parameter."),
1842                  COC_NETWORK, GUI_STUB, "localhost", NULL, 0),
1843   GEN_INT_OPTION(default_server_port,
1844                  N_("Server port"),
1845                  N_("This is the default server port that will be used "
1846                     "in the connection dialogs or with the -a command-line "
1847                     "parameter."),
1848                  COC_NETWORK, GUI_STUB, DEFAULT_SOCK_PORT, 0, 65535, NULL),
1849   GEN_STR_OPTION(default_metaserver,
1850                  N_("Metaserver"),
1851                  N_("The metaserver is a host that the client contacts to "
1852                     "find out about games on the internet.  Don't change "
1853                     "this from its default value unless you know what "
1854                     "you're doing."),
1855                  COC_NETWORK, GUI_STUB, DEFAULT_METASERVER_OPTION, NULL, 0),
1856   GEN_BOOL_OPTION(heartbeat_enabled, N_("Send heartbeat messages to server"),
1857                   N_("Periodically send an empty heartbeat message to the "
1858                      "server to probe whether the connection is still up. "
1859                      "This can help to make it obvious when the server has "
1860                      "cut the connection due to a connectivity outage, if "
1861                      "the client would otherwise sit idle for a long period."),
1862                   COC_NETWORK, GUI_STUB, TRUE, NULL),
1863   GEN_STR_LIST_OPTION(default_sound_set_name,
1864                       N_("Soundset"),
1865                       N_("This is the soundset that will be used.  Changing "
1866                          "this is the same as using the -S command-line "
1867                          "parameter."),
1868                       COC_SOUND, GUI_STUB, "stdsounds", get_soundset_list, NULL, 0),
1869   GEN_STR_LIST_OPTION(default_music_set_name,
1870                       N_("Musicset"),
1871                       N_("This is the musicset that will be used.  Changing "
1872                          "this is the same as using the -m command-line "
1873                          "parameter."),
1874                       COC_SOUND, GUI_STUB, "stdmusic",
1875                       get_musicset_list, musicspec_reread_callback, 0),
1876   GEN_STR_LIST_OPTION(default_sound_plugin_name,
1877                       N_("Sound plugin"),
1878                       N_("If you have a problem with sound, try changing "
1879                          "the sound plugin.  The new plugin won't take "
1880                          "effect until you restart Freeciv.  Changing this "
1881                          "is the same as using the -P command-line option."),
1882                       COC_SOUND, GUI_STUB, NULL, get_soundplugin_list, NULL, 0),
1883   GEN_STR_OPTION(default_chat_logfile,
1884                  N_("The chat log file"),
1885                  N_("The name of the chat log file."),
1886                  COC_INTERFACE, GUI_STUB, GUI_DEFAULT_CHAT_LOGFILE, NULL, 0),
1887   /* gui_gtk2/3_default_theme_name and gui_sdl/2_default_theme_name are
1888    * different settings to avoid client crash after loading the
1889    * style for the other gui.  Keeps 4 different options! */
1890   GEN_STR_LIST_OPTION(gui_gtk2_default_theme_name, N_("Theme"),
1891                       N_("By changing this option you change the "
1892                          "active theme."),
1893                       COC_GRAPHICS, GUI_GTK2, FC_GTK2_DEFAULT_THEME_NAME,
1894                       get_themes_list, theme_reread_callback, 0),
1895   GEN_STR_LIST_OPTION(gui_gtk3_default_theme_name, N_("Theme"),
1896                       N_("By changing this option you change the "
1897                          "active theme."),
1898                       COC_GRAPHICS, GUI_GTK3, FC_GTK3_DEFAULT_THEME_NAME,
1899                       get_themes_list, theme_reread_callback, 0),
1900   GEN_STR_LIST_OPTION(gui_gtk3_22_default_theme_name, N_("Theme"),
1901                       N_("By changing this option you change the "
1902                          "active theme."),
1903                       COC_GRAPHICS, GUI_GTK3_22, FC_GTK3_22_DEFAULT_THEME_NAME,
1904                       get_themes_list, theme_reread_callback, 0),
1905   GEN_STR_LIST_OPTION(gui_sdl_default_theme_name, N_("Theme"),
1906                       N_("By changing this option you change the "
1907                          "active theme."),
1908                       COC_GRAPHICS, GUI_SDL, FC_SDL_DEFAULT_THEME_NAME,
1909                       get_themes_list, theme_reread_callback, 0),
1910   GEN_STR_LIST_OPTION(gui_sdl2_default_theme_name, N_("Theme"),
1911                       N_("By changing this option you change the "
1912                          "active theme."),
1913                       COC_GRAPHICS, GUI_SDL2, FC_SDL2_DEFAULT_THEME_NAME,
1914                       get_themes_list, theme_reread_callback, 0),
1915   GEN_STR_LIST_OPTION(gui_qt_default_theme_name, N_("Theme"),
1916                       N_("By changing this option you change the "
1917                          "active theme."),
1918                       COC_GRAPHICS, GUI_QT, FC_QT_DEFAULT_THEME_NAME,
1919                       get_themes_list, theme_reread_callback, 0),
1920 
1921   /* It's important to give empty string instead of NULL as as default
1922    * value. For NULL value it would default to assigning first value
1923    * from the tileset list returned by get_tileset_list() as default
1924    * tileset. We don't want default tileset assigned at all here, but
1925    * leave it to tilespec code that can handle tileset priority. */
1926   GEN_STR_LIST_OPTION(default_tileset_overhead_name, N_("Tileset (Overhead)"),
1927                       N_("Select the tileset used with Overhead maps. "
1928                          "This may change the currently active tileset, if "
1929                          "you are playing on such a map, in which "
1930                          "case this is the same as using the -t "
1931                          "command-line parameter."),
1932                       COC_GRAPHICS, GUI_STUB, "",
1933                       get_tileset_list, tilespec_reread_callback, 0),
1934   GEN_STR_LIST_OPTION(default_tileset_iso_name, N_("Tileset (Isometric)"),
1935                       N_("Select the tileset used with Isometric maps. "
1936                          "This may change the currently active tileset, if "
1937                          "you are playing on such a map, in which "
1938                          "case this is the same as using the -t "
1939                          "command-line parameter."),
1940                       COC_GRAPHICS, GUI_STUB, "",
1941                       get_tileset_list, tilespec_reread_callback, TF_ISO),
1942   GEN_STR_LIST_OPTION(default_tileset_hex_name, N_("Tileset (Hex)"),
1943                       N_("Select the tileset used with Hex maps. "
1944                          "This may change the currently active tileset, if "
1945                          "you are playing on such a map, in which "
1946                          "case this is the same as using the -t "
1947                          "command-line parameter."),
1948                       COC_GRAPHICS, GUI_STUB, "",
1949                       get_tileset_list, tilespec_reread_callback, TF_HEX),
1950   GEN_STR_LIST_OPTION(default_tileset_isohex_name, N_("Tileset (Iso-Hex)"),
1951                       N_("Select the tileset used with Iso-Hex maps. "
1952                          "This may change the currently active tileset, if "
1953                          "you are playing on such a map, in which "
1954                          "case this is the same as using the -t "
1955                          "command-line parameter."),
1956                       COC_GRAPHICS, GUI_STUB, "",
1957                       get_tileset_list, tilespec_reread_callback, TF_ISO | TF_HEX),
1958 
1959   GEN_BOOL_OPTION(draw_city_outlines, N_("Draw city outlines"),
1960                   N_("Setting this option will draw a line at the city "
1961                      "workable limit."),
1962                   COC_GRAPHICS, GUI_STUB, TRUE,
1963                   view_option_changed_callback),
1964   GEN_BOOL_OPTION(draw_city_output, N_("Draw city output"),
1965                   N_("Setting this option will draw city output for every "
1966                      "citizen."),
1967                   COC_GRAPHICS, GUI_STUB, FALSE,
1968                   view_option_changed_callback),
1969   GEN_BOOL_OPTION(draw_map_grid, N_("Draw the map grid"),
1970                   N_("Setting this option will draw a grid over the map."),
1971                   COC_GRAPHICS, GUI_STUB, FALSE,
1972                   view_option_changed_callback),
1973   GEN_BOOL_OPTION(draw_full_citybar, N_("Draw the city bar"),
1974                   N_("Setting this option will display a 'city bar' "
1975                      "containing useful information beneath each city. "
1976                      "Disabling this option will display only the city's "
1977                      "name and, optionally, production."),
1978                   COC_GRAPHICS, GUI_STUB,
1979                   TRUE, view_option_changed_callback),
1980   GEN_BOOL_OPTION(draw_city_names, N_("Draw the city names"),
1981                   N_("Setting this option will draw the names of the cities "
1982                      "on the map."),
1983                   COC_GRAPHICS, GUI_STUB, TRUE,
1984                   view_option_changed_callback),
1985   GEN_BOOL_OPTION(draw_city_growth, N_("Draw the city growth"),
1986                   N_("Setting this option will draw in how many turns the "
1987                      "cities will grow or shrink."),
1988                   COC_GRAPHICS, GUI_STUB, TRUE,
1989                   view_option_changed_callback),
1990   GEN_BOOL_OPTION(draw_city_productions, N_("Draw the city productions"),
1991                   N_("Setting this option will draw what the cities are "
1992                      "currently building on the map."),
1993                   COC_GRAPHICS, GUI_STUB, TRUE,
1994                   view_option_changed_callback),
1995   GEN_BOOL_OPTION(draw_city_buycost, N_("Draw the city buy costs"),
1996                   N_("Setting this option will draw how much gold is "
1997                      "needed to buy the production of the cities."),
1998                   COC_GRAPHICS, GUI_STUB, FALSE,
1999                   view_option_changed_callback),
2000   GEN_BOOL_OPTION(draw_city_trade_routes, N_("Draw the city trade routes"),
2001                   N_("Setting this option will draw trade route lines "
2002                      "between cities which have trade routes."),
2003                   COC_GRAPHICS, GUI_STUB, FALSE,
2004                   view_option_changed_callback),
2005   GEN_BOOL_OPTION(draw_terrain, N_("Draw the terrain"),
2006                   N_("Setting this option will draw the terrain."),
2007                   COC_GRAPHICS, GUI_STUB, TRUE,
2008                   view_option_changed_callback),
2009   GEN_BOOL_OPTION(draw_coastline, N_("Draw the coast line"),
2010                   N_("Setting this option will draw a line to separate the "
2011                      "land from the ocean."),
2012                   COC_GRAPHICS, GUI_STUB, FALSE,
2013                   view_option_changed_callback),
2014   GEN_BOOL_OPTION(draw_roads_rails, N_("Draw the roads and the railroads"),
2015                   N_("Setting this option will draw the roads and the "
2016                      "railroads on the map."),
2017                   COC_GRAPHICS, GUI_STUB, TRUE,
2018                   view_option_changed_callback),
2019   GEN_BOOL_OPTION(draw_irrigation, N_("Draw the irrigation"),
2020                   N_("Setting this option will draw the irrigation systems "
2021                      "on the map."),
2022                   COC_GRAPHICS, GUI_STUB, TRUE,
2023                   view_option_changed_callback),
2024   GEN_BOOL_OPTION(draw_mines, N_("Draw the mines"),
2025                   N_("Setting this option will draw the mines on the map."),
2026                   COC_GRAPHICS, GUI_STUB, TRUE,
2027                   view_option_changed_callback),
2028   GEN_BOOL_OPTION(draw_fortress_airbase, N_("Draw the bases"),
2029                   N_("Setting this option will draw the bases on the map."),
2030                   COC_GRAPHICS, GUI_STUB, TRUE,
2031                   view_option_changed_callback),
2032   GEN_BOOL_OPTION(draw_specials, N_("Draw the resources"),
2033                   N_("Setting this option will draw the resources on the "
2034                      "map."),
2035                   COC_GRAPHICS, GUI_STUB, TRUE,
2036                   view_option_changed_callback),
2037   GEN_BOOL_OPTION(draw_huts, N_("Draw the huts"),
2038                   N_("Setting this option will draw the huts on the "
2039                      "map."),
2040                   COC_GRAPHICS, GUI_STUB, TRUE,
2041                   view_option_changed_callback),
2042   GEN_BOOL_OPTION(draw_pollution, N_("Draw the pollution/nuclear fallout"),
2043                   N_("Setting this option will draw pollution and "
2044                      "nuclear fallout on the map."),
2045                   COC_GRAPHICS, GUI_STUB, TRUE,
2046                   view_option_changed_callback),
2047   GEN_BOOL_OPTION(draw_cities, N_("Draw the cities"),
2048                   N_("Setting this option will draw the cities on the map."),
2049                   COC_GRAPHICS, GUI_STUB, TRUE,
2050                   view_option_changed_callback),
2051   GEN_BOOL_OPTION(draw_units, N_("Draw the units"),
2052                   N_("Setting this option will draw the units on the map."),
2053                   COC_GRAPHICS, GUI_STUB, TRUE,
2054                   view_option_changed_callback),
2055   GEN_BOOL_OPTION(solid_color_behind_units,
2056                   N_("Solid unit background color"),
2057                   N_("Setting this option will cause units on the map "
2058                      "view to be drawn with a solid background color "
2059                      "instead of the flag backdrop."),
2060                   COC_GRAPHICS, GUI_STUB,
2061                   FALSE, view_option_changed_callback),
2062   GEN_BOOL_OPTION(draw_unit_shields, N_("Draw shield graphics for units"),
2063                   N_("Setting this option will draw a shield icon "
2064                      "as the flags on units.  If unset, the full flag will "
2065                      "be drawn."),
2066                   COC_GRAPHICS, GUI_STUB, TRUE, view_option_changed_callback),
2067   GEN_BOOL_OPTION(draw_focus_unit, N_("Draw the units in focus"),
2068                   N_("Setting this option will cause the currently focused "
2069                      "unit(s) to always be drawn, even if units are not "
2070                      "otherwise being drawn (for instance if 'Draw the units' "
2071                      "is unset)."),
2072                   COC_GRAPHICS, GUI_STUB, FALSE,
2073                   view_option_changed_callback),
2074   GEN_BOOL_OPTION(draw_fog_of_war, N_("Draw the fog of war"),
2075                   N_("Setting this option will draw the fog of war."),
2076                   COC_GRAPHICS, GUI_STUB, TRUE,
2077                   view_option_changed_callback),
2078   GEN_BOOL_OPTION(draw_borders, N_("Draw the borders"),
2079                   N_("Setting this option will draw the national borders."),
2080                   COC_GRAPHICS, GUI_STUB, TRUE,
2081                   view_option_changed_callback),
2082   GEN_BOOL_OPTION(draw_native, N_("Draw whether tiles are native to "
2083                                   "selected unit"),
2084                   N_("Setting this option will highlight tiles that the "
2085                      "currently selected unit cannot enter unaided due to "
2086                      "non-native terrain. (If multiple units are selected, "
2087                      "only tiles that all of them can enter are indicated.)"),
2088                   COC_GRAPHICS, GUI_STUB, FALSE,
2089                   view_option_changed_callback),
2090   GEN_BOOL_OPTION(player_dlg_show_dead_players,
2091                   N_("Show dead players in Nations report"),
2092                   N_("This option controls whether defeated nations are "
2093                      "shown on the Nations report page."),
2094                   COC_GRAPHICS, GUI_STUB, TRUE,
2095                   view_option_changed_callback),
2096   GEN_BOOL_OPTION(sound_bell_at_new_turn, N_("Sound bell at new turn"),
2097                   N_("Set this option to have a \"bell\" event be generated "
2098                      "at the start of a new turn.  You can control the "
2099                      "behavior of the \"bell\" event by editing the message "
2100                      "options."),
2101                   COC_SOUND, GUI_STUB, FALSE, NULL),
2102   GEN_INT_OPTION(smooth_move_unit_msec,
2103                  N_("Unit movement animation time (milliseconds)"),
2104                  N_("This option controls how long unit \"animation\" takes "
2105                     "when a unit moves on the map view.  Set it to 0 to "
2106                     "disable animation entirely."),
2107                  COC_GRAPHICS, GUI_STUB, 30, 0, 2000, NULL),
2108   GEN_INT_OPTION(smooth_center_slide_msec,
2109                  N_("Mapview recentering time (milliseconds)"),
2110                  N_("When the map view is recentered, it will slide "
2111                     "smoothly over the map to its new position.  This "
2112                     "option controls how long this slide lasts.  Set it to "
2113                     "0 to disable mapview sliding entirely."),
2114                  COC_GRAPHICS, GUI_STUB, 200, 0, 5000, NULL),
2115   GEN_INT_OPTION(smooth_combat_step_msec,
2116                  N_("Combat animation step time (milliseconds)"),
2117                  N_("This option controls the speed of combat animation "
2118                     "between units on the mapview.  Set it to 0 to disable "
2119                     "animation entirely."),
2120                  COC_GRAPHICS, GUI_STUB, 10, 0, 100, NULL),
2121   GEN_BOOL_OPTION(reqtree_show_icons,
2122                   N_("Show icons in the technology tree"),
2123                   N_("Setting this option will display icons "
2124                      "on the technology tree diagram. Turning "
2125                      "this option off makes the technology tree "
2126                      "more compact."),
2127                   COC_GRAPHICS, GUI_STUB, TRUE, reqtree_show_icons_callback),
2128   GEN_BOOL_OPTION(reqtree_curved_lines,
2129                   N_("Use curved lines in the technology tree"),
2130                   N_("Setting this option make the technology tree "
2131                      "diagram use curved lines to show technology "
2132                      "relations. Turning this option off causes "
2133                      "the lines to be drawn straight."),
2134                   COC_GRAPHICS, GUI_STUB, FALSE,
2135                   reqtree_show_icons_callback),
2136    GEN_COLOR_OPTION(highlight_our_names,
2137                     N_("Color to highlight your player/user name"),
2138                     N_("If set, your player and user name in the new chat "
2139                        "messages will be highlighted using this color as "
2140                        "background.  If not set, it will just not highlight "
2141                        "anything."),
2142                     COC_GRAPHICS, GUI_STUB, "#000000", "#FFFF00", NULL),
2143   GEN_BOOL_OPTION(ai_manual_turn_done, N_("Manual Turn Done in AI mode"),
2144                   N_("Disable this option if you do not want to "
2145                      "press the Turn Done button manually when watching "
2146                      "an AI player."),
2147                   COC_INTERFACE, GUI_STUB, TRUE, manual_turn_done_callback),
2148   GEN_BOOL_OPTION(auto_center_on_unit, N_("Auto center on units"),
2149                   N_("Set this option to have the active unit centered "
2150                      "automatically when the unit focus changes."),
2151                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2152   GEN_BOOL_OPTION(auto_center_on_automated, N_("Show automated units"),
2153                   N_("Disable this option if you do not want to see "
2154                      "automated units autocentered and animated."),
2155                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2156   GEN_BOOL_OPTION(auto_center_on_combat, N_("Auto center on combat"),
2157                   N_("Set this option to have any combat be centered "
2158                      "automatically.  Disabling this will speed up the time "
2159                      "between turns but may cause you to miss combat "
2160                      "entirely."),
2161                   COC_INTERFACE, GUI_STUB, FALSE, NULL),
2162   GEN_BOOL_OPTION(auto_center_each_turn, N_("Auto center on new turn"),
2163                   N_("Set this option to have the client automatically "
2164                      "recenter the map on a suitable location at the "
2165                      "start of each turn."),
2166                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2167   GEN_BOOL_OPTION(wakeup_focus, N_("Focus on awakened units"),
2168                   N_("Set this option to have newly awoken units be "
2169                      "focused automatically."),
2170                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2171   GEN_BOOL_OPTION(keyboardless_goto, N_("Keyboardless goto"),
2172                   N_("If this option is set then a goto may be initiated "
2173                      "by left-clicking and then holding down the mouse "
2174                      "button while dragging the mouse onto a different "
2175                      "tile."),
2176                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2177   GEN_BOOL_OPTION(goto_into_unknown, N_("Allow goto into the unknown"),
2178                   N_("Setting this option will make the game consider "
2179                      "moving into unknown tiles.  If not, then goto routes "
2180                      "will detour around or be blocked by unknown tiles."),
2181                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2182   GEN_BOOL_OPTION(center_when_popup_city, N_("Center map when popup city"),
2183                   N_("Setting this option makes the mapview center on a "
2184                      "city when its city dialog is popped up."),
2185                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2186   GEN_BOOL_OPTION(concise_city_production, N_("Concise city production"),
2187                   N_("Set this option to make the city production (as shown "
2188                      "in the city dialog) to be more compact."),
2189                   COC_INTERFACE, GUI_STUB, FALSE, NULL),
2190   GEN_BOOL_OPTION(auto_turn_done, N_("End turn when done moving"),
2191                   N_("Setting this option makes your turn end automatically "
2192                      "when all your units are done moving."),
2193                   COC_INTERFACE, GUI_STUB, FALSE, NULL),
2194   GEN_BOOL_OPTION(ask_city_name, N_("Prompt for city names"),
2195                   N_("Disabling this option will make the names of newly "
2196                      "founded cities be chosen automatically by the server."),
2197                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2198   GEN_BOOL_OPTION(popup_new_cities, N_("Pop up city dialog for new cities"),
2199                   N_("Setting this option will pop up a newly-founded "
2200                      "city's city dialog automatically."),
2201                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2202   GEN_BOOL_OPTION(popup_actor_arrival, N_("Pop up caravan and spy actions"),
2203                   N_("If this option is enabled, when a unit arrives at "
2204                      "a city where it can perform an action like "
2205                      "establishing a trade route, helping build a wonder, or "
2206                      "establishing an embassy, a window will pop up asking "
2207                      "which action should be performed. "
2208                      "Disabling this option means you will have to do the "
2209                      "action manually by pressing either 'r' (for a trade "
2210                      "route), 'b' (for building a wonder) or 'd' (for a "
2211                      "spy action) when the unit is in the city."),
2212                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2213   GEN_BOOL_OPTION(enable_cursor_changes, N_("Enable cursor changing"),
2214                   N_("This option controls whether the client should "
2215                      "try to change the mouse cursor depending on what "
2216                      "is being pointed at, as well as to indicate "
2217                      "changes in the client or server state."),
2218                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2219   GEN_BOOL_OPTION(separate_unit_selection, N_("Select cities before units"),
2220                   N_("If this option is enabled, when both cities and "
2221                      "units are present in the selection rectangle, only "
2222                      "cities will be selected. See the help on Controls."),
2223                   COC_INTERFACE, GUI_STUB, FALSE, NULL),
2224   GEN_BOOL_OPTION(unit_selection_clears_orders,
2225                   N_("Clear unit orders on selection"),
2226                   N_("Enabling this option will cause unit orders to be "
2227                      "cleared as soon as one or more units are selected. If "
2228                      "this option is disabled, busy units will not stop "
2229                      "their current activity when selected. Giving them "
2230                      "new orders will clear their current ones; pressing "
2231                      "<space> once will clear their orders and leave them "
2232                      "selected, and pressing <space> a second time will "
2233                      "dismiss them."),
2234                   COC_INTERFACE, GUI_STUB, TRUE, NULL),
2235   GEN_BOOL_OPTION(voteinfo_bar_use, N_("Enable vote bar"),
2236                   N_("If this option is turned on, the vote bar will be "
2237                      "displayed to show vote information."),
2238                   COC_GRAPHICS, GUI_STUB, TRUE, voteinfo_bar_callback),
2239   GEN_BOOL_OPTION(voteinfo_bar_always_show,
2240                   N_("Always display the vote bar"),
2241                   N_("If this option is turned on, the vote bar will never "
2242                      "be hidden, even if there is no running vote."),
2243                   COC_GRAPHICS, GUI_STUB, FALSE, voteinfo_bar_callback),
2244   GEN_BOOL_OPTION(voteinfo_bar_hide_when_not_player,
2245                   N_("Do not show vote bar if not a player"),
2246                   N_("If this option is enabled, the client won't show the "
2247                      "vote bar if you are not a player."),
2248                   COC_GRAPHICS, GUI_STUB, FALSE, voteinfo_bar_callback),
2249   GEN_BOOL_OPTION(voteinfo_bar_new_at_front, N_("Set new votes at front"),
2250                   N_("If this option is enabled, then new votes will go "
2251                      "to the front of the vote list."),
2252                   COC_GRAPHICS, GUI_STUB, FALSE, voteinfo_bar_callback),
2253   GEN_BOOL_OPTION(autoaccept_tileset_suggestion,
2254                   N_("Autoaccept tileset suggestions"),
2255                   N_("If this option is enabled, any tileset suggested by "
2256                      "the ruleset is automatically used; otherwise you "
2257                      "are prompted to change tileset."),
2258                   COC_GRAPHICS, GUI_STUB, FALSE, NULL),
2259 
2260   GEN_BOOL_OPTION(sound_enable_effects,
2261                   N_("Enable sound effects"),
2262                   N_("Play sound effects, assuming there's suitable "
2263                      "sound plugin and soundset with the sounds."),
2264                   COC_SOUND, GUI_STUB, TRUE, NULL),
2265   GEN_BOOL_OPTION(sound_enable_game_music,
2266                   N_("Enable in-game music"),
2267                   N_("Play music during the game, assuming there's suitable "
2268                      "sound plugin and musicset with in-game tracks."),
2269                   COC_SOUND, GUI_STUB, TRUE, game_music_enable_callback),
2270  GEN_BOOL_OPTION(sound_enable_menu_music,
2271                   N_("Enable menu music"),
2272                   N_("Play music while not in actual game, "
2273                      "assuming there's suitable "
2274                      "sound plugin and musicset with menu music tracks."),
2275                   COC_SOUND, GUI_STUB, TRUE, menu_music_enable_callback),
2276   GEN_BOOL_OPTION(autoaccept_soundset_suggestion,
2277                   N_("Autoaccept soundset suggestions"),
2278                   N_("If this option is enabled, any soundset suggested by "
2279                      "the ruleset is automatically used."),
2280                   COC_SOUND, GUI_STUB, FALSE, NULL),
2281   GEN_BOOL_OPTION(autoaccept_musicset_suggestion,
2282                   N_("Autoaccept musicset suggestions"),
2283                   N_("If this option is enabled, any musicset suggested by "
2284                      "the ruleset is automatically used."),
2285                   COC_SOUND, GUI_STUB, FALSE, NULL),
2286 
2287   GEN_BOOL_OPTION(overview.layers[OLAYER_BACKGROUND],
2288                   N_("Background layer"),
2289                   N_("The background layer of the overview shows just "
2290                      "ocean and land."),
2291                   COC_OVERVIEW, GUI_STUB, TRUE, NULL),
2292   GEN_BOOL_OPTION(overview.layers[OLAYER_RELIEF],
2293                   N_("Terrain relief map layer"),
2294                   N_("The relief layer shows all terrains on the map."),
2295                   COC_OVERVIEW, GUI_STUB, FALSE, overview_redraw_callback),
2296   GEN_BOOL_OPTION(overview.layers[OLAYER_BORDERS],
2297                   N_("Borders layer"),
2298                   N_("The borders layer of the overview shows which tiles "
2299                      "are owned by each player."),
2300                   COC_OVERVIEW, GUI_STUB, FALSE, overview_redraw_callback),
2301   GEN_BOOL_OPTION(overview.layers[OLAYER_BORDERS_ON_OCEAN],
2302                   N_("Borders layer on ocean tiles"),
2303                   N_("The borders layer of the overview are drawn on "
2304                      "ocean tiles as well (this may look ugly with many "
2305                      "islands). This option is only of interest if you "
2306                      "have set the option \"Borders layer\" already."),
2307                   COC_OVERVIEW, GUI_STUB, TRUE, overview_redraw_callback),
2308   GEN_BOOL_OPTION(overview.layers[OLAYER_UNITS],
2309                   N_("Units layer"),
2310                   N_("Enabling this will draw units on the overview."),
2311                   COC_OVERVIEW, GUI_STUB, TRUE, overview_redraw_callback),
2312   GEN_BOOL_OPTION(overview.layers[OLAYER_CITIES],
2313                   N_("Cities layer"),
2314                   N_("Enabling this will draw cities on the overview."),
2315                   COC_OVERVIEW, GUI_STUB, TRUE, overview_redraw_callback),
2316   GEN_BOOL_OPTION(overview.fog,
2317                   N_("Overview fog of war"),
2318                   N_("Enabling this will show fog of war on the "
2319                      "overview."),
2320                   COC_OVERVIEW, GUI_STUB, TRUE, overview_redraw_callback),
2321 
2322   /* options for map images */
2323   GEN_STR_LIST_OPTION(mapimg_format,
2324                       N_("Image format"),
2325                       N_("The image toolkit and file format used for "
2326                          "map images."),
2327                       COC_MAPIMG, GUI_STUB, NULL, get_mapimg_format_list,
2328                       NULL, 0),
2329   GEN_INT_OPTION(mapimg_zoom,
2330                  N_("Zoom factor for map images"),
2331                  N_("The magnification used for map images."),
2332                  COC_MAPIMG, GUI_STUB, 2, 1, 5, mapimg_changed_callback),
2333   GEN_BOOL_OPTION(mapimg_layer[MAPIMG_LAYER_AREA],
2334                   N_("Show area within borders"),
2335                   N_("If set, the territory of each nation is shown "
2336                      "on the saved image."),
2337                   COC_MAPIMG, GUI_STUB, FALSE, mapimg_changed_callback),
2338   GEN_BOOL_OPTION(mapimg_layer[MAPIMG_LAYER_BORDERS],
2339                   N_("Show borders"),
2340                   N_("If set, the border of each nation is shown on the "
2341                      "saved image."),
2342                   COC_MAPIMG, GUI_STUB, TRUE, mapimg_changed_callback),
2343   GEN_BOOL_OPTION(mapimg_layer[MAPIMG_LAYER_CITIES],
2344                   N_("Show cities"),
2345                   N_("If set, cities are shown on the saved image."),
2346                   COC_MAPIMG, GUI_STUB, TRUE, mapimg_changed_callback),
2347   GEN_BOOL_OPTION(mapimg_layer[MAPIMG_LAYER_FOGOFWAR],
2348                   N_("Show fog of war"),
2349                   N_("If set, the extent of fog of war is shown on the "
2350                      "saved image."),
2351                   COC_MAPIMG, GUI_STUB, TRUE, mapimg_changed_callback),
2352   GEN_BOOL_OPTION(mapimg_layer[MAPIMG_LAYER_TERRAIN],
2353                   N_("Show full terrain"),
2354                   N_("If set, terrain relief is shown with different colors "
2355                      "in the saved image; otherwise, only land and water are "
2356                      "distinguished."),
2357                   COC_MAPIMG, GUI_STUB, TRUE, mapimg_changed_callback),
2358   GEN_BOOL_OPTION(mapimg_layer[MAPIMG_LAYER_UNITS],
2359                   N_("Show units"),
2360                   N_("If set, units are shown in the saved image."),
2361                   COC_MAPIMG, GUI_STUB, TRUE, mapimg_changed_callback),
2362   GEN_STR_OPTION(mapimg_filename,
2363                  N_("Map image file name"),
2364                  N_("The base part of the filename for saved map images. "
2365                     "A string identifying the game turn and map options will "
2366                     "be appended."),
2367                  COC_MAPIMG, GUI_STUB, GUI_DEFAULT_MAPIMG_FILENAME, NULL, 0),
2368 
2369   /* gui-gtk-2.0 client specific options. */
2370   GEN_BOOL_OPTION(gui_gtk2_fullscreen, N_("Fullscreen"),
2371                   N_("If this option is set the client will use the "
2372                      "whole screen area for drawing."),
2373                   COC_INTERFACE, GUI_GTK2, FALSE, NULL),
2374   GEN_BOOL_OPTION(gui_gtk2_map_scrollbars, N_("Show map scrollbars"),
2375                   N_("Disable this option to hide the scrollbars on the "
2376                      "map view."),
2377                   COC_INTERFACE, GUI_GTK2, FALSE, NULL),
2378   GEN_BOOL_OPTION(gui_gtk2_dialogs_on_top, N_("Keep dialogs on top"),
2379                   N_("If this option is set then dialog windows will always "
2380                      "remain in front of the main Freeciv window. "
2381                      "Disabling this has no effect in fullscreen mode."),
2382                   COC_INTERFACE, GUI_GTK2, TRUE, NULL),
2383   GEN_BOOL_OPTION(gui_gtk2_show_task_icons, N_("Show worklist task icons"),
2384                   N_("Disabling this will turn off the unit and building "
2385                      "icons in the worklist dialog and the production "
2386                      "tab of the city dialog."),
2387                   COC_GRAPHICS, GUI_GTK2, TRUE, NULL),
2388   GEN_BOOL_OPTION(gui_gtk2_enable_tabs, N_("Enable status report tabs"),
2389                   N_("If this option is enabled then report dialogs will "
2390                      "be shown as separate tabs rather than in popup "
2391                      "dialogs."),
2392                   COC_INTERFACE, GUI_GTK2, TRUE, NULL),
2393   GEN_BOOL_OPTION(gui_gtk2_better_fog,
2394                   N_("Better fog-of-war drawing"),
2395                   N_("If this is enabled then a better method is used "
2396                      "for drawing fog-of-war.  It is not any slower but "
2397                      "will consume about twice as much memory."),
2398                   COC_GRAPHICS, GUI_GTK2,
2399                   TRUE, view_option_changed_callback),
2400   GEN_BOOL_OPTION(gui_gtk2_show_chat_message_time,
2401                   N_("Show time for each chat message"),
2402                   N_("If this option is enabled then all chat messages "
2403                      "will be prefixed by a time string of the form "
2404                      "[hour:minute:second]."),
2405                   COC_INTERFACE, GUI_GTK2, FALSE, NULL),
2406   GEN_BOOL_OPTION(gui_gtk2_new_messages_go_to_top,
2407                   N_("New message events go to top of list"),
2408                   N_("If this option is enabled, new events in the "
2409                      "message window will appear at the top of the list, "
2410                      "rather than being appended at the bottom."),
2411                   COC_INTERFACE, GUI_GTK2, FALSE, NULL),
2412   GEN_BOOL_OPTION(gui_gtk2_show_message_window_buttons,
2413                   N_("Show extra message window buttons"),
2414                   N_("If this option is enabled, there will be two "
2415                      "buttons displayed in the message window for "
2416                      "inspecting a city and going to a location. If this "
2417                      "option is disabled, these buttons will not appear "
2418                      "(you can still double-click with the left mouse "
2419                      "button or right-click on a row to inspect or goto "
2420                      "respectively). This option will only take effect "
2421                      "once the message window is closed and reopened."),
2422                   COC_INTERFACE, GUI_GTK2, TRUE, NULL),
2423   GEN_BOOL_OPTION(gui_gtk2_metaserver_tab_first,
2424                   N_("Metaserver tab first in network page"),
2425                   N_("If this option is enabled, the metaserver tab will "
2426                      "be the first notebook tab in the network page. This "
2427                      "option requires a restart in order to take effect."),
2428                   COC_NETWORK, GUI_GTK2, FALSE, NULL),
2429   GEN_BOOL_OPTION(gui_gtk2_allied_chat_only,
2430                   N_("Plain chat messages are sent to allies only"),
2431                   N_("If this option is enabled, then plain messages "
2432                      "typed into the chat entry while the game is "
2433                      "running will only be sent to your allies. "
2434                      "Otherwise plain messages will be sent as "
2435                      "public chat messages. To send a public chat "
2436                      "message with this option enabled, prefix the "
2437                      "message with a single colon ':'. This option "
2438                      "can also be set using a toggle button beside "
2439                      "the chat entry (only visible in multiplayer "
2440                      "games)."),
2441                   COC_INTERFACE, GUI_GTK2, FALSE, NULL),
2442   GEN_ENUM_OPTION(gui_gtk2_message_chat_location,
2443                   N_("Messages and Chat reports location"),
2444                   /* TRANS: The strings used in the UI for 'Split' etc are
2445                    * tagged 'gui_gtk2/gtk3_message_chat_location' */
2446                   N_("Controls where the Messages and Chat reports "
2447                      "appear relative to the main view containing the map.\n"
2448                      "'Split' allows all three to be seen simultaneously, "
2449                      "which is best for multiplayer, but requires a large "
2450                      "window to be usable.\n"
2451                      "'Separate' puts Messages and Chat in a notebook "
2452                      "separate from the main view, so that one of them "
2453                      "can always be seen alongside the main view.\n"
2454                      "'Merged' makes the Messages and Chat reports into "
2455                      "tabs alongside the map and other reports; this "
2456                      "allows a larger map view on small screens.\n"
2457                      "This option requires a restart in order to take "
2458                      "effect."), COC_INTERFACE, GUI_GTK2,
2459                   GUI_GTK_MSGCHAT_SEPARATE,
2460                   gui_gtk_message_chat_location_name, NULL),
2461   GEN_BOOL_OPTION(gui_gtk2_small_display_layout,
2462                   N_("Arrange widgets for small displays"),
2463                   N_("If this option is enabled, widgets in the main "
2464                      "window will be arranged so that they take up the "
2465                      "least amount of total screen space. Specifically, "
2466                      "the left panel containing the overview, player "
2467                      "status, and the unit information box will be "
2468                      "extended over the entire left side of the window. "
2469                      "This option requires a restart in order to take "
2470                      "effect."), COC_INTERFACE, GUI_GTK2, FALSE, NULL),
2471   GEN_BOOL_OPTION(gui_gtk2_mouse_over_map_focus,
2472                   N_("Mouse over the map widget selects it automatically"),
2473                   N_("If this option is enabled, then the map will be "
2474                      "focused when the mouse hovers over it."),
2475                   COC_INTERFACE, GUI_GTK2, FALSE, NULL),
2476   GEN_BOOL_OPTION(gui_gtk2_chatline_autocompletion,
2477                   N_("Player or user name autocompletion"),
2478                   N_("If this option is turned on, the tabulation key "
2479                      "will be used in the chatline to complete the word you "
2480                      "are typing with the name of a player or a user."),
2481                   COC_INTERFACE, GUI_GTK2, TRUE, NULL),
2482   GEN_INT_OPTION(gui_gtk2_citydlg_xsize,
2483                  N_("Width of the city dialog"),
2484                  N_("This value is only used if the width of the city "
2485                     "dialog is saved."),
2486                  COC_INTERFACE, GUI_GTK2, GUI_GTK2_CITYDLG_DEFAULT_XSIZE,
2487                  GUI_GTK2_CITYDLG_MIN_XSIZE, GUI_GTK2_CITYDLG_MAX_XSIZE,
2488                  NULL),
2489   GEN_INT_OPTION(gui_gtk2_citydlg_ysize,
2490                  N_("Height of the city dialog"),
2491                  N_("This value is only used if the height of the city "
2492                     "dialog is saved."),
2493                  COC_INTERFACE, GUI_GTK2, GUI_GTK2_CITYDLG_DEFAULT_YSIZE,
2494                  GUI_GTK2_CITYDLG_MIN_YSIZE, GUI_GTK2_CITYDLG_MAX_YSIZE,
2495                  NULL),
2496   GEN_ENUM_OPTION(gui_gtk2_popup_tech_help,
2497                   N_("Popup tech help when gained"),
2498                   N_("Controls if tech help should be opened when "
2499                      "new tech has been gained.\n"
2500                      "'Ruleset' means that behavior suggested by "
2501                      "current ruleset is used."), COC_INTERFACE, GUI_GTK2,
2502                   GUI_POPUP_TECH_HELP_RULESET,
2503                   gui_popup_tech_help_name, NULL),
2504   GEN_FONT_OPTION(gui_gtk2_font_city_label, "city_label",
2505                   N_("City Label"),
2506                   N_("This font is used to display the city labels on city "
2507                      "dialogs."),
2508                   COC_FONT, GUI_GTK2,
2509                   "Monospace 8", font_changed_callback),
2510   GEN_FONT_OPTION(gui_gtk2_font_notify_label, "notify_label",
2511                   N_("Notify Label"),
2512                   N_("This font is used to display server reports such "
2513                      "as the demographic report or historian publications."),
2514                   COC_FONT, GUI_GTK2,
2515                   "Monospace Bold 9", font_changed_callback),
2516   GEN_FONT_OPTION(gui_gtk2_font_spaceship_label, "spaceship_label",
2517                   N_("Spaceship Label"),
2518                   N_("This font is used to display the spaceship widgets."),
2519                   COC_FONT, GUI_GTK2,
2520                   "Monospace 8", font_changed_callback),
2521   GEN_FONT_OPTION(gui_gtk2_font_help_label, "help_label",
2522                   N_("Help Label"),
2523                   N_("This font is used to display the help headers in the "
2524                      "help window."),
2525                   COC_FONT, GUI_GTK2,
2526                   "Sans Bold 10", font_changed_callback),
2527   GEN_FONT_OPTION(gui_gtk2_font_help_link, "help_link",
2528                   N_("Help Link"),
2529                   N_("This font is used to display the help links in the "
2530                      "help window."),
2531                   COC_FONT, GUI_GTK2,
2532                   "Sans 9", font_changed_callback),
2533   GEN_FONT_OPTION(gui_gtk2_font_help_text, "help_text",
2534                   N_("Help Text"),
2535                   N_("This font is used to display the help body text in "
2536                      "the help window."),
2537                   COC_FONT, GUI_GTK2,
2538                   "Monospace 8", font_changed_callback),
2539   GEN_FONT_OPTION(gui_gtk2_font_chatline, "chatline",
2540                   N_("Chatline Area"),
2541                   N_("This font is used to display the text in the "
2542                      "chatline area."),
2543                   COC_FONT, GUI_GTK2,
2544                   "Monospace 8", font_changed_callback),
2545   GEN_FONT_OPTION(gui_gtk2_font_beta_label, "beta_label",
2546                   N_("Beta Label"),
2547                   N_("This font is used to display the beta label."),
2548                   COC_FONT, GUI_GTK2,
2549                   "Sans Italic 10", font_changed_callback),
2550   GEN_FONT_OPTION(gui_gtk2_font_small, "small_font",
2551                   N_("Small Font"),
2552                   N_("This font is used for any small font request.  For "
2553                      "example, it is used for display the building lists "
2554                      "in the city dialog, the Economy report or the Units "
2555                      "report."),
2556                   COC_FONT, GUI_GTK2,
2557                   "Sans 9", NULL),
2558   GEN_FONT_OPTION(gui_gtk2_font_comment_label, "comment_label",
2559                   N_("Comment Label"),
2560                   N_("This font is used to display comment labels, such as "
2561                      "in the governor page of the city dialogs."),
2562                   COC_FONT, GUI_GTK2,
2563                   "Sans Italic 9", font_changed_callback),
2564   GEN_FONT_OPTION(gui_gtk2_font_city_names, "city_names",
2565                   N_("City Names"),
2566                   N_("This font is used to the display the city names "
2567                      "on the map."),
2568                   COC_FONT, GUI_GTK2,
2569                   "Sans Bold 10", NULL),
2570   GEN_FONT_OPTION(gui_gtk2_font_city_productions, "city_productions",
2571                   N_("City Productions"),
2572                   N_("This font is used to display the city production "
2573                      "on the map."),
2574                   COC_FONT, GUI_GTK2,
2575                   "Serif 10", NULL),
2576   GEN_FONT_OPTION(gui_gtk2_font_reqtree_text, "reqtree_text",
2577                   N_("Requirement Tree"),
2578                   N_("This font is used to the display the requirement tree "
2579                      "in the Research report."),
2580                   COC_FONT, GUI_GTK2,
2581                   "Serif 10", NULL),
2582 
2583   /* gui-gtk-3.0 client specific options. */
2584   GEN_BOOL_OPTION(gui_gtk3_fullscreen, N_("Fullscreen"),
2585                   N_("If this option is set the client will use the "
2586                      "whole screen area for drawing."),
2587                   COC_INTERFACE, GUI_GTK3, FALSE, NULL),
2588   GEN_BOOL_OPTION(gui_gtk3_map_scrollbars, N_("Show map scrollbars"),
2589                   N_("Disable this option to hide the scrollbars on the "
2590                      "map view."),
2591                   COC_INTERFACE, GUI_GTK3, FALSE, NULL),
2592   GEN_BOOL_OPTION(gui_gtk3_dialogs_on_top, N_("Keep dialogs on top"),
2593                   N_("If this option is set then dialog windows will always "
2594                      "remain in front of the main Freeciv window. "
2595                      "Disabling this has no effect in fullscreen mode."),
2596                   COC_INTERFACE, GUI_GTK3, TRUE, NULL),
2597   GEN_BOOL_OPTION(gui_gtk3_show_task_icons, N_("Show worklist task icons"),
2598                   N_("Disabling this will turn off the unit and building "
2599                      "icons in the worklist dialog and the production "
2600                      "tab of the city dialog."),
2601                   COC_GRAPHICS, GUI_GTK3, TRUE, NULL),
2602   GEN_BOOL_OPTION(gui_gtk3_enable_tabs, N_("Enable status report tabs"),
2603                   N_("If this option is enabled then report dialogs will "
2604                      "be shown as separate tabs rather than in popup "
2605                      "dialogs."),
2606                   COC_INTERFACE, GUI_GTK3, TRUE, NULL),
2607   GEN_BOOL_OPTION(gui_gtk3_show_chat_message_time,
2608                   N_("Show time for each chat message"),
2609                   N_("If this option is enabled then all chat messages "
2610                      "will be prefixed by a time string of the form "
2611                      "[hour:minute:second]."),
2612                   COC_INTERFACE, GUI_GTK3, FALSE, NULL),
2613   GEN_BOOL_OPTION(gui_gtk3_new_messages_go_to_top,
2614                   N_("New message events go to top of list"),
2615                   N_("If this option is enabled, new events in the "
2616                      "message window will appear at the top of the list, "
2617                      "rather than being appended at the bottom."),
2618                   COC_INTERFACE, GUI_GTK3, FALSE, NULL),
2619   GEN_BOOL_OPTION(gui_gtk3_show_message_window_buttons,
2620                   N_("Show extra message window buttons"),
2621                   N_("If this option is enabled, there will be two "
2622                      "buttons displayed in the message window for "
2623                      "inspecting a city and going to a location. If this "
2624                      "option is disabled, these buttons will not appear "
2625                      "(you can still double-click with the left mouse "
2626                      "button or right-click on a row to inspect or goto "
2627                      "respectively). This option will only take effect "
2628                      "once the message window is closed and reopened."),
2629                   COC_INTERFACE, GUI_GTK3, TRUE, NULL),
2630   GEN_BOOL_OPTION(gui_gtk3_metaserver_tab_first,
2631                   N_("Metaserver tab first in network page"),
2632                   N_("If this option is enabled, the metaserver tab will "
2633                      "be the first notebook tab in the network page. This "
2634                      "option requires a restart in order to take effect."),
2635                   COC_NETWORK, GUI_GTK3, FALSE, NULL),
2636   GEN_BOOL_OPTION(gui_gtk3_allied_chat_only,
2637                   N_("Plain chat messages are sent to allies only"),
2638                   N_("If this option is enabled, then plain messages "
2639                      "typed into the chat entry while the game is "
2640                      "running will only be sent to your allies. "
2641                      "Otherwise plain messages will be sent as "
2642                      "public chat messages. To send a public chat "
2643                      "message with this option enabled, prefix the "
2644                      "message with a single colon ':'. This option "
2645                      "can also be set using a toggle button beside "
2646                      "the chat entry (only visible in multiplayer "
2647                      "games)."),
2648                   COC_INTERFACE, GUI_GTK3, FALSE, NULL),
2649   GEN_ENUM_OPTION(gui_gtk3_message_chat_location,
2650                   N_("Messages and Chat reports location"),
2651                   /* TRANS: The strings used in the UI for 'Split' etc are
2652                    * tagged 'gui_gtk2/gtk3_message_chat_location' */
2653                   N_("Controls where the Messages and Chat reports "
2654                      "appear relative to the main view containing the map.\n"
2655                      "'Split' allows all three to be seen simultaneously, "
2656                      "which is best for multiplayer, but requires a large "
2657                      "window to be usable.\n"
2658                      "'Separate' puts Messages and Chat in a notebook "
2659                      "separate from the main view, so that one of them "
2660                      "can always be seen alongside the main view.\n"
2661                      "'Merged' makes the Messages and Chat reports into "
2662                      "tabs alongside the map and other reports; this "
2663                      "allows a larger map view on small screens.\n"
2664                      "This option requires a restart in order to take "
2665                      "effect."), COC_INTERFACE, GUI_GTK3,
2666                   GUI_GTK_MSGCHAT_SEPARATE,
2667                   gui_gtk_message_chat_location_name, NULL),
2668   GEN_BOOL_OPTION(gui_gtk3_small_display_layout,
2669                   N_("Arrange widgets for small displays"),
2670                   N_("If this option is enabled, widgets in the main "
2671                      "window will be arranged so that they take up the "
2672                      "least amount of total screen space. Specifically, "
2673                      "the left panel containing the overview, player "
2674                      "status, and the unit information box will be "
2675                      "extended over the entire left side of the window. "
2676                      "This option requires a restart in order to take "
2677                      "effect."), COC_INTERFACE, GUI_GTK3, FALSE, NULL),
2678   GEN_BOOL_OPTION(gui_gtk3_mouse_over_map_focus,
2679                   N_("Mouse over the map widget selects it automatically"),
2680                   N_("If this option is enabled, then the map will be "
2681                      "focused when the mouse hovers over it."),
2682                   COC_INTERFACE, GUI_GTK3, FALSE, NULL),
2683   GEN_BOOL_OPTION(gui_gtk3_chatline_autocompletion,
2684                   N_("Player or user name autocompletion"),
2685                   N_("If this option is turned on, the tabulation key "
2686                      "will be used in the chatline to complete the word you "
2687                      "are typing with the name of a player or a user."),
2688                   COC_INTERFACE, GUI_GTK3, TRUE, NULL),
2689   GEN_INT_OPTION(gui_gtk3_citydlg_xsize,
2690                  N_("Width of the city dialog"),
2691                  N_("This value is only used if the width of the city "
2692                     "dialog is saved."),
2693                  COC_INTERFACE, GUI_GTK3, GUI_GTK3_CITYDLG_DEFAULT_XSIZE,
2694                  GUI_GTK3_CITYDLG_MIN_XSIZE, GUI_GTK3_CITYDLG_MAX_XSIZE,
2695                  NULL),
2696   GEN_INT_OPTION(gui_gtk3_citydlg_ysize,
2697                  N_("Height of the city dialog"),
2698                  N_("This value is only used if the height of the city "
2699                     "dialog is saved."),
2700                  COC_INTERFACE, GUI_GTK3, GUI_GTK3_CITYDLG_DEFAULT_YSIZE,
2701                  GUI_GTK3_CITYDLG_MIN_YSIZE, GUI_GTK3_CITYDLG_MAX_YSIZE,
2702                  NULL),
2703   GEN_ENUM_OPTION(gui_gtk3_popup_tech_help,
2704                   N_("Popup tech help when gained"),
2705                   N_("Controls if tech help should be opened when "
2706                      "new tech has been gained.\n"
2707                      "'Ruleset' means that behavior suggested by "
2708                      "current ruleset is used."), COC_INTERFACE, GUI_GTK3,
2709                   GUI_POPUP_TECH_HELP_RULESET,
2710                   gui_popup_tech_help_name, NULL),
2711   GEN_INT_OPTION(gui_gtk3_governor_range_min,
2712                  N_("Minimum surplus for a governor"),
2713                  N_("The lower limit of the range for requesting surpluses "
2714                     "from the governor."),
2715                  COC_INTERFACE, GUI_GTK3, GUI_GTK3_GOV_RANGE_MIN_DEFAULT,
2716                  GUI_GTK3_GOV_RANGE_MIN_MIN, GUI_GTK3_GOV_RANGE_MIN_MAX,
2717                  NULL),
2718   GEN_INT_OPTION(gui_gtk3_governor_range_max,
2719                  N_("Maximum surplus for a governor"),
2720                  N_("The higher limit of the range for requesting surpluses "
2721                     "from the governor."),
2722                  COC_INTERFACE, GUI_GTK3, GUI_GTK3_GOV_RANGE_MAX_DEFAULT,
2723                  GUI_GTK3_GOV_RANGE_MAX_MIN, GUI_GTK3_GOV_RANGE_MAX_MAX,
2724                  NULL),
2725   GEN_FONT_OPTION(gui_gtk3_font_city_label, "city_label",
2726                   N_("City Label"),
2727                   N_("This font is used to display the city labels on city "
2728                      "dialogs."),
2729                   COC_FONT, GUI_GTK3,
2730                   "Monospace 8", font_changed_callback),
2731   GEN_FONT_OPTION(gui_gtk3_font_notify_label, "notify_label",
2732                   N_("Notify Label"),
2733                   N_("This font is used to display server reports such "
2734                      "as the demographic report or historian publications."),
2735                   COC_FONT, GUI_GTK3,
2736                   "Monospace Bold 9", font_changed_callback),
2737   GEN_FONT_OPTION(gui_gtk3_font_spaceship_label, "spaceship_label",
2738                   N_("Spaceship Label"),
2739                   N_("This font is used to display the spaceship widgets."),
2740                   COC_FONT, GUI_GTK3,
2741                   "Monospace 8", font_changed_callback),
2742   GEN_FONT_OPTION(gui_gtk3_font_help_label, "help_label",
2743                   N_("Help Label"),
2744                   N_("This font is used to display the help headers in the "
2745                      "help window."),
2746                   COC_FONT, GUI_GTK3,
2747                   "Sans Bold 10", font_changed_callback),
2748   GEN_FONT_OPTION(gui_gtk3_font_help_link, "help_link",
2749                   N_("Help Link"),
2750                   N_("This font is used to display the help links in the "
2751                      "help window."),
2752                   COC_FONT, GUI_GTK3,
2753                   "Sans 9", font_changed_callback),
2754   GEN_FONT_OPTION(gui_gtk3_font_help_text, "help_text",
2755                   N_("Help Text"),
2756                   N_("This font is used to display the help body text in "
2757                      "the help window."),
2758                   COC_FONT, GUI_GTK3,
2759                   "Monospace 8", font_changed_callback),
2760   GEN_FONT_OPTION(gui_gtk3_font_chatline, "chatline",
2761                   N_("Chatline Area"),
2762                   N_("This font is used to display the text in the "
2763                      "chatline area."),
2764                   COC_FONT, GUI_GTK3,
2765                   "Monospace 8", font_changed_callback),
2766   GEN_FONT_OPTION(gui_gtk3_font_beta_label, "beta_label",
2767                   N_("Beta Label"),
2768                   N_("This font is used to display the beta label."),
2769                   COC_FONT, GUI_GTK3,
2770                   "Sans Italic 10", font_changed_callback),
2771   GEN_FONT_OPTION(gui_gtk3_font_small, "small_font",
2772                   N_("Small Font"),
2773                   N_("This font is used for any small font request.  For "
2774                      "example, it is used for display the building lists "
2775                      "in the city dialog, the Economy report or the Units "
2776                      "report."),
2777                   COC_FONT, GUI_GTK3,
2778                   "Sans 9", NULL),
2779   GEN_FONT_OPTION(gui_gtk3_font_comment_label, "comment_label",
2780                   N_("Comment Label"),
2781                   N_("This font is used to display comment labels, such as "
2782                      "in the governor page of the city dialogs."),
2783                   COC_FONT, GUI_GTK3,
2784                   "Sans Italic 9", font_changed_callback),
2785   GEN_FONT_OPTION(gui_gtk3_font_city_names, "city_names",
2786                   N_("City Names"),
2787                   N_("This font is used to the display the city names "
2788                      "on the map."),
2789                   COC_FONT, GUI_GTK3,
2790                   "Sans Bold 10", NULL),
2791   GEN_FONT_OPTION(gui_gtk3_font_city_productions, "city_productions",
2792                   N_("City Productions"),
2793                   N_("This font is used to display the city production "
2794                      "on the map."),
2795                   COC_FONT, GUI_GTK3,
2796                   "Serif 10", NULL),
2797   GEN_FONT_OPTION(gui_gtk3_font_reqtree_text, "reqtree_text",
2798                   N_("Requirement Tree"),
2799                   N_("This font is used to the display the requirement tree "
2800                      "in the Research report."),
2801                   COC_FONT, GUI_GTK3,
2802                   "Serif 10", NULL),
2803 
2804   /* gui-gtk-3.22 client specific options. */
2805   GEN_BOOL_OPTION(gui_gtk3_22_fullscreen, N_("Fullscreen"),
2806                   N_("If this option is set the client will use the "
2807                      "whole screen area for drawing."),
2808                   COC_INTERFACE, GUI_GTK3_22, FALSE, NULL),
2809   GEN_BOOL_OPTION(gui_gtk3_22_map_scrollbars, N_("Show map scrollbars"),
2810                   N_("Disable this option to hide the scrollbars on the "
2811                      "map view."),
2812                   COC_INTERFACE, GUI_GTK3_22, FALSE, NULL),
2813   GEN_BOOL_OPTION(gui_gtk3_22_dialogs_on_top, N_("Keep dialogs on top"),
2814                   N_("If this option is set then dialog windows will always "
2815                      "remain in front of the main Freeciv window. "
2816                      "Disabling this has no effect in fullscreen mode."),
2817                   COC_INTERFACE, GUI_GTK3_22, TRUE, NULL),
2818   GEN_BOOL_OPTION(gui_gtk3_22_show_task_icons, N_("Show worklist task icons"),
2819                   N_("Disabling this will turn off the unit and building "
2820                      "icons in the worklist dialog and the production "
2821                      "tab of the city dialog."),
2822                   COC_GRAPHICS, GUI_GTK3_22, TRUE, NULL),
2823   GEN_BOOL_OPTION(gui_gtk3_22_enable_tabs, N_("Enable status report tabs"),
2824                   N_("If this option is enabled then report dialogs will "
2825                      "be shown as separate tabs rather than in popup "
2826                      "dialogs."),
2827                   COC_INTERFACE, GUI_GTK3_22, TRUE, NULL),
2828   GEN_BOOL_OPTION(gui_gtk3_22_show_chat_message_time,
2829                   N_("Show time for each chat message"),
2830                   N_("If this option is enabled then all chat messages "
2831                      "will be prefixed by a time string of the form "
2832                      "[hour:minute:second]."),
2833                   COC_INTERFACE, GUI_GTK3_22, FALSE, NULL),
2834   GEN_BOOL_OPTION(gui_gtk3_22_new_messages_go_to_top,
2835                   N_("New message events go to top of list"),
2836                   N_("If this option is enabled, new events in the "
2837                      "message window will appear at the top of the list, "
2838                      "rather than being appended at the bottom."),
2839                   COC_INTERFACE, GUI_GTK3_22, FALSE, NULL),
2840   GEN_BOOL_OPTION(gui_gtk3_22_show_message_window_buttons,
2841                   N_("Show extra message window buttons"),
2842                   N_("If this option is enabled, there will be two "
2843                      "buttons displayed in the message window for "
2844                      "inspecting a city and going to a location. If this "
2845                      "option is disabled, these buttons will not appear "
2846                      "(you can still double-click with the left mouse "
2847                      "button or right-click on a row to inspect or goto "
2848                      "respectively). This option will only take effect "
2849                      "once the message window is closed and reopened."),
2850                   COC_INTERFACE, GUI_GTK3_22, TRUE, NULL),
2851   GEN_BOOL_OPTION(gui_gtk3_22_metaserver_tab_first,
2852                   N_("Metaserver tab first in network page"),
2853                   N_("If this option is enabled, the metaserver tab will "
2854                      "be the first notebook tab in the network page. This "
2855                      "option requires a restart in order to take effect."),
2856                   COC_NETWORK, GUI_GTK3_22, FALSE, NULL),
2857   GEN_BOOL_OPTION(gui_gtk3_22_allied_chat_only,
2858                   N_("Plain chat messages are sent to allies only"),
2859                   N_("If this option is enabled, then plain messages "
2860                      "typed into the chat entry while the game is "
2861                      "running will only be sent to your allies. "
2862                      "Otherwise plain messages will be sent as "
2863                      "public chat messages. To send a public chat "
2864                      "message with this option enabled, prefix the "
2865                      "message with a single colon ':'. This option "
2866                      "can also be set using a toggle button beside "
2867                      "the chat entry (only visible in multiplayer "
2868                      "games)."),
2869                   COC_INTERFACE, GUI_GTK3_22, FALSE, NULL),
2870   GEN_ENUM_OPTION(gui_gtk3_22_message_chat_location,
2871                   N_("Messages and Chat reports location"),
2872                   /* TRANS: The strings used in the UI for 'Split' etc are
2873                    * tagged 'gui_gtk2/gtk3_message_chat_location' */
2874                   N_("Controls where the Messages and Chat reports "
2875                      "appear relative to the main view containing the map.\n"
2876                      "'Split' allows all three to be seen simultaneously, "
2877                      "which is best for multiplayer, but requires a large "
2878                      "window to be usable.\n"
2879                      "'Separate' puts Messages and Chat in a notebook "
2880                      "separate from the main view, so that one of them "
2881                      "can always be seen alongside the main view.\n"
2882                      "'Merged' makes the Messages and Chat reports into "
2883                      "tabs alongside the map and other reports; this "
2884                      "allows a larger map view on small screens.\n"
2885                      "This option requires a restart in order to take "
2886                      "effect."), COC_INTERFACE, GUI_GTK3_22,
2887                   GUI_GTK_MSGCHAT_SEPARATE,
2888                   gui_gtk_message_chat_location_name, NULL),
2889   GEN_BOOL_OPTION(gui_gtk3_22_small_display_layout,
2890                   N_("Arrange widgets for small displays"),
2891                   N_("If this option is enabled, widgets in the main "
2892                      "window will be arranged so that they take up the "
2893                      "least amount of total screen space. Specifically, "
2894                      "the left panel containing the overview, player "
2895                      "status, and the unit information box will be "
2896                      "extended over the entire left side of the window. "
2897                      "This option requires a restart in order to take "
2898                      "effect."), COC_INTERFACE, GUI_GTK3_22, FALSE, NULL),
2899   GEN_BOOL_OPTION(gui_gtk3_22_mouse_over_map_focus,
2900                   N_("Mouse over the map widget selects it automatically"),
2901                   N_("If this option is enabled, then the map will be "
2902                      "focused when the mouse hovers over it."),
2903                   COC_INTERFACE, GUI_GTK3_22, FALSE, NULL),
2904   GEN_BOOL_OPTION(gui_gtk3_22_chatline_autocompletion,
2905                   N_("Player or user name autocompletion"),
2906                   N_("If this option is turned on, the tabulation key "
2907                      "will be used in the chatline to complete the word you "
2908                      "are typing with the name of a player or a user."),
2909                   COC_INTERFACE, GUI_GTK3_22, TRUE, NULL),
2910   GEN_INT_OPTION(gui_gtk3_22_citydlg_xsize,
2911                  N_("Width of the city dialog"),
2912                  N_("This value is only used if the width of the city "
2913                     "dialog is saved."),
2914                  COC_INTERFACE, GUI_GTK3_22, GUI_GTK3_22_CITYDLG_DEFAULT_XSIZE,
2915                  GUI_GTK3_22_CITYDLG_MIN_XSIZE, GUI_GTK3_22_CITYDLG_MAX_XSIZE,
2916                  NULL),
2917   GEN_INT_OPTION(gui_gtk3_22_citydlg_ysize,
2918                  N_("Height of the city dialog"),
2919                  N_("This value is only used if the height of the city "
2920                     "dialog is saved."),
2921                  COC_INTERFACE, GUI_GTK3_22, GUI_GTK3_22_CITYDLG_DEFAULT_YSIZE,
2922                  GUI_GTK3_22_CITYDLG_MIN_YSIZE, GUI_GTK3_22_CITYDLG_MAX_YSIZE,
2923                  NULL),
2924   GEN_ENUM_OPTION(gui_gtk3_22_popup_tech_help,
2925                   N_("Popup tech help when gained"),
2926                   N_("Controls if tech help should be opened when "
2927                      "new tech has been gained.\n"
2928                      "'Ruleset' means that behavior suggested by "
2929                      "current ruleset is used."), COC_INTERFACE, GUI_GTK3_22,
2930                   GUI_POPUP_TECH_HELP_RULESET,
2931                   gui_popup_tech_help_name, NULL),
2932   GEN_INT_OPTION(gui_gtk3_22_governor_range_min,
2933                  N_("Minimum surplus for a governor"),
2934                  N_("The lower limit of the range for requesting surpluses "
2935                     "from the governor."),
2936                  COC_INTERFACE, GUI_GTK3_22, GUI_GTK3_22_GOV_RANGE_MIN_DEFAULT,
2937                  GUI_GTK3_22_GOV_RANGE_MIN_MIN, GUI_GTK3_22_GOV_RANGE_MIN_MAX,
2938                  NULL),
2939   GEN_INT_OPTION(gui_gtk3_22_governor_range_max,
2940                  N_("Maximum surplus for a governor"),
2941                  N_("The higher limit of the range for requesting surpluses "
2942                     "from the governor."),
2943                  COC_INTERFACE, GUI_GTK3_22, GUI_GTK3_22_GOV_RANGE_MAX_DEFAULT,
2944                  GUI_GTK3_22_GOV_RANGE_MAX_MIN, GUI_GTK3_22_GOV_RANGE_MAX_MAX,
2945                  NULL),
2946   GEN_FONT_OPTION(gui_gtk3_22_font_city_label, "city_label",
2947                   N_("City Label"),
2948                   N_("This font is used to display the city labels on city "
2949                      "dialogs."),
2950                   COC_FONT, GUI_GTK3_22,
2951                   "Monospace 8", font_changed_callback),
2952   GEN_FONT_OPTION(gui_gtk3_22_font_notify_label, "notify_label",
2953                   N_("Notify Label"),
2954                   N_("This font is used to display server reports such "
2955                      "as the demographic report or historian publications."),
2956                   COC_FONT, GUI_GTK3_22,
2957                   "Monospace Bold 9", font_changed_callback),
2958   GEN_FONT_OPTION(gui_gtk3_22_font_spaceship_label, "spaceship_label",
2959                   N_("Spaceship Label"),
2960                   N_("This font is used to display the spaceship widgets."),
2961                   COC_FONT, GUI_GTK3_22,
2962                   "Monospace 8", font_changed_callback),
2963   GEN_FONT_OPTION(gui_gtk3_22_font_help_label, "help_label",
2964                   N_("Help Label"),
2965                   N_("This font is used to display the help headers in the "
2966                      "help window."),
2967                   COC_FONT, GUI_GTK3_22,
2968                   "Sans Bold 10", font_changed_callback),
2969   GEN_FONT_OPTION(gui_gtk3_22_font_help_link, "help_link",
2970                   N_("Help Link"),
2971                   N_("This font is used to display the help links in the "
2972                      "help window."),
2973                   COC_FONT, GUI_GTK3_22,
2974                   "Sans 9", font_changed_callback),
2975   GEN_FONT_OPTION(gui_gtk3_22_font_help_text, "help_text",
2976                   N_("Help Text"),
2977                   N_("This font is used to display the help body text in "
2978                      "the help window."),
2979                   COC_FONT, GUI_GTK3_22,
2980                   "Monospace 8", font_changed_callback),
2981   GEN_FONT_OPTION(gui_gtk3_22_font_chatline, "chatline",
2982                   N_("Chatline Area"),
2983                   N_("This font is used to display the text in the "
2984                      "chatline area."),
2985                   COC_FONT, GUI_GTK3_22,
2986                   "Monospace 8", font_changed_callback),
2987   GEN_FONT_OPTION(gui_gtk3_22_font_beta_label, "beta_label",
2988                   N_("Beta Label"),
2989                   N_("This font is used to display the beta label."),
2990                   COC_FONT, GUI_GTK3_22,
2991                   "Sans Italic 10", font_changed_callback),
2992   GEN_FONT_OPTION(gui_gtk3_22_font_small, "small_font",
2993                   N_("Small Font"),
2994                   N_("This font is used for any small font request.  For "
2995                      "example, it is used for display the building lists "
2996                      "in the city dialog, the Economy report or the Units "
2997                      "report."),
2998                   COC_FONT, GUI_GTK3_22,
2999                   "Sans 9", NULL),
3000   GEN_FONT_OPTION(gui_gtk3_22_font_comment_label, "comment_label",
3001                   N_("Comment Label"),
3002                   N_("This font is used to display comment labels, such as "
3003                      "in the governor page of the city dialogs."),
3004                   COC_FONT, GUI_GTK3_22,
3005                   "Sans Italic 9", font_changed_callback),
3006   GEN_FONT_OPTION(gui_gtk3_22_font_city_names, "city_names",
3007                   N_("City Names"),
3008                   N_("This font is used to the display the city names "
3009                      "on the map."),
3010                   COC_FONT, GUI_GTK3_22,
3011                   "Sans Bold 10", NULL),
3012   GEN_FONT_OPTION(gui_gtk3_22_font_city_productions, "city_productions",
3013                   N_("City Productions"),
3014                   N_("This font is used to display the city production "
3015                      "on the map."),
3016                   COC_FONT, GUI_GTK3_22,
3017                   "Serif 10", NULL),
3018   GEN_FONT_OPTION(gui_gtk3_22_font_reqtree_text, "reqtree_text",
3019                   N_("Requirement Tree"),
3020                   N_("This font is used to the display the requirement tree "
3021                      "in the Research report."),
3022                   COC_FONT, GUI_GTK3_22,
3023                   "Serif 10", NULL),
3024 
3025   /* gui-sdl client specific options. */
3026   GEN_BOOL_OPTION(gui_sdl_fullscreen, N_("Fullscreen"),
3027                   N_("If this option is set the client will use the "
3028                      "whole screen area for drawing."),
3029                   COC_INTERFACE, GUI_SDL, FALSE, NULL),
3030   GEN_VIDEO_OPTION(gui_sdl_screen, N_("Screen resolution"),
3031                    N_("This option controls the resolution of the "
3032                       "selected screen."),
3033                    COC_INTERFACE, GUI_SDL, 640, 480, NULL),
3034   GEN_BOOL_OPTION(gui_sdl_do_cursor_animation, N_("Do cursor animation"),
3035                   N_("If this option is disabled, the cursor will "
3036                      "always be displayed as static."),
3037                   COC_INTERFACE, GUI_SDL, TRUE, NULL),
3038   GEN_BOOL_OPTION(gui_sdl_use_color_cursors, N_("Use color cursors"),
3039                   N_("If this option is disabled, the cursor will "
3040                      "always be displayed in black and white."),
3041                   COC_INTERFACE, GUI_SDL, TRUE, NULL),
3042 
3043   /* gui-sdl2 client specific options. */
3044   GEN_BOOL_OPTION(gui_sdl2_fullscreen, N_("Fullscreen"),
3045                   N_("If this option is set the client will use the "
3046                      "whole screen area for drawing."),
3047                   COC_INTERFACE, GUI_SDL2, FALSE, NULL),
3048   GEN_VIDEO_OPTION(gui_sdl2_screen, N_("Screen resolution"),
3049                    N_("This option controls the resolution of the "
3050                       "selected screen."),
3051                    COC_INTERFACE, GUI_SDL2, 640, 480, NULL),
3052   GEN_BOOL_OPTION(gui_sdl2_swrenderer, N_("Use software rendering"),
3053                   N_("Usually hardware rendering is used when possible. "
3054                      "With this option set, software rendering is always used."),
3055                   COC_GRAPHICS, GUI_SDL2, FALSE, NULL),
3056   GEN_BOOL_OPTION(gui_sdl2_do_cursor_animation, N_("Do cursor animation"),
3057                   N_("If this option is disabled, the cursor will "
3058                      "always be displayed as static."),
3059                   COC_INTERFACE, GUI_SDL2, TRUE, NULL),
3060   GEN_BOOL_OPTION(gui_sdl2_use_color_cursors, N_("Use color cursors"),
3061                   N_("If this option is disabled, the cursor will "
3062                      "always be displayed in black and white."),
3063                   COC_INTERFACE, GUI_SDL2, TRUE, NULL),
3064 
3065   /* gui-qt client specific options. */
3066   GEN_BOOL_OPTION(gui_qt_fullscreen, N_("Fullscreen"),
3067                   N_("If this option is set the client will use the "
3068                      "whole screen area for drawing."),
3069                   COC_INTERFACE, GUI_QT, FALSE, NULL),
3070   GEN_BOOL_OPTION(gui_qt_show_titlebar, N_("Show titlebar"),
3071                   N_("If this option is set the client will show a titlebar. "
3072                      "If disabled, then no titlebar will be shown, and "
3073                      "minimize/maximize/etc buttons will be placed on the "
3074                      "menu bar."),
3075                   COC_INTERFACE, GUI_QT, TRUE, NULL),
3076   GEN_FONT_OPTION(gui_qt_font_city_label, "city_label",
3077                   N_("City Label"),
3078                   N_("This font is used to display the city labels on city "
3079                      "dialogs."),
3080                   COC_FONT, GUI_QT,
3081                   "Monospace,8,-1,5,50,0,0,0,0,0", font_changed_callback),
3082   GEN_FONT_OPTION(gui_qt_font_default, "default_font",
3083                   N_("Default font"),
3084                   N_("This is default font"),
3085                   COC_FONT, GUI_QT,
3086                   "Sans Serif,10,-1,5,75,0,0,0,0,0", font_changed_callback),
3087   GEN_FONT_OPTION(gui_qt_font_notify_label, "notify_label",
3088                   N_("Notify Label"),
3089                   N_("This font is used to display server reports such "
3090                      "as the demographic report or historian publications."),
3091                   COC_FONT, GUI_QT,
3092                   "Monospace,9,-1,5,75,0,0,0,0,0", font_changed_callback),
3093   GEN_FONT_OPTION(gui_qt_font_spaceship_label, "spaceship_label",
3094                   N_("Spaceship Label"),
3095                   N_("This font is used to display the spaceship widgets."),
3096                   COC_FONT, GUI_QT,
3097                   "Monospace,8,-1,5,50,0,0,0,0,0", font_changed_callback),
3098   GEN_FONT_OPTION(gui_qt_font_help_label, "help_label",
3099                   N_("Help Label"),
3100                   N_("This font is used to display the help labels in the "
3101                      "help window."),
3102                   COC_FONT, GUI_QT,
3103                   "Sans Serif,9,-1,5,50,0,0,0,0,0", font_changed_callback),
3104   GEN_FONT_OPTION(gui_qt_font_help_link, "help_link",
3105                   N_("Help Link"),
3106                   N_("This font is used to display the help links in the "
3107                      "help window."),
3108                   COC_FONT, GUI_QT,
3109                   "Sans Serif,9,-1,5,50,0,0,0,0,0", font_changed_callback),
3110   GEN_FONT_OPTION(gui_qt_font_help_text, "help_text",
3111                   N_("Help Text"),
3112                   N_("This font is used to display the help body text in "
3113                      "the help window."),
3114                   COC_FONT, GUI_QT,
3115                   "Monospace,8,-1,5,50,0,0,0,0,0", font_changed_callback),
3116   GEN_FONT_OPTION(gui_qt_font_help_title, "help_title",
3117                   N_("Help Title"),
3118                   N_("This font is used to display the help title in "
3119                      "the help window."),
3120                   COC_FONT, GUI_QT,
3121                   "Sans Serif,10,-1,5,75,0,0,0,0,0", font_changed_callback),
3122   GEN_FONT_OPTION(gui_qt_font_chatline, "chatline",
3123                   N_("Chatline Area"),
3124                   N_("This font is used to display the text in the "
3125                      "chatline area."),
3126                   COC_FONT, GUI_QT,
3127                   "Monospace,8,-1,5,50,0,0,0,0,0", font_changed_callback),
3128   GEN_FONT_OPTION(gui_qt_font_beta_label, "beta_label",
3129                   N_("Beta Label"),
3130                   N_("This font is used to display the beta label."),
3131                   COC_FONT, GUI_QT,
3132                   "Sans Serif,10,-1,5,50,1,0,0,0,0", font_changed_callback),
3133   GEN_FONT_OPTION(gui_qt_font_small, "small_font",
3134                   N_("Small Font"),
3135                   N_("This font is used for any small font request.  For "
3136                      "example, it is used for display the building lists "
3137                      "in the city dialog, the Economy report or the Units "
3138                      "report."),
3139                   COC_FONT, GUI_QT,
3140                   "Sans Serif,9,-1,5,50,0,0,0,0,0", font_changed_callback),
3141   GEN_FONT_OPTION(gui_qt_font_comment_label, "comment_label",
3142                   N_("Comment Label"),
3143                   N_("This font is used to display comment labels, such as "
3144                      "in the governor page of the city dialogs."),
3145                   COC_FONT, GUI_QT,
3146                   "Sans Serif,9,-1,5,50,1,0,0,0,0", font_changed_callback),
3147   GEN_FONT_OPTION(gui_qt_font_city_names, "city_names",
3148                   N_("City Names"),
3149                   N_("This font is used to the display the city names "
3150                      "on the map."),
3151                   COC_FONT, GUI_QT,
3152                   "Sans Serif,10,-1,5,75,0,0,0,0,0", font_changed_callback),
3153   GEN_FONT_OPTION(gui_qt_font_city_productions, "city_productions",
3154                   N_("City Productions"),
3155                   N_("This font is used to display the city production "
3156                      "on the map."),
3157                   COC_FONT, GUI_QT,
3158                   "Sans Serif,10,-1,5,50,1,0,0,0,0", font_changed_callback),
3159   GEN_FONT_OPTION(gui_qt_font_reqtree_text, "reqtree_text",
3160                   N_("Requirement Tree"),
3161                   N_("This font is used to the display the requirement tree "
3162                      "in the Research report."),
3163                   COC_FONT, GUI_QT,
3164                   "Sans Serif,10,-1,5,50,1,0,0,0,0", font_changed_callback),
3165   GEN_BOOL_OPTION(gui_qt_show_preview, N_("Show savegame information"),
3166                   N_("If this option is set the client will show "
3167                      "information and map preview of current savegame."),
3168                   COC_GRAPHICS, GUI_QT, TRUE, NULL),
3169   GEN_BOOL_OPTION(gui_qt_sidebar_left, N_("Sidebar position"),
3170                   N_("If this option is set, the sidebar will be to the left "
3171                      "of the map, otherwise to the right."),
3172                   COC_INTERFACE, GUI_QT, TRUE, NULL),
3173   GEN_STR_OPTION(gui_qt_wakeup_text,
3174                  N_("Wake up sequence"),
3175                  N_("String which will trigger sound in pregame page; "
3176                     "%1 stands for username."),
3177                  COC_INTERFACE, GUI_QT, "Wake up %1", NULL, 0)
3178 
3179 };
3180 static const int client_options_num = ARRAY_SIZE(client_options);
3181 
3182 /* Iteration loop, including invalid options for the current gui type. */
3183 #define client_options_iterate_all(poption)                                 \
3184 {                                                                           \
3185   const struct client_option *const poption##_max =                         \
3186       client_options + client_options_num;                                  \
3187   struct client_option *client_##poption = client_options;                  \
3188   struct option *poption;                                                   \
3189   for (; client_##poption < poption##_max; client_##poption++) {            \
3190     poption = OPTION(client_##poption);
3191 
3192 #define client_options_iterate_all_end                                      \
3193   }                                                                         \
3194 }
3195 
3196 
3197 /****************************************************************************
3198   Returns the next valid option pointer for the current gui type.
3199 ****************************************************************************/
3200 static struct client_option *
client_option_next_valid(struct client_option * poption)3201     client_option_next_valid(struct client_option *poption)
3202 {
3203   const struct client_option *const max =
3204     client_options + client_options_num;
3205   const enum gui_type our_type = get_gui_type();
3206 
3207   while (poption < max
3208          && poption->specific != GUI_STUB
3209          && poption->specific != our_type) {
3210     poption++;
3211   }
3212 
3213   return (poption < max ? poption : NULL);
3214 }
3215 
3216 /****************************************************************************
3217   Returns the option corresponding to this id.
3218 ****************************************************************************/
client_optset_option_by_number(int id)3219 static struct option *client_optset_option_by_number(int id)
3220 {
3221   if (0 > id || id > client_options_num)  {
3222     return NULL;
3223   }
3224   return OPTION(client_options + id);
3225 }
3226 
3227 /****************************************************************************
3228   Returns the first valid option pointer for the current gui type.
3229 ****************************************************************************/
client_optset_option_first(void)3230 static struct option *client_optset_option_first(void)
3231 {
3232   return OPTION(client_option_next_valid(client_options));
3233 }
3234 
3235 /****************************************************************************
3236   Returns the number of client option categories.
3237 ****************************************************************************/
client_optset_category_number(void)3238 static int client_optset_category_number(void)
3239 {
3240   return COC_MAX;
3241 }
3242 
3243 /****************************************************************************
3244   Returns the name (translated) of the option class.
3245 ****************************************************************************/
client_optset_category_name(int category)3246 static const char *client_optset_category_name(int category)
3247 {
3248   switch (category) {
3249   case COC_GRAPHICS:
3250     return _("Graphics");
3251   case COC_OVERVIEW:
3252     /* TRANS: Options section for overview map (mini-map) */
3253     return Q_("?map:Overview");
3254   case COC_SOUND:
3255     return _("Sound");
3256   case COC_INTERFACE:
3257     return _("Interface");
3258   case COC_MAPIMG:
3259     return _("Map Image");
3260   case COC_NETWORK:
3261     return _("Network");
3262   case COC_FONT:
3263     return _("Font");
3264   case COC_MAX:
3265     break;
3266   }
3267 
3268   log_error("%s: invalid option category number %d.",
3269             __FUNCTION__, category);
3270   return NULL;
3271 }
3272 
3273 /***************************************************************************
3274   Returns the number of this client option.
3275 ****************************************************************************/
client_option_number(const struct option * poption)3276 static int client_option_number(const struct option *poption)
3277 {
3278   return CLIENT_OPTION(poption) - client_options;
3279 }
3280 
3281 /****************************************************************************
3282   Returns the name of this client option.
3283 ****************************************************************************/
client_option_name(const struct option * poption)3284 static const char *client_option_name(const struct option *poption)
3285 {
3286   return CLIENT_OPTION(poption)->name;
3287 }
3288 
3289 /****************************************************************************
3290   Returns the description of this client option.
3291 ****************************************************************************/
client_option_description(const struct option * poption)3292 static const char *client_option_description(const struct option *poption)
3293 {
3294   return _(CLIENT_OPTION(poption)->description);
3295 }
3296 
3297 /****************************************************************************
3298   Returns the help text for this client option.
3299 ****************************************************************************/
client_option_help_text(const struct option * poption)3300 static const char *client_option_help_text(const struct option *poption)
3301 {
3302   return _(CLIENT_OPTION(poption)->help_text);
3303 }
3304 
3305 /****************************************************************************
3306   Returns the category of this client option.
3307 ****************************************************************************/
client_option_category(const struct option * poption)3308 static int client_option_category(const struct option *poption)
3309 {
3310   return CLIENT_OPTION(poption)->category;
3311 }
3312 
3313 /****************************************************************************
3314   Returns TRUE if this client option can be modified.
3315 ****************************************************************************/
client_option_is_changeable(const struct option * poption)3316 static bool client_option_is_changeable(const struct option *poption)
3317 {
3318   return TRUE;
3319 }
3320 
3321 /****************************************************************************
3322   Returns the next valid option pointer for the current gui type.
3323 ****************************************************************************/
client_option_next(const struct option * poption)3324 static struct option *client_option_next(const struct option *poption)
3325 {
3326   return OPTION(client_option_next_valid(CLIENT_OPTION(poption) + 1));
3327 }
3328 
3329 /****************************************************************************
3330   Returns the value of this client option of type OT_BOOLEAN.
3331 ****************************************************************************/
client_option_bool_get(const struct option * poption)3332 static bool client_option_bool_get(const struct option *poption)
3333 {
3334   return *(CLIENT_OPTION(poption)->boolean.pvalue);
3335 }
3336 
3337 /****************************************************************************
3338   Returns the default value of this client option of type OT_BOOLEAN.
3339 ****************************************************************************/
client_option_bool_def(const struct option * poption)3340 static bool client_option_bool_def(const struct option *poption)
3341 {
3342   return CLIENT_OPTION(poption)->boolean.def;
3343 }
3344 
3345 /****************************************************************************
3346   Set the value of this client option of type OT_BOOLEAN.  Returns TRUE if
3347   the value changed.
3348 ****************************************************************************/
client_option_bool_set(struct option * poption,bool val)3349 static bool client_option_bool_set(struct option *poption, bool val)
3350 {
3351   struct client_option *pcoption = CLIENT_OPTION(poption);
3352 
3353   if (*pcoption->boolean.pvalue == val) {
3354     return FALSE;
3355   }
3356 
3357   *pcoption->boolean.pvalue = val;
3358   return TRUE;
3359 }
3360 
3361 /****************************************************************************
3362   Returns the value of this client option of type OT_INTEGER.
3363 ****************************************************************************/
client_option_int_get(const struct option * poption)3364 static int client_option_int_get(const struct option *poption)
3365 {
3366   return *(CLIENT_OPTION(poption)->integer.pvalue);
3367 }
3368 
3369 /****************************************************************************
3370   Returns the default value of this client option of type OT_INTEGER.
3371 ****************************************************************************/
client_option_int_def(const struct option * poption)3372 static int client_option_int_def(const struct option *poption)
3373 {
3374   return CLIENT_OPTION(poption)->integer.def;
3375 }
3376 
3377 /****************************************************************************
3378   Returns the minimal value for this client option of type OT_INTEGER.
3379 ****************************************************************************/
client_option_int_min(const struct option * poption)3380 static int client_option_int_min(const struct option *poption)
3381 {
3382   return CLIENT_OPTION(poption)->integer.min;
3383 }
3384 
3385 /****************************************************************************
3386   Returns the maximal value for this client option of type OT_INTEGER.
3387 ****************************************************************************/
client_option_int_max(const struct option * poption)3388 static int client_option_int_max(const struct option *poption)
3389 {
3390   return CLIENT_OPTION(poption)->integer.max;
3391 }
3392 
3393 /****************************************************************************
3394   Set the value of this client option of type OT_INTEGER.  Returns TRUE if
3395   the value changed.
3396 ****************************************************************************/
client_option_int_set(struct option * poption,int val)3397 static bool client_option_int_set(struct option *poption, int val)
3398 {
3399   struct client_option *pcoption = CLIENT_OPTION(poption);
3400 
3401   if (val < pcoption->integer.min
3402       || val > pcoption->integer.max
3403       || *pcoption->integer.pvalue == val) {
3404     return FALSE;
3405   }
3406 
3407   *pcoption->integer.pvalue = val;
3408   return TRUE;
3409 }
3410 
3411 /****************************************************************************
3412   Returns the value of this client option of type OT_STRING.
3413 ****************************************************************************/
client_option_str_get(const struct option * poption)3414 static const char *client_option_str_get(const struct option *poption)
3415 {
3416   return CLIENT_OPTION(poption)->string.pvalue;
3417 }
3418 
3419 /****************************************************************************
3420   Returns the default value of this client option of type OT_STRING.
3421 ****************************************************************************/
client_option_str_def(const struct option * poption)3422 static const char *client_option_str_def(const struct option *poption)
3423 {
3424   return CLIENT_OPTION(poption)->string.def;
3425 }
3426 
3427 /****************************************************************************
3428   Returns the possible string values of this client option of type
3429   OT_STRING.
3430 ****************************************************************************/
3431 static const struct strvec *
client_option_str_values(const struct option * poption)3432     client_option_str_values(const struct option *poption)
3433 {
3434   return (CLIENT_OPTION(poption)->string.val_accessor
3435           ? CLIENT_OPTION(poption)->string.val_accessor(poption) : NULL);
3436 }
3437 
3438 /****************************************************************************
3439   Set the value of this client option of type OT_STRING.  Returns TRUE if
3440   the value changed.
3441 ****************************************************************************/
client_option_str_set(struct option * poption,const char * str)3442 static bool client_option_str_set(struct option *poption, const char *str)
3443 {
3444   struct client_option *pcoption = CLIENT_OPTION(poption);
3445 
3446   if (strlen(str) >= pcoption->string.size
3447       || 0 == strcmp(pcoption->string.pvalue, str)) {
3448     return FALSE;
3449   }
3450 
3451   fc_strlcpy(pcoption->string.pvalue, str, pcoption->string.size);
3452   return TRUE;
3453 }
3454 
3455 /****************************************************************************
3456   Returns the current value of this client option of type OT_ENUM.
3457 ****************************************************************************/
client_option_enum_get(const struct option * poption)3458 static int client_option_enum_get(const struct option *poption)
3459 {
3460   return *(CLIENT_OPTION(poption)->enumerator.pvalue);
3461 }
3462 
3463 /****************************************************************************
3464   Returns the default value of this client option of type OT_ENUM.
3465 ****************************************************************************/
client_option_enum_def(const struct option * poption)3466 static int client_option_enum_def(const struct option *poption)
3467 {
3468   return CLIENT_OPTION(poption)->enumerator.def;
3469 }
3470 
3471 /****************************************************************************
3472   Returns the possible values of this client option of type OT_ENUM, as
3473   user-visible (translatable but not translated) strings.
3474 ****************************************************************************/
3475 static const struct strvec *
client_option_enum_pretty_names(const struct option * poption)3476     client_option_enum_pretty_names(const struct option *poption)
3477 {
3478   return CLIENT_OPTION(poption)->enumerator.pretty_names;
3479 }
3480 
3481 /****************************************************************************
3482   Set the value of this client option of type OT_ENUM.  Returns TRUE if
3483   the value changed.
3484 ****************************************************************************/
client_option_enum_set(struct option * poption,int val)3485 static bool client_option_enum_set(struct option *poption, int val)
3486 {
3487   struct client_option *pcoption = CLIENT_OPTION(poption);
3488 
3489   if (*pcoption->enumerator.pvalue == val
3490       || 0 > val
3491       || val >= strvec_size(pcoption->enumerator.support_names)) {
3492     return FALSE;
3493   }
3494 
3495   *pcoption->enumerator.pvalue = val;
3496   return TRUE;
3497 }
3498 
3499 /****************************************************************************
3500   Returns the "support" name of the value for this client option of type
3501   OT_ENUM (a string suitable for saving in a file).
3502   The prototype must match the 'secfile_enum_name_data_fn_t' type.
3503 ****************************************************************************/
client_option_enum_secfile_str(secfile_data_t data,int val)3504 static const char *client_option_enum_secfile_str(secfile_data_t data,
3505                                                   int val)
3506 {
3507   const struct strvec *names = CLIENT_OPTION(data)->enumerator.support_names;
3508 
3509   return (0 <= val && val < strvec_size(names)
3510           ? strvec_get(names, val) : NULL);
3511 }
3512 
3513 #if 0 /* There's no bitwise options currently */
3514 /****************************************************************************
3515   Returns the current value of this client option of type OT_BITWISE.
3516 ****************************************************************************/
3517 static unsigned client_option_bitwise_get(const struct option *poption)
3518 {
3519   return *(CLIENT_OPTION(poption)->bitwise.pvalue);
3520 }
3521 
3522 /****************************************************************************
3523   Returns the default value of this client option of type OT_BITWISE.
3524 ****************************************************************************/
3525 static unsigned client_option_bitwise_def(const struct option *poption)
3526 {
3527   return CLIENT_OPTION(poption)->bitwise.def;
3528 }
3529 
3530 /****************************************************************************
3531   Returns the possible values of this client option of type OT_BITWISE, as
3532   user-visible (translatable but not translated) strings.
3533 ****************************************************************************/
3534 static const struct strvec *
3535     client_option_bitwise_pretty_names(const struct option *poption)
3536 {
3537   return CLIENT_OPTION(poption)->bitwise.pretty_names;
3538 }
3539 
3540 /****************************************************************************
3541   Set the value of this client option of type OT_BITWISE.  Returns TRUE if
3542   the value changed.
3543 ****************************************************************************/
3544 static bool client_option_bitwise_set(struct option *poption, unsigned val)
3545 {
3546   struct client_option *pcoption = CLIENT_OPTION(poption);
3547 
3548   if (*pcoption->bitwise.pvalue == val) {
3549     return FALSE;
3550   }
3551 
3552   *pcoption->bitwise.pvalue = val;
3553   return TRUE;
3554 }
3555 #endif /* 0 */
3556 
3557 /****************************************************************************
3558   Returns the "support" name of a single value for this client option of type
3559   OT_BITWISE (a string suitable for saving in a file).
3560   The prototype must match the 'secfile_enum_name_data_fn_t' type.
3561 ****************************************************************************/
client_option_bitwise_secfile_str(secfile_data_t data,int val)3562 static const char *client_option_bitwise_secfile_str(secfile_data_t data,
3563                                                      int val)
3564 {
3565   const struct strvec *names = CLIENT_OPTION(data)->bitwise.support_names;
3566 
3567   return (0 <= val && val < strvec_size(names)
3568           ? strvec_get(names, val) : NULL);
3569 }
3570 
3571 /****************************************************************************
3572   Returns the value of this client option of type OT_FONT.
3573 ****************************************************************************/
client_option_font_get(const struct option * poption)3574 static const char *client_option_font_get(const struct option *poption)
3575 {
3576   return CLIENT_OPTION(poption)->font.pvalue;
3577 }
3578 
3579 /****************************************************************************
3580   Returns the default value of this client option of type OT_FONT.
3581 ****************************************************************************/
client_option_font_def(const struct option * poption)3582 static const char *client_option_font_def(const struct option *poption)
3583 {
3584   return CLIENT_OPTION(poption)->font.def;
3585 }
3586 
3587 /****************************************************************************
3588   Returns the target style name of this client option of type OT_FONT.
3589 ****************************************************************************/
client_option_font_target(const struct option * poption)3590 static const char *client_option_font_target(const struct option *poption)
3591 {
3592   return CLIENT_OPTION(poption)->font.target;
3593 }
3594 
3595 /****************************************************************************
3596   Set the value of this client option of type OT_FONT.  Returns TRUE if
3597   the value changed.
3598 ****************************************************************************/
client_option_font_set(struct option * poption,const char * font)3599 static bool client_option_font_set(struct option *poption, const char *font)
3600 {
3601   struct client_option *pcoption = CLIENT_OPTION(poption);
3602 
3603   if (strlen(font) >= pcoption->font.size
3604       || 0 == strcmp(pcoption->font.pvalue, font)) {
3605     return FALSE;
3606   }
3607 
3608   fc_strlcpy(pcoption->font.pvalue, font, pcoption->font.size);
3609   return TRUE;
3610 }
3611 
3612 /****************************************************************************
3613   Returns the value of this client option of type OT_COLOR.
3614 ****************************************************************************/
client_option_color_get(const struct option * poption)3615 static struct ft_color client_option_color_get(const struct option *poption)
3616 {
3617   return *CLIENT_OPTION(poption)->color.pvalue;
3618 }
3619 
3620 /****************************************************************************
3621   Returns the default value of this client option of type OT_COLOR.
3622 ****************************************************************************/
client_option_color_def(const struct option * poption)3623 static struct ft_color client_option_color_def(const struct option *poption)
3624 {
3625   return CLIENT_OPTION(poption)->color.def;
3626 }
3627 
3628 /****************************************************************************
3629   Set the value of this client option of type OT_COLOR.  Returns TRUE if
3630   the value changed.
3631 ****************************************************************************/
client_option_color_set(struct option * poption,struct ft_color color)3632 static bool client_option_color_set(struct option *poption,
3633                                     struct ft_color color)
3634 {
3635   struct ft_color *pcolor = CLIENT_OPTION(poption)->color.pvalue;
3636   bool changed = FALSE;
3637 
3638 #define color_set(color_tgt, color)                                         \
3639   if (NULL == color_tgt) {                                                  \
3640     if (NULL != color) {                                                    \
3641       color_tgt = fc_strdup(color);                                         \
3642       changed = TRUE;                                                       \
3643     }                                                                       \
3644   } else {                                                                  \
3645     if (NULL == color) {                                                    \
3646       free((void *) color_tgt);                                             \
3647       color_tgt = NULL;                                                     \
3648       changed = TRUE;                                                       \
3649     } else if (0 != strcmp(color_tgt, color)) {                             \
3650       free((void *) color_tgt);                                             \
3651       color_tgt = fc_strdup(color);                                         \
3652       changed = TRUE;                                                       \
3653     }                                                                       \
3654   }
3655 
3656   color_set(pcolor->foreground, color.foreground);
3657   color_set(pcolor->background, color.background);
3658 
3659 #undef color_set
3660 
3661   return changed;
3662 }
3663 
3664 /****************************************************************************
3665   Returns the value of this client option of type OT_VIDEO_MODE.
3666 ****************************************************************************/
3667 static struct video_mode
client_option_video_mode_get(const struct option * poption)3668 client_option_video_mode_get(const struct option *poption)
3669 {
3670   return *CLIENT_OPTION(poption)->video_mode.pvalue;
3671 }
3672 
3673 /****************************************************************************
3674   Returns the default value of this client option of type OT_VIDEO_MODE.
3675 ****************************************************************************/
3676 static struct video_mode
client_option_video_mode_def(const struct option * poption)3677 client_option_video_mode_def(const struct option *poption)
3678 {
3679   return CLIENT_OPTION(poption)->video_mode.def;
3680 }
3681 
3682 /****************************************************************************
3683   Set the value of this client option of type OT_VIDEO_MODE.  Returns TRUE
3684   if the value changed.
3685 ****************************************************************************/
client_option_video_mode_set(struct option * poption,struct video_mode mode)3686 static bool client_option_video_mode_set(struct option *poption,
3687                                          struct video_mode mode)
3688 {
3689   struct client_option *pcoption = CLIENT_OPTION(poption);
3690 
3691   if (0 == memcmp(&mode, pcoption->video_mode.pvalue,
3692                   sizeof(struct video_mode))) {
3693     return FALSE;
3694   }
3695 
3696   *pcoption->video_mode.pvalue = mode;
3697   return TRUE;
3698 }
3699 
3700 /****************************************************************************
3701   Load the option from a file.  Returns TRUE if the option changed.
3702 ****************************************************************************/
client_option_load(struct option * poption,struct section_file * sf)3703 static bool client_option_load(struct option *poption,
3704                                struct section_file *sf)
3705 {
3706   fc_assert_ret_val(NULL != poption, FALSE);
3707   fc_assert_ret_val(NULL != sf, FALSE);
3708 
3709   switch (option_type(poption)) {
3710   case OT_BOOLEAN:
3711     {
3712       bool value;
3713 
3714       return (secfile_lookup_bool(sf, &value, "client.%s",
3715                                   option_name(poption))
3716               && option_bool_set(poption, value));
3717     }
3718   case OT_INTEGER:
3719     {
3720       int value;
3721 
3722       return (secfile_lookup_int(sf, &value, "client.%s",
3723                                  option_name(poption))
3724               && option_int_set(poption, value));
3725     }
3726   case OT_STRING:
3727     {
3728       const char *string;
3729 
3730       return ((string = secfile_lookup_str(sf, "client.%s",
3731                                            option_name(poption)))
3732               && option_str_set(poption, string));
3733     }
3734   case OT_ENUM:
3735     {
3736       int value;
3737 
3738       return (secfile_lookup_enum_data(sf, &value, FALSE,
3739                                        client_option_enum_secfile_str,
3740                                        poption, "client.%s",
3741                                        option_name(poption))
3742               && option_enum_set_int(poption, value));
3743     }
3744   case OT_BITWISE:
3745     {
3746       int value;
3747 
3748       return (secfile_lookup_enum_data(sf, &value, TRUE,
3749                                        client_option_bitwise_secfile_str,
3750                                        poption, "client.%s",
3751                                        option_name(poption))
3752               && option_bitwise_set(poption, value));
3753     }
3754   case OT_FONT:
3755     {
3756       const char *string;
3757 
3758       return ((string = secfile_lookup_str(sf, "client.%s",
3759                                            option_name(poption)))
3760               && option_font_set(poption, string));
3761     }
3762   case OT_COLOR:
3763     {
3764       struct ft_color color;
3765 
3766       return ((color.foreground =
3767                    secfile_lookup_str(sf, "client.%s.foreground",
3768                                       option_name(poption)))
3769               && (color.background =
3770                       secfile_lookup_str(sf, "client.%s.background",
3771                                          option_name(poption)))
3772               && option_color_set(poption, color));
3773     }
3774   case OT_VIDEO_MODE:
3775     {
3776       struct video_mode mode;
3777 
3778       return (secfile_lookup_int(sf, &mode.width, "client.%s.width",
3779                                  option_name(poption))
3780               && secfile_lookup_int(sf, &mode.height, "client.%s.height",
3781                                     option_name(poption))
3782               && option_video_mode_set(poption, mode));
3783     }
3784   }
3785   return FALSE;
3786 }
3787 
3788 /****************************************************************************
3789   Save the option to a file.
3790 ****************************************************************************/
client_option_save(struct option * poption,struct section_file * sf)3791 static void client_option_save(struct option *poption,
3792                                struct section_file *sf)
3793 {
3794   fc_assert_ret(NULL != poption);
3795   fc_assert_ret(NULL != sf);
3796 
3797   switch (option_type(poption)) {
3798   case OT_BOOLEAN:
3799     secfile_insert_bool(sf, option_bool_get(poption),
3800                         "client.%s", option_name(poption));
3801     break;
3802   case OT_INTEGER:
3803     secfile_insert_int(sf, option_int_get(poption),
3804                        "client.%s", option_name(poption));
3805     break;
3806   case OT_STRING:
3807     secfile_insert_str(sf, option_str_get(poption),
3808                        "client.%s", option_name(poption));
3809     break;
3810   case OT_ENUM:
3811     secfile_insert_enum_data(sf, option_enum_get_int(poption), FALSE,
3812                              client_option_enum_secfile_str, poption,
3813                              "client.%s", option_name(poption));
3814     break;
3815   case OT_BITWISE:
3816     secfile_insert_enum_data(sf, option_bitwise_get(poption), TRUE,
3817                              client_option_bitwise_secfile_str, poption,
3818                              "client.%s", option_name(poption));
3819     break;
3820   case OT_FONT:
3821     secfile_insert_str(sf, option_font_get(poption),
3822                        "client.%s", option_name(poption));
3823     break;
3824   case OT_COLOR:
3825     {
3826       struct ft_color color = option_color_get(poption);
3827 
3828       secfile_insert_str(sf, color.foreground, "client.%s.foreground",
3829                          option_name(poption));
3830       secfile_insert_str(sf, color.background, "client.%s.background",
3831                          option_name(poption));
3832     }
3833     break;
3834   case OT_VIDEO_MODE:
3835     {
3836       struct video_mode mode = option_video_mode_get(poption);
3837 
3838       secfile_insert_int(sf, mode.width, "client.%s.width",
3839                          option_name(poption));
3840       secfile_insert_int(sf, mode.height, "client.%s.height",
3841                          option_name(poption));
3842     }
3843     break;
3844   }
3845 }
3846 
3847 
3848 /****************************************************************************
3849   Server options variables.
3850 ****************************************************************************/
3851 static char **server_options_categories = NULL;
3852 static struct server_option *server_options = NULL;
3853 
3854 static int server_options_categories_num = 0;
3855 static int server_options_num = 0;
3856 
3857 
3858 /****************************************************************************
3859   Server option set.
3860 ****************************************************************************/
3861 static struct option *server_optset_option_by_number(int id);
3862 static struct option *server_optset_option_first(void);
3863 static int server_optset_category_number(void);
3864 static const char *server_optset_category_name(int category);
3865 
3866 static struct option_set server_optset_static = {
3867   .option_by_number = server_optset_option_by_number,
3868   .option_first = server_optset_option_first,
3869   .category_number = server_optset_category_number,
3870   .category_name = server_optset_category_name
3871 };
3872 const struct option_set *server_optset = &server_optset_static;
3873 
3874 
3875 /****************************************************************************
3876   Virtuals tables for the client options.
3877 ****************************************************************************/
3878 static int server_option_number(const struct option *poption);
3879 static const char *server_option_name(const struct option *poption);
3880 static const char *server_option_description(const struct option *poption);
3881 static const char *server_option_help_text(const struct option *poption);
3882 static int server_option_category(const struct option *poption);
3883 static bool server_option_is_changeable(const struct option *poption);
3884 static struct option *server_option_next(const struct option *poption);
3885 
3886 static const struct option_common_vtable server_option_common_vtable = {
3887   .number = server_option_number,
3888   .name = server_option_name,
3889   .description = server_option_description,
3890   .help_text = server_option_help_text,
3891   .category = server_option_category,
3892   .is_changeable = server_option_is_changeable,
3893   .next = server_option_next
3894 };
3895 
3896 static bool server_option_bool_get(const struct option *poption);
3897 static bool server_option_bool_def(const struct option *poption);
3898 static bool server_option_bool_set(struct option *poption, bool val);
3899 
3900 static const struct option_bool_vtable server_option_bool_vtable = {
3901   .get = server_option_bool_get,
3902   .def = server_option_bool_def,
3903   .set = server_option_bool_set
3904 };
3905 
3906 static int server_option_int_get(const struct option *poption);
3907 static int server_option_int_def(const struct option *poption);
3908 static int server_option_int_min(const struct option *poption);
3909 static int server_option_int_max(const struct option *poption);
3910 static bool server_option_int_set(struct option *poption, int val);
3911 
3912 static const struct option_int_vtable server_option_int_vtable = {
3913   .get = server_option_int_get,
3914   .def = server_option_int_def,
3915   .minimum = server_option_int_min,
3916   .maximum = server_option_int_max,
3917   .set = server_option_int_set
3918 };
3919 
3920 static const char *server_option_str_get(const struct option *poption);
3921 static const char *server_option_str_def(const struct option *poption);
3922 static const struct strvec *
3923     server_option_str_values(const struct option *poption);
3924 static bool server_option_str_set(struct option *poption, const char *str);
3925 
3926 static const struct option_str_vtable server_option_str_vtable = {
3927   .get = server_option_str_get,
3928   .def = server_option_str_def,
3929   .values = server_option_str_values,
3930   .set = server_option_str_set
3931 };
3932 
3933 static int server_option_enum_get(const struct option *poption);
3934 static int server_option_enum_def(const struct option *poption);
3935 static const struct strvec *
3936     server_option_enum_pretty(const struct option *poption);
3937 static bool server_option_enum_set(struct option *poption, int val);
3938 
3939 static const struct option_enum_vtable server_option_enum_vtable = {
3940   .get = server_option_enum_get,
3941   .def = server_option_enum_def,
3942   .values = server_option_enum_pretty,
3943   .set = server_option_enum_set,
3944   .cmp = strcmp
3945 };
3946 
3947 static unsigned server_option_bitwise_get(const struct option *poption);
3948 static unsigned server_option_bitwise_def(const struct option *poption);
3949 static const struct strvec *
3950     server_option_bitwise_pretty(const struct option *poption);
3951 static bool server_option_bitwise_set(struct option *poption, unsigned val);
3952 
3953 static const struct option_bitwise_vtable server_option_bitwise_vtable = {
3954   .get = server_option_bitwise_get,
3955   .def = server_option_bitwise_def,
3956   .values = server_option_bitwise_pretty,
3957   .set = server_option_bitwise_set
3958 };
3959 
3960 /****************************************************************************
3961   Derived class server option, inheriting from base class option.
3962 ****************************************************************************/
3963 struct server_option {
3964   struct option base_option;    /* Base structure, must be the first! */
3965 
3966   char *name;                   /* Short name - used as an identifier */
3967   char *description;            /* One-line description */
3968   char *help_text;              /* Paragraph-length help text */
3969   unsigned char category;
3970   bool desired_sent;
3971   bool is_changeable;
3972   bool is_visible;
3973 
3974   union {
3975     /* OT_BOOLEAN type option. */
3976     struct {
3977       bool value;
3978       bool def;
3979     } boolean;
3980     /* OT_INTEGER type option. */
3981     struct {
3982       int value;
3983       int def, min, max;
3984     } integer;
3985     /* OT_STRING type option. */
3986     struct {
3987       char *value;
3988       char *def;
3989     } string;
3990     /* OT_ENUM type option. */
3991     struct {
3992       int value;
3993       int def;
3994       struct strvec *support_names;
3995       struct strvec *pretty_names; /* untranslated */
3996     } enumerator;
3997     /* OT_BITWISE type option. */
3998     struct {
3999       unsigned value;
4000       unsigned def;
4001       struct strvec *support_names;
4002       struct strvec *pretty_names; /* untranslated */
4003     } bitwise;
4004   };
4005 };
4006 
4007 #define SERVER_OPTION(poption) ((struct server_option *) (poption))
4008 
4009 static void desired_settable_option_send(struct option *poption);
4010 
4011 
4012 /****************************************************************************
4013   Initialize the server options (not received yet).
4014 ****************************************************************************/
server_options_init(void)4015 void server_options_init(void)
4016 {
4017   fc_assert(NULL == server_options_categories);
4018   fc_assert(NULL == server_options);
4019   fc_assert(0 == server_options_categories_num);
4020   fc_assert(0 == server_options_num);
4021 }
4022 
4023 /****************************************************************************
4024   Free one server option.
4025 ****************************************************************************/
server_option_free(struct server_option * poption)4026 static void server_option_free(struct server_option *poption)
4027 {
4028   switch (poption->base_option.type) {
4029   case OT_STRING:
4030     if (NULL != poption->string.value) {
4031       FC_FREE(poption->string.value);
4032     }
4033     if (NULL != poption->string.def) {
4034       FC_FREE(poption->string.def);
4035     }
4036     break;
4037 
4038   case OT_ENUM:
4039     if (NULL != poption->enumerator.support_names) {
4040       strvec_destroy(poption->enumerator.support_names);
4041       poption->enumerator.support_names = NULL;
4042     }
4043     if (NULL != poption->enumerator.pretty_names) {
4044       strvec_destroy(poption->enumerator.pretty_names);
4045       poption->enumerator.pretty_names = NULL;
4046     }
4047     break;
4048 
4049   case OT_BITWISE:
4050     if (NULL != poption->bitwise.support_names) {
4051       strvec_destroy(poption->bitwise.support_names);
4052       poption->bitwise.support_names = NULL;
4053     }
4054     if (NULL != poption->bitwise.pretty_names) {
4055       strvec_destroy(poption->bitwise.pretty_names);
4056       poption->bitwise.pretty_names = NULL;
4057     }
4058     break;
4059 
4060   case OT_BOOLEAN:
4061   case OT_INTEGER:
4062   case OT_FONT:
4063   case OT_COLOR:
4064   case OT_VIDEO_MODE:
4065     break;
4066   }
4067 
4068   if (NULL != poption->name) {
4069     FC_FREE(poption->name);
4070   }
4071   if (NULL != poption->description) {
4072     FC_FREE(poption->description);
4073   }
4074   if (NULL != poption->help_text) {
4075     FC_FREE(poption->help_text);
4076   }
4077 }
4078 
4079 /****************************************************************************
4080   Free the server options, if already received.
4081 ****************************************************************************/
server_options_free(void)4082 void server_options_free(void)
4083 {
4084   int i;
4085 
4086   /* Don't keep this dialog open. */
4087   option_dialog_popdown(server_optset);
4088 
4089   /* Free the options themselves. */
4090   if (NULL != server_options) {
4091     for (i = 0; i < server_options_num; i++) {
4092       server_option_free(server_options + i);
4093     }
4094     FC_FREE(server_options);
4095     server_options_num = 0;
4096   }
4097 
4098   /* Free the categories. */
4099   if (NULL != server_options_categories) {
4100     for (i = 0; i < server_options_categories_num; i++) {
4101       if (NULL != server_options_categories[i]) {
4102         FC_FREE(server_options_categories[i]);
4103       }
4104     }
4105     FC_FREE(server_options_categories);
4106     server_options_categories_num = 0;
4107   }
4108 }
4109 
4110 /****************************************************************************
4111   Allocate the server options and categories.
4112 ****************************************************************************/
handle_server_setting_control(const struct packet_server_setting_control * packet)4113 void handle_server_setting_control
4114     (const struct packet_server_setting_control *packet)
4115 {
4116   int i;
4117 
4118   /* This packet should be received only once. */
4119   fc_assert_ret(NULL == server_options_categories);
4120   fc_assert_ret(NULL == server_options);
4121   fc_assert_ret(0 == server_options_categories_num);
4122   fc_assert_ret(0 == server_options_num);
4123 
4124   /* Allocate server option categories. */
4125   if (0 < packet->categories_num) {
4126     server_options_categories_num = packet->categories_num;
4127     server_options_categories =
4128         fc_calloc(server_options_categories_num,
4129                   sizeof(*server_options_categories));
4130 
4131     for (i = 0; i < server_options_categories_num; i++) {
4132       /* NB: Translate now. */
4133       server_options_categories[i] = fc_strdup(_(packet->category_names[i]));
4134     }
4135   }
4136 
4137   /* Allocate server options. */
4138   if (0 < packet->settings_num) {
4139     server_options_num = packet->settings_num;
4140     server_options = fc_calloc(server_options_num, sizeof(*server_options));
4141   }
4142 }
4143 
4144 /****************************************************************************
4145   Receive a server setting info packet.
4146 ****************************************************************************/
handle_server_setting_const(const struct packet_server_setting_const * packet)4147 void handle_server_setting_const
4148     (const struct packet_server_setting_const *packet)
4149 {
4150   struct option *poption = server_optset_option_by_number(packet->id);
4151   struct server_option *psoption = SERVER_OPTION(poption);
4152 
4153   fc_assert_ret(NULL != poption);
4154 
4155   fc_assert(NULL == psoption->name);
4156   psoption->name = fc_strdup(packet->name);
4157   fc_assert(NULL == psoption->description);
4158   /* NB: Translate now. */
4159   psoption->description = fc_strdup(_(packet->short_help));
4160   fc_assert(NULL == psoption->help_text);
4161   /* NB: Translate now. */
4162   psoption->help_text = fc_strdup(_(packet->extra_help));
4163   psoption->category = packet->category;
4164 }
4165 
4166 /****************************************************************************
4167   Common part of handle_server_setting_*() functions. See below.
4168 ****************************************************************************/
4169 #define handle_server_setting_common(psoption, packet)                      \
4170   psoption->is_changeable = packet->is_changeable;                          \
4171   if (psoption->is_visible != packet->is_visible) {                         \
4172     if (psoption->is_visible) {                                             \
4173       need_gui_remove = TRUE;                                               \
4174     } else if (packet->is_visible) {                                        \
4175       need_gui_add = TRUE;                                                  \
4176     }                                                                       \
4177     psoption->is_visible = packet->is_visible;                              \
4178   }                                                                         \
4179                                                                             \
4180   if (!psoption->desired_sent                                               \
4181       && psoption->is_visible                                               \
4182       && psoption->is_changeable                                            \
4183       && is_server_running()                                                \
4184       && packet->initial_setting) {                                         \
4185     /* Only send our private settings if we are running                     \
4186      * on a forked local server, i.e. started by the                        \
4187      * client with the "Start New Game" button.                             \
4188      * Do now override settings that are already saved to savegame          \
4189      * and now loaded. */                                                   \
4190     desired_settable_option_send(OPTION(poption));                          \
4191     psoption->desired_sent = TRUE;                                          \
4192   }                                                                         \
4193                                                                             \
4194   /* Update the GUI. */                                                     \
4195   if (need_gui_remove) {                                                    \
4196     option_gui_remove(poption);                                             \
4197   } else if (need_gui_add) {                                                \
4198     option_gui_add(poption);                                                \
4199   } else {                                                                  \
4200     option_gui_update(poption);                                             \
4201   }
4202 
4203 /****************************************************************************
4204   Receive a boolean server setting info packet.
4205 ****************************************************************************/
handle_server_setting_bool(const struct packet_server_setting_bool * packet)4206 void handle_server_setting_bool
4207     (const struct packet_server_setting_bool *packet)
4208 {
4209   struct option *poption = server_optset_option_by_number(packet->id);
4210   struct server_option *psoption = SERVER_OPTION(poption);
4211   bool need_gui_remove = FALSE;
4212   bool need_gui_add = FALSE;
4213 
4214   fc_assert_ret(NULL != poption);
4215 
4216   if (NULL == poption->common_vtable) {
4217     /* Not initialized yet. */
4218     poption->poptset = server_optset;
4219     poption->common_vtable = &server_option_common_vtable;
4220     poption->type = OT_BOOLEAN;
4221     poption->bool_vtable = &server_option_bool_vtable;
4222   }
4223   fc_assert_ret_msg(OT_BOOLEAN == poption->type,
4224                     "Server setting \"%s\" (nb %d) has type %s (%d), "
4225                     "expected %s (%d)",
4226                     option_name(poption), option_number(poption),
4227                     option_type_name(poption->type), poption->type,
4228                     option_type_name(OT_BOOLEAN), OT_BOOLEAN);
4229 
4230   if (packet->is_visible) {
4231     psoption->boolean.value = packet->val;
4232     psoption->boolean.def = packet->default_val;
4233   }
4234 
4235   handle_server_setting_common(psoption, packet);
4236 }
4237 
4238 /****************************************************************************
4239   Receive a integer server setting info packet.
4240 ****************************************************************************/
handle_server_setting_int(const struct packet_server_setting_int * packet)4241 void handle_server_setting_int
4242     (const struct packet_server_setting_int *packet)
4243 {
4244   struct option *poption = server_optset_option_by_number(packet->id);
4245   struct server_option *psoption = SERVER_OPTION(poption);
4246   bool need_gui_remove = FALSE;
4247   bool need_gui_add = FALSE;
4248 
4249   fc_assert_ret(NULL != poption);
4250 
4251   if (NULL == poption->common_vtable) {
4252     /* Not initialized yet. */
4253     poption->poptset = server_optset;
4254     poption->common_vtable = &server_option_common_vtable;
4255     poption->type = OT_INTEGER;
4256     poption->int_vtable = &server_option_int_vtable;
4257   }
4258   fc_assert_ret_msg(OT_INTEGER == poption->type,
4259                     "Server setting \"%s\" (nb %d) has type %s (%d), "
4260                     "expected %s (%d)",
4261                     option_name(poption), option_number(poption),
4262                     option_type_name(poption->type), poption->type,
4263                     option_type_name(OT_INTEGER), OT_INTEGER);
4264 
4265   if (packet->is_visible) {
4266     psoption->integer.value = packet->val;
4267     psoption->integer.def = packet->default_val;
4268     psoption->integer.min = packet->min_val;
4269     psoption->integer.max = packet->max_val;
4270   }
4271 
4272   /* Backward compatibility hack: early 2.6 beta servers didn't send this
4273    * in the GAME_INFO packet, so for their benefit, scrape it from the
4274    * option packet. Elsewhere we take care to preserve it. */
4275   if (!has_capability("techloss_forgiveness", client.conn.capability)
4276       && strcmp(option_name(poption), "techlossforgiveness") == 0) {
4277     game.info.techloss_forgiveness = packet->val;
4278   }
4279 
4280   handle_server_setting_common(psoption, packet);
4281 }
4282 
4283 /****************************************************************************
4284   Receive a string server setting info packet.
4285 ****************************************************************************/
handle_server_setting_str(const struct packet_server_setting_str * packet)4286 void handle_server_setting_str
4287     (const struct packet_server_setting_str *packet)
4288 {
4289   struct option *poption = server_optset_option_by_number(packet->id);
4290   struct server_option *psoption = SERVER_OPTION(poption);
4291   bool need_gui_remove = FALSE;
4292   bool need_gui_add = FALSE;
4293 
4294   fc_assert_ret(NULL != poption);
4295 
4296   if (NULL == poption->common_vtable) {
4297     /* Not initialized yet. */
4298     poption->poptset = server_optset;
4299     poption->common_vtable = &server_option_common_vtable;
4300     poption->type = OT_STRING;
4301     poption->str_vtable = &server_option_str_vtable;
4302   }
4303   fc_assert_ret_msg(OT_STRING == poption->type,
4304                     "Server setting \"%s\" (nb %d) has type %s (%d), "
4305                     "expected %s (%d)",
4306                     option_name(poption), option_number(poption),
4307                     option_type_name(poption->type), poption->type,
4308                     option_type_name(OT_STRING), OT_STRING);
4309 
4310   if (packet->is_visible) {
4311     if (NULL == psoption->string.value) {
4312       psoption->string.value = fc_strdup(packet->val);
4313     } else if (0 != strcmp(packet->val, psoption->string.value)) {
4314       free(psoption->string.value);
4315       psoption->string.value = fc_strdup(packet->val);
4316     }
4317     if (NULL == psoption->string.def) {
4318       psoption->string.def = fc_strdup(packet->default_val);
4319     } else if (0 != strcmp(packet->default_val, psoption->string.def)) {
4320       free(psoption->string.def);
4321       psoption->string.def = fc_strdup(packet->default_val);
4322     }
4323   }
4324 
4325   handle_server_setting_common(psoption, packet);
4326 }
4327 
4328 /****************************************************************************
4329   Receive an enumerator server setting info packet.
4330 ****************************************************************************/
handle_server_setting_enum(const struct packet_server_setting_enum * packet)4331 void handle_server_setting_enum
4332     (const struct packet_server_setting_enum *packet)
4333 {
4334   struct option *poption = server_optset_option_by_number(packet->id);
4335   struct server_option *psoption = SERVER_OPTION(poption);
4336   bool need_gui_remove = FALSE;
4337   bool need_gui_add = FALSE;
4338 
4339   fc_assert_ret(NULL != poption);
4340 
4341   if (NULL == poption->common_vtable) {
4342     /* Not initialized yet. */
4343     poption->poptset = server_optset;
4344     poption->common_vtable = &server_option_common_vtable;
4345     poption->type = OT_ENUM;
4346     poption->enum_vtable = &server_option_enum_vtable;
4347   }
4348   fc_assert_ret_msg(OT_ENUM == poption->type,
4349                     "Server setting \"%s\" (nb %d) has type %s (%d), "
4350                     "expected %s (%d)",
4351                     option_name(poption), option_number(poption),
4352                     option_type_name(poption->type), poption->type,
4353                     option_type_name(OT_ENUM), OT_ENUM);
4354 
4355   if (packet->is_visible) {
4356     int i;
4357 
4358     psoption->enumerator.value = packet->val;
4359     psoption->enumerator.def = packet->default_val;
4360 
4361     if (NULL == psoption->enumerator.support_names) {
4362       /* First time we get this packet. */
4363       fc_assert(NULL == psoption->enumerator.pretty_names);
4364       psoption->enumerator.support_names = strvec_new();
4365       strvec_reserve(psoption->enumerator.support_names, packet->values_num);
4366       psoption->enumerator.pretty_names = strvec_new();
4367       strvec_reserve(psoption->enumerator.pretty_names, packet->values_num);
4368       for (i = 0; i < packet->values_num; i++) {
4369         strvec_set(psoption->enumerator.support_names, i,
4370                    packet->support_names[i]);
4371         /* Store untranslated string from server. */
4372         strvec_set(psoption->enumerator.pretty_names, i,
4373                    packet->pretty_names[i]);
4374       }
4375     } else if (strvec_size(psoption->enumerator.support_names)
4376                != packet->values_num) {
4377       fc_assert(strvec_size(psoption->enumerator.support_names)
4378                 == strvec_size(psoption->enumerator.pretty_names));
4379       /* The number of values have changed, we need to reset the list
4380        * of possible values. */
4381       strvec_reserve(psoption->enumerator.support_names, packet->values_num);
4382       strvec_reserve(psoption->enumerator.pretty_names, packet->values_num);
4383       for (i = 0; i < packet->values_num; i++) {
4384         strvec_set(psoption->enumerator.support_names, i,
4385                    packet->support_names[i]);
4386         /* Store untranslated string from server. */
4387         strvec_set(psoption->enumerator.pretty_names, i,
4388                    packet->pretty_names[i]);
4389       }
4390       need_gui_remove = TRUE;
4391       need_gui_add = TRUE;
4392     } else {
4393       /* Check if a value changed, then we need to reset the list
4394        * of possible values. */
4395       const char *str;
4396 
4397       for (i = 0; i < packet->values_num; i++) {
4398         str = strvec_get(psoption->enumerator.pretty_names, i);
4399         if (NULL == str || 0 != strcmp(str, packet->pretty_names[i])) {
4400           /* Store untranslated string from server. */
4401           strvec_set(psoption->enumerator.pretty_names, i,
4402                      packet->pretty_names[i]);
4403           need_gui_remove = TRUE;
4404           need_gui_add = TRUE;
4405         }
4406         /* Support names are not visible, we don't need to check if it
4407          * has changed. */
4408         strvec_set(psoption->enumerator.support_names, i,
4409                    packet->support_names[i]);
4410       }
4411     }
4412   }
4413 
4414   handle_server_setting_common(psoption, packet);
4415 }
4416 
4417 /****************************************************************************
4418   Receive a bitwise server setting info packet.
4419 ****************************************************************************/
handle_server_setting_bitwise(const struct packet_server_setting_bitwise * packet)4420 void handle_server_setting_bitwise
4421     (const struct packet_server_setting_bitwise *packet)
4422 {
4423   struct option *poption = server_optset_option_by_number(packet->id);
4424   struct server_option *psoption = SERVER_OPTION(poption);
4425   bool need_gui_remove = FALSE;
4426   bool need_gui_add = FALSE;
4427 
4428   fc_assert_ret(NULL != poption);
4429 
4430   if (NULL == poption->common_vtable) {
4431     /* Not initialized yet. */
4432     poption->poptset = server_optset;
4433     poption->common_vtable = &server_option_common_vtable;
4434     poption->type = OT_BITWISE;
4435     poption->bitwise_vtable = &server_option_bitwise_vtable;
4436   }
4437   fc_assert_ret_msg(OT_BITWISE == poption->type,
4438                     "Server setting \"%s\" (nb %d) has type %s (%d), "
4439                     "expected %s (%d)",
4440                     option_name(poption), option_number(poption),
4441                     option_type_name(poption->type), poption->type,
4442                     option_type_name(OT_BITWISE), OT_BITWISE);
4443 
4444   if (packet->is_visible) {
4445     int i;
4446 
4447     psoption->bitwise.value = packet->val;
4448     psoption->bitwise.def = packet->default_val;
4449 
4450     if (NULL == psoption->bitwise.support_names) {
4451       /* First time we get this packet. */
4452       fc_assert(NULL == psoption->bitwise.pretty_names);
4453       psoption->bitwise.support_names = strvec_new();
4454       strvec_reserve(psoption->bitwise.support_names, packet->bits_num);
4455       psoption->bitwise.pretty_names = strvec_new();
4456       strvec_reserve(psoption->bitwise.pretty_names, packet->bits_num);
4457       for (i = 0; i < packet->bits_num; i++) {
4458         strvec_set(psoption->bitwise.support_names, i,
4459                    packet->support_names[i]);
4460         /* Store untranslated string from server. */
4461         strvec_set(psoption->bitwise.pretty_names, i,
4462                    packet->pretty_names[i]);
4463       }
4464     } else if (strvec_size(psoption->bitwise.support_names)
4465                != packet->bits_num) {
4466       fc_assert(strvec_size(psoption->bitwise.support_names)
4467                 == strvec_size(psoption->bitwise.pretty_names));
4468       /* The number of values have changed, we need to reset the list
4469        * of possible values. */
4470       strvec_reserve(psoption->bitwise.support_names, packet->bits_num);
4471       strvec_reserve(psoption->bitwise.pretty_names, packet->bits_num);
4472       for (i = 0; i < packet->bits_num; i++) {
4473         strvec_set(psoption->bitwise.support_names, i,
4474                    packet->support_names[i]);
4475         /* Store untranslated string from server. */
4476         strvec_set(psoption->bitwise.pretty_names, i,
4477                    packet->pretty_names[i]);
4478       }
4479       need_gui_remove = TRUE;
4480       need_gui_add = TRUE;
4481     } else {
4482       /* Check if a value changed, then we need to reset the list
4483        * of possible values. */
4484       const char *str;
4485 
4486       for (i = 0; i < packet->bits_num; i++) {
4487         str = strvec_get(psoption->bitwise.pretty_names, i);
4488         if (NULL == str || 0 != strcmp(str, packet->pretty_names[i])) {
4489           /* Store untranslated string from server. */
4490           strvec_set(psoption->bitwise.pretty_names, i,
4491                      packet->pretty_names[i]);
4492           need_gui_remove = TRUE;
4493           need_gui_add = TRUE;
4494         }
4495         /* Support names are not visible, we don't need to check if it
4496          * has changed. */
4497         strvec_set(psoption->bitwise.support_names, i,
4498                    packet->support_names[i]);
4499       }
4500     }
4501   }
4502 
4503   handle_server_setting_common(psoption, packet);
4504 }
4505 
4506 /****************************************************************************
4507   Returns the next valid option pointer for the current gui type.
4508 ****************************************************************************/
4509 static struct server_option *
server_option_next_valid(struct server_option * poption)4510     server_option_next_valid(struct server_option *poption)
4511 {
4512   const struct server_option *const max =
4513     server_options + server_options_num;
4514 
4515   while (NULL != poption && poption < max && !poption->is_visible) {
4516     poption++;
4517   }
4518 
4519   return (poption < max ? poption : NULL);
4520 }
4521 
4522 /****************************************************************************
4523   Returns the server option associated to the number
4524 ****************************************************************************/
server_optset_option_by_number(int id)4525 struct option *server_optset_option_by_number(int id)
4526 {
4527   if (0 > id || id > server_options_num)  {
4528     return NULL;
4529   }
4530   return OPTION(server_options + id);
4531 }
4532 
4533 /****************************************************************************
4534   Returns the first valid (visible) option pointer.
4535 ****************************************************************************/
server_optset_option_first(void)4536 struct option *server_optset_option_first(void)
4537 {
4538   return OPTION(server_option_next_valid(server_options));
4539 }
4540 
4541 /****************************************************************************
4542   Returns the number of server option categories.
4543 ****************************************************************************/
server_optset_category_number(void)4544 int server_optset_category_number(void)
4545 {
4546   return server_options_categories_num;
4547 }
4548 
4549 /****************************************************************************
4550   Returns the name (translated) of the server option category.
4551 ****************************************************************************/
server_optset_category_name(int category)4552 const char *server_optset_category_name(int category)
4553 {
4554   if (0 > category || category >= server_options_categories_num) {
4555     return NULL;
4556   }
4557 
4558   return server_options_categories[category];
4559 }
4560 
4561 /***************************************************************************
4562   Returns the number of this server option.
4563 ****************************************************************************/
server_option_number(const struct option * poption)4564 static int server_option_number(const struct option *poption)
4565 {
4566   return SERVER_OPTION(poption) - server_options;
4567 }
4568 
4569 /****************************************************************************
4570   Returns the name of this server option.
4571 ****************************************************************************/
server_option_name(const struct option * poption)4572 static const char *server_option_name(const struct option *poption)
4573 {
4574   return SERVER_OPTION(poption)->name;
4575 }
4576 
4577 /****************************************************************************
4578   Returns the (translated) description of this server option.
4579 ****************************************************************************/
server_option_description(const struct option * poption)4580 static const char *server_option_description(const struct option *poption)
4581 {
4582   return SERVER_OPTION(poption)->description;
4583 }
4584 
4585 /****************************************************************************
4586   Returns the (translated) help text for this server option.
4587 ****************************************************************************/
server_option_help_text(const struct option * poption)4588 static const char *server_option_help_text(const struct option *poption)
4589 {
4590   return SERVER_OPTION(poption)->help_text;
4591 }
4592 
4593 /****************************************************************************
4594   Returns the category of this server option.
4595 ****************************************************************************/
server_option_category(const struct option * poption)4596 static int server_option_category(const struct option *poption)
4597 {
4598   return SERVER_OPTION(poption)->category;
4599 }
4600 
4601 /****************************************************************************
4602   Returns TRUE if this client option can be modified.
4603 ****************************************************************************/
server_option_is_changeable(const struct option * poption)4604 static bool server_option_is_changeable(const struct option *poption)
4605 {
4606   return SERVER_OPTION(poption)->is_changeable;
4607 }
4608 
4609 /****************************************************************************
4610   Returns the next valid (visible) option pointer.
4611 ****************************************************************************/
server_option_next(const struct option * poption)4612 static struct option *server_option_next(const struct option *poption)
4613 {
4614   return OPTION(server_option_next_valid(SERVER_OPTION(poption) + 1));
4615 }
4616 
4617 /****************************************************************************
4618   Returns the value of this server option of type OT_BOOLEAN.
4619 ****************************************************************************/
server_option_bool_get(const struct option * poption)4620 static bool server_option_bool_get(const struct option *poption)
4621 {
4622   return SERVER_OPTION(poption)->boolean.value;
4623 }
4624 
4625 /****************************************************************************
4626   Returns the default value of this server option of type OT_BOOLEAN.
4627 ****************************************************************************/
server_option_bool_def(const struct option * poption)4628 static bool server_option_bool_def(const struct option *poption)
4629 {
4630   return SERVER_OPTION(poption)->boolean.def;
4631 }
4632 
4633 /****************************************************************************
4634   Set the value of this server option of type OT_BOOLEAN.  Returns TRUE if
4635   the value changed.
4636 ****************************************************************************/
server_option_bool_set(struct option * poption,bool val)4637 static bool server_option_bool_set(struct option *poption, bool val)
4638 {
4639   struct server_option *psoption = SERVER_OPTION(poption);
4640 
4641   if (psoption->boolean.value == val) {
4642     return FALSE;
4643   }
4644 
4645   send_chat_printf("/set %s %s", psoption->name,
4646                    val ? "enabled" : "disabled");
4647   return TRUE;
4648 }
4649 
4650 /****************************************************************************
4651   Returns the value of this server option of type OT_INTEGER.
4652 ****************************************************************************/
server_option_int_get(const struct option * poption)4653 static int server_option_int_get(const struct option *poption)
4654 {
4655   return SERVER_OPTION(poption)->integer.value;
4656 }
4657 
4658 /****************************************************************************
4659   Returns the default value of this server option of type OT_INTEGER.
4660 ****************************************************************************/
server_option_int_def(const struct option * poption)4661 static int server_option_int_def(const struct option *poption)
4662 {
4663   return SERVER_OPTION(poption)->integer.def;
4664 }
4665 
4666 /****************************************************************************
4667   Returns the minimal value for this server option of type OT_INTEGER.
4668 ****************************************************************************/
server_option_int_min(const struct option * poption)4669 static int server_option_int_min(const struct option *poption)
4670 {
4671   return SERVER_OPTION(poption)->integer.min;
4672 }
4673 
4674 /****************************************************************************
4675   Returns the maximal value for this server option of type OT_INTEGER.
4676 ****************************************************************************/
server_option_int_max(const struct option * poption)4677 static int server_option_int_max(const struct option *poption)
4678 {
4679   return SERVER_OPTION(poption)->integer.max;
4680 }
4681 
4682 /****************************************************************************
4683   Set the value of this server option of type OT_INTEGER.  Returns TRUE if
4684   the value changed.
4685 ****************************************************************************/
server_option_int_set(struct option * poption,int val)4686 static bool server_option_int_set(struct option *poption, int val)
4687 {
4688   struct server_option *psoption = SERVER_OPTION(poption);
4689 
4690   if (val < psoption->integer.min
4691       || val > psoption->integer.max
4692       || psoption->integer.value == val) {
4693     return FALSE;
4694   }
4695 
4696   send_chat_printf("/set %s %d", psoption->name, val);
4697   return TRUE;
4698 }
4699 
4700 /****************************************************************************
4701   Returns the value of this server option of type OT_STRING.
4702 ****************************************************************************/
server_option_str_get(const struct option * poption)4703 static const char *server_option_str_get(const struct option *poption)
4704 {
4705   return SERVER_OPTION(poption)->string.value;
4706 }
4707 
4708 /****************************************************************************
4709   Returns the default value of this server option of type OT_STRING.
4710 ****************************************************************************/
server_option_str_def(const struct option * poption)4711 static const char *server_option_str_def(const struct option *poption)
4712 {
4713   return SERVER_OPTION(poption)->string.def;
4714 }
4715 
4716 /****************************************************************************
4717   Returns the possible string values of this server option of type
4718   OT_STRING.
4719 ****************************************************************************/
4720 static const struct strvec *
server_option_str_values(const struct option * poption)4721     server_option_str_values(const struct option *poption)
4722 {
4723   return NULL;
4724 }
4725 
4726 /****************************************************************************
4727   Set the value of this server option of type OT_STRING.  Returns TRUE if
4728   the value changed.
4729 ****************************************************************************/
server_option_str_set(struct option * poption,const char * str)4730 static bool server_option_str_set(struct option *poption, const char *str)
4731 {
4732   struct server_option *psoption = SERVER_OPTION(poption);
4733 
4734   if (0 == strcmp(psoption->string.value, str)) {
4735     return FALSE;
4736   }
4737 
4738   send_chat_printf("/set %s \"%s\"", psoption->name, str);
4739   return TRUE;
4740 }
4741 
4742 /****************************************************************************
4743   Returns the current value of this server option of type OT_ENUM.
4744 ****************************************************************************/
server_option_enum_get(const struct option * poption)4745 static int server_option_enum_get(const struct option *poption)
4746 {
4747   return SERVER_OPTION(poption)->enumerator.value;
4748 }
4749 
4750 /****************************************************************************
4751   Returns the default value of this server option of type OT_ENUM.
4752 ****************************************************************************/
server_option_enum_def(const struct option * poption)4753 static int server_option_enum_def(const struct option *poption)
4754 {
4755   return SERVER_OPTION(poption)->enumerator.def;
4756 }
4757 
4758 /****************************************************************************
4759   Returns the user-visible, translatable (but untranslated) "pretty" names
4760   of this server option of type OT_ENUM.
4761 ****************************************************************************/
4762 static const struct strvec *
server_option_enum_pretty(const struct option * poption)4763     server_option_enum_pretty(const struct option *poption)
4764 {
4765   return SERVER_OPTION(poption)->enumerator.pretty_names;
4766 }
4767 
4768 /****************************************************************************
4769   Set the value of this server option of type OT_ENUM.  Returns TRUE if
4770   the value changed.
4771 ****************************************************************************/
server_option_enum_set(struct option * poption,int val)4772 static bool server_option_enum_set(struct option *poption, int val)
4773 {
4774   struct server_option *psoption = SERVER_OPTION(poption);
4775   const char *name;
4776 
4777   if (val == psoption->enumerator.value
4778       || !(name = strvec_get(psoption->enumerator.support_names, val))) {
4779     return FALSE;
4780   }
4781 
4782   send_chat_printf("/set %s \"%s\"", psoption->name, name);
4783   return TRUE;
4784 }
4785 
4786 /****************************************************************************
4787   Returns the long support names of the values of the server option of type
4788   OT_ENUM.
4789 ****************************************************************************/
server_option_enum_support_name(const struct option * poption,const char ** pvalue,const char ** pdefault)4790 static void server_option_enum_support_name(const struct option *poption,
4791                                             const char **pvalue,
4792                                             const char **pdefault)
4793 {
4794   const struct server_option *psoption = SERVER_OPTION(poption);
4795   const struct strvec *values = psoption->enumerator.support_names;
4796 
4797   if (NULL != pvalue) {
4798     *pvalue = strvec_get(values, psoption->enumerator.value);
4799   }
4800   if (NULL != pdefault) {
4801     *pdefault = strvec_get(values, psoption->enumerator.def);
4802   }
4803 }
4804 
4805 /****************************************************************************
4806   Returns the current value of this server option of type OT_BITWISE.
4807 ****************************************************************************/
server_option_bitwise_get(const struct option * poption)4808 static unsigned server_option_bitwise_get(const struct option *poption)
4809 {
4810   return SERVER_OPTION(poption)->bitwise.value;
4811 }
4812 
4813 /****************************************************************************
4814   Returns the default value of this server option of type OT_BITWISE.
4815 ****************************************************************************/
server_option_bitwise_def(const struct option * poption)4816 static unsigned server_option_bitwise_def(const struct option *poption)
4817 {
4818   return SERVER_OPTION(poption)->bitwise.def;
4819 }
4820 
4821 /****************************************************************************
4822   Returns the user-visible, translatable (but untranslated) "pretty" names
4823   of this server option of type OT_BITWISE.
4824 ****************************************************************************/
4825 static const struct strvec *
server_option_bitwise_pretty(const struct option * poption)4826     server_option_bitwise_pretty(const struct option *poption)
4827 {
4828   return SERVER_OPTION(poption)->bitwise.pretty_names;
4829 }
4830 
4831 /****************************************************************************
4832   Compute the long support names of a value.
4833 ****************************************************************************/
server_option_bitwise_support_base(const struct strvec * values,unsigned val,char * buf,size_t buf_len)4834 static void server_option_bitwise_support_base(const struct strvec *values,
4835                                                unsigned val,
4836                                                char *buf, size_t buf_len)
4837 {
4838   int bit;
4839 
4840   buf[0] = '\0';
4841   for (bit = 0; bit < strvec_size(values); bit++) {
4842     if ((1 << bit) & val) {
4843       if ('\0' != buf[0]) {
4844         fc_strlcat(buf, "|", buf_len);
4845       }
4846       fc_strlcat(buf, strvec_get(values, bit), buf_len);
4847     }
4848   }
4849 }
4850 
4851 /****************************************************************************
4852   Set the value of this server option of type OT_BITWISE.  Returns TRUE if
4853   the value changed.
4854 ****************************************************************************/
server_option_bitwise_set(struct option * poption,unsigned val)4855 static bool server_option_bitwise_set(struct option *poption, unsigned val)
4856 {
4857   struct server_option *psoption = SERVER_OPTION(poption);
4858   char name[MAX_LEN_MSG];
4859 
4860   if (val == psoption->bitwise.value) {
4861     return FALSE;
4862   }
4863 
4864   server_option_bitwise_support_base(psoption->bitwise.support_names, val,
4865                                      name, sizeof(name));
4866   send_chat_printf("/set %s \"%s\"", psoption->name, name);
4867   return TRUE;
4868 }
4869 
4870 /****************************************************************************
4871   Compute the long support names of the values of the server option of type
4872   OT_BITWISE.
4873 ****************************************************************************/
server_option_bitwise_support_name(const struct option * poption,char * val_buf,size_t val_len,char * def_buf,size_t def_len)4874 static void server_option_bitwise_support_name(const struct option *poption,
4875                                                char *val_buf, size_t val_len,
4876                                                char *def_buf, size_t def_len)
4877 {
4878   const struct server_option *psoption = SERVER_OPTION(poption);
4879   const struct strvec *values = psoption->bitwise.support_names;
4880 
4881   if (NULL != val_buf && 0 < val_len) {
4882     server_option_bitwise_support_base(values, psoption->bitwise.value,
4883                                        val_buf, val_len);
4884   }
4885   if (NULL != def_buf && 0 < def_len) {
4886     server_option_bitwise_support_base(values, psoption->bitwise.def,
4887                                        def_buf, def_len);
4888   }
4889 }
4890 
4891 
4892 /** Message Options: **/
4893 
4894 int messages_where[E_COUNT];
4895 
4896 
4897 /****************************************************************
4898   These could be a static table initialisation, except
4899   its easier to do it this way.
4900 *****************************************************************/
message_options_init(void)4901 static void message_options_init(void)
4902 {
4903   int none[] = {
4904     E_IMP_BUY, E_IMP_SOLD, E_UNIT_BUY,
4905     E_UNIT_LOST_ATT, E_UNIT_WIN_ATT, E_GAME_START,
4906     E_CITY_BUILD, E_NEXT_YEAR,
4907     E_CITY_PRODUCTION_CHANGED,
4908     E_CITY_MAY_SOON_GROW, E_WORKLIST, E_AI_DEBUG
4909   };
4910   int out_only[] = {
4911     E_NATION_SELECTED, E_CHAT_MSG, E_CHAT_ERROR, E_CONNECTION,
4912     E_LOG_ERROR, E_SETTING, E_VOTE_NEW, E_VOTE_RESOLVED, E_VOTE_ABORTED
4913   };
4914   int all[] = {
4915     E_LOG_FATAL, E_SCRIPT, E_DEPRECATION_WARNING, E_MESSAGE_WALL
4916   };
4917   int i;
4918 
4919   for (i = 0; i <= event_type_max(); i++) {
4920     /* Include possible undefined values. */
4921     messages_where[i] = MW_MESSAGES;
4922   }
4923   for (i = 0; i < ARRAY_SIZE(none); i++) {
4924     messages_where[none[i]] = 0;
4925   }
4926   for (i = 0; i < ARRAY_SIZE(out_only); i++) {
4927     messages_where[out_only[i]] = MW_OUTPUT;
4928   }
4929   for (i = 0; i < ARRAY_SIZE(all); i++) {
4930     messages_where[all[i]] = MW_MESSAGES | MW_POPUP;
4931   }
4932 
4933   events_init();
4934 }
4935 
4936 /****************************************************************
4937   Free resources allocated for message options system
4938 *****************************************************************/
message_options_free(void)4939 static void message_options_free(void)
4940 {
4941   events_free();
4942 }
4943 
4944 /****************************************************************
4945   Load the message options; use the function defined by
4946   specnum.h (see also events.h).
4947 *****************************************************************/
message_options_load(struct section_file * file,const char * prefix)4948 static void message_options_load(struct section_file *file,
4949                                  const char *prefix)
4950 {
4951   enum event_type event;
4952   int i, num_events;
4953   const char *p;
4954 
4955   if (!secfile_lookup_int(file, &num_events, "messages.count")) {
4956     /* version < 2.2 */
4957     /* Order of the events in 2.1. */
4958     const enum event_type old_events[] = {
4959       E_CITY_CANTBUILD, E_CITY_LOST, E_CITY_LOVE, E_CITY_DISORDER,
4960       E_CITY_FAMINE, E_CITY_FAMINE_FEARED, E_CITY_GROWTH,
4961       E_CITY_MAY_SOON_GROW, E_CITY_AQUEDUCT, E_CITY_AQ_BUILDING,
4962       E_CITY_NORMAL, E_CITY_NUKED, E_CITY_CMA_RELEASE, E_CITY_GRAN_THROTTLE,
4963       E_CITY_TRANSFER, E_CITY_BUILD, E_CITY_PRODUCTION_CHANGED,
4964       E_WORKLIST, E_UPRISING, E_CIVIL_WAR, E_ANARCHY, E_FIRST_CONTACT,
4965       E_NEW_GOVERNMENT, E_LOW_ON_FUNDS, E_POLLUTION, E_REVOLT_DONE,
4966       E_REVOLT_START, E_SPACESHIP, E_MY_DIPLOMAT_BRIBE,
4967       E_DIPLOMATIC_INCIDENT, E_MY_DIPLOMAT_ESCAPE, E_MY_DIPLOMAT_EMBASSY,
4968       E_MY_DIPLOMAT_FAILED, E_MY_DIPLOMAT_INCITE, E_MY_DIPLOMAT_POISON,
4969       E_MY_DIPLOMAT_SABOTAGE, E_MY_DIPLOMAT_THEFT, E_ENEMY_DIPLOMAT_BRIBE,
4970       E_ENEMY_DIPLOMAT_EMBASSY, E_ENEMY_DIPLOMAT_FAILED,
4971       E_ENEMY_DIPLOMAT_INCITE, E_ENEMY_DIPLOMAT_POISON,
4972       E_ENEMY_DIPLOMAT_SABOTAGE, E_ENEMY_DIPLOMAT_THEFT,
4973       E_CARAVAN_ACTION, E_SCRIPT, E_BROADCAST_REPORT, E_GAME_END,
4974       E_GAME_START, E_NATION_SELECTED, E_DESTROYED, E_REPORT, E_TURN_BELL,
4975       E_NEXT_YEAR, E_GLOBAL_ECO, E_NUKE, E_HUT_BARB, E_HUT_CITY, E_HUT_GOLD,
4976       E_HUT_BARB_KILLED, E_HUT_MERC, E_HUT_SETTLER, E_HUT_TECH,
4977       E_HUT_BARB_CITY_NEAR, E_IMP_BUY, E_IMP_BUILD, E_IMP_AUCTIONED,
4978       E_IMP_AUTO, E_IMP_SOLD, E_TECH_GAIN, E_TECH_LEARNED, E_TREATY_ALLIANCE,
4979       E_TREATY_BROKEN, E_TREATY_CEASEFIRE, E_TREATY_PEACE,
4980       E_TREATY_SHARED_VISION, E_UNIT_LOST_ATT, E_UNIT_WIN_ATT, E_UNIT_BUY,
4981       E_UNIT_BUILT, E_UNIT_LOST_DEF, E_UNIT_WIN, E_UNIT_BECAME_VET,
4982       E_UNIT_UPGRADED, E_UNIT_RELOCATED, E_UNIT_ORDERS, E_WONDER_BUILD,
4983       E_WONDER_OBSOLETE, E_WONDER_STARTED, E_WONDER_STOPPED,
4984       E_WONDER_WILL_BE_BUILT, E_DIPLOMACY, E_TREATY_EMBASSY,
4985       E_BAD_COMMAND, E_SETTING, E_CHAT_MSG, E_MESSAGE_WALL, E_CHAT_ERROR,
4986       E_CONNECTION, E_AI_DEBUG
4987     };
4988     const size_t old_events_num = ARRAY_SIZE(old_events);
4989 
4990     for (i = 0; i < old_events_num; i++) {
4991       messages_where[old_events[i]] =
4992         secfile_lookup_int_default(file, messages_where[old_events[i]],
4993                                    "%s.message_where_%02d", prefix, i);
4994     }
4995     return;
4996   }
4997 
4998   for (i = 0; i < num_events; i++) {
4999     p = secfile_lookup_str(file, "messages.event%d.name", i);
5000     if (NULL == p) {
5001       log_error("Corruption in file %s: %s",
5002                 secfile_name(file), secfile_error());
5003       continue;
5004     }
5005     event = event_type_by_name(p, strcmp);
5006     if (!event_type_is_valid(event)) {
5007       log_error("Event not supported: %s", p);
5008       continue;
5009     }
5010 
5011     if (!secfile_lookup_int(file, &messages_where[event],
5012                             "messages.event%d.where", i)) {
5013       log_error("Corruption in file %s: %s",
5014                 secfile_name(file), secfile_error());
5015     }
5016   }
5017 }
5018 
5019 /****************************************************************
5020   Save the message options; use the function defined by
5021   specnum.h (see also events.h).
5022 *****************************************************************/
message_options_save(struct section_file * file,const char * prefix)5023 static void message_options_save(struct section_file *file,
5024                                  const char *prefix)
5025 {
5026   enum event_type event;
5027   int i = 0;
5028 
5029   for (event = event_type_begin(); event != event_type_end();
5030        event = event_type_next(event)) {
5031     secfile_insert_str(file, event_type_name(event),
5032                        "messages.event%d.name", i);
5033     secfile_insert_int(file, messages_where[i],
5034                        "messages.event%d.where", i);
5035     i++;
5036   }
5037 
5038   secfile_insert_int(file, i, "messages.count");
5039 }
5040 
5041 
5042 /****************************************************************
5043  Does heavy lifting for looking up a preset.
5044 *****************************************************************/
load_cma_preset(struct section_file * file,int i)5045 static void load_cma_preset(struct section_file *file, int i)
5046 {
5047   struct cm_parameter parameter;
5048   const char *name =
5049     secfile_lookup_str_default(file, "preset",
5050                                "cma.preset%d.name", i);
5051 
5052   output_type_iterate(o) {
5053     parameter.minimal_surplus[o] =
5054         secfile_lookup_int_default(file, 0, "cma.preset%d.minsurp%d", i, o);
5055     parameter.factor[o] =
5056         secfile_lookup_int_default(file, 0, "cma.preset%d.factor%d", i, o);
5057   } output_type_iterate_end;
5058   parameter.require_happy =
5059       secfile_lookup_bool_default(file, FALSE, "cma.preset%d.reqhappy", i);
5060   parameter.happy_factor =
5061       secfile_lookup_int_default(file, 0, "cma.preset%d.happyfactor", i);
5062   parameter.allow_disorder = FALSE;
5063   parameter.allow_specialists = TRUE;
5064 
5065   cmafec_preset_add(name, &parameter);
5066 }
5067 
5068 /****************************************************************
5069  Does heavy lifting for inserting a preset.
5070 *****************************************************************/
save_cma_preset(struct section_file * file,int i)5071 static void save_cma_preset(struct section_file *file, int i)
5072 {
5073   const struct cm_parameter *const pparam = cmafec_preset_get_parameter(i);
5074   char *name = cmafec_preset_get_descr(i);
5075 
5076   secfile_insert_str(file, name, "cma.preset%d.name", i);
5077 
5078   output_type_iterate(o) {
5079     secfile_insert_int(file, pparam->minimal_surplus[o],
5080                        "cma.preset%d.minsurp%d", i, o);
5081     secfile_insert_int(file, pparam->factor[o],
5082                        "cma.preset%d.factor%d", i, o);
5083   } output_type_iterate_end;
5084   secfile_insert_bool(file, pparam->require_happy,
5085                       "cma.preset%d.reqhappy", i);
5086   secfile_insert_int(file, pparam->happy_factor,
5087                      "cma.preset%d.happyfactor", i);
5088 }
5089 
5090 /****************************************************************
5091  Insert all cma presets.
5092 *****************************************************************/
save_cma_presets(struct section_file * file)5093 static void save_cma_presets(struct section_file *file)
5094 {
5095   int i;
5096 
5097   secfile_insert_int_comment(file, cmafec_preset_num(),
5098                              _("If you add a preset by hand,"
5099                                " also update \"number_of_presets\""),
5100                              "cma.number_of_presets");
5101   for (i = 0; i < cmafec_preset_num(); i++) {
5102     save_cma_preset(file, i);
5103   }
5104 }
5105 
5106 /* Old rc file name. */
5107 #define OLD_OPTION_FILE_NAME ".civclientrc"
5108 /* New rc file name. */
5109 #define MID_OPTION_FILE_NAME ".freeciv-client-rc-%d.%d"
5110 #define NEW_OPTION_FILE_NAME "freeciv-client-rc-%d.%d"
5111 #if MINOR_VERSION >= 90
5112 #define MAJOR_NEW_OPTION_FILE_NAME (MAJOR_VERSION + 1)
5113 #define MINOR_NEW_OPTION_FILE_NAME 0
5114 #else /* MINOR_VERSION < 90 */
5115 #define MAJOR_NEW_OPTION_FILE_NAME MAJOR_VERSION
5116 #if IS_DEVEL_VERSION && ! IS_FREEZE_VERSION
5117 #define MINOR_NEW_OPTION_FILE_NAME (MINOR_VERSION + 1)
5118 #else
5119 #define MINOR_NEW_OPTION_FILE_NAME MINOR_VERSION
5120 #endif /* IS_DEVEL_VERSION */
5121 #endif /* MINOR_VERSION >= 90 */
5122 /* The first version the new option name appeared (2.6). */
5123 #define FIRST_MAJOR_NEW_OPTION_FILE_NAME 2
5124 #define FIRST_MINOR_NEW_OPTION_FILE_NAME 6
5125 /* The first version the mid option name appeared (2.2). */
5126 #define FIRST_MAJOR_MID_OPTION_FILE_NAME 2
5127 #define FIRST_MINOR_MID_OPTION_FILE_NAME 2
5128 /* The first version the new boolean values appeared (2.3). */
5129 #define FIRST_MAJOR_NEW_BOOLEAN 2
5130 #define FIRST_MINOR_NEW_BOOLEAN 3
5131 /****************************************************************
5132   Returns pointer to static memory containing name of the current
5133   option file.  Usually used for saving.
5134   Ie, based on FREECIV_OPT env var, and home dir. (or a
5135   OPTION_FILE_NAME define defined in fc_config.h)
5136   Or NULL if problem.
5137 *****************************************************************/
get_current_option_file_name(void)5138 static const char *get_current_option_file_name(void)
5139 {
5140   static char name_buffer[256];
5141   const char *name;
5142 
5143   name = getenv("FREECIV_OPT");
5144 
5145   if (name) {
5146     sz_strlcpy(name_buffer, name);
5147   } else {
5148 #ifdef OPTION_FILE_NAME
5149     fc_strlcpy(name_buffer, OPTION_FILE_NAME, sizeof(name_buffer));
5150 #else
5151     name = user_home_dir();
5152     if (!name) {
5153       log_error(_("Cannot find your home directory"));
5154       return NULL;
5155     }
5156 #ifdef HAIKU
5157     fc_snprintf(name_buffer, sizeof(name_buffer),
5158                 "%s" DIR_SEPARATOR "config" DIR_SEPARATOR "settings" DIR_SEPARATOR
5159                 "freeciv" DIR_SEPARATOR NEW_OPTION_FILE_NAME,
5160                 name, MAJOR_NEW_OPTION_FILE_NAME, MINOR_NEW_OPTION_FILE_NAME);
5161 #else  /* HAIKU */
5162     fc_snprintf(name_buffer, sizeof(name_buffer),
5163                 "%s" DIR_SEPARATOR ".freeciv" DIR_SEPARATOR NEW_OPTION_FILE_NAME,
5164                 name, MAJOR_NEW_OPTION_FILE_NAME, MINOR_NEW_OPTION_FILE_NAME);
5165 #endif  /* HAIKU */
5166 #endif /* OPTION_FILE_NAME */
5167   }
5168   log_verbose("settings file is %s", name_buffer);
5169   return name_buffer;
5170 }
5171 
5172 /****************************************************************************
5173   Check the last option file we saved. Usually used to load. Ie, based on
5174   FREECIV_OPT env var, and home dir. (or a OPTION_FILE_NAME define defined
5175   in fc_config.h), or NULL if not found.
5176 
5177   Set in allow_digital_boolean if we should look for old boolean values
5178   (saved as 0 and 1), so if the rc file version is older than 2.3.0.
5179 ****************************************************************************/
get_last_option_file_name(bool * allow_digital_boolean)5180 static const char *get_last_option_file_name(bool *allow_digital_boolean)
5181 {
5182   static char name_buffer[256];
5183   const char *name;
5184   static int last_minors[] = {
5185     0,  /* There was no 0.x releases */
5186     14, /* 1.14 */
5187     6   /* 2.6 */
5188   };
5189 
5190   FC_STATIC_ASSERT(MAJOR_VERSION < sizeof(last_minors) / sizeof(int), missing_last_minor);
5191 
5192   *allow_digital_boolean = FALSE;
5193   name = getenv("FREECIV_OPT");
5194   if (name) {
5195     sz_strlcpy(name_buffer, name);
5196   } else {
5197 #ifdef OPTION_FILE_NAME
5198     fc_strlcpy(name_buffer, OPTION_FILE_NAME, sizeof(name_buffer));
5199 #else
5200     int major, minor;
5201     struct stat buf;
5202 
5203     name = user_home_dir();
5204     if (!name) {
5205       log_error(_("Cannot find your home directory"));
5206       return NULL;
5207     }
5208     for (major = MAJOR_NEW_OPTION_FILE_NAME,
5209          minor = MINOR_NEW_OPTION_FILE_NAME;
5210          major >= FIRST_MAJOR_NEW_OPTION_FILE_NAME; major--) {
5211       for (; (major == FIRST_MAJOR_NEW_OPTION_FILE_NAME
5212               ? minor >= FIRST_MINOR_NEW_OPTION_FILE_NAME
5213               : minor >= 0); minor--) {
5214         fc_snprintf(name_buffer, sizeof(name_buffer),
5215 #ifdef HAIKU
5216                     "%s" DIR_SEPARATOR "config" DIR_SEPARATOR "settings" DIR_SEPARATOR
5217                     "freeciv" DIR_SEPARATOR NEW_OPTION_FILE_NAME,
5218                     name, major, minor);
5219 #else /* HAIKU */
5220                     "%s" DIR_SEPARATOR ".freeciv" DIR_SEPARATOR NEW_OPTION_FILE_NAME,
5221                     name, major, minor);
5222 #endif /* HAIKU */
5223         if (0 == fc_stat(name_buffer, &buf)) {
5224           if (MAJOR_NEW_OPTION_FILE_NAME != major
5225               || MINOR_NEW_OPTION_FILE_NAME != minor) {
5226             log_normal(_("Didn't find '%s' option file, "
5227                          "loading from '%s' instead."),
5228                        get_current_option_file_name() + strlen(name) + 1,
5229                        name_buffer + strlen(name) + 1);
5230           }
5231 
5232           return name_buffer;
5233         }
5234       }
5235       minor = last_minors[major - 1];
5236     }
5237 
5238     /* minor having max value of FIRST_MINOR_NEW_OPTION_FILE_NAME
5239      * works since MID versioning scheme was used within major version 2
5240      * only (2.2 - 2.6) so the last minor is bigger than any earlier minor. */
5241     for (major = FIRST_MAJOR_MID_OPTION_FILE_NAME,
5242          minor = FIRST_MINOR_NEW_OPTION_FILE_NAME ;
5243          minor >= FIRST_MINOR_MID_OPTION_FILE_NAME ;
5244          minor--) {
5245       fc_snprintf(name_buffer, sizeof(name_buffer),
5246                   "%s" DIR_SEPARATOR MID_OPTION_FILE_NAME, name, major, minor);
5247       if (0 == fc_stat(name_buffer, &buf)) {
5248         log_normal(_("Didn't find '%s' option file, "
5249                      "loading from '%s' instead."),
5250                    get_current_option_file_name() + strlen(name) + 1,
5251                    name_buffer + strlen(name) + 1);
5252 
5253         if (FIRST_MINOR_NEW_BOOLEAN > minor) {
5254           *allow_digital_boolean = TRUE;
5255         }
5256         return name_buffer;
5257       }
5258     }
5259 
5260     /* Try with the old one. */
5261     fc_snprintf(name_buffer, sizeof(name_buffer),
5262                 "%s" DIR_SEPARATOR OLD_OPTION_FILE_NAME, name);
5263     if (0 == fc_stat(name_buffer, &buf)) {
5264       log_normal(_("Didn't find '%s' option file, "
5265                    "loading from '%s' instead."),
5266                  get_current_option_file_name() + strlen(name) + 1,
5267                  OLD_OPTION_FILE_NAME);
5268       *allow_digital_boolean = TRUE;
5269       return name_buffer;
5270     } else {
5271       return NULL;
5272     }
5273 #endif /* OPTION_FILE_NAME */
5274   }
5275   log_verbose("settings file is %s", name_buffer);
5276   return name_buffer;
5277 }
5278 #undef OLD_OPTION_FILE_NAME
5279 #undef MID_OPTION_FILE_NAME
5280 #undef NEW_OPTION_FILE_NAME
5281 #undef FIRST_MAJOR_NEW_OPTION_FILE_NAME
5282 #undef FIRST_MINOR_NEW_OPTION_FILE_NAME
5283 #undef FIRST_MAJOR_MID_OPTION_FILE_NAME
5284 #undef FIRST_MINOR_MID_OPTION_FILE_NAME
5285 #undef FIRST_MINOR_NEW_BOOLEAN
5286 
5287 
5288 /****************************************************************************
5289   Desired settable options.
5290 ****************************************************************************/
5291 #define SPECHASH_TAG settable_options
5292 #define SPECHASH_ASTR_KEY_TYPE
5293 #define SPECHASH_ASTR_DATA_TYPE
5294 #include "spechash.h"
5295 #define settable_options_hash_iterate(hash, name, value)                    \
5296   TYPED_HASH_ITERATE(const char *, const char *, hash, name, value)
5297 #define settable_options_hash_iterate_end HASH_ITERATE_END
5298 
5299 static struct settable_options_hash *settable_options_hash = NULL;
5300 
5301 /**************************************************************************
5302   Load the server options.
5303 **************************************************************************/
settable_options_load(struct section_file * sf)5304 static void settable_options_load(struct section_file *sf)
5305 {
5306   char buf[64];
5307   const struct section *psection;
5308   const struct entry_list *entries;
5309   const char *string;
5310   bool bval;
5311   int ival;
5312 
5313   fc_assert_ret(NULL != settable_options_hash);
5314 
5315   settable_options_hash_clear(settable_options_hash);
5316 
5317   psection = secfile_section_by_name(sf, "server");
5318   if (NULL == psection) {
5319     /* Does not exist! */
5320     return;
5321   }
5322 
5323   entries = section_entries(psection);
5324   entry_list_iterate(entries, pentry) {
5325     string = NULL;
5326     switch (entry_type(pentry)) {
5327     case ENTRY_BOOL:
5328       if (entry_bool_get(pentry, &bval)) {
5329         fc_strlcpy(buf, bval ? "enabled" : "disabled", sizeof(buf));
5330         string = buf;
5331       }
5332       break;
5333 
5334     case ENTRY_INT:
5335       if (entry_int_get(pentry, &ival)) {
5336         fc_snprintf(buf, sizeof(buf), "%d", ival);
5337         string = buf;
5338       }
5339       break;
5340 
5341     case ENTRY_STR:
5342       (void) entry_str_get(pentry, &string);
5343       break;
5344 
5345     case ENTRY_FLOAT:
5346     case ENTRY_FILEREFERENCE:
5347       /* Not supported yet */
5348       break;
5349     case ENTRY_ILLEGAL:
5350       fc_assert(entry_type(pentry) != ENTRY_ILLEGAL);
5351       break;
5352     }
5353 
5354     if (NULL == string) {
5355       log_error("Entry type variant of \"%s.%s\" is not supported.",
5356                 section_name(psection), entry_name(pentry));
5357       continue;
5358     }
5359 
5360     settable_options_hash_insert(settable_options_hash, entry_name(pentry),
5361                                  string);
5362   } entry_list_iterate_end;
5363 }
5364 
5365 /****************************************************************
5366   Save the desired server options.
5367 *****************************************************************/
settable_options_save(struct section_file * sf)5368 static void settable_options_save(struct section_file *sf)
5369 {
5370   fc_assert_ret(NULL != settable_options_hash);
5371 
5372   settable_options_hash_iterate(settable_options_hash, name, value) {
5373     if (!fc_strcasecmp(name, "gameseed") || !fc_strcasecmp(name, "mapseed")) {
5374       /* Do not save mapseed or gameseed. */
5375       continue;
5376     }
5377     if (!fc_strcasecmp(name, "topology")) {
5378       /* client_start_server() sets topology based on tileset. Don't store
5379        * its choice. The tileset is already stored. Storing topology leads
5380        * to all sort of breakage:
5381        * - it breaks ruleset default topology.
5382        * - it interacts badly with tileset ruleset change, ruleset tileset
5383        *   change and topology tileset change.
5384        * - its value is probably based on what tileset was loaded when
5385        *   client_start_server() decided to set topology, not on player
5386        *   choice.
5387        */
5388       continue;
5389     }
5390     secfile_insert_str(sf, value, "server.%s", name);
5391   } settable_options_hash_iterate_end;
5392 }
5393 
5394 /****************************************************************************
5395   Update the desired settable options hash table from the current
5396   setting configuration.
5397 ****************************************************************************/
desired_settable_options_update(void)5398 void desired_settable_options_update(void)
5399 {
5400   char val_buf[1024], def_buf[1024];
5401   const char *value, *def_val;
5402 
5403   fc_assert_ret(NULL != settable_options_hash);
5404 
5405   options_iterate(server_optset, poption) {
5406     value = NULL;
5407     def_val = NULL;
5408     switch (option_type(poption)) {
5409     case OT_BOOLEAN:
5410       fc_strlcpy(val_buf, option_bool_get(poption) ? "enabled" : "disabled",
5411                  sizeof(val_buf));
5412       value = val_buf;
5413       fc_strlcpy(def_buf, option_bool_def(poption) ? "enabled" : "disabled",
5414                  sizeof(def_buf));
5415       def_val = def_buf;
5416       break;
5417     case OT_INTEGER:
5418       fc_snprintf(val_buf, sizeof(val_buf), "%d", option_int_get(poption));
5419       value = val_buf;
5420       fc_snprintf(def_buf, sizeof(def_buf), "%d", option_int_def(poption));
5421       def_val = def_buf;
5422       break;
5423     case OT_STRING:
5424       value = option_str_get(poption);
5425       def_val = option_str_def(poption);
5426       break;
5427     case OT_ENUM:
5428       server_option_enum_support_name(poption, &value, &def_val);
5429       break;
5430     case OT_BITWISE:
5431       server_option_bitwise_support_name(poption, val_buf, sizeof(val_buf),
5432                                          def_buf, sizeof(def_buf));
5433       value = val_buf;
5434       def_val = def_buf;
5435       break;
5436     case OT_FONT:
5437     case OT_COLOR:
5438     case OT_VIDEO_MODE:
5439       break;
5440     }
5441 
5442     if (NULL == value || NULL == def_val) {
5443       log_error("Option type %s (%d) not supported for '%s'.",
5444                 option_type_name(option_type(poption)), option_type(poption),
5445                 option_name(poption));
5446       continue;
5447     }
5448 
5449     if (0 == strcmp(value, def_val)) {
5450       /* Not set, using default... */
5451       settable_options_hash_remove(settable_options_hash,
5452                                    option_name(poption));
5453     } else {
5454       /* Really desired. */
5455       settable_options_hash_replace(settable_options_hash,
5456                                     option_name(poption), value);
5457     }
5458   } options_iterate_end;
5459 }
5460 
5461 /****************************************************************
5462   Update a desired settable option in the hash table from a value
5463   which can be different of the current configuration.
5464 *****************************************************************/
desired_settable_option_update(const char * op_name,const char * op_value,bool allow_replace)5465 void desired_settable_option_update(const char *op_name,
5466                                     const char *op_value,
5467                                     bool allow_replace)
5468 {
5469   fc_assert_ret(NULL != settable_options_hash);
5470 
5471   if (allow_replace) {
5472     settable_options_hash_replace(settable_options_hash, op_name, op_value);
5473   } else {
5474     settable_options_hash_insert(settable_options_hash, op_name, op_value);
5475   }
5476 }
5477 
5478 /****************************************************************************
5479   Convert old integer to new values (Freeciv 2.2.x to Freeciv 2.3.x).
5480   Very ugly hack. TODO: Remove this later.
5481 ****************************************************************************/
settable_option_upgrade_value(const struct option * poption,int old_value,char * buf,size_t buf_len)5482 static bool settable_option_upgrade_value(const struct option *poption,
5483                                           int old_value,
5484                                           char *buf, size_t buf_len)
5485 {
5486   const char *name = option_name(poption);
5487 
5488 #define SETTING_CASE(ARG_name, ...)                                         \
5489   if (0 == strcmp(ARG_name, name)) {                                        \
5490     static const char *values[] = { __VA_ARGS__ };                          \
5491     if (0 <= old_value && old_value < ARRAY_SIZE(values)                    \
5492         && NULL != values[old_value]) {                                     \
5493       fc_strlcpy(buf, values[old_value], buf_len);                          \
5494       return TRUE;                                                          \
5495     } else {                                                                \
5496       return FALSE;                                                         \
5497     }                                                                       \
5498   }
5499 
5500   SETTING_CASE("topology", "", "WRAPX", "WRAPY", "WRAPX|WRAPY", "ISO",
5501                "WRAPX|ISO", "WRAPY|ISO", "WRAPX|WRAPY|ISO", "HEX",
5502                "WRAPX|HEX", "WRAPY|HEX", "WRAPX|WRAPY|HEX", "ISO|HEX",
5503                "WRAPX|ISO|HEX", "WRAPY|ISO|HEX", "WRAPX|WRAPY|ISO|HEX");
5504   SETTING_CASE("generator", NULL, "RANDOM", "FRACTAL", "ISLAND");
5505   SETTING_CASE("startpos", "DEFAULT", "SINGLE", "2or3", "ALL", "VARIABLE");
5506   SETTING_CASE("borders", "DISABLED", "ENABLED", "SEE_INSIDE", "EXPAND");
5507   SETTING_CASE("diplomacy", "ALL", "HUMAN", "AI", "TEAM", "DISABLED");
5508   SETTING_CASE("citynames", "NO_RESTRICTIONS", "PLAYER_UNIQUE",
5509                "GLOBAL_UNIQUE", "NO_STEALING");
5510   SETTING_CASE("barbarians", "DISABLED", "HUTS_ONLY", "NORMAL", "FREQUENT",
5511                "HORDES");
5512   SETTING_CASE("phasemode", "ALL", "PLAYER", "TEAM");
5513   SETTING_CASE("compresstype", "PLAIN", "LIBZ", "BZIP2");
5514 
5515 #undef SETTING_CASE
5516   return FALSE;
5517 }
5518 
5519 /****************************************************************************
5520   Send the desired server options to the server.
5521 ****************************************************************************/
desired_settable_option_send(struct option * poption)5522 static void desired_settable_option_send(struct option *poption)
5523 {
5524   char *desired;
5525   int value;
5526 
5527   fc_assert_ret(NULL != settable_options_hash);
5528 
5529   if (!settable_options_hash_lookup(settable_options_hash,
5530                                     option_name(poption), &desired)) {
5531     /* No change explicitly  desired. */
5532     return;
5533   }
5534 
5535   switch (option_type(poption)) {
5536   case OT_BOOLEAN:
5537     if ((0 == fc_strcasecmp("enabled", desired)
5538          || (str_to_int(desired, &value) && 1 == value))
5539         && !option_bool_get(poption)) {
5540       send_chat_printf("/set %s enabled", option_name(poption));
5541     } else if ((0 == fc_strcasecmp("disabled", desired)
5542                 || (str_to_int(desired, &value) && 0 == value))
5543                && option_bool_get(poption)) {
5544       send_chat_printf("/set %s disabled", option_name(poption));
5545     }
5546     return;
5547   case OT_INTEGER:
5548     if (str_to_int(desired, &value) && value != option_int_get(poption)) {
5549       send_chat_printf("/set %s %d", option_name(poption), value);
5550     }
5551     return;
5552   case OT_STRING:
5553     if (0 != strcmp(desired, option_str_get(poption))) {
5554       send_chat_printf("/set %s \"%s\"", option_name(poption), desired);
5555     }
5556     return;
5557   case OT_ENUM:
5558     {
5559       char desired_buf[256];
5560       const char *value_str;
5561 
5562       /* Handle old values. */
5563       if (str_to_int(desired, &value)
5564           && settable_option_upgrade_value(poption, value, desired_buf,
5565                                            sizeof(desired_buf))) {
5566         desired = desired_buf;
5567       }
5568 
5569       server_option_enum_support_name(poption, &value_str, NULL);
5570       if (0 != strcmp(desired, value_str)) {
5571         send_chat_printf("/set %s \"%s\"", option_name(poption), desired);
5572       }
5573     }
5574     return;
5575   case OT_BITWISE:
5576     {
5577       char desired_buf[256], value_buf[256];
5578 
5579       /* Handle old values. */
5580       if (str_to_int(desired, &value)
5581           && settable_option_upgrade_value(poption, value, desired_buf,
5582                                            sizeof(desired_buf))) {
5583         desired = desired_buf;
5584       }
5585 
5586       server_option_bitwise_support_name(poption, value_buf,
5587                                          sizeof(value_buf), NULL, 0);
5588       if (0 != strcmp(desired, value_buf)) {
5589         send_chat_printf("/set %s \"%s\"", option_name(poption), desired);
5590       }
5591     }
5592     return;
5593   case OT_FONT:
5594   case OT_COLOR:
5595   case OT_VIDEO_MODE:
5596     break;
5597   }
5598 
5599   log_error("Option type %s (%d) not supported for '%s'.",
5600             option_type_name(option_type(poption)), option_type(poption),
5601             option_name(poption));
5602 }
5603 
5604 
5605 /****************************************************************************
5606   City and player report dialog options.
5607 ****************************************************************************/
5608 #define SPECHASH_TAG dialog_options
5609 #define SPECHASH_ASTR_KEY_TYPE
5610 #define SPECHASH_IDATA_TYPE bool
5611 #define SPECHASH_UDATA_TO_IDATA FC_INT_TO_PTR
5612 #define SPECHASH_IDATA_TO_UDATA FC_PTR_TO_INT
5613 #include "spechash.h"
5614 #define dialog_options_hash_iterate(hash, column, visible)                  \
5615   TYPED_HASH_ITERATE(const char *, intptr_t, hash, column, visible)
5616 #define dialog_options_hash_iterate_end HASH_ITERATE_END
5617 
5618 static struct dialog_options_hash *dialog_options_hash = NULL;
5619 
5620 /****************************************************************************
5621   Load the city and player report dialog options.
5622 ****************************************************************************/
options_dialogs_load(struct section_file * sf)5623 static void options_dialogs_load(struct section_file *sf)
5624 {
5625   const struct entry_list *entries;
5626   const char *prefixes[] = { "player_dlg_", "city_report_", NULL };
5627   const char **prefix;
5628   bool visible;
5629 
5630   fc_assert_ret(NULL != dialog_options_hash);
5631 
5632   entries = section_entries(secfile_section_by_name(sf, "client"));
5633 
5634   if (NULL != entries) {
5635     entry_list_iterate(entries, pentry) {
5636       for (prefix = prefixes; NULL != *prefix; prefix++) {
5637         if (0 == strncmp(*prefix, entry_name(pentry), strlen(*prefix))
5638             && secfile_lookup_bool(sf, &visible, "client.%s",
5639                                    entry_name(pentry))) {
5640           dialog_options_hash_replace(dialog_options_hash,
5641                                       entry_name(pentry), visible);
5642           break;
5643         }
5644       }
5645     } entry_list_iterate_end;
5646   }
5647 }
5648 
5649 /****************************************************************************
5650   Save the city and player report dialog options.
5651 ****************************************************************************/
options_dialogs_save(struct section_file * sf)5652 static void options_dialogs_save(struct section_file *sf)
5653 {
5654   fc_assert_ret(NULL != dialog_options_hash);
5655 
5656   options_dialogs_update();
5657   dialog_options_hash_iterate(dialog_options_hash, column, visible) {
5658     secfile_insert_bool(sf, visible, "client.%s", column);
5659   } dialog_options_hash_iterate_end;
5660 }
5661 
5662 /****************************************************************
5663   This set the city and player report dialog options to the
5664   current ones.  It's called when the client goes to
5665   C_S_DISCONNECTED state.
5666 *****************************************************************/
options_dialogs_update(void)5667 void options_dialogs_update(void)
5668 {
5669   char buf[64];
5670   int i;
5671 
5672   fc_assert_ret(NULL != dialog_options_hash);
5673 
5674   /* Player report dialog options. */
5675   for (i = 1; i < num_player_dlg_columns; i++) {
5676     fc_snprintf(buf, sizeof(buf), "player_dlg_%s",
5677                 player_dlg_columns[i].tagname);
5678     dialog_options_hash_replace(dialog_options_hash, buf,
5679                                 player_dlg_columns[i].show);
5680   }
5681 
5682   /* City report dialog options. */
5683   for (i = 0; i < num_city_report_spec(); i++) {
5684     fc_snprintf(buf, sizeof(buf), "city_report_%s",
5685                 city_report_spec_tagname(i));
5686     dialog_options_hash_replace(dialog_options_hash, buf,
5687                                 *city_report_spec_show_ptr(i));
5688   }
5689 }
5690 
5691 /****************************************************************
5692   This set the city and player report dialog options.  It's called
5693   when the client goes to C_S_RUNNING state.
5694 *****************************************************************/
options_dialogs_set(void)5695 void options_dialogs_set(void)
5696 {
5697   char buf[64];
5698   bool visible;
5699   int i;
5700 
5701   fc_assert_ret(NULL != dialog_options_hash);
5702 
5703   /* Player report dialog options. */
5704   for (i = 1; i < num_player_dlg_columns; i++) {
5705     fc_snprintf(buf, sizeof(buf), "player_dlg_%s",
5706                 player_dlg_columns[i].tagname);
5707     if (dialog_options_hash_lookup(dialog_options_hash, buf, &visible)) {
5708       player_dlg_columns[i].show = visible;
5709     }
5710   }
5711 
5712   /* City report dialog options. */
5713   for (i = 0; i < num_city_report_spec(); i++) {
5714     fc_snprintf(buf, sizeof(buf), "city_report_%s",
5715                 city_report_spec_tagname(i));
5716     if (dialog_options_hash_lookup(dialog_options_hash, buf, &visible)) {
5717       *city_report_spec_show_ptr(i) = visible;
5718     }
5719   }
5720 }
5721 
5722 
5723 /****************************************************************
5724   Load from the rc file any options that are not ruleset specific.
5725   It is called after ui_init(), yet before ui_main().
5726   Unfortunately, this means that some clients cannot display.
5727   Instead, use log_*().
5728 *****************************************************************/
options_load(void)5729 void options_load(void)
5730 {
5731   struct section_file *sf;
5732   bool allow_digital_boolean;
5733   int i, num;
5734   const char *name;
5735   const char *const prefix = "client";
5736   const char *str;
5737 
5738   name = get_last_option_file_name(&allow_digital_boolean);
5739   if (!name) {
5740     log_normal(_("Didn't find the option file. Creating a new one."));
5741     options_fully_initialized = TRUE;
5742     create_default_cma_presets();
5743     gui_options.first_boot = TRUE;
5744     return;
5745   }
5746   if (!(sf = secfile_load(name, TRUE))) {
5747     log_debug("Error loading option file '%s':\n%s", name, secfile_error());
5748     /* try to create the rc file */
5749     sf = secfile_new(TRUE);
5750     secfile_insert_str(sf, VERSION_STRING, "client.version");
5751 
5752     create_default_cma_presets();
5753     gui_options.first_boot = TRUE;
5754     save_cma_presets(sf);
5755 
5756     /* FIXME: need better messages */
5757     if (!secfile_save(sf, name, 0, FZ_PLAIN)) {
5758       log_error(_("Save failed, cannot write to file %s"), name);
5759     } else {
5760       log_normal(_("Saved settings to file %s"), name);
5761     }
5762     secfile_destroy(sf);
5763     options_fully_initialized = TRUE;
5764     return;
5765   }
5766   secfile_allow_digital_boolean(sf, allow_digital_boolean);
5767 
5768   /* a "secret" option for the lazy. TODO: make this saveable */
5769   sz_strlcpy(fc_password,
5770              secfile_lookup_str_default(sf, "", "%s.password", prefix));
5771 
5772   gui_options.save_options_on_exit =
5773     secfile_lookup_bool_default(sf, gui_options.save_options_on_exit,
5774                                 "%s.save_options_on_exit", prefix);
5775   gui_options.migrate_fullscreen =
5776     secfile_lookup_bool_default(sf, gui_options.migrate_fullscreen,
5777                                 "%s.fullscreen_mode", prefix);
5778 
5779   /* Settings migrations */
5780   gui_options.gui_gtk3_22_migrated_from_gtk3 =
5781     secfile_lookup_bool_default(sf, gui_options.gui_gtk3_22_migrated_from_gtk3,
5782                                 "%s.migration_gtk3_22_from_gtk3", prefix);
5783   gui_options.gui_gtk3_migrated_from_gtk2 =
5784     secfile_lookup_bool_default(sf, gui_options.gui_gtk3_migrated_from_gtk2,
5785                                 "%s.migration_gtk3_from_gtk2", prefix);
5786   gui_options.gui_sdl2_migrated_from_sdl =
5787     secfile_lookup_bool_default(sf, gui_options.gui_sdl2_migrated_from_sdl,
5788                                 "%s.migration_sdl2_from_sdl", prefix);
5789   gui_options.gui_gtk2_migrated_from_2_5 =
5790     secfile_lookup_bool_default(sf, gui_options.gui_gtk2_migrated_from_2_5,
5791                                 "%s.migration_gtk2_from_2_5", prefix);
5792   gui_options.gui_gtk3_migrated_from_2_5 =
5793     secfile_lookup_bool_default(sf, gui_options.gui_gtk3_migrated_from_2_5,
5794                                 "%s.migration_gtk3_from_2_5", prefix);
5795   gui_options.gui_qt_migrated_from_2_5 =
5796     secfile_lookup_bool_default(sf, gui_options.gui_qt_migrated_from_2_5,
5797                                 "%s.migration_qt_from_2_5", prefix);
5798 
5799   /* These are not gui-enabled yet */
5800   gui_options.zoom_set =
5801     secfile_lookup_bool_default(sf, FALSE, "%s.zoom_set", prefix);
5802   gui_options.zoom_default_level =
5803     secfile_lookup_float_default(sf, 1.0,
5804                                  "%s.zoom_default_level", prefix);
5805 
5806   str = secfile_lookup_str_default(sf, NULL, "client.default_tileset_name");
5807   if (str != NULL) {
5808     sz_strlcpy(gui_options.default_tileset_name, str);
5809   }
5810 
5811   /* Backwards compatibility for removed options replaced by entirely "new"
5812    * options. The equivalent "new" option will override these, if set. */
5813 
5814   /* Removed in 2.3 */
5815   /* The effect of this migration:
5816    *  - If there's no rc-file, we don't reach this code at all;
5817    *  - An existing 2.3-or-later rc-file will almost certainly have a
5818    *    setting for the new option name, that will be read later and
5819    *    override this calculation, which will thus have no effect;
5820    *  - An existing pre-2.3 rc-file will use this migration to
5821    *    override the gui_gtk2_message_chat_location option's hardcoded
5822    *    default with the old user options;
5823    *  - If an rc-file exists but is so old as to pre-date the existence
5824    *    of these 'old' options, then the 'FALSE' default(s) here will
5825    *    take effect, overriding the hardcoded default. (If the rc-file
5826    *    pre-dates the options mentioned, it most likely pre-dates the
5827    *    behaviour too, so this is usually the right answer.) */
5828   /* gtk3+ clients never had the old form of this option. */
5829   if (secfile_lookup_bool_default(sf, FALSE,
5830                                   "%s.gui_gtk2_merge_notebooks", prefix)) {
5831     gui_options.gui_gtk2_message_chat_location = GUI_GTK_MSGCHAT_MERGED;
5832   } else if (secfile_lookup_bool_default(sf, FALSE,
5833                                          "%s.gui_gtk2_split_bottom_notebook",
5834                                          prefix)) {
5835     gui_options.gui_gtk2_message_chat_location = GUI_GTK_MSGCHAT_SPLIT;
5836   } else {
5837     gui_options.gui_gtk2_message_chat_location = GUI_GTK_MSGCHAT_SEPARATE;
5838   }
5839 
5840   /* Renamed in 2.6 */
5841   gui_options.popup_actor_arrival = secfile_lookup_bool_default(sf, TRUE,
5842       "%s.popup_caravan_arrival", prefix);
5843 
5844   /* Load all the regular options */
5845   client_options_iterate_all(poption) {
5846     client_option_load(poption, sf);
5847   } client_options_iterate_all_end;
5848 
5849   /* More backwards compatibility, for removed options that had been
5850    * folded into then-existing options. Here, the backwards-compatibility
5851    * behaviour overrides the "destination" option. */
5852 
5853   /* Removed in 2.4 */
5854   if (!secfile_lookup_bool_default(sf, TRUE,
5855                                    "%s.do_combat_animation", prefix)) {
5856     gui_options.smooth_combat_step_msec = 0;
5857   }
5858 
5859   message_options_load(sf, prefix);
5860   options_dialogs_load(sf);
5861 
5862   /* Load cma presets. If cma.number_of_presets doesn't exist, don't load
5863    * any, the order here should be reversed to keep the order the same */
5864   if (secfile_lookup_int(sf, &num, "cma.number_of_presets")) {
5865     for (i = num - 1; i >= 0; i--) {
5866       load_cma_preset(sf, i);
5867     }
5868   } else {
5869     create_default_cma_presets();
5870   }
5871 
5872   settable_options_load(sf);
5873   global_worklists_load(sf);
5874 
5875   secfile_destroy(sf);
5876   options_fully_initialized = TRUE;
5877 }
5878 
5879 /**************************************************************************
5880   Write messages from option saving to the output window.
5881 **************************************************************************/
option_save_output_window_callback(enum log_level lvl,const char * msg,...)5882 static void option_save_output_window_callback(enum log_level lvl,
5883                                                const char *msg, ...)
5884 {
5885   va_list args;
5886 
5887   va_start(args, msg);
5888   output_window_vprintf(ftc_client, msg, args);
5889   va_end(args);
5890 }
5891 
5892 /**************************************************************************
5893   Save all options.
5894 **************************************************************************/
options_save(option_save_log_callback log_cb)5895 void options_save(option_save_log_callback log_cb)
5896 {
5897   struct section_file *sf;
5898   const char *name = get_current_option_file_name();
5899   char dir_name[2048];
5900   int i;
5901 
5902   if (log_cb == NULL) {
5903     /* Default callback */
5904     log_cb = option_save_output_window_callback;
5905   }
5906 
5907   if (!name) {
5908     log_cb(LOG_ERROR, _("Save failed, cannot find a filename."));
5909     return;
5910   }
5911 
5912   sf = secfile_new(TRUE);
5913   secfile_insert_str(sf, VERSION_STRING, "client.version");
5914 
5915   secfile_insert_bool(sf, gui_options.save_options_on_exit,
5916                       "client.save_options_on_exit");
5917   secfile_insert_bool_comment(sf, gui_options.migrate_fullscreen,
5918                               "deprecated", "client.fullscreen_mode");
5919 
5920   /* Migrations */
5921   secfile_insert_bool(sf, gui_options.gui_gtk3_22_migrated_from_gtk3,
5922                       "client.migration_gtk3_22_from_gtk3");
5923   secfile_insert_bool(sf, gui_options.gui_gtk3_migrated_from_gtk2,
5924                       "client.migration_gtk3_from_gtk2");
5925   secfile_insert_bool(sf, gui_options.gui_sdl2_migrated_from_sdl,
5926                       "client.migration_sdl2_from_sdl");
5927   secfile_insert_bool(sf, gui_options.gui_gtk2_migrated_from_2_5,
5928                       "client.migration_gtk2_from_2_5");
5929   secfile_insert_bool(sf, gui_options.gui_gtk3_migrated_from_2_5,
5930                       "client.migration_gtk3_from_2_5");
5931   secfile_insert_bool(sf, gui_options.gui_qt_migrated_from_2_5,
5932                       "client.migration_qt_from_2_5");
5933 
5934   /* gui-enabled options */
5935   client_options_iterate_all(poption) {
5936     client_option_save(poption, sf);
5937   } client_options_iterate_all_end;
5938 
5939   /* These are not gui-enabled yet. */
5940   secfile_insert_bool(sf, gui_options.zoom_set, "client.zoom_set");
5941   secfile_insert_float(sf, gui_options.zoom_default_level,
5942                          "client.zoom_default_level");
5943 
5944   if (gui_options.default_tileset_name[0] != '\0') {
5945     secfile_insert_str(sf, gui_options.default_tileset_name,
5946                        "client.default_tileset_name");
5947   }
5948 
5949   message_options_save(sf, "client");
5950   options_dialogs_save(sf);
5951 
5952   /* server settings */
5953   save_cma_presets(sf);
5954   settable_options_save(sf);
5955 
5956   /* insert global worklists */
5957   global_worklists_save(sf);
5958 
5959   /* Directory name */
5960   sz_strlcpy(dir_name, name);
5961   for (i = strlen(dir_name) - 1 ; dir_name[i] != DIR_SEPARATOR_CHAR && i >= 0; i--) {
5962     /* Nothing */
5963   }
5964   if (i > 0) {
5965     dir_name[i] = '\0';
5966     make_dir(dir_name);
5967   }
5968 
5969   /* save to disk */
5970   if (!secfile_save(sf, name, 0, FZ_PLAIN)) {
5971     log_cb(LOG_ERROR, _("Save failed, cannot write to file %s"), name);
5972   } else {
5973     log_cb(LOG_VERBOSE, _("Saved settings to file %s"), name);
5974   }
5975   secfile_destroy(sf);
5976 }
5977 
5978 
5979 /**************************************************************************
5980   Initialize lists of names for a client option.
5981 **************************************************************************/
options_init_names(const struct copt_val_name * (* acc)(int),struct strvec ** support,struct strvec ** pretty)5982 static void options_init_names(const struct copt_val_name *(*acc)(int),
5983                                struct strvec **support, struct strvec **pretty)
5984 {
5985   int val;
5986   const struct copt_val_name *name;
5987   fc_assert_ret(NULL != acc);
5988   *support = strvec_new();
5989   *pretty = strvec_new();
5990   for (val=0; (name = acc(val)); val++) {
5991     strvec_append(*support, name->support);
5992     strvec_append(*pretty, name->pretty);
5993   }
5994 }
5995 
5996 /**************************************************************************
5997   Initialize the option module.
5998 **************************************************************************/
options_init(void)5999 void options_init(void)
6000 {
6001   message_options_init();
6002   options_extra_init();
6003   global_worklists_init();
6004 
6005   settable_options_hash = settable_options_hash_new();
6006   dialog_options_hash = dialog_options_hash_new();
6007 
6008   client_options_iterate_all(poption) {
6009     struct client_option *pcoption = CLIENT_OPTION(poption);
6010 
6011     switch (option_type(poption)) {
6012     case OT_INTEGER:
6013       if (option_int_def(poption) < option_int_min(poption)
6014           || option_int_def(poption) > option_int_max(poption)) {
6015         int new_default = MAX(MIN(option_int_def(poption),
6016                                   option_int_max(poption)),
6017                               option_int_min(poption));
6018 
6019         log_error("option %s has default value of %d, which is "
6020                   "out of its range [%d; %d], changing to %d.",
6021                   option_name(poption), option_int_def(poption),
6022                   option_int_min(poption), option_int_max(poption),
6023                   new_default);
6024         *((int *) &(pcoption->integer.def)) = new_default;
6025       }
6026       break;
6027 
6028     case OT_STRING:
6029       if (gui_options.default_user_name == option_str_get(poption)) {
6030         /* Hack to get a default value. */
6031         *((const char **) &(pcoption->string.def)) =
6032             fc_strdup(gui_options.default_user_name);
6033       }
6034 
6035       if (NULL == option_str_def(poption)) {
6036         const struct strvec *values = option_str_values(poption);
6037 
6038         if (NULL == values || strvec_size(values) == 0) {
6039           log_error("Invalid NULL default string for option %s.",
6040                     option_name(poption));
6041         } else {
6042           *((const char **) &(pcoption->string.def)) =
6043               strvec_get(values, 0);
6044         }
6045       }
6046       break;
6047 
6048     case OT_ENUM:
6049       fc_assert(NULL == pcoption->enumerator.support_names);
6050       fc_assert(NULL == pcoption->enumerator.pretty_names);
6051       options_init_names(pcoption->enumerator.name_accessor,
6052                          &pcoption->enumerator.support_names,
6053                          &pcoption->enumerator.pretty_names);
6054       fc_assert(NULL != pcoption->enumerator.support_names);
6055       fc_assert(NULL != pcoption->enumerator.pretty_names);
6056       break;
6057 
6058     case OT_BITWISE:
6059       fc_assert(NULL == pcoption->bitwise.support_names);
6060       fc_assert(NULL == pcoption->bitwise.pretty_names);
6061       options_init_names(pcoption->bitwise.name_accessor,
6062                          &pcoption->bitwise.support_names,
6063                          &pcoption->bitwise.pretty_names);
6064       fc_assert(NULL != pcoption->bitwise.support_names);
6065       fc_assert(NULL != pcoption->bitwise.pretty_names);
6066       break;
6067 
6068     case OT_COLOR:
6069       {
6070         /* Duplicate the string pointers. */
6071         struct ft_color *pcolor = pcoption->color.pvalue;
6072 
6073         if (NULL != pcolor->foreground) {
6074           pcolor->foreground = fc_strdup(pcolor->foreground);
6075         }
6076         if (NULL != pcolor->background) {
6077           pcolor->background = fc_strdup(pcolor->background);
6078         }
6079       }
6080 
6081     case OT_BOOLEAN:
6082     case OT_FONT:
6083     case OT_VIDEO_MODE:
6084       break;
6085     }
6086 
6087     /* Set to default. */
6088     option_reset(poption);
6089   } client_options_iterate_all_end;
6090 }
6091 
6092 /**************************************************************************
6093   Free the option module.
6094 **************************************************************************/
options_free(void)6095 void options_free(void)
6096 {
6097   client_options_iterate_all(poption) {
6098     struct client_option *pcoption = CLIENT_OPTION(poption);
6099 
6100     switch (option_type(poption)) {
6101     case OT_ENUM:
6102       fc_assert_action(NULL != pcoption->enumerator.support_names, break);
6103       strvec_destroy(pcoption->enumerator.support_names);
6104       pcoption->enumerator.support_names = NULL;
6105       fc_assert_action(NULL != pcoption->enumerator.pretty_names, break);
6106       strvec_destroy(pcoption->enumerator.pretty_names);
6107       pcoption->enumerator.pretty_names = NULL;
6108       break;
6109 
6110     case OT_BITWISE:
6111       fc_assert_action(NULL != pcoption->bitwise.support_names, break);
6112       strvec_destroy(pcoption->bitwise.support_names);
6113       pcoption->bitwise.support_names = NULL;
6114       fc_assert_action(NULL != pcoption->bitwise.pretty_names, break);
6115       strvec_destroy(pcoption->bitwise.pretty_names);
6116       pcoption->bitwise.pretty_names = NULL;
6117       break;
6118 
6119     case OT_BOOLEAN:
6120     case OT_INTEGER:
6121     case OT_STRING:
6122     case OT_FONT:
6123     case OT_COLOR:
6124     case OT_VIDEO_MODE:
6125       break;
6126     }
6127   } client_options_iterate_all_end;
6128 
6129   if (NULL != settable_options_hash) {
6130     settable_options_hash_destroy(settable_options_hash);
6131     settable_options_hash = NULL;
6132   }
6133 
6134   if (NULL != dialog_options_hash) {
6135     dialog_options_hash_destroy(dialog_options_hash);
6136     dialog_options_hash = NULL;
6137   }
6138 
6139   message_options_free();
6140   global_worklists_free();
6141 }
6142 
6143 /****************************************************************************
6144   Callback when the reqtree show icons option is changed. The tree is
6145   recalculated.
6146 ****************************************************************************/
reqtree_show_icons_callback(struct option * poption)6147 static void reqtree_show_icons_callback(struct option *poption)
6148 {
6149   science_report_dialog_redraw();
6150 }
6151 
6152 /****************************************************************************
6153   Callback for when any view option is changed.
6154 ****************************************************************************/
view_option_changed_callback(struct option * poption)6155 static void view_option_changed_callback(struct option *poption)
6156 {
6157   menus_init();
6158   update_map_canvas_visible();
6159 }
6160 
6161 /****************************************************************************
6162   Callback for when ai_manual_turn_done is changed.
6163 ****************************************************************************/
manual_turn_done_callback(struct option * poption)6164 static void manual_turn_done_callback(struct option *poption)
6165 {
6166   update_turn_done_button_state();
6167   if (!gui_options.ai_manual_turn_done && client.conn.playing->ai_controlled) {
6168     if (can_end_turn()) {
6169       user_ended_turn();
6170     }
6171   }
6172 }
6173 
6174 /****************************************************************************
6175   Callback for when any voteinfo bar option is changed.
6176 ****************************************************************************/
voteinfo_bar_callback(struct option * poption)6177 static void voteinfo_bar_callback(struct option *poption)
6178 {
6179   voteinfo_gui_update();
6180 }
6181 
6182 /****************************************************************************
6183   Callback for font options.
6184 ****************************************************************************/
font_changed_callback(struct option * poption)6185 static void font_changed_callback(struct option *poption)
6186 {
6187   fc_assert_ret(OT_FONT == option_type(OPTION(poption)));
6188   gui_update_font(option_font_target(poption), option_font_get(poption));
6189 }
6190 
6191 /****************************************************************************
6192   Callback for mapimg options.
6193 ****************************************************************************/
mapimg_changed_callback(struct option * poption)6194 static void mapimg_changed_callback(struct option *poption)
6195 {
6196   if (mapimg_initialised() && !mapimg_client_define()) {
6197     bool success;
6198 
6199     log_normal("Error setting the value for %s (%s). Restoring the default "
6200                "value.", option_name(poption), mapimg_error());
6201 
6202     /* Reset the value to the default value. */
6203     success = option_reset(poption);
6204     fc_assert_msg(success == TRUE,
6205                   "Failed to reset the option \"%s\".",
6206                   option_name(poption));
6207     success = mapimg_client_define();
6208     fc_assert_msg(success == TRUE,
6209                   "Failed to restore mapimg definition for option \"%s\".",
6210                   option_name(poption));
6211   }
6212 }
6213 
6214 /****************************************************************************
6215   Callback for music enabling option.
6216 ****************************************************************************/
game_music_enable_callback(struct option * poption)6217 static void game_music_enable_callback(struct option *poption)
6218 {
6219   if (client_state() == C_S_RUNNING) {
6220     if (gui_options.sound_enable_game_music) {
6221       start_style_music();
6222     } else {
6223       stop_style_music();
6224     }
6225   }
6226 }
6227 
6228 /****************************************************************************
6229   Callback for music enabling option.
6230 ****************************************************************************/
menu_music_enable_callback(struct option * poption)6231 static void menu_music_enable_callback(struct option *poption)
6232 {
6233   if (client_state() != C_S_RUNNING) {
6234     if (gui_options.sound_enable_menu_music) {
6235       start_menu_music("music_menu", NULL);
6236     } else {
6237       stop_menu_music();
6238     }
6239   }
6240 }
6241 
6242 /****************************************************************************
6243   Convert a video mode to string. Returns TRUE on success.
6244 ****************************************************************************/
video_mode_to_string(char * buf,size_t buf_len,struct video_mode * mode)6245 bool video_mode_to_string(char *buf, size_t buf_len, struct video_mode *mode)
6246 {
6247   return (2 < fc_snprintf(buf, buf_len, "%dx%d", mode->width, mode->height));
6248 }
6249 
6250 /****************************************************************************
6251   Convert a string to video mode. Returns TRUE on success.
6252 ****************************************************************************/
string_to_video_mode(const char * buf,struct video_mode * mode)6253 bool string_to_video_mode(const char *buf, struct video_mode *mode)
6254 {
6255   return (2 == sscanf(buf, "%dx%d", &mode->width, &mode->height));
6256 }
6257 
6258 /****************************************************************************
6259   Option framework wrapper for mapimg_get_format_list()
6260 ****************************************************************************/
get_mapimg_format_list(const struct option * poption)6261 static const struct strvec *get_mapimg_format_list(const struct option *poption)
6262 {
6263   return mapimg_get_format_list();
6264 }
6265 
6266 /****************************************************************************
6267   What is the user defined tileset for the given topology
6268 ****************************************************************************/
tileset_name_for_topology(int topology_id)6269 const char *tileset_name_for_topology(int topology_id)
6270 {
6271   const char *tsn = NULL;
6272 
6273   switch (topology_id & (TF_ISO | TF_HEX)) {
6274   case 0:
6275     tsn = gui_options.default_tileset_overhead_name;
6276     break;
6277   case TF_ISO:
6278     tsn = gui_options.default_tileset_iso_name;
6279     break;
6280   case TF_HEX:
6281     tsn = gui_options.default_tileset_hex_name;
6282     break;
6283   case TF_ISO | TF_HEX:
6284     tsn = gui_options.default_tileset_isohex_name;
6285     break;
6286   }
6287 
6288   if (tsn == NULL) {
6289     tsn = gui_options.default_tileset_name;
6290   }
6291 
6292   return tsn;
6293 }
6294 
6295 /****************************************************************************
6296   Set given tileset as the default for suitable topology
6297 ****************************************************************************/
option_set_default_ts(struct tileset * t)6298 void option_set_default_ts(struct tileset *t)
6299 {
6300   const char *optname = "<not set>";
6301   struct option *opt;
6302 
6303   switch (tileset_topo_index(t)) {
6304   case TS_TOPO_OVERHEAD:
6305     /* Overhead */
6306     optname = "default_tileset_overhead_name";
6307     break;
6308   case TS_TOPO_ISO:
6309     /* Iso */
6310     optname = "default_tileset_iso_name";
6311     break;
6312   case TS_TOPO_HEX:
6313     /* Hex */
6314     optname = "default_tileset_hex_name";
6315     break;
6316   case TS_TOPO_ISOHEX:
6317     /* Isohex */
6318     optname = "default_tileset_isohex_name";
6319     break;
6320   }
6321 
6322   opt = optset_option_by_name(client_optset, optname);
6323 
6324   if (opt == NULL) {
6325     log_error("Unknown option name \"%s\" in option_set_default_ts()", optname);
6326     return;
6327   }
6328 
6329   /* Do not call option_str_set() since we don't want option changed callback
6330    * to reload this tileset. */
6331   opt->str_vtable->set(opt, tileset_basename(t));
6332   option_gui_update(opt);
6333 }
6334 
6335 /****************************************************************************
6336   Does topology-specific tileset option lack value?
6337 ****************************************************************************/
is_ts_option_unset(const char * optname)6338 static bool is_ts_option_unset(const char *optname)
6339 {
6340   struct option *opt;
6341   const char *val;
6342 
6343   opt = optset_option_by_name(client_optset, optname);
6344 
6345   if (opt == NULL) {
6346     return TRUE;
6347   }
6348 
6349   val = opt->str_vtable->get(opt);
6350 
6351   if (val == NULL || val[0] == '\0') {
6352     return TRUE;
6353   }
6354 
6355   return FALSE;
6356 }
6357 
6358 /****************************************************************************
6359   Fill default tilesets for topology-specific settings.
6360 ****************************************************************************/
fill_topo_ts_default(void)6361 void fill_topo_ts_default(void)
6362 {
6363   if (is_ts_option_unset("default_tileset_overhead_name")) {
6364     log_debug("Setting tileset for overhead topology.");
6365     tilespec_try_read(NULL, FALSE, 0, FALSE);
6366   }
6367   if (is_ts_option_unset("default_tileset_iso_name")) {
6368     log_debug("Setting tileset for iso topology.");
6369     tilespec_try_read(NULL, FALSE, TF_ISO, FALSE);
6370   }
6371   if (is_ts_option_unset("default_tileset_hex_name")) {
6372     log_debug("Setting tileset for hex topology.");
6373     tilespec_try_read(NULL, FALSE, TF_HEX, FALSE);
6374   }
6375   if (is_ts_option_unset("default_tileset_isohex_name")) {
6376     log_debug("Setting tileset for isohex topology.");
6377     tilespec_try_read(NULL, FALSE, TF_ISO | TF_HEX, FALSE);
6378   }
6379 }
6380