Freeciv-3.3: /fast/freeciv/nightly/main/client/gui-gtk-5.0/pages.c Source File

Freeciv-3.3

Loading...
Searching...
No Matches
pages.c
Go to the documentation of this file.
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 <stdio.h>
19#include <time.h>
20
21#include <sys/stat.h>
22
23#include <gtk/gtk.h>
24
25/* utility */
26#include "fcintl.h"
27#include "log.h"
28#include "mem.h"
29#include "shared.h"
30#include "support.h"
31
32/* common */
33#include "chat.h"
34#include "dataio.h"
35#include "game.h"
36#include "mapimg.h"
37#include "version.h"
38
39/* client */
40#include "client_main.h"
41#include "climisc.h"
42#include "clinet.h"
43#include "connectdlg_common.h"
44#include "packhand.h"
45#include "servers.h"
46#include "update_queue.h"
47
48/* client/gui-gtk-5.0 */
49#include "chatline.h"
50#include "connectdlg.h"
51#include "dialogs.h"
52#include "graphics.h"
53#include "gui_main.h"
54#include "gui_stuff.h"
55#include "mapview.h"
56#include "menu.h"
57#include "optiondlg.h"
58#include "plrdlg.h" /* get_flag() */
59#include "repodlgs.h"
60#include "voteinfo_bar.h"
61
62#include "pages.h"
63
64
65 static GtkWidget *scenario_description;
66 static GtkWidget *scenario_authors;
67 static GtkWidget *scenario_filename;
68 static GtkWidget *scenario_version;
69
70 static GtkListStore *load_store, *scenario_store, *meta_store, *lan_store;
71
72 static GtkListStore *server_playerlist_store;
73 static GtkWidget *server_playerlist_view;
74
75 static GtkTreeSelection *load_selection, *scenario_selection;
76 static GtkTreeSelection *meta_selection, *lan_selection;
77
78/* This is the current page. Invalid value at start, to be sure that it won't
79 * be catch throught a switch() statement. */
80 static enum client_pages current_page = -1;
81
82struct server_scan_timer_data
83{
84 struct server_scan *scan;
85 guint timer;
86};
87
88 static struct server_scan_timer_data meta_scan = { NULL, 0 };
89 static struct server_scan_timer_data lan_scan = { NULL, 0 };
90
91 static GtkWidget *statusbar, *statusbar_frame;
92 static GQueue *statusbar_queue;
93 static guint statusbar_timer = 0;
94
95 static GtkWidget *ruleset_combo;
96
97 static GtkWidget *conn_popover = NULL;
98
99 static bool holding_srv_list_mutex = FALSE;
100
101static void connection_state_reset(void);
102
103/**********************************************************************/
106 static void start_new_game_callback(GtkWidget *w, gpointer data)
107{
108 if (!is_server_running()) {
109 client_start_server();
110
111 /* Saved settings are sent in client/options.c
112 * resend_desired_settable_options() */
113 }
114}
115
116/**********************************************************************/
119 static void start_scenario_callback(GtkWidget *w, gpointer data)
120{
121 output_window_append(ftc_client, _("Compiling scenario list."));
122 client_start_server_and_set_page(PAGE_SCENARIO);
123}
124
125/**********************************************************************/
128 static void load_saved_game_callback(GtkWidget *w, gpointer data)
129{
130 client_start_server_and_set_page(PAGE_LOAD);
131}
132
133/**********************************************************************/
136 static void connect_network_game_callback(GtkWidget *w, gpointer data)
137{
138 connection_state_reset();
139 set_client_page(PAGE_NETWORK);
140}
141
142/**********************************************************************/
145 static void open_settings(void)
146{
147 option_dialog_popup(_("Set local options"), client_optset);
148}
149
150/**********************************************************************/
153 static void main_callback(GtkWidget *w, gpointer data)
154{
155 enum client_pages page = PAGE_MAIN;
156
157 if (client.conn.used) {
158 disconnect_from_server(TRUE);
159 }
160 if (page != get_client_page()) {
161 set_client_page(page);
162 }
163}
164
165/**********************************************************************/
168 static void intro_expose(GtkDrawingArea *w, cairo_t *cr,
169 int width, int height, gpointer data)
170{
171 static PangoLayout *layout;
172 static int pwidth, pheight;
173 static bool left = FALSE;
174 GtkAllocation allocation;
175 struct sprite *intro = (struct sprite *)data;
176
177 cairo_set_source_surface(cr, intro->surface, 0, 0);
178 cairo_paint(cr);
179
180 if (!layout) {
181 char msgbuf[128];
182 const char *rev_ver;
183
184 layout = pango_layout_new(gtk_widget_create_pango_context(GTK_WIDGET(w)));
185 pango_layout_set_font_description(layout,
186 pango_font_description_from_string("Sans Bold 10"));
187
188 rev_ver = fc_git_revision();
189
190 if (rev_ver == NULL) {
191 /* TRANS: "version 2.6.0, gui-gtk-3.22 client" */
192 fc_snprintf(msgbuf, sizeof(msgbuf), _("%s%s, %s client"),
193 word_version(), VERSION_STRING, client_string);
194 } else {
195 /* TRANS: "version 2.6.0
196 * commit: [modified] <git commit id>
197 * gui-gtk-3.22 client" */
198 fc_snprintf(msgbuf, sizeof(msgbuf), _("%s%s\ncommit: %s\n%s client"),
199 word_version(), VERSION_STRING, rev_ver, client_string);
200 left = TRUE;
201 }
202 pango_layout_set_text(layout, msgbuf, -1);
203
204 pango_layout_get_pixel_size(layout, &pwidth, &pheight);
205 }
206 gtk_widget_get_allocation(GTK_WIDGET(w), &allocation);
207
208 cairo_set_source_rgb(cr, 0, 0, 0);
209 cairo_move_to(cr, left ? 4 : allocation.width - pwidth - 3,
210 allocation.height - pheight - 3);
211 pango_cairo_show_layout(cr, layout);
212
213 cairo_set_source_rgb(cr, 1, 1, 1);
214 cairo_move_to(cr, left ? 3 : allocation.width - pwidth - 4,
215 allocation.height - pheight - 4);
216 pango_cairo_show_layout(cr, layout);
217}
218
219/**********************************************************************/
222 static void intro_free(GtkWidget *w, gpointer *data)
223{
224 struct sprite *intro = (struct sprite *)data;
225
226 free_sprite(intro);
227}
228
229/**********************************************************************/
232 GtkWidget *create_main_page(void)
233{
234 GtkWidget *widget, *vgrid, *frame, *darea, *button, *table;
235 GtkSizeGroup *size;
236 struct sprite *intro_in, *intro;
237 int width, height;
238 int sh;
239 int space_needed;
240 int grid_row = 0;
241
242 size = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
243
244 vgrid = gtk_grid_new();
245 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
246 GTK_ORIENTATION_VERTICAL);
247 widget = vgrid;
248
249 frame = gtk_frame_new(NULL);
250 gtk_widget_set_margin_bottom(frame, 18);
251 gtk_widget_set_margin_end(frame, 18);
252 gtk_widget_set_margin_start(frame, 18);
253 gtk_widget_set_margin_top(frame, 18);
254 gtk_widget_set_halign(frame, GTK_ALIGN_CENTER);
255 gtk_grid_attach(GTK_GRID(vgrid), frame, 0, grid_row++, 1, 1);
256
257 intro_in = load_gfxfile(tileset_main_intro_filename(tileset), FALSE);
258 get_sprite_dimensions(intro_in, &width, &height);
259 sh = screen_height();
260
261 if (sh <= 0) {
262 /* Assume some minimum height */
263 sh = 600;
264 }
265
266 space_needed = 250;
267#if IS_BETA_VERSION || IS_DEVEL_VERSION
268 /* Alpha or Beta notice takes extra space */
269 space_needed += 50;
270#endif
271
272 if (sh - height < space_needed) {
273 float scale;
274
275 if (sh < (space_needed + 0.2 * height)) {
276 /* Screen is simply too small, use minimum scale */
277 scale = 0.2;
278 } else {
279 scale = (double)(sh - space_needed) / height;
280 }
281 height *= scale;
282 width *= scale;
283 intro = sprite_scale(intro_in, width, height);
284 free_sprite(intro_in);
285 } else {
286 intro = intro_in;
287 }
288 darea = gtk_drawing_area_new();
289 gtk_widget_set_size_request(darea, width, height);
290 gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(darea),
291 intro_expose, intro, NULL);
292 g_signal_connect(widget, "destroy",
293 G_CALLBACK(intro_free), intro);
294 gtk_frame_set_child(GTK_FRAME(frame), darea);
295
296#if IS_BETA_VERSION || IS_DEVEL_VERSION
297 {
298 GtkWidget *label;
299
300 label = gtk_label_new(unstable_message());
301 gtk_widget_set_name(label, "beta_label");
302 gtk_widget_set_halign(label, GTK_ALIGN_CENTER);
303 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
304 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
305 gtk_grid_attach(GTK_GRID(vgrid), label, 0, grid_row++, 1, 1);
306 }
307#endif /* IS_BETA_VERSION || IS_DEVEL_VERSION */
308
309 table = gtk_grid_new();
310 gtk_widget_set_margin_bottom(table, 12);
311 gtk_widget_set_margin_end(table, 12);
312 gtk_widget_set_margin_start(table, 12);
313 gtk_widget_set_margin_top(table, 12);
314 gtk_widget_set_hexpand(table, TRUE);
315 gtk_widget_set_vexpand(table, TRUE);
316 gtk_widget_set_halign(table, GTK_ALIGN_CENTER);
317 gtk_widget_set_valign(table, GTK_ALIGN_CENTER);
318
319 gtk_grid_set_row_spacing(GTK_GRID(table), 8);
320 gtk_grid_set_column_spacing(GTK_GRID(table), 18);
321 gtk_grid_attach(GTK_GRID(vgrid), table, 0, grid_row++, 1, 1);
322
323 button = gtk_button_new_with_mnemonic(_("Start _New Game"));
324 gtk_size_group_add_widget(size, button);
325 gtk_grid_attach(GTK_GRID(table), button, 0, 0, 1, 1);
326 gtk_widget_set_tooltip_text(button,
327 _("Launches local server, and connects to it for a single-player game."));
328 g_signal_connect(button, "clicked",
329 G_CALLBACK(start_new_game_callback), NULL);
330
331 button = gtk_button_new_with_mnemonic(_("Start _Scenario Game"));
332 gtk_size_group_add_widget(size, button);
333 gtk_grid_attach(GTK_GRID(table), button, 0, 1, 1, 1);
334 gtk_widget_set_tooltip_text(button,
335 _("Loads one of the scenarios for a single-player game. "
336 "Tutorial is one of the scenarios."));
337 g_signal_connect(button, "clicked",
338 G_CALLBACK(start_scenario_callback), NULL);
339
340 button = gtk_button_new_with_mnemonic(_("_Load Saved Game"));
341 gtk_size_group_add_widget(size, button);
342 gtk_grid_attach(GTK_GRID(table), button, 0, 2, 1, 1);
343 gtk_widget_set_tooltip_text(button,
344 _("Continues previously saved single-player game."));
345 g_signal_connect(button, "clicked",
346 G_CALLBACK(load_saved_game_callback), NULL);
347
348 button = gtk_button_new_with_mnemonic(_("C_onnect to Network Game"));
349 gtk_size_group_add_widget(size, button);
350 gtk_grid_attach(GTK_GRID(table), button, 1, 0, 1, 1);
351 gtk_widget_set_tooltip_text(button,
352 _("Connects to outside server. "
353 "Sometimes you want to launch a separate server even for local games."));
354 g_signal_connect(button, "clicked",
355 G_CALLBACK(connect_network_game_callback), NULL);
356
357 button = gtk_button_new_with_mnemonic(_("Client Settings"));
358 gtk_size_group_add_widget(size, button);
359 gtk_grid_attach(GTK_GRID(table), button, 1, 1, 1, 1);
360 gtk_widget_set_tooltip_text(button,
361 _("Adjusting client-side options."));
362 g_signal_connect(button, "clicked", open_settings, NULL);
363
364 button = icon_label_button_new("application-exit", _("E_xit"));
365 gtk_size_group_add_widget(size, button);
366 g_object_unref(size);
367 gtk_grid_attach(GTK_GRID(table), button, 1, 2, 1, 1);
368 gtk_widget_set_tooltip_text(button,
369 _("Gives you a break from playing freeciv."));
370 g_signal_connect(button, "clicked",
371 G_CALLBACK(quit_gtk_main), NULL);
372
373 return widget;
374}
375
376/****************************************************************************
377 GENERIC SAVE DIALOG
378****************************************************************************/
379 typedef void (*save_dialog_action_fn_t) (const char *filename);
380typedef struct fileinfo_list * (*save_dialog_files_fn_t) (void);
381
382struct save_dialog {
383 GtkDialog *shell;
384 GtkTreeView *tree_view;
385 GtkEntry *entry;
386 save_dialog_action_fn_t action;
387 save_dialog_files_fn_t files;
388};
389
390 enum save_dialog_columns {
391 SD_COL_PRETTY_NAME = 0,
392 SD_COL_FULL_PATH,
393
394 SD_COL_NUM
395};
396
397 enum save_dialog_response {
398 SD_RES_BROWSE,
399 SD_RES_DELETE,
400 SD_RES_SAVE
401};
402
403/**********************************************************************/
406 static inline GtkListStore *save_dialog_store_new(void)
407{
408 return gtk_list_store_new(SD_COL_NUM,
409 G_TYPE_STRING, /* SD_COL_PRETTY_NAME */
410 G_TYPE_STRING); /* SD_COL_FULL_PATH */
411}
412
413/**********************************************************************/
416 static void save_dialog_store_update(GtkListStore *store,
417 const struct fileinfo_list *files)
418{
419 GtkTreeIter iter;
420
421 gtk_list_store_clear(store);
422 fileinfo_list_iterate(files, pfile) {
423 gtk_list_store_append(store, &iter);
424 gtk_list_store_set(store, &iter,
425 SD_COL_PRETTY_NAME, pfile->name,
426 SD_COL_FULL_PATH, pfile->fullname,
427 -1);
428 } fileinfo_list_iterate_end;
429}
430
431/**********************************************************************/
434 static void save_dialog_update(struct save_dialog *pdialog)
435{
436 struct fileinfo_list *files;
437
438 fc_assert_ret(NULL != pdialog);
439
440 /* Update the store. */
441 files = pdialog->files();
442 save_dialog_store_update(GTK_LIST_STORE
443 (gtk_tree_view_get_model(pdialog->tree_view)),
444 files);
445 fileinfo_list_destroy(files);
446}
447
448/**********************************************************************/
451 static void save_dialog_file_chooser_callback(GtkWidget *widget,
452 gint response, gpointer data)
453{
454 if (response == GTK_RESPONSE_OK) {
455 save_dialog_action_fn_t action = data;
456 GFile *file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(widget));
457
458 if (file != NULL) {
459 gchar *filename = g_file_get_parse_name(file);
460
461 if (NULL != filename) {
462 action(filename);
463 g_free(filename);
464 }
465
466 g_object_unref(file);
467 }
468 }
469
470 gtk_window_destroy(GTK_WINDOW(widget));
471}
472
473/**********************************************************************/
476 static void save_dialog_file_chooser_popup(const char *title,
477 GtkFileChooserAction action,
478 save_dialog_action_fn_t cb)
479{
480 GtkWidget *filechoose;
481
482 /* Create the chooser */
483 filechoose = gtk_file_chooser_dialog_new(title, GTK_WINDOW(toplevel), action,
484 _("_Cancel"), GTK_RESPONSE_CANCEL,
485 (action == GTK_FILE_CHOOSER_ACTION_SAVE) ?
486 _("_Save") : _("_Open"),
487 GTK_RESPONSE_OK, NULL);
488 setup_dialog(filechoose, toplevel);
489
490 g_signal_connect(filechoose, "response",
491 G_CALLBACK(save_dialog_file_chooser_callback), cb);
492
493 /* Display that dialog */
494 gtk_window_present(GTK_WINDOW(filechoose));
495}
496
497/**********************************************************************/
500 static void save_dialog_response_callback(GtkWidget *w, gint response,
501 gpointer data)
502{
503 struct save_dialog *pdialog = data;
504
505 switch (response) {
506 case SD_RES_BROWSE:
507 save_dialog_file_chooser_popup(_("Select Location to Save"),
508 GTK_FILE_CHOOSER_ACTION_SAVE,
509 pdialog->action);
510 break;
511 case SD_RES_DELETE:
512 {
513 GtkTreeSelection *selection;
514 GtkTreeModel *model;
515 GtkTreeIter iter;
516 const gchar *full_path;
517
518 selection = gtk_tree_view_get_selection(pdialog->tree_view);
519 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
520 return;
521 }
522
523 gtk_tree_model_get(model, &iter, SD_COL_FULL_PATH, &full_path, -1);
524 fc_remove(full_path);
525 save_dialog_update(pdialog);
526 }
527 return;
528 case SD_RES_SAVE:
529 {
530 const char *text = gtk_entry_buffer_get_text(gtk_entry_get_buffer(pdialog->entry));
531 gchar *filename = g_filename_from_utf8(text, -1, NULL, NULL, NULL);
532
533 if (NULL == filename) {
534 return;
535 }
536 pdialog->action(filename);
537 g_free(filename);
538 }
539 break;
540 default:
541 break;
542 }
543
544 gtk_window_destroy(GTK_WINDOW(pdialog->shell));
545}
546
547/**********************************************************************/
550 static void save_dialog_row_callback(GtkTreeView *tree_view,
551 GtkTreePath *path,
552 GtkTreeViewColumn *column,
553 gpointer data)
554{
555 save_dialog_response_callback(NULL, SD_RES_SAVE, data);
556}
557
558/**********************************************************************/
561 static void save_dialog_entry_callback(GtkEntry *entry, gpointer data)
562{
563 save_dialog_response_callback(NULL, SD_RES_SAVE, data);
564}
565
566/**********************************************************************/
569 static void save_dialog_list_callback(GtkTreeSelection *selection,
570 gpointer data)
571{
572 struct save_dialog *pdialog = data;
573 GtkTreeModel *model;
574 GtkTreeIter iter;
575 const gchar *filename;
576
577 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
578 gtk_dialog_set_response_sensitive(pdialog->shell, SD_RES_DELETE, FALSE);
579 return;
580 }
581
582 gtk_dialog_set_response_sensitive(pdialog->shell, SD_RES_DELETE, TRUE);
583 gtk_tree_model_get(model, &iter, SD_COL_PRETTY_NAME, &filename, -1);
584 gtk_entry_buffer_set_text(gtk_entry_get_buffer(pdialog->entry), filename, -1);
585}
586
587/**********************************************************************/
590 static GtkWidget *save_dialog_new(const char *title, const char *savelabel,
591 const char *savefilelabel,
592 save_dialog_action_fn_t action,
593 save_dialog_files_fn_t files)
594{
595 GtkWidget *shell, *sbox, *sw, *label, *view, *entry;
596 GtkBox *vbox;
597 GtkListStore *store;
598 GtkCellRenderer *rend;
599 GtkTreeSelection *selection;
600 struct save_dialog *pdialog;
601
602 fc_assert_ret_val(NULL != action, NULL);
603 fc_assert_ret_val(NULL != files, NULL);
604
605 /* Save dialog structure. */
606 pdialog = fc_malloc(sizeof(*pdialog));
607 pdialog->action = action;
608 pdialog->files = files;
609
610 /* Shell. */
611 shell = gtk_dialog_new_with_buttons(title, NULL, 0,
612 _("_Browse..."), SD_RES_BROWSE,
613 _("_Delete"), SD_RES_DELETE,
614 _("_Cancel"), GTK_RESPONSE_CANCEL,
615 _("_Save"), SD_RES_SAVE,
616 NULL);
617 g_object_set_data_full(G_OBJECT(shell), "save_dialog", pdialog,
618 (GDestroyNotify) free);
619 gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_CANCEL);
620 gtk_dialog_set_response_sensitive(GTK_DIALOG(shell), SD_RES_DELETE, FALSE);
621 setup_dialog(shell, toplevel);
622 g_signal_connect(shell, "response",
623 G_CALLBACK(save_dialog_response_callback), pdialog);
624 pdialog->shell = GTK_DIALOG(shell);
625 vbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(shell)));
626
627 /* Tree view. */
628 store = save_dialog_store_new();
629 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
630 gtk_widget_set_hexpand(view, TRUE);
631 gtk_widget_set_vexpand(view, TRUE);
632 g_object_unref(store);
633 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
634 g_signal_connect(view, "row-activated",
635 G_CALLBACK(save_dialog_row_callback), pdialog);
636 pdialog->tree_view = GTK_TREE_VIEW(view);
637
638 sbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
639 gtk_box_append(vbox, sbox);
640
641 label = g_object_new(GTK_TYPE_LABEL,
642 "use-underline", TRUE,
643 "mnemonic-widget", view,
644 "label", savelabel,
645 "xalign", 0.0,
646 "yalign", 0.5,
647 NULL);
648 gtk_box_append(GTK_BOX(sbox), label);
649
650 sw = gtk_scrolled_window_new();
651 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(sw), 300);
652 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(sw), 300);
653 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
654 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
655 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
656 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), view);
657 gtk_box_append(GTK_BOX(sbox), sw);
658
659 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
660 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
661 g_signal_connect(selection, "changed",
662 G_CALLBACK(save_dialog_list_callback), pdialog);
663
664 rend = gtk_cell_renderer_text_new();
665 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
666 -1, NULL, rend, "text",
667 SD_COL_PRETTY_NAME, NULL);
668
669 /* Entry. */
670 entry = gtk_entry_new();
671 gtk_widget_set_hexpand(entry, TRUE);
672 g_signal_connect(entry, "activate",
673 G_CALLBACK(save_dialog_entry_callback), pdialog);
674 pdialog->entry = GTK_ENTRY(entry);
675
676 sbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
677 gtk_widget_set_margin_bottom(sbox, 12);
678 gtk_widget_set_margin_end(sbox, 12);
679 gtk_widget_set_margin_start(sbox, 12);
680 gtk_widget_set_margin_top(sbox, 12);
681
682 label = g_object_new(GTK_TYPE_LABEL,
683 "use-underline", TRUE,
684 "mnemonic-widget", entry,
685 "label", savefilelabel,
686 "xalign", 0.0,
687 "yalign", 0.5,
688 NULL);
689 gtk_box_append(GTK_BOX(sbox), label);
690
691 gtk_box_append(GTK_BOX(sbox), entry);
692 gtk_box_append(vbox, sbox);
693
694 save_dialog_update(pdialog);
695 gtk_window_set_focus(GTK_WINDOW(shell), entry);
696 gtk_widget_set_visible(GTK_WIDGET(vbox), TRUE);
697
698 return shell;
699}
700
701/****************************************************************************
702 NETWORK PAGE
703****************************************************************************/
704 static GtkWidget *network_login_label, *network_login;
705 static GtkWidget *network_host_label, *network_host;
706 static GtkWidget *network_port_label, *network_port;
707 static GtkWidget *network_password_label, *network_password;
708 static GtkWidget *network_confirm_password_label, *network_confirm_password;
709
710/**********************************************************************/
713 static void update_server_list(enum server_scan_type sstype,
714 const struct server_list *list)
715{
716 GtkTreeSelection *sel = NULL;
717 GtkTreeView *view;
718 GtkTreeIter it;
719 GtkListStore *store;
720 const gchar *host, *portstr;
721 int port;
722
723 switch (sstype) {
724 case SERVER_SCAN_LOCAL:
725 sel = lan_selection;
726 break;
727 case SERVER_SCAN_GLOBAL:
728 sel = meta_selection;
729 break;
730 default:
731 break;
732 }
733
734 if (!sel) {
735 return;
736 }
737
738 view = gtk_tree_selection_get_tree_view(sel);
739 store = GTK_LIST_STORE(gtk_tree_view_get_model(view));
740 gtk_list_store_clear(store);
741
742 if (!list) {
743 return;
744 }
745
746 host = gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(network_host)));
747 portstr = gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(network_port)));
748 port = atoi(portstr);
749
750 server_list_iterate(list, pserver) {
751 char buf[35];
752
753 if (pserver->humans >= 0) {
754 fc_snprintf(buf, sizeof(buf), "%d", pserver->humans);
755 } else {
756 sz_strlcpy(buf, _("Unknown"));
757 }
758 gtk_list_store_append(store, &it);
759 gtk_list_store_set(store, &it,
760 0, pserver->host,
761 1, pserver->port,
762 2, pserver->version,
763 3, _(pserver->state),
764 4, pserver->nplayers,
765 5, buf,
766 6, pserver->message,
767 -1);
768 if (strcmp(host, pserver->host) == 0 && port == pserver->port) {
769 gtk_tree_selection_select_iter(sel, &it);
770 }
771 } server_list_iterate_end;
772}
773
774/**********************************************************************/
777 void destroy_server_scans(void)
778{
779 if (meta_scan.scan) {
780 server_scan_finish(meta_scan.scan);
781 meta_scan.scan = NULL;
782 }
783 if (meta_scan.timer != 0) {
784 g_source_remove(meta_scan.timer);
785 meta_scan.timer = 0;
786 }
787 if (lan_scan.scan) {
788 server_scan_finish(lan_scan.scan);
789 lan_scan.scan = NULL;
790 }
791 if (lan_scan.timer != 0) {
792 g_source_remove(lan_scan.timer);
793 lan_scan.timer = 0;
794 }
795}
796
797/**********************************************************************/
800 static gboolean check_server_scan(gpointer data)
801{
802 struct server_scan_timer_data *scan_data = data;
803 struct server_scan *scan = scan_data->scan;
804 enum server_scan_status stat;
805
806 if (!scan) {
807 return FALSE;
808 }
809
810 stat = server_scan_poll(scan);
811 if (stat >= SCAN_STATUS_PARTIAL) {
812 enum server_scan_type type;
813 struct srv_list *srvrs;
814
815 type = server_scan_get_type(scan);
816 srvrs = server_scan_get_list(scan);
817 fc_mutex_allocate(&srvrs->mutex);
818 holding_srv_list_mutex = TRUE;
819 update_server_list(type, srvrs->servers);
820 holding_srv_list_mutex = FALSE;
821 fc_mutex_release(&srvrs->mutex);
822 }
823
824 if (stat == SCAN_STATUS_ERROR || stat == SCAN_STATUS_DONE) {
825 scan_data->timer = 0;
826 return FALSE;
827 }
828 return TRUE;
829}
830
831/**********************************************************************/
834 static void server_scan_error(struct server_scan *scan,
835 const char *message)
836{
837 output_window_append(ftc_client, message);
838 log_error("%s", message);
839
840 /* Main thread will finalize the scan later (or even concurrently) -
841 * do not do anything here to cause double free or raze condition. */
842}
843
844/**********************************************************************/
847 static void update_network_lists(void)
848{
849 destroy_server_scans();
850
851 meta_scan.scan = server_scan_begin(SERVER_SCAN_GLOBAL, server_scan_error);
852 meta_scan.timer = g_timeout_add(200, check_server_scan, &meta_scan);
853
854 lan_scan.scan = server_scan_begin(SERVER_SCAN_LOCAL, server_scan_error);
855 lan_scan.timer = g_timeout_add(500, check_server_scan, &lan_scan);
856}
857
858/**************************************************************************
859 Network connection state defines.
860**************************************************************************/
861 enum connection_state {
862 LOGIN_TYPE,
863 NEW_PASSWORD_TYPE,
864 ENTER_PASSWORD_TYPE,
865 WAITING_TYPE
866};
867
868 static enum connection_state connection_status;
869
870/**********************************************************************/
873 static gboolean update_network_statusbar(gpointer data)
874{
875 if (!g_queue_is_empty(statusbar_queue)) {
876 char *txt;
877
878 txt = g_queue_pop_head(statusbar_queue);
879 gtk_label_set_text(GTK_LABEL(statusbar), txt);
880 free(txt);
881 }
882
883 return TRUE;
884}
885
886/**********************************************************************/
889 static void clear_network_statusbar(void)
890{
891 while (!g_queue_is_empty(statusbar_queue)) {
892 char *txt;
893
894 txt = g_queue_pop_head(statusbar_queue);
895 free(txt);
896 }
897
898 gtk_label_set_text(GTK_LABEL(statusbar), "");
899}
900
901/**********************************************************************/
904 void append_network_statusbar(const char *text, bool force)
905{
906 if (gtk_widget_get_visible(statusbar_frame)) {
907 if (force) {
908 clear_network_statusbar();
909 gtk_label_set_text(GTK_LABEL(statusbar), text);
910 } else {
911 g_queue_push_tail(statusbar_queue, fc_strdup(text));
912 }
913 }
914}
915
916/**********************************************************************/
919 GtkWidget *create_statusbar(void)
920{
921 statusbar_frame = gtk_frame_new(NULL);
922
923 statusbar = gtk_label_new("");
924 gtk_widget_set_margin_start(statusbar, 2);
925 gtk_widget_set_margin_end(statusbar, 2);
926 gtk_widget_set_margin_top(statusbar, 2);
927 gtk_widget_set_margin_bottom(statusbar, 2);
928 gtk_frame_set_child(GTK_FRAME(statusbar_frame), statusbar);
929
930 statusbar_queue = g_queue_new();
931 statusbar_timer = g_timeout_add(2000, update_network_statusbar, NULL);
932
933 return statusbar_frame;
934}
935
936/**********************************************************************/
939 static void set_connection_state(enum connection_state state)
940{
941 switch (state) {
942 case LOGIN_TYPE:
943 append_network_statusbar("", FALSE);
944
945 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_password)),
946 "", -1);
947 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_confirm_password)),
948 "", -1);
949
950 gtk_widget_set_sensitive(network_host, TRUE);
951 gtk_widget_set_sensitive(network_port, TRUE);
952 gtk_widget_set_sensitive(network_login, TRUE);
953 gtk_widget_set_sensitive(network_password_label, FALSE);
954 gtk_label_set_markup_with_mnemonic(GTK_LABEL(network_password_label), _("Pass_word:"));
955 gtk_widget_set_sensitive(network_password, FALSE);
956 gtk_widget_set_sensitive(network_confirm_password_label, FALSE);
957 gtk_widget_set_sensitive(network_confirm_password, FALSE);
958 break;
959 case NEW_PASSWORD_TYPE:
960 set_client_page(PAGE_NETWORK);
961 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_password)), "", -1);
962 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_confirm_password)),
963 "", -1);
964
965 gtk_widget_set_sensitive(network_host, FALSE);
966 gtk_widget_set_sensitive(network_port, FALSE);
967 gtk_widget_set_sensitive(network_login, FALSE);
968 gtk_widget_set_sensitive(network_password_label, TRUE);
969 gtk_label_set_markup_with_mnemonic(GTK_LABEL(network_password_label), _("New Pass_word:"));
970 gtk_widget_set_sensitive(network_password, TRUE);
971 gtk_widget_set_sensitive(network_confirm_password_label, TRUE);
972 gtk_widget_set_sensitive(network_confirm_password, TRUE);
973
974 gtk_widget_grab_focus(network_password);
975 break;
976 case ENTER_PASSWORD_TYPE:
977 set_client_page(PAGE_NETWORK);
978 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_password)), "", -1);
979 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_confirm_password)),
980 "", -1);
981
982 gtk_widget_set_sensitive(network_host, FALSE);
983 gtk_widget_set_sensitive(network_port, FALSE);
984 gtk_widget_set_sensitive(network_login, FALSE);
985 gtk_widget_set_sensitive(network_password_label, TRUE);
986 gtk_label_set_markup_with_mnemonic(GTK_LABEL(network_password_label), _("Pass_word:"));
987 gtk_widget_set_sensitive(network_password, TRUE);
988 gtk_widget_set_sensitive(network_confirm_password_label, FALSE);
989 gtk_widget_set_sensitive(network_confirm_password, FALSE);
990
991 gtk_widget_grab_focus(network_password);
992 break;
993 case WAITING_TYPE:
994 append_network_statusbar("", TRUE);
995
996 gtk_widget_set_sensitive(network_login, FALSE);
997 gtk_widget_set_sensitive(network_password_label, FALSE);
998 gtk_label_set_markup_with_mnemonic(GTK_LABEL(network_password_label), _("Pass_word:"));
999 gtk_widget_set_sensitive(network_password, FALSE);
1000 gtk_widget_set_sensitive(network_confirm_password_label, FALSE);
1001 gtk_widget_set_sensitive(network_confirm_password, FALSE);
1002 break;
1003 }
1004
1005 connection_status = state;
1006}
1007
1008/**********************************************************************/
1011 static void connection_state_reset(void)
1012{
1013 set_connection_state(LOGIN_TYPE);
1014}
1015
1016/**********************************************************************/
1020 void handle_authentication_req(enum authentication_type type,
1021 const char *message)
1022{
1023 append_network_statusbar(message, TRUE);
1024
1025 switch (type) {
1026 case AUTH_NEWUSER_FIRST:
1027 case AUTH_NEWUSER_RETRY:
1028 set_connection_state(NEW_PASSWORD_TYPE);
1029 return;
1030 case AUTH_LOGIN_FIRST:
1031 /* if we magically have a password already present in 'fc_password'
1032 * then, use that and skip the password entry dialog */
1033 if (fc_password[0] != '\0') {
1034 struct packet_authentication_reply reply;
1035
1036 sz_strlcpy(reply.password, fc_password);
1037 send_packet_authentication_reply(&client.conn, &reply);
1038 return;
1039 } else {
1040 set_connection_state(ENTER_PASSWORD_TYPE);
1041 }
1042 return;
1043 case AUTH_LOGIN_RETRY:
1044 set_connection_state(ENTER_PASSWORD_TYPE);
1045 return;
1046 }
1047
1048 log_error("Unsupported authentication type %d: %s.", type, message);
1049}
1050
1051/**********************************************************************/
1056 static void connect_callback(GtkWidget *w, gpointer data)
1057{
1058 char errbuf [512];
1059 struct packet_authentication_reply reply;
1060
1061 switch (connection_status) {
1062 case LOGIN_TYPE:
1063 sz_strlcpy(user_name,
1064 gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(network_login))));
1065 sz_strlcpy(server_host,
1066 gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(network_host))));
1067 server_port = atoi(gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(network_port))));
1068
1069 if (connect_to_server(user_name, server_host, server_port,
1070 errbuf, sizeof(errbuf)) != -1) {
1071 } else {
1072 append_network_statusbar(errbuf, TRUE);
1073
1074 output_window_append(ftc_client, errbuf);
1075 }
1076 return;
1077 case NEW_PASSWORD_TYPE:
1078 if (w != network_password) {
1079 sz_strlcpy(fc_password,
1080 gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(network_password))));
1081 sz_strlcpy(reply.password,
1082 gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(network_confirm_password))));
1083 if (!fc_strncmp(reply.password, fc_password, MAX_LEN_NAME)) {
1084 fc_password[0] = '\0';
1085 send_packet_authentication_reply(&client.conn, &reply);
1086
1087 set_connection_state(WAITING_TYPE);
1088 } else {
1089 append_network_statusbar(_("Passwords don't match, enter password."),
1090 TRUE);
1091
1092 set_connection_state(NEW_PASSWORD_TYPE);
1093 }
1094 }
1095 return;
1096 case ENTER_PASSWORD_TYPE:
1097 sz_strlcpy(reply.password,
1098 gtk_entry_buffer_get_text(gtk_entry_get_buffer(GTK_ENTRY(network_password))));
1099 send_packet_authentication_reply(&client.conn, &reply);
1100
1101 set_connection_state(WAITING_TYPE);
1102 return;
1103 case WAITING_TYPE:
1104 return;
1105 }
1106
1107 log_error("Unsupported connection status: %d", connection_status);
1108}
1109
1110/**********************************************************************/
1113 static void network_activate_callback(GtkTreeView *view,
1114 GtkTreePath *arg1,
1115 GtkTreeViewColumn *arg2,
1116 gpointer data)
1117{
1118 connect_callback(NULL, data);
1119}
1120
1121/**********************************************************************/
1125 static void update_server_playerlist(const struct server *pserver)
1126{
1127 GtkListStore *store;
1128 GtkTreeIter iter;
1129 int n, i;
1130
1131 store = server_playerlist_store;
1132 fc_assert_ret(store != NULL);
1133
1134 gtk_list_store_clear(store);
1135 if (!pserver || !pserver->players) {
1136 return;
1137 }
1138
1139 n = pserver->nplayers;
1140 for (i = 0; i < n; i++) {
1141 gtk_list_store_append(store, &iter);
1142 gtk_list_store_set(store, &iter,
1143 0, pserver->players[i].name,
1144 1, pserver->players[i].type,
1145 2, pserver->players[i].host,
1146 3, pserver->players[i].nation,
1147 -1);
1148 }
1149}
1150
1151/**********************************************************************/
1154 static void network_list_callback(GtkTreeSelection *select, gpointer data)
1155{
1156 GtkTreeModel *model;
1157 GtkTreeIter it;
1158 const char *host;
1159 int port;
1160 char portstr[32];
1161 const struct server *pserver = NULL;
1162
1163 if (!gtk_tree_selection_get_selected(select, &model, &it)) {
1164 return;
1165 }
1166
1167 if (select == meta_selection) {
1168 GtkTreePath *path;
1169 struct srv_list *srvrs;
1170
1171 srvrs = server_scan_get_list(meta_scan.scan);
1172 path = gtk_tree_model_get_path(model, &it);
1173 if (!holding_srv_list_mutex) {
1174 /* We are not yet inside mutex protected block */
1175 fc_mutex_allocate(&srvrs->mutex);
1176 }
1177 if (srvrs->servers && path) {
1178 gint pos = gtk_tree_path_get_indices(path)[0];
1179
1180 pserver = server_list_get(srvrs->servers, pos);
1181 }
1182 if (!holding_srv_list_mutex) {
1183 /* We are not yet inside mutex protected block */
1184 fc_mutex_release(&srvrs->mutex);
1185 }
1186 gtk_tree_path_free(path);
1187 }
1188 update_server_playerlist(pserver);
1189
1190 gtk_tree_model_get(model, &it, 0, &host, 1, &port, -1);
1191
1192 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_host)), host, -1);
1193 fc_snprintf(portstr, sizeof(portstr), "%d", port);
1194 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_port)), portstr, -1);
1195}
1196
1197/**********************************************************************/
1200 static void update_network_page(void)
1201{
1202 char buf[256];
1203
1204 gtk_tree_selection_unselect_all(lan_selection);
1205 gtk_tree_selection_unselect_all(meta_selection);
1206
1207 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_login)), user_name, -1);
1208 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_host)), server_host, -1);
1209 fc_snprintf(buf, sizeof(buf), "%d", server_port);
1210 gtk_entry_buffer_set_text(gtk_entry_get_buffer(GTK_ENTRY(network_port)), buf, -1);
1211}
1212
1213/**********************************************************************/
1216 GtkWidget *create_network_page(void)
1217{
1218 GtkWidget *box, *sbox, *bbox, *hbox, *notebook;
1219 GtkWidget *button, *label, *view, *sw, *table;
1220 GtkTreeSelection *selection;
1221 GtkListStore *store;
1222 GtkEventController *controller;
1223
1224 box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
1225 gtk_widget_set_margin_start(box, 4);
1226 gtk_widget_set_margin_end(box, 4);
1227 gtk_widget_set_margin_top(box, 4);
1228 gtk_widget_set_margin_bottom(box, 4);
1229
1230 notebook = gtk_notebook_new();
1231 gtk_box_append(GTK_BOX(box), notebook);
1232
1233 /* LAN pane. */
1234 lan_store = gtk_list_store_new(7, G_TYPE_STRING, /* host */
1235 G_TYPE_INT, /* port */
1236 G_TYPE_STRING, /* version */
1237 G_TYPE_STRING, /* state */
1238 G_TYPE_INT, /* nplayers */
1239 G_TYPE_STRING, /* humans */
1240 G_TYPE_STRING); /* message */
1241
1242 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(lan_store));
1243 gtk_widget_set_hexpand(view, TRUE);
1244 gtk_widget_set_vexpand(view, TRUE);
1245 g_object_unref(lan_store);
1246 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(view));
1247
1248 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1249 lan_selection = selection;
1250 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
1251
1252 controller = gtk_event_controller_focus_new();
1253 g_signal_connect(controller, "enter",
1254 G_CALLBACK(terminate_signal_processing), NULL);
1255 gtk_widget_add_controller(view, controller);
1256
1257 g_signal_connect(view, "row-activated",
1258 G_CALLBACK(network_activate_callback), NULL);
1259 g_signal_connect(selection, "changed",
1260 G_CALLBACK(network_list_callback), NULL);
1261
1262 add_treeview_column(view, _("Server Name"), G_TYPE_STRING, 0);
1263 add_treeview_column(view, _("Port"), G_TYPE_INT, 1);
1264 add_treeview_column(view, _("Version"), G_TYPE_STRING, 2);
1265 add_treeview_column(view, _("Status"), G_TYPE_STRING, 3);
1266 add_treeview_column(view, _("Players"), G_TYPE_INT, 4);
1267 add_treeview_column(view, _("Humans"), G_TYPE_STRING, 5);
1268 add_treeview_column(view, _("Comment"), G_TYPE_STRING, 6);
1269
1270 label = gtk_label_new_with_mnemonic(_("Local _Area Network"));
1271
1272 sw = gtk_scrolled_window_new();
1273 gtk_widget_set_margin_start(sw, 4);
1274 gtk_widget_set_margin_end(sw, 4);
1275 gtk_widget_set_margin_top(sw, 4);
1276 gtk_widget_set_margin_bottom(sw, 4);
1277 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
1278 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1279 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1280 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), view);
1281 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sw, label);
1282
1283
1284 /* Metaserver pane. */
1285 meta_store = gtk_list_store_new(7, G_TYPE_STRING, /* host */
1286 G_TYPE_INT, /* port */
1287 G_TYPE_STRING, /* version */
1288 G_TYPE_STRING, /* state */
1289 G_TYPE_INT, /* nplayers */
1290 G_TYPE_STRING, /* humans */
1291 G_TYPE_STRING); /* message */
1292
1293 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(meta_store));
1294 gtk_widget_set_hexpand(view, TRUE);
1295 gtk_widget_set_vexpand(view, TRUE);
1296 g_object_unref(meta_store);
1297 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(view));
1298
1299 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1300 meta_selection = selection;
1301 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
1302
1303 controller = gtk_event_controller_focus_new();
1304 g_signal_connect(controller, "enter",
1305 G_CALLBACK(terminate_signal_processing), NULL);
1306 gtk_widget_add_controller(view, controller);
1307
1308 g_signal_connect(view, "row-activated",
1309 G_CALLBACK(network_activate_callback), NULL);
1310 g_signal_connect(selection, "changed",
1311 G_CALLBACK(network_list_callback), NULL);
1312
1313 add_treeview_column(view, _("Server Name"), G_TYPE_STRING, 0);
1314 add_treeview_column(view, _("Port"), G_TYPE_INT, 1);
1315 add_treeview_column(view, _("Version"), G_TYPE_STRING, 2);
1316 add_treeview_column(view, _("Status"), G_TYPE_STRING, 3);
1317 add_treeview_column(view, _("Players"), G_TYPE_INT, 4);
1318 add_treeview_column(view, _("Humans"), G_TYPE_STRING, 5);
1319 add_treeview_column(view, _("Comment"), G_TYPE_STRING, 6);
1320
1321 label = gtk_label_new_with_mnemonic(_("Internet _Metaserver"));
1322
1323 sw = gtk_scrolled_window_new();
1324 gtk_widget_set_margin_start(sw, 4);
1325 gtk_widget_set_margin_end(sw, 4);
1326 gtk_widget_set_margin_top(sw, 4);
1327 gtk_widget_set_margin_bottom(sw, 4);
1328 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
1329 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1330 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1331 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), view);
1332 if (GUI_GTK_OPTION(metaserver_tab_first)) {
1333 gtk_notebook_prepend_page(GTK_NOTEBOOK(notebook), sw, label);
1334 } else {
1335 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sw, label);
1336 }
1337
1338 /* Bottom part of the page, outside the inner notebook. */
1339 sbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
1340 gtk_box_append(GTK_BOX(box), sbox);
1341
1342 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
1343 gtk_widget_set_margin_bottom(hbox, 8);
1344 gtk_widget_set_margin_end(hbox, 8);
1345 gtk_widget_set_margin_start(hbox, 8);
1346 gtk_widget_set_margin_top(hbox, 8);
1347 gtk_box_append(GTK_BOX(sbox), hbox);
1348
1349 table = gtk_grid_new();
1350 gtk_grid_set_row_spacing(GTK_GRID(table), 2);
1351 gtk_grid_set_column_spacing(GTK_GRID(table), 12);
1352 gtk_box_append(GTK_BOX(hbox), table);
1353
1354 network_host = gtk_entry_new();
1355 g_signal_connect(network_host, "activate",
1356 G_CALLBACK(connect_callback), NULL);
1357 gtk_grid_attach(GTK_GRID(table), network_host, 1, 0, 1, 1);
1358
1359 label = g_object_new(GTK_TYPE_LABEL,
1360 "use-underline", TRUE,
1361 "mnemonic-widget", network_host,
1362 "label", _("_Host:"),
1363 "xalign", 0.0,
1364 "yalign", 0.5,
1365 NULL);
1366 network_host_label = label;
1367 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
1368
1369 network_port = gtk_entry_new();
1370 g_signal_connect(network_port, "activate",
1371 G_CALLBACK(connect_callback), NULL);
1372 gtk_grid_attach(GTK_GRID(table), network_port, 1, 1, 1, 1);
1373
1374 label = g_object_new(GTK_TYPE_LABEL,
1375 "use-underline", TRUE,
1376 "mnemonic-widget", network_port,
1377 "label", _("_Port:"),
1378 "xalign", 0.0,
1379 "yalign", 0.5,
1380 NULL);
1381 network_port_label = label;
1382 gtk_grid_attach(GTK_GRID(table), label, 0, 1, 1, 1);
1383
1384 network_login = gtk_entry_new();
1385 gtk_widget_set_margin_top(network_login, 10);
1386 g_signal_connect(network_login, "activate",
1387 G_CALLBACK(connect_callback), NULL);
1388 gtk_grid_attach(GTK_GRID(table), network_login, 1, 3, 1, 1);
1389
1390 label = g_object_new(GTK_TYPE_LABEL,
1391 "use-underline", TRUE,
1392 "mnemonic-widget", network_login,
1393 "label", _("_Login:"),
1394 "xalign", 0.0,
1395 "yalign", 0.5,
1396 NULL);
1397 gtk_widget_set_margin_top(label, 10);
1398 network_login_label = label;
1399 gtk_grid_attach(GTK_GRID(table), label, 0, 3, 1, 1);
1400
1401 network_password = gtk_entry_new();
1402 g_signal_connect(network_password, "activate",
1403 G_CALLBACK(connect_callback), NULL);
1404 gtk_entry_set_visibility(GTK_ENTRY(network_password), FALSE);
1405 gtk_grid_attach(GTK_GRID(table), network_password, 1, 4, 1, 1);
1406
1407 label = g_object_new(GTK_TYPE_LABEL,
1408 "use-underline", TRUE,
1409 "mnemonic-widget", network_password,
1410 "label", _("Pass_word:"),
1411 "xalign", 0.0,
1412 "yalign", 0.5,
1413 NULL);
1414 network_password_label = label;
1415 gtk_grid_attach(GTK_GRID(table), label, 0, 4, 1, 1);
1416
1417 network_confirm_password = gtk_entry_new();
1418 g_signal_connect(network_confirm_password, "activate",
1419 G_CALLBACK(connect_callback), NULL);
1420 gtk_entry_set_visibility(GTK_ENTRY(network_confirm_password), FALSE);
1421 gtk_grid_attach(GTK_GRID(table), network_confirm_password, 1, 5, 1, 1);
1422
1423 label = g_object_new(GTK_TYPE_LABEL,
1424 "use-underline", TRUE,
1425 "mnemonic-widget", network_confirm_password,
1426 "label", _("Conf_irm Password:"),
1427 "xalign", 0.0,
1428 "yalign", 0.5,
1429 NULL);
1430 network_confirm_password_label = label;
1431 gtk_grid_attach(GTK_GRID(table), label, 0, 5, 1, 1);
1432
1433 /* Server player list. */
1434 store = gtk_list_store_new(4, G_TYPE_STRING,
1435 G_TYPE_STRING,
1436 G_TYPE_STRING,
1437 G_TYPE_STRING);
1438 server_playerlist_store = store;
1439
1440 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1441 gtk_widget_set_hexpand(view, TRUE);
1442 add_treeview_column(view, _("Name"), G_TYPE_STRING, 0);
1443 add_treeview_column(view, _("Type"), G_TYPE_STRING, 1);
1444 add_treeview_column(view, _("Host"), G_TYPE_STRING, 2);
1445 add_treeview_column(view, _("Nation"), G_TYPE_STRING, 3);
1446 server_playerlist_view = view;
1447
1448 sw = gtk_scrolled_window_new();
1449 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
1450 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1451 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1452 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), view);
1453 gtk_box_append(GTK_BOX(hbox), sw);
1454
1455 bbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
1456 gtk_widget_set_margin_bottom(bbox, 2);
1457 gtk_widget_set_margin_end(bbox, 2);
1458 gtk_widget_set_margin_start(bbox, 2);
1459 gtk_widget_set_margin_top(bbox, 2);
1460 gtk_box_set_spacing(GTK_BOX(bbox), 12);
1461 gtk_box_append(GTK_BOX(sbox), bbox);
1462
1463 button = gtk_button_new_from_icon_name("view-refresh");
1464 gtk_box_append(GTK_BOX(bbox), button);
1465 g_signal_connect(button, "clicked",
1466 G_CALLBACK(update_network_lists), NULL);
1467
1468 button = gtk_button_new_with_mnemonic(_("_Cancel"));
1469 gtk_box_append(GTK_BOX(bbox), button);
1470 g_signal_connect(button, "clicked",
1471 G_CALLBACK(main_callback), NULL);
1472
1473 button = gtk_button_new_with_mnemonic(_("C_onnect"));
1474 gtk_box_append(GTK_BOX(bbox), button);
1475 g_signal_connect(button, "clicked",
1476 G_CALLBACK(connect_callback), NULL);
1477
1478 return box;
1479}
1480
1481/****************************************************************************
1482 START PAGE
1483****************************************************************************/
1484 GtkWidget *start_message_area;
1485
1486 static GtkWidget *start_options_table;
1487 static GtkWidget *observe_button, *ready_button, *nation_button;
1488 static GtkTreeStore *connection_list_store;
1489 static GtkTreeView *connection_list_view;
1490 static GtkWidget *start_aifill_spin = NULL;
1491 static GtkWidget *ai_lvl_combobox = NULL;
1492
1493
1494/* NB: Must match creation arguments in connection_list_store_new(). */
1495 enum connection_list_columns {
1496 CL_COL_PLAYER_NUMBER = 0,
1497 CL_COL_USER_NAME,
1498 CL_COL_READY_STATE,
1499 CL_COL_PLAYER_NAME,
1500 CL_COL_FLAG,
1501 CL_COL_COLOR,
1502 CL_COL_NATION,
1503 CL_COL_TEAM,
1504 CL_COL_CONN_ID,
1505 CL_COL_STYLE,
1506 CL_COL_WEIGHT,
1507 CL_COL_COLLAPSED,
1508
1509 CL_NUM_COLUMNS
1510};
1511
1512/**********************************************************************/
1515 static inline GtkTreeStore *connection_list_store_new(void)
1516{
1517 return gtk_tree_store_new(CL_NUM_COLUMNS,
1518 G_TYPE_INT, /* CL_COL_PLAYER_NUMBER */
1519 G_TYPE_STRING, /* CL_COL_USER_NAME */
1520 G_TYPE_BOOLEAN, /* CL_COL_READY_STATE */
1521 G_TYPE_STRING, /* CL_COL_PLAYER_NAME */
1522 GDK_TYPE_PIXBUF, /* CL_COL_FLAG */
1523 GDK_TYPE_PIXBUF, /* CL_COL_COLOR */
1524 G_TYPE_STRING, /* CL_COL_NATION */
1525 G_TYPE_STRING, /* CL_COL_TEAM */
1526 G_TYPE_INT, /* CL_COL_CONN_ID */
1527 G_TYPE_INT, /* CL_COL_STYLE */
1528 G_TYPE_INT, /* CL_COL_WEIGHT */
1529 G_TYPE_BOOLEAN); /* CL_COL_COLLAPSED */
1530}
1531
1532/**********************************************************************/
1536 static void client_aitoggle_player(void *data)
1537{
1538 struct player *pplayer = player_by_number(FC_PTR_TO_INT(data));
1539
1540 if (NULL != pplayer
1541 && pplayer == client_player()
1542 && !is_human(pplayer)) {
1543 send_chat("/away");
1544 }
1545}
1546
1547/**********************************************************************/
1550 static void client_take_player(struct player *pplayer)
1551{
1552 int request_id = send_chat_printf("/take \"%s\"", player_name(pplayer));
1553 void *data = FC_INT_TO_PTR(player_number(pplayer));
1554
1555 update_queue_connect_processing_finished(request_id,
1556 client_aitoggle_player, data);
1557}
1558
1559/**********************************************************************/
1562 static void object_put(GObject *object, struct player *pplayer,
1563 struct connection *pconn)
1564{
1565 /* Note that passing -1 to GINT_TO_POINTER() is buggy with some versions
1566 * of gcc. player_slot_count() is not a valid player number. 0 is not
1567 * a valid connection id (see comment in server/sernet.c:
1568 * makeup_connection_name()). */
1569 g_object_set_data(object, "player_id",
1570 GINT_TO_POINTER(NULL != pplayer
1571 ? player_number(pplayer)
1572 : player_slot_count()));
1573 g_object_set_data(object, "connection_id",
1574 GINT_TO_POINTER(NULL != pconn ? pconn->id : 0));
1575}
1576
1577/**********************************************************************/
1581 static bool object_extract(GObject *object, struct player **ppplayer,
1582 struct connection **ppconn)
1583{
1584 bool ret = FALSE;
1585 int id;
1586
1587 if (NULL != ppplayer) {
1588 id = GPOINTER_TO_INT(g_object_get_data(object, "player_id"));
1589 *ppplayer = player_by_number(id);
1590 if (NULL != *ppplayer) {
1591 ret = TRUE;
1592 }
1593 }
1594 if (NULL != ppconn) {
1595 id = GPOINTER_TO_INT(g_object_get_data(object, "connection_id"));
1596 *ppconn = conn_by_number(id);
1597 if (NULL != *ppconn) {
1598 ret = TRUE;
1599 }
1600 }
1601
1602 return ret;
1603}
1604
1605/**********************************************************************/
1608 static void game_options_callback(GtkWidget *w, gpointer data)
1609{
1610 option_dialog_popup(_("Game Settings"), server_optset);
1611}
1612
1613/**********************************************************************/
1616 static void ai_skill_callback(GtkWidget *w, gpointer data)
1617{
1618 enum ai_level *levels = (enum ai_level *)data;
1619 const char *name;
1620 int i;
1621
1622 i = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
1623
1624 if (i != -1) {
1625 enum ai_level level = levels[i];
1626
1627 /* Suppress changes provoked by server rather than local user */
1628 if (server_ai_level() != level) {
1629 name = ai_level_cmd(level);
1630 send_chat_printf("/%s", name);
1631 }
1632 }
1633}
1634
1635/* HACK: sometimes when creating the ruleset combo the value is set without
1636 * the user's control. In this case we don't want to do a /read. */
1637 static bool no_ruleset_callback = FALSE;
1638
1639/**********************************************************************/
1642 static void ruleset_selected(const char *name)
1643{
1644 if (name && name[0] != '\0' && !no_ruleset_callback) {
1645 set_ruleset(name);
1646 }
1647}
1648
1649/**********************************************************************/
1654 static void ruleset_entry_changed(GtkWidget *w, gpointer data)
1655{
1656 const char *name = NULL;
1657
1658 name = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(ruleset_combo));
1659
1660 if (name != NULL) {
1661 ruleset_selected(name);
1662 }
1663}
1664
1665/**********************************************************************/
1668 static bool send_new_aifill_to_server = TRUE;
1669 static void ai_fill_changed_by_user(GtkWidget *w, gpointer data)
1670{
1671 if (send_new_aifill_to_server) {
1672 option_int_set(optset_option_by_name(server_optset, "aifill"),
1673 gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w)));
1674 }
1675}
1676
1677/**********************************************************************/
1680 void ai_fill_changed_by_server(int aifill)
1681{
1682 if (start_aifill_spin) {
1683 bool old = send_new_aifill_to_server;
1684 /* Suppress callback from this change to avoid a loop. */
1685 send_new_aifill_to_server = FALSE;
1686 /* HACK: this GUI control doesn't have quite the same semantics as the
1687 * server 'aifill' option, in that it claims to represent the minimum
1688 * number of players _including humans_. The GUI control has a minimum
1689 * value of 1, so aifill == 0 will not be represented correctly.
1690 * But there's generally exactly one human player because the control
1691 * only shows up for a locally spawned server, so we more or less
1692 * get away with this. */
1693 gtk_spin_button_set_value(GTK_SPIN_BUTTON(start_aifill_spin), aifill);
1694 send_new_aifill_to_server = old;
1695 }
1696}
1697
1698/**********************************************************************/
1701 void update_start_page(void)
1702{
1703 conn_list_dialog_update();
1704}
1705
1706/**********************************************************************/
1709 static void close_conn_menu_popover(void)
1710{
1711 if (conn_popover != NULL){
1712 gtk_widget_unparent(conn_popover);
1713 g_object_unref(conn_popover);
1714
1715 conn_popover = NULL;
1716 }
1717}
1718
1719/**********************************************************************/
1722 static void conn_menu_team_chosen(GSimpleAction *action, GVariant *parameter,
1723 gpointer data)
1724{
1725 struct player *pplayer;
1726 struct team_slot *tslot = g_object_get_data(G_OBJECT(action), "slot");
1727 GMenu *menu = data;
1728
1729 if (object_extract(G_OBJECT(menu), &pplayer, NULL)
1730 && NULL != tslot
1731 && team_slot_index(tslot) != team_number(pplayer->team)) {
1732 send_chat_printf("/team \"%s\" \"%s\"",
1733 player_name(pplayer),
1734 team_slot_rule_name(tslot));
1735 }
1736
1737 close_conn_menu_popover();
1738}
1739
1740/**********************************************************************/
1743 static void conn_menu_ready_chosen(GSimpleAction *action, GVariant *parameter,
1744 gpointer data)
1745{
1746 struct player *pplayer;
1747 GMenu *menu = data;
1748
1749 if (object_extract(G_OBJECT(menu), &pplayer, NULL)) {
1750 dsend_packet_player_ready(&client.conn,
1751 player_number(pplayer), !pplayer->is_ready);
1752 }
1753
1754 close_conn_menu_popover();
1755}
1756
1757/**********************************************************************/
1760 static void conn_menu_nation_chosen(GSimpleAction *action, GVariant *parameter,
1761 gpointer data)
1762{
1763 struct player *pplayer;
1764 GMenu *menu = data;
1765
1766 if (object_extract(G_OBJECT(menu), &pplayer, NULL)) {
1767 popup_races_dialog(pplayer);
1768 }
1769
1770 close_conn_menu_popover();
1771}
1772
1773/**********************************************************************/
1777 static void conn_menu_player_command(GSimpleAction *action, GVariant *parameter,
1778 gpointer data)
1779{
1780 struct player *pplayer;
1781 GMenu *menu = data;
1782
1783 if (object_extract(G_OBJECT(menu), &pplayer, NULL)) {
1784 send_chat_printf("/%s \"%s\"",
1785 (char *) g_object_get_data(G_OBJECT(action), "command"),
1786 player_name(pplayer));
1787 }
1788
1789 close_conn_menu_popover();
1790}
1791
1792/**********************************************************************/
1795 static void conn_menu_player_take(GSimpleAction *action, GVariant *parameter,
1796 gpointer data)
1797{
1798 struct player *pplayer;
1799 GMenu *menu = data;
1800
1801 if (object_extract(G_OBJECT(menu), &pplayer, NULL)) {
1802 client_take_player(pplayer);
1803 }
1804
1805 close_conn_menu_popover();
1806}
1807
1808/**********************************************************************/
1812 static void conn_menu_connection_command(GSimpleAction *action,
1813 GVariant *parameter, gpointer data)
1814{
1815 struct connection *pconn;
1816 GMenu *menu = data;
1817
1818 if (object_extract(G_OBJECT(menu), NULL, &pconn)) {
1819 send_chat_printf(SERVER_COMMAND_PREFIX_STR "%s \"%s\"",
1820 (char *) g_object_get_data(G_OBJECT(action), "command"),
1821 pconn->username);
1822 }
1823
1824 close_conn_menu_popover();
1825}
1826
1827/**********************************************************************/
1830 static void show_conn_popup(struct player *pplayer, struct connection *pconn)
1831{
1832 GtkWidget *popup;
1833 char buf[4096] = "";
1834
1835 if (pconn) {
1836 cat_snprintf(buf, sizeof(buf), _("Connection name: %s"),
1837 pconn->username);
1838 } else {
1839 cat_snprintf(buf, sizeof(buf), _("Player name: %s"),
1840 player_name(pplayer));
1841 }
1842 cat_snprintf(buf, sizeof(buf), "\n");
1843 if (pconn) {
1844 cat_snprintf(buf, sizeof(buf), _("Host: %s"), pconn->addr);
1845 }
1846 cat_snprintf(buf, sizeof(buf), "\n");
1847
1848 /* Show popup. */
1849 popup = gtk_message_dialog_new(NULL, 0,
1850 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1851 "%s", buf);
1852 gtk_window_set_title(GTK_WINDOW(popup), _("Player/conn info"));
1853 setup_dialog(popup, toplevel);
1854 g_signal_connect(popup, "response", G_CALLBACK(gtk_window_destroy), NULL);
1855 gtk_window_present(GTK_WINDOW(popup));
1856}
1857
1858/**********************************************************************/
1861 static void conn_menu_info_chosen(GSimpleAction *action, GVariant *parameter,
1862 gpointer data)
1863{
1864 struct player *pplayer;
1865 struct connection *pconn;
1866 GMenu *menu = data;
1867
1868 if (object_extract(G_OBJECT(menu), &pplayer, &pconn)) {
1869 show_conn_popup(pplayer, pconn);
1870 }
1871
1872 close_conn_menu_popover();
1873}
1874
1875/**********************************************************************/
1879 static GtkWidget *create_conn_menu(struct player *pplayer,
1880 struct connection *pconn)
1881{
1882 GMenu *menu;
1883 gchar *buf;
1884 GSimpleAction *act;
1885 GActionGroup *group;
1886
1887 group = G_ACTION_GROUP(g_simple_action_group_new());
1888
1889 menu = g_menu_new();
1890
1891 object_put(G_OBJECT(menu), pplayer, pconn);
1892
1893 buf = g_strdup_printf(_("%s info"),
1894 pconn ? pconn->username : player_name(pplayer));
1895
1896 act = g_simple_action_new("info", NULL);
1897 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
1898 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_info_chosen), menu);
1899 menu_item_append_unref(menu, g_menu_item_new(buf, "win.info"));
1900
1901 if (NULL != pplayer) {
1902 act = g_simple_action_new("toggle_ready", NULL);
1903 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
1904 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_ready_chosen), menu);
1905 g_simple_action_set_enabled(G_SIMPLE_ACTION(act), is_human(pplayer));
1906 menu_item_append_unref(menu, g_menu_item_new(_("Toggle player ready"),
1907 "win.toggle_ready"));
1908
1909 act = g_simple_action_new("pick_nation", NULL);
1910 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
1911 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_nation_chosen), menu);
1912 g_simple_action_set_enabled(G_SIMPLE_ACTION(act),
1913 can_conn_edit_players_nation(&client.conn,
1914 pplayer));
1915 menu_item_append_unref(menu, g_menu_item_new(_("Pick nation"), "win.pick_nation"));
1916
1917 act = g_simple_action_new("observe", NULL);
1918 g_object_set_data_full(G_OBJECT(act), "command", g_strdup("observe"),
1919 (GDestroyNotify) g_free);
1920 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
1921 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_player_command), menu);
1922 menu_item_append_unref(menu, g_menu_item_new(_("Observe this player"),
1923 "win.observe"));
1924
1925 act = g_simple_action_new("take_plr", NULL);
1926 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
1927 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_player_take), menu);
1928 menu_item_append_unref(menu, g_menu_item_new(_("Take this player"),
1929 "win.take_plr"));
1930 }
1931
1932 if (ALLOW_CTRL <= client.conn.access_level && NULL != pconn
1933 && pconn->id != client.conn.id) {
1934 act = g_simple_action_new("cut_conn", NULL);
1935 g_object_set_data_full(G_OBJECT(act), "command", g_strdup("cut"),
1936 (GDestroyNotify) g_free);
1937 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
1938 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_connection_command), menu);
1939 menu_item_append_unref(menu, g_menu_item_new(_("Cut connection"), "win.cut_conn"));
1940 }
1941
1942 if (ALLOW_CTRL <= client.conn.access_level && NULL != pplayer) {
1943 act = g_simple_action_new("aitoggle", NULL);
1944 g_object_set_data_full(G_OBJECT(act), "command", g_strdup("aitoggle"),
1945 (GDestroyNotify) g_free);
1946 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
1947 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_connection_command), menu);
1948 menu_item_append_unref(menu, g_menu_item_new(_("Aitoggle player"), "win.aitoggle"));
1949
1950 if (pplayer != client.conn.playing && game.info.is_new_game) {
1951 act = g_simple_action_new("remove", NULL);
1952 g_object_set_data_full(G_OBJECT(act), "command", g_strdup("remove"),
1953 (GDestroyNotify) g_free);
1954 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
1955 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_connection_command), menu);
1956 menu_item_append_unref(menu, g_menu_item_new(_("Remove player"), "win.remove"));
1957 }
1958 }
1959
1960 if (ALLOW_ADMIN <= client.conn.access_level && NULL != pconn
1961 && pconn->id != client.conn.id) {
1962 enum cmdlevel level;
1963
1964 /* No item for hack access; that would be a serious security hole. */
1965 for (level = cmdlevel_min(); level < client.conn.access_level; level++) {
1966 char actbuf[128];
1967
1968 buf = g_strdup_printf(_("Give %s access"), cmdlevel_name(level));
1969 fc_snprintf(actbuf, sizeof(actbuf), "cmdlevel_%d", level);
1970
1971 act = g_simple_action_new(actbuf, NULL);
1972 g_object_set_data_full(G_OBJECT(act), "command",
1973 g_strdup_printf("cmdlevel %s",
1974 cmdlevel_name(level)),
1975 (GDestroyNotify) g_free);
1976 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
1977 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_connection_command), menu);
1978 fc_snprintf(actbuf, sizeof(actbuf), "win.cmdlevel_%d", level);
1979 menu_item_append_unref(menu, g_menu_item_new(buf, actbuf));
1980 g_free(buf);
1981 }
1982 }
1983
1984 if (ALLOW_CTRL <= client.conn.access_level
1985 && NULL != pplayer && is_ai(pplayer)) {
1986 enum ai_level level;
1987
1988 for (level = 0; level < AI_LEVEL_COUNT; level++) {
1989 if (is_settable_ai_level(level)) {
1990 char actbuf[128];
1991
1992 buf = g_strdup_printf(_("Difficulty: %s"), ai_level_translated_name(level));
1993 fc_snprintf(actbuf, sizeof(actbuf), "ailevel_%d", level);
1994
1995 act = g_simple_action_new(actbuf, NULL);
1996 g_object_set_data_full(G_OBJECT(act), "command",
1997 g_strdup(ai_level_cmd(level)),
1998 (GDestroyNotify) g_free);
1999 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2000 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_player_command), menu);
2001 fc_snprintf(actbuf, sizeof(actbuf), "win.ailevel_%d", level);
2002 menu_item_append_unref(menu, g_menu_item_new(buf, actbuf));
2003 g_free(buf);
2004 }
2005 }
2006 }
2007
2008 if (pplayer != NULL /* && game.info.is_new_game */) {
2009 const int count = pplayer->team
2010 ? player_list_size(team_members(pplayer->team)) : 0;
2011 bool need_empty_team = (count != 1);
2012
2013 /* Can't use team_iterate here since it skips empty teams. */
2014 team_slots_iterate(tslot) {
2015 char actbuf[128];
2016 int id;
2017
2018 if (!team_slot_is_used(tslot)) {
2019 if (!need_empty_team) {
2020 continue;
2021 }
2022 need_empty_team = FALSE;
2023 }
2024
2025 id = team_number(team_slot_get_team(tslot));
2026
2027 /* TRANS: e.g., "Put on Team 5" */
2028 buf = g_strdup_printf(_("Put on %s"),
2029 team_slot_name_translation(tslot));
2030 fc_snprintf(actbuf, sizeof(actbuf), "team_%d", id);
2031
2032 act = g_simple_action_new(actbuf, NULL);
2033 g_object_set_data(G_OBJECT(act), "slot", tslot);
2034 g_action_map_add_action(G_ACTION_MAP(group), G_ACTION(act));
2035 g_signal_connect(act, "activate", G_CALLBACK(conn_menu_team_chosen), menu);
2036 fc_snprintf(actbuf, sizeof(actbuf), "win.team_%d", id);
2037 menu_item_append_unref(menu, g_menu_item_new(buf, actbuf));
2038 g_free(buf);
2039 } team_slots_iterate_end;
2040 }
2041
2042 close_conn_menu_popover();
2043 conn_popover = gtk_popover_menu_new_from_model(G_MENU_MODEL(menu));
2044 g_object_ref(conn_popover);
2045 gtk_widget_insert_action_group(conn_popover, "win", group);
2046
2047 return conn_popover;
2048}
2049
2050/**********************************************************************/
2053 static gboolean delayed_unselect_path(gpointer data)
2054{
2055 if (NULL != connection_list_view) {
2056 GtkTreeSelection *selection =
2057 gtk_tree_view_get_selection(connection_list_view);
2058 GtkTreePath *path = data;
2059
2060 gtk_tree_selection_unselect_path(selection, path);
2061 gtk_tree_path_free(path);
2062 }
2063 return FALSE;
2064}
2065
2066/**********************************************************************/
2069 static gboolean connect_list_left_button(GtkGestureClick *gesture,
2070 int n_press,
2071 double x, double y, gpointer data)
2072{
2073 GtkEventController *controller = GTK_EVENT_CONTROLLER(gesture);
2074 GtkTreeView *tree = GTK_TREE_VIEW(gtk_event_controller_get_widget(controller));
2075 GtkTreePath *path = NULL;
2076 GtkTreeSelection *selection = gtk_tree_view_get_selection(tree);
2077
2078 if (!gtk_tree_view_get_path_at_pos(tree,
2079 x, y,
2080 &path, NULL, NULL, NULL)) {
2081 return FALSE;
2082 }
2083
2084 if (gtk_tree_selection_path_is_selected(selection, path)) {
2085 /* Need to delay to avoid problem with the expander. */
2086 g_idle_add(delayed_unselect_path, path);
2087 return FALSE; /* Return now, don't free the path. */
2088 }
2089
2090 gtk_tree_path_free(path);
2091
2092 return FALSE;
2093}
2094
2095/**********************************************************************/
2098 static gboolean connect_list_right_button(GtkGestureClick *gesture,
2099 int n_press,
2100 double x, double y, gpointer data)
2101{
2102 GtkEventController *controller = GTK_EVENT_CONTROLLER(gesture);
2103 GtkWidget *tree = gtk_event_controller_get_widget(controller);
2104 GtkWidget *parent = data;
2105 GtkTreePath *path = NULL;
2106 GtkWidget *menu;
2107 GtkTreeSelection *selection;
2108 GtkTreeModel *model;
2109 GtkTreeIter iter;
2110 int player_no, conn_id;
2111 struct player *pplayer;
2112 struct connection *pconn;
2113 int bx, by;
2114 GdkRectangle rect = { .x = x, .y = y, .width = 1, .height = 1};
2115
2116 gtk_tree_view_convert_widget_to_bin_window_coords(GTK_TREE_VIEW(tree), x, y, &bx, &by);
2117
2118 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tree), bx, by,
2119 &path, NULL, NULL, NULL)) {
2120 return FALSE;
2121 }
2122
2123 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
2124 model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree));
2125
2126 if (!gtk_tree_selection_path_is_selected(selection, path)) {
2127 gtk_tree_selection_select_path(selection, path);
2128 }
2129 gtk_tree_model_get_iter(model, &iter, path);
2130
2131 gtk_tree_model_get(model, &iter, CL_COL_PLAYER_NUMBER, &player_no, -1);
2132 pplayer = player_by_number(player_no);
2133
2134 gtk_tree_model_get(model, &iter, CL_COL_CONN_ID, &conn_id, -1);
2135 pconn = conn_by_number(conn_id);
2136
2137 menu = create_conn_menu(pplayer, pconn);
2138 gtk_widget_set_parent(menu, parent); /* Gtk bug prevents tree view parenting */
2139 gtk_popover_set_pointing_to(GTK_POPOVER(menu), &rect);
2140
2141 gtk_popover_popup(GTK_POPOVER(menu));
2142
2143 gtk_tree_path_free(path);
2144
2145 return TRUE;
2146}
2147
2148/**********************************************************************/
2151 static void connection_list_row_callback(GtkTreeView *tree_view,
2152 GtkTreeIter *iter,
2153 GtkTreePath *path,
2154 gpointer data)
2155{
2156 GtkTreeStore *store = GTK_TREE_STORE(gtk_tree_view_get_model(tree_view));
2157
2158 gtk_tree_store_set(store, iter,
2159 CL_COL_COLLAPSED, GPOINTER_TO_INT(data), -1);
2160}
2161
2162/**********************************************************************/
2166 static bool conn_list_selection(struct player **ppplayer,
2167 struct connection **ppconn)
2168{
2169 if (NULL != connection_list_view) {
2170 GtkTreeIter iter;
2171 GtkTreeModel *model;
2172 GtkTreeSelection *selection =
2173 gtk_tree_view_get_selection(connection_list_view);
2174
2175 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
2176 int id;
2177
2178 if (NULL != ppplayer) {
2179 gtk_tree_model_get(model, &iter, CL_COL_PLAYER_NUMBER, &id, -1);
2180 *ppplayer = player_by_number(id);
2181 }
2182 if (NULL != ppconn) {
2183 gtk_tree_model_get(model, &iter, CL_COL_CONN_ID, &id, -1);
2184 *ppconn = conn_by_number(id);
2185 }
2186 return TRUE;
2187 }
2188 }
2189
2190 if (NULL != ppplayer) {
2191 *ppplayer = NULL;
2192 }
2193 if (NULL != ppconn) {
2194 *ppconn = NULL;
2195 }
2196 return FALSE;
2197}
2198
2199/**********************************************************************/
2202 static void conn_list_select_conn(struct connection *pconn)
2203{
2204 GtkTreeModel *model;
2205 GtkTreeIter parent, child, *iter = NULL;
2206 GtkTreeSelection *selection;
2207 gboolean valid;
2208 const int search_id = pconn->id;
2209 int id;
2210
2211 if (NULL == connection_list_view) {
2212 return;
2213 }
2214
2215 model = gtk_tree_view_get_model(connection_list_view);
2216 selection = gtk_tree_view_get_selection(connection_list_view);
2217
2218 /* Main iteration. */
2219 valid = gtk_tree_model_get_iter_first(model, &parent);
2220 while (valid && NULL == iter) {
2221 gtk_tree_model_get(model, &parent, CL_COL_CONN_ID, &id, -1);
2222 if (search_id == id) {
2223 iter = &parent;
2224 break;
2225 }
2226
2227 /* Node children iteration. */
2228 valid = gtk_tree_model_iter_children(model, &child, &parent);
2229 while (valid && NULL == iter) {
2230 gtk_tree_model_get(model, &child, CL_COL_CONN_ID, &id, -1);
2231 if (search_id == id) {
2232 iter = &child;
2233 break;
2234 }
2235 valid = gtk_tree_model_iter_next(model, &child);
2236 }
2237
2238 valid = gtk_tree_model_iter_next(model, &parent);
2239 }
2240
2241 /* Select iterator. */
2242 if (NULL != iter) {
2243 gtk_tree_selection_select_iter(selection, iter);
2244 } else {
2245 log_error("%s(): connection %s not found.",
2246 __FUNCTION__, conn_description(pconn));
2247 }
2248}
2249
2250/**********************************************************************/
2253 static void ready_button_callback(GtkWidget *w, gpointer data)
2254{
2255 if (can_client_control()) {
2256 dsend_packet_player_ready(&client.conn,
2257 player_number(client_player()),
2258 !client_player()->is_ready);
2259 } else {
2260 dsend_packet_player_ready(&client.conn, 0, TRUE);
2261 }
2262}
2263
2264/**********************************************************************/
2267 static void nation_button_callback(GtkWidget *w, gpointer data)
2268{
2269 struct player *selected_plr;
2270 bool row_selected = conn_list_selection(&selected_plr, NULL);
2271
2272 if (row_selected && NULL != selected_plr) {
2273 /* "Take <player_name>" */
2274 client_take_player(selected_plr);
2275 } else if (can_client_control()) {
2276 /* "Pick Nation" */
2277 popup_races_dialog(client_player());
2278 } else {
2279 /* "Take a Player" */
2280 send_chat("/take -");
2281 }
2282}
2283
2284/**********************************************************************/
2287 static void observe_button_callback(GtkWidget *w, gpointer data)
2288{
2289 struct player *selected_plr;
2290 bool row_selected = conn_list_selection(&selected_plr, NULL);
2291
2292 if (row_selected && NULL != selected_plr) {
2293 /* "Observe <player_name>" */
2294 send_chat_printf("/observe \"%s\"", player_name(selected_plr));
2295 } else if (!client_is_global_observer()) {
2296 /* "Observe" */
2297 send_chat("/observe");
2298 } else {
2299 /* "Do not observe" */
2300 send_chat("/detach");
2301 }
2302}
2303
2304/**********************************************************************/
2307 static void update_start_page_buttons(void)
2308{
2309 char buf[2 * MAX_LEN_NAME];
2310 const char *text;
2311 struct player *selected_plr;
2312 bool row_selected = conn_list_selection(&selected_plr, NULL);
2313 bool sensitive;
2314
2315 /*** Ready button. ***/
2316 if (can_client_control()) {
2317 sensitive = client_player()->is_alive;
2318 if (client_player()->is_ready) {
2319 text = _("Not _ready");
2320 } else {
2321 int num_unready = 0;
2322
2323 players_iterate_alive(pplayer) {
2324 if (is_human(pplayer) && !pplayer->is_ready) {
2325 num_unready++;
2326 }
2327 } players_iterate_alive_end;
2328
2329 if (num_unready > 1) {
2330 text = _("_Ready");
2331 } else {
2332 /* We are the last unready player so clicking here will
2333 * immediately start the game. */
2334 text = _("_Start");
2335 }
2336 }
2337 } else {
2338 text = _("_Start");
2339 if (can_client_access_hack()) {
2340 sensitive = TRUE;
2341 players_iterate_alive(plr) {
2342 if (is_human(plr)) {
2343 /* There's human controlled player(s) in game, so it's their
2344 * job to start the game. */
2345 sensitive = FALSE;
2346 break;
2347 }
2348 } players_iterate_alive_end;
2349 } else {
2350 sensitive = FALSE;
2351 }
2352 }
2353 gtk_stockbutton_set_label(ready_button, text);
2354 gtk_widget_set_sensitive(ready_button, sensitive);
2355
2356 /*** Nation button. ***/
2357 if (row_selected && NULL != selected_plr) {
2358 fc_snprintf(buf, sizeof(buf), _("_Take %s"), player_name(selected_plr));
2359 text = buf;
2360 sensitive = (client_is_observer() || selected_plr != client_player());
2361 } else if (can_client_control()) {
2362 text = _("Pick _Nation");
2363 sensitive = game.info.is_new_game;
2364 } else {
2365 text = _("_Take a Player");
2366 sensitive = game.info.is_new_game;
2367 }
2368 gtk_stockbutton_set_label(nation_button, text);
2369 gtk_widget_set_sensitive(nation_button, sensitive);
2370
2371 /*** Observe button. ***/
2372 if (row_selected && NULL != selected_plr) {
2373 fc_snprintf(buf, sizeof(buf), _("_Observe %s"),
2374 player_name(selected_plr));
2375 text = buf;
2376 sensitive = (!client_is_observer() || selected_plr != client_player());
2377 } else if (!client_is_global_observer()) {
2378 text = _("_Observe");
2379 sensitive = TRUE;
2380 } else {
2381 text = _("Do not _observe");
2382 sensitive = TRUE;
2383 }
2384 gtk_stockbutton_set_label(observe_button, text);
2385 gtk_widget_set_sensitive(observe_button, sensitive);
2386}
2387
2388/**********************************************************************/
2392 static bool model_get_player_iter(GtkTreeModel *model,
2393 GtkTreeIter *iter,
2394 GtkTreeIter *start,
2395 const struct player *pplayer)
2396{
2397 const int search_id = player_number(pplayer);
2398 int id;
2399
2400 if (NULL != start) {
2401 *iter = *start;
2402 if (!gtk_tree_model_iter_next(model, iter)) {
2403 return FALSE;
2404 }
2405 } else if (!gtk_tree_model_get_iter_first(model, iter)) {
2406 return FALSE;
2407 }
2408
2409 do {
2410 gtk_tree_model_get(model, iter, CL_COL_PLAYER_NUMBER, &id, -1);
2411 if (id == search_id) {
2412 return TRUE;
2413 }
2414 } while (gtk_tree_model_iter_next(model, iter));
2415
2416 return FALSE;
2417}
2418
2419/**********************************************************************/
2423 static bool model_get_conn_iter(GtkTreeModel *model, GtkTreeIter *iter,
2424 GtkTreeIter *parent, GtkTreeIter *start,
2425 const struct connection *pconn)
2426{
2427 const int search_id = pconn->id;
2428 int id;
2429
2430 if (NULL != start) {
2431 *iter = *start;
2432 if (!gtk_tree_model_iter_next(model, iter)) {
2433 return FALSE;
2434 }
2435 } else if (!gtk_tree_model_iter_children(model, iter, parent)) {
2436 return FALSE;
2437 }
2438
2439 do {
2440 gtk_tree_model_get(model, iter, CL_COL_CONN_ID, &id, -1);
2441 if (id == search_id) {
2442 return TRUE;
2443 }
2444 } while (gtk_tree_model_iter_next(model, iter));
2445
2446 return FALSE;
2447}
2448
2449/**********************************************************************/
2452 void real_conn_list_dialog_update(void *unused)
2453{
2454 if (client_state() == C_S_PREPARING
2455 && get_client_page() == PAGE_START
2456 && connection_list_store != NULL) {
2457 GtkTreeStore *store = connection_list_store;
2458 GtkTreeModel *model = GTK_TREE_MODEL(store);
2459 GtkTreePath *path;
2460 GtkTreeIter child, prev_child, *pprev_child;
2461 GtkTreeIter parent, prev_parent, *pprev_parent = NULL;
2462 GdkPixbuf *flag, *color;
2463 gboolean collapsed;
2464 struct player *pselected_player;
2465 struct connection *pselected_conn;
2466 bool is_ready;
2467 const char *nation, *plr_name, *team;
2468 char name[MAX_LEN_NAME + 8];
2469 enum cmdlevel access_level;
2470 int conn_id;
2471
2472 /* Refresh the AI skill level control */
2473 if (ai_lvl_combobox) {
2474 enum ai_level new_level = server_ai_level(), level;
2475 int i = 0;
2476
2477 for (level = 0; level < AI_LEVEL_COUNT; level++) {
2478 if (is_settable_ai_level(level)) {
2479 if (level == new_level) {
2480 gtk_combo_box_set_active(GTK_COMBO_BOX(ai_lvl_combobox), i);
2481 break;
2482 }
2483 i++;
2484 }
2485 }
2486 if (level == AI_LEVEL_COUNT) {
2487 /* Probably ai_level_invalid() */
2488 gtk_combo_box_set_active(GTK_COMBO_BOX(ai_lvl_combobox), -1);
2489 }
2490 }
2491
2492 /* Save the selected connection. */
2493 (void) conn_list_selection(&pselected_player, &pselected_conn);
2494
2495 /* Insert players into the connection list. */
2496 players_iterate(pplayer) {
2497 if (!player_has_flag(pplayer, PLRF_SCENARIO_RESERVED)) {
2498 conn_id = -1;
2499 access_level = ALLOW_NONE;
2500 flag = pplayer->nation ? get_flag(pplayer->nation) : NULL;
2501 color = create_player_icon(pplayer);
2502
2503 conn_list_iterate(pplayer->connections, pconn) {
2504 if (pconn->playing == pplayer && !pconn->observer) {
2505 conn_id = pconn->id;
2506 access_level = pconn->access_level;
2507 break;
2508 }
2509 } conn_list_iterate_end;
2510
2511 if (is_ai(pplayer) && !pplayer->was_created
2512 && !pplayer->is_connected) {
2513 /* TRANS: "<Novice AI>" */
2514 fc_snprintf(name, sizeof(name), _("<%s AI>"),
2515 ai_level_translated_name(pplayer->ai_common.skill_level));
2516 } else {
2517 sz_strlcpy(name, pplayer->username);
2518 if (access_level > ALLOW_BASIC) {
2519 sz_strlcat(name, "*");
2520 }
2521 }
2522
2523 is_ready = !is_human(pplayer) ? TRUE : pplayer->is_ready;
2524
2525 if (pplayer->nation == NO_NATION_SELECTED) {
2526 nation = _("Random");
2527 if (pplayer->was_created) {
2528 plr_name = player_name(pplayer);
2529 } else {
2530 plr_name = "";
2531 }
2532 } else {
2533 nation = nation_adjective_for_player(pplayer);
2534 plr_name = player_name(pplayer);
2535 }
2536
2537 team = pplayer->team ? team_name_translation(pplayer->team) : "";
2538
2539 if (model_get_player_iter(model, &parent, pprev_parent, pplayer)) {
2540 gtk_tree_store_move_after(store, &parent, pprev_parent);
2541 } else {
2542 gtk_tree_store_insert_after(store, &parent, NULL, pprev_parent);
2543 }
2544
2545 gtk_tree_store_set(store, &parent,
2546 CL_COL_PLAYER_NUMBER, player_number(pplayer),
2547 CL_COL_USER_NAME, name,
2548 CL_COL_READY_STATE, is_ready,
2549 CL_COL_PLAYER_NAME, plr_name,
2550 CL_COL_FLAG, flag,
2551 CL_COL_COLOR, color,
2552 CL_COL_NATION, nation,
2553 CL_COL_TEAM, team,
2554 CL_COL_CONN_ID, conn_id,
2555 CL_COL_STYLE, PANGO_STYLE_NORMAL,
2556 CL_COL_WEIGHT, PANGO_WEIGHT_BOLD,
2557 -1);
2558
2559 /* Insert observers of this player as child nodes. */
2560 pprev_child = NULL;
2561 conn_list_iterate(pplayer->connections, pconn) {
2562 if (pconn->id == conn_id) {
2563 continue;
2564 }
2565 if (model_get_conn_iter(model, &child, &parent,
2566 pprev_child, pconn)) {
2567 gtk_tree_store_move_after(store, &child, pprev_child);
2568 } else {
2569 gtk_tree_store_insert_after(store, &child, &parent, pprev_child);
2570 }
2571
2572 gtk_tree_store_set(store, &child,
2573 CL_COL_PLAYER_NUMBER, -1,
2574 CL_COL_USER_NAME, pconn->username,
2575 CL_COL_TEAM, _("Observer"),
2576 CL_COL_CONN_ID, pconn->id,
2577 CL_COL_STYLE, PANGO_STYLE_NORMAL,
2578 CL_COL_WEIGHT, PANGO_WEIGHT_NORMAL,
2579 -1);
2580
2581 prev_child = child;
2582 pprev_child = &prev_child;
2583 } conn_list_iterate_end;
2584
2585 /* Expand node? */
2586 if (NULL != pprev_child) {
2587 gtk_tree_model_get(model, &parent, CL_COL_COLLAPSED, &collapsed, -1);
2588 if (!collapsed) {
2589 path = gtk_tree_model_get_path(model, &parent);
2590 gtk_tree_view_expand_row(GTK_TREE_VIEW(connection_list_view),
2591 path, FALSE);
2592 gtk_tree_path_free(path);
2593 }
2594 }
2595
2596 /* Remove trailing rows. */
2597 if (NULL != pprev_child) {
2598 child = prev_child;
2599 if (gtk_tree_model_iter_next(model, &child)) {
2600 while (gtk_tree_store_remove(store, &child)) {
2601 /* Do nothing more. */
2602 }
2603 }
2604 } else if (gtk_tree_model_iter_children(model, &child, &parent)) {
2605 while (gtk_tree_store_remove(store, &child)) {
2606 /* Do nothing more. */
2607 }
2608 }
2609
2610 prev_parent = parent;
2611 pprev_parent = &prev_parent;
2612 if (flag) {
2613 g_object_unref(flag);
2614 }
2615 if (color) {
2616 g_object_unref(color);
2617 }
2618 }
2619 } players_iterate_end;
2620
2621 /* Finally, insert global observers... */
2622 conn_list_iterate(game.est_connections, pconn) {
2623 if (NULL != pconn->playing || !pconn->observer) {
2624 continue;
2625 }
2626
2627 if (model_get_conn_iter(model, &parent, NULL, pprev_parent, pconn)) {
2628 gtk_tree_store_move_after(store, &parent, pprev_parent);
2629 } else {
2630 gtk_tree_store_insert_after(store, &parent, NULL, pprev_parent);
2631 }
2632
2633 gtk_tree_store_set(store, &parent,
2634 CL_COL_PLAYER_NUMBER, -1,
2635 CL_COL_USER_NAME, pconn->username,
2636 CL_COL_TEAM, _("Observer"),
2637 CL_COL_CONN_ID, pconn->id,
2638 CL_COL_STYLE, PANGO_STYLE_NORMAL,
2639 CL_COL_WEIGHT, PANGO_WEIGHT_NORMAL,
2640 -1);
2641
2642 prev_parent = parent;
2643 pprev_parent = &prev_parent;
2644 } conn_list_iterate_end;
2645
2646 /* ...and detached connections. */
2647 conn_list_iterate(game.est_connections, pconn) {
2648 if (NULL != pconn->playing || pconn->observer) {
2649 continue;
2650 }
2651
2652 if (model_get_conn_iter(model, &parent, NULL, pprev_parent, pconn)) {
2653 gtk_tree_store_move_after(store, &parent, pprev_parent);
2654 } else {
2655 gtk_tree_store_insert_after(store, &parent, NULL, pprev_parent);
2656 }
2657
2658 gtk_tree_store_set(store, &parent,
2659 CL_COL_PLAYER_NUMBER, -1,
2660 CL_COL_USER_NAME, pconn->username,
2661 CL_COL_TEAM, _("Detached"),
2662 CL_COL_CONN_ID, pconn->id,
2663 CL_COL_STYLE, PANGO_STYLE_ITALIC,
2664 CL_COL_WEIGHT, PANGO_WEIGHT_NORMAL,
2665 -1);
2666
2667 prev_parent = parent;
2668 pprev_parent = &prev_parent;
2669 } conn_list_iterate_end;
2670
2671 /* Remove trailing rows. */
2672 if (NULL != pprev_parent) {
2673 parent = prev_parent;
2674 if (gtk_tree_model_iter_next(model, &parent)) {
2675 while (gtk_tree_store_remove(store, &parent)) {
2676 /* Do nothing more. */
2677 }
2678 }
2679 } else {
2680 gtk_tree_store_clear(store);
2681 }
2682
2683 /* If we were selecting a single connection, let's try to reselect it. */
2684 if (NULL == pselected_player && NULL != pselected_conn) {
2685 conn_list_select_conn(pselected_conn);
2686 }
2687 }
2688
2689 update_start_page_buttons();
2690}
2691
2692/**********************************************************************/
2697 static void add_tree_col(GtkWidget *treeview, GType gtype,
2698 const char *title, int colnum, const char *key)
2699{
2700 GtkCellRenderer *rend;
2701 GtkTreeViewColumn *col;
2702
2703 if (gtype == G_TYPE_BOOLEAN) {
2704 rend = gtk_cell_renderer_toggle_new();
2705 col = gtk_tree_view_column_new_with_attributes(title, rend,
2706 "active", colnum, NULL);
2707 } else if (gtype == GDK_TYPE_PIXBUF) {
2708 rend = gtk_cell_renderer_pixbuf_new();
2709 col = gtk_tree_view_column_new_with_attributes(title, rend,
2710 "pixbuf", colnum, NULL);
2711 } else {
2712 rend = gtk_cell_renderer_text_new();
2713 col = gtk_tree_view_column_new_with_attributes(title, rend,
2714 "text", colnum,
2715 "style", CL_COL_STYLE,
2716 "weight", CL_COL_WEIGHT,
2717 NULL);
2718 }
2719
2720 gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
2721 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col);
2722
2723 if (key != NULL) {
2724 g_object_set_data(G_OBJECT(treeview), key, col);
2725 }
2726}
2727
2728/**********************************************************************/
2731 GtkWidget *create_start_page(void)
2732{
2733 GtkWidget *box, *sbox, *table, *vgrid;
2734 GtkWidget *view, *sw, *text, *toolkit_view, *button, *spin;
2735 GtkWidget *label;
2736 GtkTreeSelection *selection;
2737 enum ai_level level;
2738 /* There's less than AI_LEVEL_COUNT entries as not all levels have
2739 entries (that's the whole point of this array: index != value),
2740 but this is set safely to the max */
2741 static enum ai_level levels[AI_LEVEL_COUNT];
2742 int i = 0;
2743 int box_row = 0;
2744 int sbox_col = 0;
2745 int grid_row = 0;
2746 GtkGesture *gesture;
2747 GtkEventController *controller;
2748
2749 box = gtk_grid_new();
2750 gtk_orientable_set_orientation(GTK_ORIENTABLE(box),
2751 GTK_ORIENTATION_VERTICAL);
2752 gtk_grid_set_row_spacing(GTK_GRID(box), 8);
2753 gtk_widget_set_margin_start(box, 4);
2754 gtk_widget_set_margin_end(box, 4);
2755 gtk_widget_set_margin_top(box, 4);
2756 gtk_widget_set_margin_bottom(box, 4);
2757
2758 sbox = gtk_grid_new();
2759 gtk_grid_set_column_spacing(GTK_GRID(sbox), 12);
2760 gtk_grid_attach(GTK_GRID(box), sbox, 0, box_row++, 1, 1);
2761
2762 vgrid = gtk_grid_new();
2763 gtk_widget_set_margin_bottom(vgrid, 12);
2764 gtk_widget_set_margin_end(vgrid, 12);
2765 gtk_widget_set_margin_start(vgrid, 12);
2766 gtk_widget_set_margin_top(vgrid, 12);
2767 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
2768 GTK_ORIENTATION_VERTICAL);
2769 gtk_grid_set_row_spacing(GTK_GRID(vgrid), 2);
2770 gtk_widget_set_halign(vgrid, GTK_ALIGN_CENTER);
2771 gtk_widget_set_valign(vgrid, GTK_ALIGN_CENTER);
2772 gtk_grid_attach(GTK_GRID(sbox), vgrid, sbox_col++, 0, 1, 1);
2773
2774 table = gtk_grid_new();
2775 start_options_table = table;
2776 gtk_grid_set_row_spacing(GTK_GRID(table), 2);
2777 gtk_grid_set_column_spacing(GTK_GRID(table), 12);
2778 gtk_grid_attach(GTK_GRID(vgrid), table, 0, grid_row++, 1, 1);
2779
2780 spin = gtk_spin_button_new_with_range(1, MAX_NUM_PLAYERS, 1);
2781 start_aifill_spin = spin;
2782 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), 0);
2783 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin),
2784 GTK_UPDATE_IF_VALID);
2785 if (server_optset != NULL) {
2786 struct option *paifill = optset_option_by_name(server_optset, "aifill");
2787
2788 if (paifill) {
2789 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin),
2790 option_int_get(paifill));
2791 } /* else it'll be updated later */
2792 }
2793 g_signal_connect_after(spin, "value_changed",
2794 G_CALLBACK(ai_fill_changed_by_user), NULL);
2795
2796 gtk_grid_attach(GTK_GRID(table), spin, 1, 0, 1, 1);
2797
2798 label = g_object_new(GTK_TYPE_LABEL,
2799 "use-underline", TRUE,
2800 "mnemonic-widget", spin,
2801 /* TRANS: Keep individual lines short */
2802 "label", _("Number of _Players\n(including AI):"),
2803 "xalign", 0.0,
2804 "yalign", 0.5,
2805 NULL);
2806 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
2807
2808 ai_lvl_combobox = gtk_combo_box_text_new();
2809
2810 for (level = 0; level < AI_LEVEL_COUNT; level++) {
2811 if (is_settable_ai_level(level)) {
2812 const char *level_name = ai_level_translated_name(level);
2813
2814 gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(ai_lvl_combobox), i, level_name);
2815 levels[i] = level;
2816 i++;
2817 }
2818 }
2819 gtk_combo_box_set_active(GTK_COMBO_BOX(ai_lvl_combobox), -1);
2820 g_signal_connect(ai_lvl_combobox, "changed",
2821 G_CALLBACK(ai_skill_callback), levels);
2822
2823 gtk_grid_attach(GTK_GRID(table), ai_lvl_combobox, 1, 1, 1, 1);
2824
2825 label = g_object_new(GTK_TYPE_LABEL,
2826 "use-underline", TRUE,
2827 "mnemonic-widget", ai_lvl_combobox,
2828 "label", _("AI Skill _Level:"),
2829 "xalign", 0.0,
2830 "yalign", 0.5,
2831 NULL);
2832 gtk_grid_attach(GTK_GRID(table), label, 0, 1, 1, 1);
2833
2834 ruleset_combo = gtk_combo_box_text_new();
2835 g_signal_connect(G_OBJECT(ruleset_combo), "changed",
2836 G_CALLBACK(ruleset_entry_changed), NULL);
2837
2838 gtk_grid_attach(GTK_GRID(table), ruleset_combo, 1, 2, 1, 1);
2839
2840 label = g_object_new(GTK_TYPE_LABEL,
2841 "use-underline", TRUE,
2842 "mnemonic-widget", GTK_COMBO_BOX_TEXT(ruleset_combo),
2843 "label", _("Ruleset:"),
2844 "xalign", 0.0,
2845 "yalign", 0.5,
2846 NULL);
2847 gtk_grid_attach(GTK_GRID(table), label, 0, 2, 1, 1);
2848
2849 button = icon_label_button_new("preferences-system",
2850 _("_More Game Options..."));
2851 gtk_widget_set_margin_bottom(button, 8);
2852 gtk_widget_set_margin_end(button, 8);
2853 gtk_widget_set_margin_start(button, 8);
2854 gtk_widget_set_margin_top(button, 8);
2855 gtk_widget_set_halign(button, GTK_ALIGN_CENTER);
2856 gtk_widget_set_valign(button, GTK_ALIGN_CENTER);
2857 g_signal_connect(button, "clicked",
2858 G_CALLBACK(game_options_callback), NULL);
2859 gtk_grid_attach(GTK_GRID(vgrid), button, 0, grid_row++, 1, 1);
2860
2861 connection_list_store = connection_list_store_new();
2862 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(connection_list_store));
2863 gtk_widget_set_hexpand(view, TRUE);
2864 g_object_unref(G_OBJECT(connection_list_store));
2865 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
2866 connection_list_view = GTK_TREE_VIEW(view);
2867
2868 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
2869 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
2870 g_signal_connect(selection, "changed",
2871 G_CALLBACK(update_start_page_buttons), NULL);
2872
2873 add_tree_col(view, G_TYPE_STRING, _("Name"),
2874 CL_COL_USER_NAME, NULL);
2875 add_tree_col(view, G_TYPE_BOOLEAN, _("Ready"),
2876 CL_COL_READY_STATE, NULL);
2877 add_tree_col(view, G_TYPE_STRING, Q_("?player:Leader"),
2878 CL_COL_PLAYER_NAME, NULL);
2879 add_tree_col(view, GDK_TYPE_PIXBUF, _("Flag"),
2880 CL_COL_FLAG, NULL);
2881 add_tree_col(view, GDK_TYPE_PIXBUF, _("Border"),
2882 CL_COL_COLOR, NULL);
2883 add_tree_col(view, G_TYPE_STRING, _("Nation"),
2884 CL_COL_NATION, NULL);
2885 add_tree_col(view, G_TYPE_STRING, _("Team"),
2886 CL_COL_TEAM, NULL);
2887
2888 controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new());
2889 g_signal_connect(controller, "pressed",
2890 G_CALLBACK(connect_list_left_button), NULL);
2891 gtk_widget_add_controller(view, controller);
2892
2893 g_signal_connect(view, "row-collapsed",
2894 G_CALLBACK(connection_list_row_callback),
2895 GINT_TO_POINTER(TRUE));
2896 g_signal_connect(view, "row-expanded",
2897 G_CALLBACK(connection_list_row_callback),
2898 GINT_TO_POINTER(FALSE));
2899
2900 sw = gtk_scrolled_window_new();
2901 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
2902 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
2903 GTK_POLICY_AUTOMATIC,
2904 GTK_POLICY_ALWAYS);
2905 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(sw), 200);
2906 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), view);
2907
2908 /* This is for a workaround against gtk bug that we can't parent
2909 * popup to the tree view - we have to parent it all the way to sw */
2910 gesture = gtk_gesture_click_new();
2911 gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 3);
2912 controller = GTK_EVENT_CONTROLLER(gesture);
2913 g_signal_connect(controller, "pressed",
2914 G_CALLBACK(connect_list_right_button), sw);
2915 gtk_widget_add_controller(view, controller);
2916
2917 gtk_grid_attach(GTK_GRID(sbox), sw, sbox_col++, 0, 1, 1);
2918
2919 sw = gtk_scrolled_window_new();
2920 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
2921 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
2922 GTK_POLICY_AUTOMATIC,
2923 GTK_POLICY_ALWAYS);
2924 gtk_grid_attach(GTK_GRID(box), sw, 0, box_row++, 1, 1);
2925
2926 text = gtk_text_view_new_with_buffer(message_buffer);
2927 gtk_widget_set_hexpand(text, TRUE);
2928 gtk_widget_set_vexpand(text, TRUE);
2929 start_message_area = text;
2930 gtk_widget_set_name(text, "chatline");
2931 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
2932 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 5);
2933 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
2934 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), text);
2935
2936
2937 /* Vote widgets. */
2938 if (pregame_votebar == NULL) {
2939 pregame_votebar = voteinfo_bar_new(TRUE);
2940 }
2941 gtk_grid_attach(GTK_GRID(box), pregame_votebar, 0, box_row++, 1, 1);
2942
2943 toolkit_view = inputline_toolkit_view_new();
2944 gtk_grid_attach(GTK_GRID(box), toolkit_view, 0, box_row++, 1, 1);
2945
2946 button = gtk_button_new_with_mnemonic(_("_Cancel"));
2947 inputline_toolkit_view_append_button(toolkit_view, button);
2948 g_signal_connect(button, "clicked", G_CALLBACK(main_callback), NULL);
2949
2950 nation_button = icon_label_button_new("document-properties",
2951 _("Pick _Nation"));
2952 inputline_toolkit_view_append_button(toolkit_view, nation_button);
2953 g_signal_connect(nation_button, "clicked",
2954 G_CALLBACK(nation_button_callback), NULL);
2955
2956 observe_button = icon_label_button_new("zoom-in", _("_Observe"));
2957 inputline_toolkit_view_append_button(toolkit_view, observe_button);
2958 g_signal_connect(observe_button, "clicked",
2959 G_CALLBACK(observe_button_callback), NULL);
2960
2961 ready_button = icon_label_button_new("system-run", _("_Ready"));
2962 inputline_toolkit_view_append_button(toolkit_view, ready_button);
2963 g_signal_connect(ready_button, "clicked",
2964 G_CALLBACK(ready_button_callback), NULL);
2965
2966 return box;
2967}
2968
2969
2970/**********************************************************************/
2973 void handle_game_load(bool load_successful, const char *filename)
2974{
2975 if (load_successful) {
2976 set_client_page(PAGE_START);
2977
2978 if (game.info.is_new_game) {
2979 /* It's pregame. Create a player and connect to it */
2980 send_chat("/take -");
2981 }
2982 }
2983}
2984
2985/**********************************************************************/
2988 static void load_filename(const char *filename)
2989{
2990 send_chat_printf("/load %s", filename);
2991}
2992
2993/**********************************************************************/
2996 static void load_callback(void)
2997{
2998 GtkTreeIter it;
2999 const gchar *filename;
3000
3001 if (!gtk_tree_selection_get_selected(load_selection, NULL, &it)) {
3002 return;
3003 }
3004
3005 gtk_tree_model_get(GTK_TREE_MODEL(load_store), &it,
3006 SD_COL_FULL_PATH, &filename, -1);
3007 load_filename(filename);
3008}
3009
3010/**********************************************************************/
3013 static void load_browse_callback(GtkWidget *w, gpointer data)
3014{
3015 save_dialog_file_chooser_popup(_("Choose Saved Game to Load"),
3016 GTK_FILE_CHOOSER_ACTION_OPEN,
3017 load_filename);
3018}
3019
3020/**********************************************************************/
3023 static void update_load_page(void)
3024{
3025 /* Search for user saved games. */
3026 struct fileinfo_list *files = fileinfolist_infix(get_save_dirs(),
3027 ".sav", FALSE);
3028
3029 save_dialog_store_update(load_store, files);
3030 fileinfo_list_destroy(files);
3031}
3032
3033/**********************************************************************/
3036 GtkWidget *create_load_page(void)
3037{
3038 GtkWidget *box, *sbox, *bbox;
3039
3040 GtkWidget *button, *label, *view, *sw;
3041 GtkCellRenderer *rend;
3042 int box_row = 0;
3043 int sbox_row = 0;
3044
3045 box = gtk_grid_new();
3046 gtk_orientable_set_orientation(GTK_ORIENTABLE(box),
3047 GTK_ORIENTATION_VERTICAL);
3048 gtk_grid_set_row_spacing(GTK_GRID(box), 18);
3049 gtk_widget_set_margin_start(box, 4);
3050 gtk_widget_set_margin_end(box, 4);
3051 gtk_widget_set_margin_top(box, 4);
3052 gtk_widget_set_margin_bottom(box, 4);
3053
3054 load_store = save_dialog_store_new();
3055 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(load_store));
3056 gtk_widget_set_vexpand(view, TRUE);
3057 g_object_unref(load_store);
3058
3059 rend = gtk_cell_renderer_text_new();
3060 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
3061 -1, NULL, rend, "text", 0, NULL);
3062
3063 load_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
3064 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
3065
3066 gtk_tree_selection_set_mode(load_selection, GTK_SELECTION_SINGLE);
3067
3068 g_signal_connect(view, "row-activated",
3069 G_CALLBACK(load_callback), NULL);
3070
3071 sbox = gtk_grid_new();
3072 gtk_widget_set_halign(sbox, GTK_ALIGN_CENTER);
3073 gtk_orientable_set_orientation(GTK_ORIENTABLE(sbox),
3074 GTK_ORIENTATION_VERTICAL);
3075 gtk_grid_set_row_spacing(GTK_GRID(sbox), 2);
3076 gtk_grid_attach(GTK_GRID(box), sbox, 0, box_row++, 1, 1);
3077
3078 label = g_object_new(GTK_TYPE_LABEL,
3079 "use-underline", TRUE,
3080 "mnemonic-widget", view,
3081 "label", _("Choose Saved Game to _Load:"),
3082 "xalign", 0.0,
3083 "yalign", 0.5,
3084 NULL);
3085 gtk_grid_attach(GTK_GRID(sbox), label, 0, sbox_row++, 1, 1);
3086
3087 sw = gtk_scrolled_window_new();
3088 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(sw), 300);
3089 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
3090 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC,
3091 GTK_POLICY_AUTOMATIC);
3092 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), view);
3093 gtk_grid_attach(GTK_GRID(sbox), sw, 0, sbox_row++, 1, 1);
3094
3095 bbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
3096 gtk_widget_set_hexpand(bbox, TRUE);
3097 gtk_box_set_spacing(GTK_BOX(bbox), 12);
3098 gtk_grid_attach(GTK_GRID(box), bbox, 0, box_row++, 1, 1);
3099
3100 button = gtk_button_new_with_mnemonic(_("_Browse..."));
3101 gtk_box_append(GTK_BOX(bbox), button);
3102 g_signal_connect(button, "clicked",
3103 G_CALLBACK(load_browse_callback), NULL);
3104
3105 button = gtk_button_new_with_mnemonic(_("_Cancel"));
3106 gtk_box_append(GTK_BOX(bbox), button);
3107 g_signal_connect(button, "clicked",
3108 G_CALLBACK(main_callback), NULL);
3109
3110 button = gtk_button_new_with_mnemonic(_("_OK"));
3111 gtk_box_append(GTK_BOX(bbox), button);
3112 g_signal_connect(button, "clicked",
3113 G_CALLBACK(load_callback), NULL);
3114
3115 return box;
3116}
3117
3118/**********************************************************************/
3121 static void scenario_list_callback(void)
3122{
3123 GtkTreeIter it;
3124 GtkTextBuffer *buffer;
3125 char *description;
3126 char *authors;
3127 char *filename;
3128 int ver;
3129 char vername[50];
3130
3131 if (gtk_tree_selection_get_selected(scenario_selection, NULL, &it)) {
3132 gtk_tree_model_get(GTK_TREE_MODEL(scenario_store), &it,
3133 2, &description, -1);
3134 gtk_tree_model_get(GTK_TREE_MODEL(scenario_store), &it,
3135 3, &authors, -1);
3136 gtk_tree_model_get(GTK_TREE_MODEL(scenario_store), &it,
3137 1, &filename, -1);
3138 gtk_tree_model_get(GTK_TREE_MODEL(scenario_store), &it,
3139 4, &ver, -1);
3140 filename = skip_to_basename(filename);
3141 if (ver > 0) {
3142 int maj;
3143 int min;
3144
3145 maj = ver / 1000000;
3146 ver %= 1000000;
3147 min = ver / 10000;
3148 ver %= 10000;
3149 if (ver >= 9000) {
3150 /* Development version, have '+' */
3151 fc_snprintf(vername, sizeof(vername), "%d.%d+", maj, min);
3152 } else {
3153 fc_snprintf(vername, sizeof(vername), "%d.%d", maj, min);
3154 }
3155 } else {
3156 /* TRANS: Old scenario format version */
3157 fc_snprintf(vername, sizeof(vername), _("pre-2.6"));
3158 }
3159 } else {
3160 description = "";
3161 authors = "";
3162 filename = "";
3163 vername[0] = '\0';
3164 }
3165
3166 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(scenario_description));
3167 gtk_text_buffer_set_text(buffer, description, -1);
3168 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(scenario_authors));
3169 gtk_text_buffer_set_text(buffer, authors, -1);
3170 gtk_label_set_text(GTK_LABEL(scenario_filename), filename);
3171 gtk_label_set_text(GTK_LABEL(scenario_version), vername);
3172}
3173
3174/**********************************************************************/
3177 static void scenario_callback(void)
3178{
3179 GtkTreeIter it;
3180 char *filename;
3181
3182 if (!gtk_tree_selection_get_selected(scenario_selection, NULL, &it)) {
3183 return;
3184 }
3185
3186 gtk_tree_model_get(GTK_TREE_MODEL(scenario_store), &it, 1, &filename, -1);
3187 load_filename(filename);
3188}
3189
3190/**********************************************************************/
3193 static void scenario_browse_callback(GtkWidget *w, gpointer data)
3194{
3195 save_dialog_file_chooser_popup(_("Choose a Scenario"),
3196 GTK_FILE_CHOOSER_ACTION_OPEN,
3197 load_filename);
3198}
3199
3200/**********************************************************************/
3203 static void update_scenario_page(void)
3204{
3205 struct fileinfo_list *files;
3206
3207 gtk_list_store_clear(scenario_store);
3208
3209 /* search for scenario files. */
3210 files = fileinfolist_infix(get_scenario_dirs(), ".sav", TRUE);
3211 fileinfo_list_iterate(files, pfile) {
3212 struct section_file *sf;
3213
3214 if ((sf = secfile_load_section(pfile->fullname, "scenario", TRUE))
3215 && secfile_lookup_bool_default(sf, TRUE, "scenario.is_scenario")) {
3216 const char *sname, *sdescription, *sauthors;
3217 int fcver;
3218 int fcdev;
3219 int current_ver = MAJOR_VERSION * 1000000 + MINOR_VERSION * 10000;
3220 int current_dev;
3221
3222 current_dev = current_ver;
3223 if (PATCH_VERSION >= 90) {
3224 /* Patch level matters on development versions */
3225 current_dev += PATCH_VERSION * 100;
3226 }
3227
3228 fcver = secfile_lookup_int_default(sf, 0, "scenario.game_version");
3229 if (fcver < 30000) {
3230 /* Pre-3.0 versions stored version number without emergency version
3231 * part in the end. To get comparable version number stored,
3232 * multiply by 100. */
3233 fcver *= 100;
3234 }
3235 if (fcver % 10000 >= 9000) {
3236 fcdev = fcver - (fcver % 100); /* Emergency version does not count. */
3237 } else {
3238 fcdev = fcver - (fcver % 10000); /* Patch version does not count. */
3239 }
3240 sname = secfile_lookup_str_default(sf, NULL, "scenario.name");
3241 sdescription = secfile_lookup_str_default(sf, NULL,
3242 "scenario.description");
3243 sauthors = secfile_lookup_str_default(sf, NULL, "scenario.authors");
3244 log_debug("scenario file: %s from %s", sname, pfile->fullname);
3245
3246 /* Ignore scenarios for newer freeciv versions than we are. */
3247 if (fcdev <= current_dev) {
3248 bool add_new = TRUE;
3249
3250 if (sname != NULL) {
3251 GtkTreeIter it;
3252 bool valid;
3253
3254 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(scenario_store), &it);
3255 while (valid) {
3256 char *oname;
3257
3258 gtk_tree_model_get(GTK_TREE_MODEL(scenario_store), &it,
3259 0, &oname, -1);
3260
3261 if (!strcmp(sname, oname)) {
3262 /* Already listed scenario has the same name as the one we just found */
3263 int existing;
3264
3265 gtk_tree_model_get(GTK_TREE_MODEL(scenario_store), &it,
3266 4, &existing, -1);
3267 log_debug("Duplicate %s (%d vs %d)", sname, existing, fcver);
3268
3269 if (existing > fcver) {
3270 /* Already listed one has higher version number */
3271 add_new = FALSE;
3272 } else if (existing < fcver) {
3273 /* New one has higher version number */
3274 add_new = FALSE;
3275
3276 gtk_list_store_set(scenario_store, &it,
3277 0, sname && strlen(sname) ? Q_(sname) : pfile->name,
3278 1, pfile->fullname,
3279 2, (NULL != sdescription && '\0' != sdescription[0]
3280 ? Q_(sdescription) : ""),
3281 3, (NULL != sauthors && sauthors[0] != '\0'
3282 ? Q_(sauthors) : ""),
3283 4, fcver,
3284 -1);
3285 } else {
3286 /* Same version number -> list both */
3287 }
3288 }
3289 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(scenario_store), &it);
3290 }
3291 }
3292
3293 if (add_new) {
3294 GtkTreeIter it;
3295
3296 gtk_list_store_append(scenario_store, &it);
3297 gtk_list_store_set(scenario_store, &it,
3298 0, sname && strlen(sname) ? Q_(sname) : pfile->name,
3299 1, pfile->fullname,
3300 2, (NULL != sdescription && '\0' != sdescription[0]
3301 ? Q_(sdescription) : ""),
3302 3, (NULL != sauthors && sauthors[0] != '\0'
3303 ? Q_(sauthors) : ""),
3304 4, fcver,
3305 -1);
3306 }
3307 }
3308
3309 secfile_destroy(sf);
3310 }
3311 } fileinfo_list_iterate_end;
3312
3313 fileinfo_list_destroy(files);
3314}
3315
3316/**********************************************************************/
3319 GtkWidget *create_scenario_page(void)
3320{
3321 GtkWidget *vgrid, *hbox, *sbox, *bbox, *filenamebox, *descbox;
3322 GtkWidget *versionbox, *vertext;
3323 GtkWidget *button, *label, *view, *sw, *swa, *text;
3324 GtkCellRenderer *rend;
3325 int grid_row = 0;
3326 int filenamecol = 0;
3327 int vercol = 0;
3328 int descrow = 0;
3329
3330 vgrid = gtk_grid_new();
3331 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
3332 GTK_ORIENTATION_VERTICAL);
3333 gtk_grid_set_row_spacing(GTK_GRID(vgrid), 18);
3334 gtk_widget_set_margin_start(vgrid, 4);
3335 gtk_widget_set_margin_end(vgrid, 4);
3336 gtk_widget_set_margin_top(vgrid, 4);
3337 gtk_widget_set_margin_bottom(vgrid, 4);
3338
3339 scenario_store = gtk_list_store_new(5, G_TYPE_STRING,
3340 G_TYPE_STRING,
3341 G_TYPE_STRING,
3342 G_TYPE_STRING,
3343 G_TYPE_INT);
3344 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(scenario_store));
3345 gtk_widget_set_hexpand(view, TRUE);
3346 gtk_widget_set_vexpand(view, TRUE);
3347 g_object_unref(scenario_store);
3348
3349 rend = gtk_cell_renderer_text_new();
3350 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
3351 -1, NULL, rend, "text", 0, NULL);
3352
3353 scenario_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
3354 g_signal_connect(scenario_selection, "changed",
3355 G_CALLBACK(scenario_list_callback), NULL);
3356 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
3357
3358 gtk_tree_selection_set_mode(scenario_selection, GTK_SELECTION_SINGLE);
3359
3360 g_signal_connect(view, "row-activated",
3361 G_CALLBACK(scenario_callback), NULL);
3362
3363 label = g_object_new(GTK_TYPE_LABEL,
3364 "use-underline", TRUE,
3365 "mnemonic-widget", view,
3366 "label", _("Choose a _Scenario:"),
3367 "xalign", 0.0,
3368 "yalign", 0.5,
3369 NULL);
3370 gtk_grid_attach(GTK_GRID(vgrid), label, 0, grid_row++, 1, 1);
3371
3372 sbox = gtk_grid_new();
3373 gtk_grid_set_column_spacing(GTK_GRID(sbox), 12);
3374 gtk_grid_set_row_homogeneous(GTK_GRID(sbox), TRUE);
3375 gtk_orientable_set_orientation(GTK_ORIENTABLE(sbox),
3376 GTK_ORIENTATION_VERTICAL);
3377 gtk_grid_set_row_spacing(GTK_GRID(sbox), 2);
3378 gtk_grid_attach(GTK_GRID(vgrid), sbox, 0, grid_row++, 1, 1);
3379
3380 hbox = gtk_grid_new();
3381 gtk_grid_set_column_homogeneous(GTK_GRID(hbox), TRUE);
3382 gtk_grid_set_column_spacing(GTK_GRID(hbox), 12);
3383
3384 sw = gtk_scrolled_window_new();
3385 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
3386 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC,
3387 GTK_POLICY_AUTOMATIC);
3388 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), view);
3389 gtk_grid_attach(GTK_GRID(sbox), sw, 0, 0, 1, 2);
3390
3391 text = gtk_text_view_new();
3392 gtk_widget_set_hexpand(text, TRUE);
3393 gtk_widget_set_vexpand(text, TRUE);
3394 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
3395 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 2);
3396 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
3397 scenario_description = text;
3398
3399 sw = gtk_scrolled_window_new();
3400 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), TRUE);
3401 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC,
3402 GTK_POLICY_AUTOMATIC);
3403 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), text);
3404
3405 text = gtk_text_view_new();
3406 gtk_widget_set_hexpand(text, TRUE);
3407 gtk_widget_set_vexpand(text, TRUE);
3408 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
3409 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 2);
3410 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
3411 scenario_authors = text;
3412
3413 swa = gtk_scrolled_window_new();
3414 gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(swa), TRUE);
3415 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swa), GTK_POLICY_AUTOMATIC,
3416 GTK_POLICY_AUTOMATIC);
3417 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(swa), text);
3418
3419 text = gtk_label_new(_("Filename:"));
3420 scenario_filename = gtk_label_new("");
3421 gtk_widget_set_halign(scenario_filename, GTK_ALIGN_START);
3422 gtk_widget_set_valign(scenario_filename, GTK_ALIGN_CENTER);
3423 gtk_label_set_selectable(GTK_LABEL(scenario_filename), TRUE);
3424
3425 filenamebox = gtk_grid_new();
3426 gtk_grid_set_column_spacing(GTK_GRID(hbox), 12);
3427 gtk_widget_set_margin_bottom(filenamebox, 5);
3428 gtk_widget_set_margin_end(filenamebox, 5);
3429 gtk_widget_set_margin_start(filenamebox, 5);
3430 gtk_widget_set_margin_top(filenamebox, 5);
3431
3432 gtk_grid_attach(GTK_GRID(filenamebox), text, filenamecol++, 0, 1, 1);
3433 gtk_grid_attach(GTK_GRID(filenamebox), scenario_filename,
3434 filenamecol++, 0, 1, 1);
3435
3436 /* TRANS: Scenario format version */
3437 vertext = gtk_label_new(_("Format:"));
3438 scenario_version = gtk_label_new("");
3439 gtk_widget_set_halign(scenario_version, GTK_ALIGN_START);
3440 gtk_widget_set_valign(scenario_version, GTK_ALIGN_CENTER);
3441 gtk_label_set_selectable(GTK_LABEL(scenario_version), TRUE);
3442
3443 versionbox = gtk_grid_new();
3444 gtk_grid_set_column_spacing(GTK_GRID(hbox), 12);
3445 gtk_widget_set_margin_bottom(versionbox, 5);
3446 gtk_widget_set_margin_end(versionbox, 5);
3447 gtk_widget_set_margin_start(versionbox, 5);
3448 gtk_widget_set_margin_top(versionbox, 5);
3449
3450 gtk_grid_attach(GTK_GRID(versionbox), vertext, vercol++, 0, 1, 1);
3451 gtk_grid_attach(GTK_GRID(versionbox), scenario_version,
3452 vercol++, 0, 1, 1);
3453
3454 descbox = gtk_grid_new();
3455 gtk_orientable_set_orientation(GTK_ORIENTABLE(descbox),
3456 GTK_ORIENTATION_VERTICAL);
3457 gtk_grid_set_row_spacing(GTK_GRID(descbox), 6);
3458 gtk_grid_attach(GTK_GRID(descbox), sw, 0, descrow++, 1, 1);
3459 gtk_grid_attach(GTK_GRID(descbox), swa, 0, descrow++, 1, 1);
3460 gtk_grid_attach(GTK_GRID(descbox), filenamebox,
3461 0, descrow++, 1, 1);
3462 gtk_grid_attach(GTK_GRID(descbox), versionbox,
3463 0, descrow++, 1, 1);
3464 gtk_grid_attach(GTK_GRID(sbox), descbox, 1, 0, 1, 2);
3465
3466 bbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
3467 gtk_box_set_spacing(GTK_BOX(bbox), 12);
3468 gtk_grid_attach(GTK_GRID(vgrid), bbox, 0, grid_row++, 1, 1);
3469
3470 button = gtk_button_new_with_mnemonic(_("_Browse..."));
3471 gtk_box_append(GTK_BOX(bbox), button);
3472 g_signal_connect(button, "clicked",
3473 G_CALLBACK(scenario_browse_callback), NULL);
3474
3475 button = gtk_button_new_with_mnemonic(_("_Cancel"));
3476 gtk_box_append(GTK_BOX(bbox), button);
3477 g_signal_connect(button, "clicked",
3478 G_CALLBACK(main_callback), NULL);
3479
3480 button = gtk_button_new_with_mnemonic(_("_OK"));
3481 gtk_box_append(GTK_BOX(bbox), button);
3482 g_signal_connect(button, "clicked",
3483 G_CALLBACK(scenario_callback), NULL);
3484
3485 return vgrid;
3486}
3487
3488/**********************************************************************/
3491 enum client_pages get_current_client_page(void)
3492{
3493 return current_page;
3494}
3495
3496/**********************************************************************/
3499 void real_set_client_page(enum client_pages new_page)
3500{
3501 /* Don't use current_page directly here because maybe it could be modified
3502 * before we reach the end of this function. */
3503 enum client_pages old_page = current_page;
3504
3505 /* If the page remains the same, don't do anything. */
3506 if (old_page == new_page) {
3507 return;
3508 }
3509
3510 log_debug("Switching client page from %s to %s.",
3511 -1 == old_page ? "(no page)" : client_pages_name(old_page),
3512 client_pages_name(new_page));
3513
3514 current_page = new_page;
3515
3516 switch (old_page) {
3517 case PAGE_SCENARIO:
3518 case PAGE_LOAD:
3519 break;
3520 case PAGE_GAME:
3521 {
3522 struct video_mode *vmode = resolution_request_get();
3523
3524 enable_menus(FALSE);
3525 if (vmode == NULL) {
3526 gtk_window_unmaximize(GTK_WINDOW(toplevel));
3527 }
3528 }
3529 break;
3530 default:
3531 break;
3532 }
3533
3534 switch (new_page) {
3535 case PAGE_MAIN:
3536 case PAGE_START:
3537 if (is_server_running()) {
3538 gtk_widget_set_visible(start_options_table, game.info.is_new_game);
3539 update_start_page();
3540 } else {
3541 gtk_widget_set_visible(start_options_table, FALSE);
3542 }
3543 voteinfo_gui_update();
3544 overview_size_changed();
3545 conn_list_dialog_update();
3546 break;
3547 case PAGE_GAME:
3548 {
3549 struct video_mode *vmode = resolution_request_get();
3550
3551 reset_unit_table();
3552 enable_menus(TRUE);
3553 if (vmode == NULL) {
3554 gtk_window_maximize(GTK_WINDOW(toplevel));
3555 }
3556 voteinfo_gui_update();
3557 mapview_freeze();
3558 }
3559 break;
3560 case PAGE_LOAD:
3561 update_load_page();
3562 break;
3563 case PAGE_SCENARIO:
3564 update_scenario_page();
3565 break;
3566 case PAGE_NETWORK:
3567 update_network_page();
3568 break;
3569 }
3570
3571 /* Hide/show statusbar. */
3572 if (new_page == PAGE_START || new_page == PAGE_GAME) {
3573 clear_network_statusbar();
3574 gtk_widget_set_visible(statusbar_frame, FALSE);
3575 } else {
3576 gtk_widget_set_visible(statusbar_frame, TRUE);
3577 }
3578
3579 gtk_notebook_set_current_page(GTK_NOTEBOOK(toplevel_tabs), new_page);
3580
3581 /* Update the GUI. */
3582 while (g_main_context_pending(NULL)) {
3583 g_main_context_iteration(NULL, FALSE);
3584 }
3585
3586 switch (new_page) {
3587 case PAGE_MAIN:
3588 break;
3589 case PAGE_START:
3590 chatline_scroll_to_bottom(FALSE);
3591 inputline_grab_focus();
3592 break;
3593 case PAGE_LOAD:
3594 gtk_tree_view_focus(gtk_tree_selection_get_tree_view(load_selection));
3595 break;
3596 case PAGE_SCENARIO:
3597 gtk_tree_view_focus(gtk_tree_selection_get_tree_view(scenario_selection));
3598 break;
3599 case PAGE_GAME:
3600 chatline_scroll_to_bottom(FALSE);
3601 refresh_chat_buttons();
3602 center_on_something();
3603 mapview_thaw();
3604 add_idle_callback(main_message_area_resize, NULL);
3605 add_idle_callback(animation_idle_cb, NULL);
3606 break;
3607 case PAGE_NETWORK:
3608 update_network_lists();
3609 gtk_widget_grab_focus(network_login);
3610 gtk_editable_set_position(GTK_EDITABLE(network_login), 0);
3611 set_connection_state(connection_status);
3612 break;
3613 }
3614}
3615
3616/****************************************************************************
3617 SAVE GAME DIALOGs
3618****************************************************************************/
3619
3620/**********************************************************************/
3623 static struct fileinfo_list *save_dialog_savegame_list(void)
3624{
3625 return fileinfolist_infix(get_save_dirs(), ".sav", FALSE);
3626}
3627
3628/**********************************************************************/
3631 void save_game_dialog_popup(void)
3632{
3633 static GtkWidget *shell = NULL;
3634
3635 if (NULL != shell) {
3636 return;
3637 }
3638
3639 shell = save_dialog_new(_("Save Game"), _("Saved _Games:"),
3640 _("Save _Filename:"), send_save_game,
3641 save_dialog_savegame_list);
3642 g_signal_connect(shell, "destroy", G_CALLBACK(widget_destroyed),
3643 &shell);
3644 gtk_window_present(GTK_WINDOW(shell));
3645}
3646
3647/**********************************************************************/
3650 static void save_dialog_save_scenario(const char *filename)
3651{
3652 dsend_packet_save_scenario(&client.conn, filename);
3653}
3654
3655/**********************************************************************/
3658 static struct fileinfo_list *save_dialog_scenario_list(void)
3659{
3660 return fileinfolist_infix(get_scenario_dirs(), ".sav", FALSE);
3661}
3662
3663/**********************************************************************/
3666 void save_scenario_dialog_popup(void)
3667{
3668 static GtkWidget *shell = NULL;
3669
3670 if (NULL != shell) {
3671 return;
3672 }
3673
3674 shell = save_dialog_new(_("Save Scenario"), _("Saved Sce_narios:"),
3675 _("Save Sc_enario:"), save_dialog_save_scenario,
3676 save_dialog_scenario_list);
3677 g_signal_connect(shell, "destroy", G_CALLBACK(widget_destroyed),
3678 &shell);
3679 gtk_window_present(GTK_WINDOW(shell));
3680}
3681
3682/**********************************************************************/
3687 static struct fileinfo_list *save_dialog_mapimg_list(void)
3688{
3689 return fileinfolist_infix(get_save_dirs(), ".map", FALSE);
3690}
3691
3692/**********************************************************************/
3695 void save_mapimg_dialog_popup(void)
3696{
3697 static GtkWidget *shell = NULL;
3698
3699 if (NULL != shell) {
3700 return;
3701 }
3702
3703 shell = save_dialog_new(_("Save Map Image"), _("Saved Map _Images:"),
3704 _("Save _Map Images:"), mapimg_client_save,
3705 save_dialog_mapimg_list);
3706 g_signal_connect(shell, "destroy", G_CALLBACK(widget_destroyed),
3707 &shell);
3708 gtk_window_present(GTK_WINDOW(shell));
3709}
3710
3711/**********************************************************************/
3714 void mapimg_client_save(const char *filename)
3715{
3716 if (!mapimg_client_createmap(filename)) {
3717 char msg[512];
3718
3719 fc_snprintf(msg, sizeof(msg), "(%s)", mapimg_error());
3720 popup_notify_dialog(_("Error"),
3721 _("Error Creating the Map Image!"), msg);
3722 }
3723}
3724
3725/**********************************************************************/
3730 void set_rulesets(int num_rulesets, char **rulesets)
3731{
3732 int i;
3733 int def_idx = -1;
3734
3735 gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(ruleset_combo));
3736 for (i = 0; i < num_rulesets; i++) {
3737
3738 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(ruleset_combo), rulesets[i]);
3739 if (!strcmp("default", rulesets[i])) {
3740 def_idx = i;
3741 }
3742 }
3743
3744 no_ruleset_callback = TRUE;
3745
3746 /* HACK: Server should tell us the current ruleset. */
3747 gtk_combo_box_set_active(GTK_COMBO_BOX(ruleset_combo), def_idx);
3748
3749 no_ruleset_callback = FALSE;
3750}
n
#define n
Definition astring.c:77
height
struct canvas int int struct sprite int int int int height
Definition canvas_g.h:44
width
struct canvas int int struct sprite int int int width
Definition canvas_g.h:44
chat.h
SERVER_COMMAND_PREFIX_STR
#define SERVER_COMMAND_PREFIX_STR
Definition chat.h:29
send_chat_printf
int send_chat_printf(const char *format,...)
Definition chatline_common.c:55
send_chat
int send_chat(const char *message)
Definition chatline_common.c:46
output_window_append
void output_window_append(const struct ft_color color, const char *featured_text)
Definition chatline_common.c:104
can_client_control
bool can_client_control(void)
Definition client_main.c:1261
client_is_global_observer
bool client_is_global_observer(void)
Definition client_main.c:1353
client_is_observer
bool client_is_observer(void)
Definition client_main.c:1091
user_name
char user_name[512]
Definition client_main.c:145
server_host
char server_host[512]
Definition client_main.c:144
client
struct civclient client
Definition client_main.c:153
client_state
enum client_states client_state(void)
Definition client_main.c:1034
fc_password
char fc_password[MAX_LEN_PASSWORD]
Definition client_main.c:146
server_port
int server_port
Definition client_main.c:148
client_main.h
client_player
#define client_player()
Definition client_main.h:106
C_S_PREPARING
@ C_S_PREPARING
Definition client_main.h:46
server_ai_level
enum ai_level server_ai_level(void)
Definition climisc.c:1508
mapimg_client_createmap
bool mapimg_client_createmap(const char *filename)
Definition climisc.c:1455
center_on_something
void center_on_something(void)
Definition climisc.c:430
climisc.h
list
static struct fc_sockaddr_list * list
Definition clinet.c:102
connect_to_server
int connect_to_server(const char *username, const char *hostname, int port, char *errbuf, int errbufsize)
Definition clinet.c:249
disconnect_from_server
void disconnect_from_server(bool leaving_sound)
Definition clinet.c:306
clinet.h
incite_cost
char * incite_cost
Definition comments.c:74
authentication_type
authentication_type
Definition conn_types.h:41
AUTH_NEWUSER_RETRY
@ AUTH_NEWUSER_RETRY
Definition conn_types.h:45
AUTH_NEWUSER_FIRST
@ AUTH_NEWUSER_FIRST
Definition conn_types.h:43
AUTH_LOGIN_RETRY
@ AUTH_LOGIN_RETRY
Definition conn_types.h:44
AUTH_LOGIN_FIRST
@ AUTH_LOGIN_FIRST
Definition conn_types.h:42
send_save_game
void send_save_game(const char *filename)
Definition connectdlg_common.c:751
set_ruleset
void set_ruleset(const char *ruleset)
Definition connectdlg_common.c:792
is_server_running
bool is_server_running(void)
Definition connectdlg_common.c:124
client_start_server
bool client_start_server(void)
Definition connectdlg_common.c:224
can_client_access_hack
bool can_client_access_hack(void)
Definition connectdlg_common.c:141
connectdlg_common.h
conn_description
const char * conn_description(const struct connection *pconn)
Definition connection.c:474
conn_by_number
struct connection * conn_by_number(int id)
Definition connection.c:421
conn_list_iterate
#define conn_list_iterate(connlist, pconn)
Definition connection.h:108
conn_list_iterate_end
#define conn_list_iterate_end
Definition connection.h:110
dataio.h
popup_notify_dialog
popup_notify_dialog
Definition dialogs_g.h:37
id
int int id
Definition editgui_g.h:28
MAX_NUM_PLAYERS
#define MAX_NUM_PLAYERS
Definition fc_types.h:36
MAX_LEN_NAME
#define MAX_LEN_NAME
Definition fc_types.h:66
fcintl.h
Q_
#define Q_(String)
Definition fcintl.h:70
_
#define _(String)
Definition fcintl.h:67
fc_mutex_allocate
void fc_mutex_allocate(fc_mutex *mutex)
fc_mutex_release
void fc_mutex_release(fc_mutex *mutex)
ftc_client
const struct ft_color ftc_client
Definition featured_text.c:78
game
struct civ_game game
Definition game.c:61
game.h
layout
static PangoLayout * layout
Definition canvas.c:325
inputline_toolkit_view_append_button
void inputline_toolkit_view_append_button(GtkWidget *toolkit_view, GtkWidget *button)
Definition chatline.c:1293
inputline_toolkit_view_new
GtkWidget * inputline_toolkit_view_new(void)
Definition chatline.c:1271
inputline_grab_focus
void inputline_grab_focus(void)
Definition chatline.c:80
chatline_scroll_to_bottom
void chatline_scroll_to_bottom(bool delayed)
Definition chatline.c:1007
popup_races_dialog
void popup_races_dialog(struct player *pplayer)
Definition dialogs.c:1215
pos
static struct tile * pos
Definition finddlg.c:53
client_string
const char * client_string
Definition gui_main.c:105
message_buffer
GtkTextBuffer * message_buffer
Definition gui_main.c:178
resolution_request_get
struct video_mode * resolution_request_get(void)
Definition gui_main.c:2634
enable_menus
void enable_menus(bool enable)
Definition gui_main.c:1075
refresh_chat_buttons
void refresh_chat_buttons(void)
Definition gui_main.c:2532
add_idle_callback
void add_idle_callback(void(callback)(void *), void *data)
Definition gui_main.c:2428
reset_unit_table
void reset_unit_table(void)
Definition gui_main.c:1046
toplevel
GtkWidget * toplevel
Definition gui_main.c:125
quit_gtk_main
void quit_gtk_main(void)
Definition gui_main.c:2360
vmode
static struct video_mode vmode
Definition gui_main.c:191
toplevel_tabs
GtkWidget * toplevel_tabs
Definition gui_main.c:127
screen_height
int screen_height(void)
Definition gui_main.c:2616
GUI_GTK_OPTION
#define GUI_GTK_OPTION(optname)
Definition gui_main.h:25
gtk_tree_view_focus
void gtk_tree_view_focus(GtkTreeView *view)
Definition gui_stuff.c:236
gtk_stockbutton_set_label
void gtk_stockbutton_set_label(GtkWidget *button, const gchar *label_text)
Definition gui_stuff.c:96
icon_label_button_new
GtkWidget * icon_label_button_new(const gchar *icon_name, const gchar *label_text)
Definition gui_stuff.c:76
add_treeview_column
GtkTreeViewColumn * add_treeview_column(GtkWidget *view, const char *title, GType gtype, int model_index)
Definition gui_stuff.c:1123
setup_dialog
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:287
mapview_freeze
void mapview_freeze(void)
Definition mapview.c:373
overview_size_changed
void overview_size_changed(void)
Definition mapview.c:326
mapview_thaw
void mapview_thaw(void)
Definition mapview.c:381
shell
static struct gui_dialog * shell
Definition messagedlg.c:39
option_dialog_popup
void option_dialog_popup(const char *name, const struct option_set *poptset)
Definition optiondlg.c:972
load_store
static GtkListStore * load_store
Definition pages.c:68
update_network_page
static void update_network_page(void)
Definition pages.c:1183
handle_game_load
void handle_game_load(bool load_successful, const char *filename)
Definition pages.c:2839
create_start_page
GtkWidget * create_start_page(void)
Definition pages.c:2621
create_network_page
GtkWidget * create_network_page(void)
Definition pages.c:1199
client_aitoggle_player
static void client_aitoggle_player(void *data)
Definition pages.c:1507
nation_button
static GtkWidget * nation_button
Definition pages.c:1458
update_server_list
static void update_server_list(enum server_scan_type sstype, const struct server_list *list)
Definition pages.c:702
start_scenario_callback
static void start_scenario_callback(GtkWidget *w, gpointer data)
Definition pages.c:115
scenario_selection
static GtkTreeSelection * scenario_selection
Definition pages.c:73
update_start_page_buttons
static void update_start_page_buttons(void)
Definition pages.c:2197
save_dialog_response_callback
static void save_dialog_response_callback(GtkWidget *w, gint response, gpointer data)
Definition pages.c:487
create_scenario_page
GtkWidget * create_scenario_page(void)
Definition pages.c:3183
show_conn_popup
static void show_conn_popup(struct player *pplayer, struct connection *pconn)
Definition pages.c:1765
network_confirm_password_label
static GtkWidget * network_confirm_password_label
Definition pages.c:697
save_mapimg_dialog_popup
void save_mapimg_dialog_popup(void)
Definition pages.c:3549
ruleset_selected
static void ruleset_selected(const char *name)
Definition pages.c:1613
ready_button_callback
static void ready_button_callback(GtkWidget *w, gpointer data)
Definition pages.c:2143
conn_list_selection
static bool conn_list_selection(struct player **ppplayer, struct connection **ppconn)
Definition pages.c:2056
meta_scan
static struct server_scan_timer_data meta_scan
Definition pages.c:86
update_network_lists
static void update_network_lists(void)
Definition pages.c:836
statusbar
static GtkWidget * statusbar
Definition pages.c:89
server_playerlist_view
static GtkWidget * server_playerlist_view
Definition pages.c:71
save_dialog_store_new
static GtkListStore * save_dialog_store_new(void)
Definition pages.c:397
append_network_statusbar
void append_network_statusbar(const char *text, bool force)
Definition pages.c:892
update_network_statusbar
static gboolean update_network_statusbar(gpointer data)
Definition pages.c:862
set_rulesets
void set_rulesets(int num_rulesets, char **rulesets)
Definition pages.c:3584
mapimg_client_save
void mapimg_client_save(const char *filename)
Definition pages.c:3568
conn_menu_player_command
static void conn_menu_player_command(GObject *object, gpointer data)
Definition pages.c:1724
load_filename
static void load_filename(const char *filename)
Definition pages.c:2854
conn_menu_nation_chosen
static void conn_menu_nation_chosen(GObject *object, gpointer data)
Definition pages.c:1711
scenario_description
static GtkWidget * scenario_description
Definition pages.c:63
save_game_dialog_popup
void save_game_dialog_popup(void)
Definition pages.c:3485
get_current_client_page
enum client_pages get_current_client_page(void)
Definition pages.c:3343
lan_store
static GtkListStore * lan_store
Definition pages.c:68
connection_status
static enum connection_state connection_status
Definition pages.c:857
save_dialog_columns
save_dialog_columns
Definition pages.c:381
SD_COL_NUM
@ SD_COL_NUM
Definition pages.c:385
SD_COL_FULL_PATH
@ SD_COL_FULL_PATH
Definition pages.c:383
SD_COL_PRETTY_NAME
@ SD_COL_PRETTY_NAME
Definition pages.c:382
lan_scan
static struct server_scan_timer_data lan_scan
Definition pages.c:87
save_dialog_list_callback
static void save_dialog_list_callback(GtkTreeSelection *selection, gpointer data)
Definition pages.c:555
connect_network_game_callback
static void connect_network_game_callback(GtkWidget *w, gpointer data)
Definition pages.c:132
connection_list_view
static GtkTreeView * connection_list_view
Definition pages.c:1460
network_login
static GtkWidget * network_login
Definition pages.c:693
network_login_label
static GtkWidget * network_login_label
Definition pages.c:693
connection_state
connection_state
Definition pages.c:850
LOGIN_TYPE
@ LOGIN_TYPE
Definition pages.c:851
NEW_PASSWORD_TYPE
@ NEW_PASSWORD_TYPE
Definition pages.c:852
WAITING_TYPE
@ WAITING_TYPE
Definition pages.c:854
ENTER_PASSWORD_TYPE
@ ENTER_PASSWORD_TYPE
Definition pages.c:853
connect_callback
static void connect_callback(GtkWidget *w, gpointer data)
Definition pages.c:1041
scenario_browse_callback
static void scenario_browse_callback(GtkWidget *w, gpointer data)
Definition pages.c:3057
meta_store
static GtkListStore * meta_store
Definition pages.c:68
connection_list_columns
connection_list_columns
Definition pages.c:1466
CL_COL_STYLE
@ CL_COL_STYLE
Definition pages.c:1476
CL_COL_USER_NAME
@ CL_COL_USER_NAME
Definition pages.c:1468
CL_COL_READY_STATE
@ CL_COL_READY_STATE
Definition pages.c:1469
CL_COL_WEIGHT
@ CL_COL_WEIGHT
Definition pages.c:1477
CL_COL_PLAYER_NAME
@ CL_COL_PLAYER_NAME
Definition pages.c:1470
CL_COL_NATION
@ CL_COL_NATION
Definition pages.c:1473
CL_COL_CONN_ID
@ CL_COL_CONN_ID
Definition pages.c:1475
CL_COL_PLAYER_NUMBER
@ CL_COL_PLAYER_NUMBER
Definition pages.c:1467
CL_NUM_COLUMNS
@ CL_NUM_COLUMNS
Definition pages.c:1480
CL_COL_TEAM
@ CL_COL_TEAM
Definition pages.c:1474
CL_COL_COLOR
@ CL_COL_COLOR
Definition pages.c:1472
CL_COL_COLLAPSED
@ CL_COL_COLLAPSED
Definition pages.c:1478
CL_COL_FLAG
@ CL_COL_FLAG
Definition pages.c:1471
update_load_page
static void update_load_page(void)
Definition pages.c:2889
save_dialog_update
static void save_dialog_update(struct save_dialog *pdialog)
Definition pages.c:425
scenario_authors
static GtkWidget * scenario_authors
Definition pages.c:64
start_aifill_spin
static GtkWidget * start_aifill_spin
Definition pages.c:1461
ruleset_entry_changed
static void ruleset_entry_changed(GtkWidget *w, gpointer data)
Definition pages.c:1625
save_dialog_action_fn_t
void(* save_dialog_action_fn_t)(const char *filename)
Definition pages.c:370
open_settings
static void open_settings(void)
Definition pages.c:141
set_connection_state
static void set_connection_state(enum connection_state state)
Definition pages.c:928
ruleset_combo
static GtkWidget * ruleset_combo
Definition pages.c:93
observe_button_callback
static void observe_button_callback(GtkWidget *w, gpointer data)
Definition pages.c:2177
conn_menu_ready_chosen
static void conn_menu_ready_chosen(GObject *object, gpointer data)
Definition pages.c:1698
server_scan_error
static void server_scan_error(struct server_scan *scan, const char *message)
Definition pages.c:823
load_callback
static void load_callback(void)
Definition pages.c:2862
save_dialog_file_chooser_callback
static void save_dialog_file_chooser_callback(GtkWidget *widget, gint response, gpointer data)
Definition pages.c:442
network_list_callback
static void network_list_callback(GtkTreeSelection *select, gpointer data)
Definition pages.c:1137
server_playerlist_store
static GtkListStore * server_playerlist_store
Definition pages.c:70
nation_button_callback
static void nation_button_callback(GtkWidget *w, gpointer data)
Definition pages.c:2157
real_set_client_page
void real_set_client_page(enum client_pages new_page)
Definition pages.c:3351
conn_menu_connection_command
static void conn_menu_connection_command(GObject *object, gpointer data)
Definition pages.c:1751
scenario_list_callback
static void scenario_list_callback(void)
Definition pages.c:2985
intro_expose
static gboolean intro_expose(GtkWidget *w, cairo_t *cr, gpointer *data)
Definition pages.c:164
load_browse_callback
static void load_browse_callback(GtkWidget *w, gpointer data)
Definition pages.c:2879
network_activate_callback
static void network_activate_callback(GtkTreeView *view, GtkTreePath *arg1, GtkTreeViewColumn *arg2, gpointer data)
Definition pages.c:1096
save_dialog_scenario_list
static struct fileinfo_list * save_dialog_scenario_list(void)
Definition pages.c:3512
connection_state_reset
static void connection_state_reset(void)
Definition pages.c:996
real_conn_list_dialog_update
void real_conn_list_dialog_update(void *unused)
Definition pages.c:2342
holding_srv_list_mutex
static bool holding_srv_list_mutex
Definition pages.c:95
connection_list_store
static GtkTreeStore * connection_list_store
Definition pages.c:1459
save_dialog_savegame_list
static struct fileinfo_list * save_dialog_savegame_list(void)
Definition pages.c:3477
start_new_game_callback
static void start_new_game_callback(GtkWidget *w, gpointer data)
Definition pages.c:102
destroy_server_scans
void destroy_server_scans(void)
Definition pages.c:766
save_scenario_dialog_popup
void save_scenario_dialog_popup(void)
Definition pages.c:3520
lan_selection
static GtkTreeSelection * lan_selection
Definition pages.c:74
save_dialog_save_scenario
static void save_dialog_save_scenario(const char *filename)
Definition pages.c:3504
save_dialog_files_fn_t
struct fileinfo_list *(* save_dialog_files_fn_t)(void)
Definition pages.c:371
check_server_scan
static gboolean check_server_scan(gpointer data)
Definition pages.c:789
save_dialog_store_update
static void save_dialog_store_update(GtkListStore *store, const struct fileinfo_list *files)
Definition pages.c:407
ai_fill_changed_by_user
static void ai_fill_changed_by_user(GtkWidget *w, gpointer data)
Definition pages.c:1640
delayed_unselect_path
static gboolean delayed_unselect_path(gpointer data)
Definition pages.c:1971
conn_menu_player_take
static void conn_menu_player_take(GObject *object, gpointer data)
Definition pages.c:1738
conn_menu_info_chosen
static void conn_menu_info_chosen(GObject *object, gpointer data)
Definition pages.c:1796
model_get_player_iter
static bool model_get_player_iter(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *start, const struct player *pplayer)
Definition pages.c:2282
load_selection
static GtkTreeSelection * load_selection
Definition pages.c:73
ai_skill_callback
static void ai_skill_callback(GtkWidget *w, gpointer data)
Definition pages.c:1587
current_page
static enum client_pages current_page
Definition pages.c:78
statusbar_frame
static GtkWidget * statusbar_frame
Definition pages.c:89
network_confirm_password
static GtkWidget * network_confirm_password
Definition pages.c:697
client_take_player
static void client_take_player(struct player *pplayer)
Definition pages.c:1521
clear_network_statusbar
static void clear_network_statusbar(void)
Definition pages.c:878
meta_selection
static GtkTreeSelection * meta_selection
Definition pages.c:74
save_dialog_row_callback
static void save_dialog_row_callback(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data)
Definition pages.c:536
connection_list_row_callback
static void connection_list_row_callback(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
Definition pages.c:2041
save_dialog_response
save_dialog_response
Definition pages.c:388
SD_RES_DELETE
@ SD_RES_DELETE
Definition pages.c:390
SD_RES_SAVE
@ SD_RES_SAVE
Definition pages.c:391
SD_RES_BROWSE
@ SD_RES_BROWSE
Definition pages.c:389
create_load_page
GtkWidget * create_load_page(void)
Definition pages.c:2902
ai_lvl_combobox
static GtkWidget * ai_lvl_combobox
Definition pages.c:1462
network_password_label
static GtkWidget * network_password_label
Definition pages.c:696
save_dialog_new
static GtkWidget * save_dialog_new(const char *title, const char *savelabel, const char *savefilelabel, save_dialog_action_fn_t action, save_dialog_files_fn_t files)
Definition pages.c:576
intro_free
static void intro_free(GtkWidget *w, gpointer *data)
Definition pages.c:219
network_password
static GtkWidget * network_password
Definition pages.c:696
network_host
static GtkWidget * network_host
Definition pages.c:694
handle_authentication_req
void handle_authentication_req(enum authentication_type type, const char *message)
Definition pages.c:1005
connection_list_store_new
static GtkTreeStore * connection_list_store_new(void)
Definition pages.c:1486
send_new_aifill_to_server
static bool send_new_aifill_to_server
Definition pages.c:1639
save_dialog_file_chooser_popup
static void save_dialog_file_chooser_popup(const char *title, GtkFileChooserAction action, save_dialog_action_fn_t cb)
Definition pages.c:462
network_port
static GtkWidget * network_port
Definition pages.c:695
add_tree_col
static void add_tree_col(GtkWidget *treeview, GType gtype, const char *title, int colnum, const char *key)
Definition pages.c:2587
save_dialog_entry_callback
static void save_dialog_entry_callback(GtkEntry *entry, gpointer data)
Definition pages.c:547
main_callback
static void main_callback(GtkWidget *w, gpointer data)
Definition pages.c:149
update_start_page
void update_start_page(void)
Definition pages.c:1673
scenario_callback
static void scenario_callback(void)
Definition pages.c:3041
start_options_table
static GtkWidget * start_options_table
Definition pages.c:1457
no_ruleset_callback
static bool no_ruleset_callback
Definition pages.c:1608
ai_fill_changed_by_server
void ai_fill_changed_by_server(int aifill)
Definition pages.c:1651
update_server_playerlist
static void update_server_playerlist(const struct server *pserver)
Definition pages.c:1108
observe_button
static GtkWidget * observe_button
Definition pages.c:1458
scenario_version
static GtkWidget * scenario_version
Definition pages.c:66
create_statusbar
GtkWidget * create_statusbar(void)
Definition pages.c:907
game_options_callback
static void game_options_callback(GtkWidget *w, gpointer data)
Definition pages.c:1579
scenario_store
static GtkListStore * scenario_store
Definition pages.c:68
network_host_label
static GtkWidget * network_host_label
Definition pages.c:694
model_get_conn_iter
static bool model_get_conn_iter(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent, GtkTreeIter *start, const struct connection *pconn)
Definition pages.c:2313
statusbar_queue
static GQueue * statusbar_queue
Definition pages.c:90
start_message_area
GtkWidget * start_message_area
Definition pages.c:1455
network_port_label
static GtkWidget * network_port_label
Definition pages.c:695
update_scenario_page
static void update_scenario_page(void)
Definition pages.c:3067
scenario_filename
static GtkWidget * scenario_filename
Definition pages.c:65
conn_menu_team_chosen
static void conn_menu_team_chosen(GObject *object, gpointer data)
Definition pages.c:1681
create_conn_menu
static GtkWidget * create_conn_menu(struct player *pplayer, struct connection *pconn)
Definition pages.c:1810
load_saved_game_callback
static void load_saved_game_callback(GtkWidget *w, gpointer data)
Definition pages.c:124
statusbar_timer
static guint statusbar_timer
Definition pages.c:91
object_extract
static bool object_extract(GObject *object, struct player **ppplayer, struct connection **ppconn)
Definition pages.c:1552
object_put
static void object_put(GObject *object, struct player *pplayer, struct connection *pconn)
Definition pages.c:1533
save_dialog_mapimg_list
static struct fileinfo_list * save_dialog_mapimg_list(void)
Definition pages.c:3541
create_main_page
GtkWidget * create_main_page(void)
Definition pages.c:229
conn_list_select_conn
static void conn_list_select_conn(struct connection *pconn)
Definition pages.c:2092
ready_button
static GtkWidget * ready_button
Definition pages.c:1458
create_player_icon
GdkPixbuf * create_player_icon(const struct player *plr)
Definition plrdlg.c:117
get_flag
GdkPixbuf * get_flag(const struct nation_type *nation)
Definition plrdlg.c:607
title
const char * title
Definition repodlgs.c:1314
type
GType type
Definition repodlgs.c:1313
free_sprite
void free_sprite(struct sprite *s)
Definition sprite.c:278
sprite_scale
struct sprite * sprite_scale(struct sprite *src, int new_w, int new_h)
Definition sprite.c:291
load_gfxfile
struct sprite * load_gfxfile(const char *filename, bool svgflag)
Definition sprite.c:170
voteinfo_gui_update
void voteinfo_gui_update(void)
Definition voteinfo_bar.c:214
voteinfo_bar_new
GtkWidget * voteinfo_bar_new(bool split_bar)
Definition voteinfo_bar.c:92
pregame_votebar
GtkWidget * pregame_votebar
Definition voteinfo_bar.c:49
terminate_signal_processing
gboolean terminate_signal_processing(GtkEventControllerFocus *controller, gpointer data)
Definition gui_main.c:1051
animation_idle_cb
void animation_idle_cb(void *data)
Definition gui_main.c:2437
main_message_area_resize
void main_message_area_resize(void *data)
Definition gui_main.c:368
widget_destroyed
void widget_destroyed(GtkWidget *wdg, void *data)
Definition gui_stuff.c:1155
menu_item_append_unref
#define menu_item_append_unref(menu, item)
Definition gui_stuff.h:149
connect_list_right_button
static gboolean connect_list_right_button(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition pages.c:2098
close_conn_menu_popover
static void close_conn_menu_popover(void)
Definition pages.c:1709
connect_list_left_button
static gboolean connect_list_left_button(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data)
Definition pages.c:2069
conn_popover
static GtkWidget * conn_popover
Definition pages.c:97
gui_stuff.h
save_dialog_action_fn_t
void(* save_dialog_action_fn_t)(const char *filename)
Definition pages.c:379
save_dialog_files_fn_t
struct fileinfo_list *(* save_dialog_files_fn_t)(void)
Definition pages.c:380
server_list
static struct server_list * server_list
Definition connectdlg.c:61
old_page
static enum client_pages old_page
Definition pages.c:46
chatline.h
connectdlg.h
dialogs.h
graphics.h
gui_main.h
mapview.h
menu.h
optiondlg.h
pages.h
plrdlg.h
repodlgs.h
voteinfo_bar.h
conn_list_dialog_update
void conn_list_dialog_update(void)
Definition update_queue.c:650
name
const char * name
Definition inputfile.c:127
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
log_debug
#define log_debug(message,...)
Definition log.h:115
log_error
#define log_error(message,...)
Definition log.h:103
mapimg_error
const char * mapimg_error(void)
Definition mapimg.c:759
mapimg.h
mem.h
fc_strdup
#define fc_strdup(str)
Definition mem.h:43
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
nation_adjective_for_player
const char * nation_adjective_for_player(const struct player *pplayer)
Definition nation.c:169
can_conn_edit_players_nation
bool can_conn_edit_players_nation(const struct connection *pconn, const struct player *pplayer)
Definition nation.c:1187
NO_NATION_SELECTED
#define NO_NATION_SELECTED
Definition nation.h:30
server_optset
const struct option_set * server_optset
Definition options.c:4281
client_optset
const struct option_set * client_optset
Definition options.c:1315
option_int_get
int option_int_get(const struct option *poption)
Definition options.c:869
optset_option_by_name
struct option * optset_option_by_name(const struct option_set *poptset, const char *name)
Definition options.c:466
option_int_set
bool option_int_set(struct option *poption, int val)
Definition options.c:913
send_packet_authentication_reply
int send_packet_authentication_reply(struct connection *pc, const struct packet_authentication_reply *packet)
Definition packets_gen.c:1870
dsend_packet_save_scenario
int dsend_packet_save_scenario(struct connection *pc, const char *name)
Definition packets_gen.c:89704
dsend_packet_player_ready
int dsend_packet_player_ready(struct connection *pc, int player_no, bool is_ready)
Definition packets_gen.c:2533
packhand.h
is_settable_ai_level
bool is_settable_ai_level(enum ai_level level)
Definition player.c:1925
player_by_number
struct player * player_by_number(const int player_id)
Definition player.c:849
player_slot_count
int player_slot_count(void)
Definition player.c:418
player_number
int player_number(const struct player *pplayer)
Definition player.c:837
player_name
const char * player_name(const struct player *pplayer)
Definition player.c:895
player_has_flag
bool player_has_flag(const struct player *pplayer, enum plr_flag_id flag)
Definition player.c:1996
ai_level_cmd
#define ai_level_cmd(_level_)
Definition player.h:569
players_iterate_end
#define players_iterate_end
Definition player.h:539
players_iterate
#define players_iterate(_pplayer)
Definition player.h:534
is_ai
#define is_ai(plr)
Definition player.h:232
players_iterate_alive_end
#define players_iterate_alive_end
Definition player.h:549
is_human
#define is_human(plr)
Definition player.h:231
players_iterate_alive
#define players_iterate_alive(_pplayer)
Definition player.h:544
secfile_destroy
void secfile_destroy(struct section_file *secfile)
Definition section_file.c:95
secfile_load_section
struct section_file * secfile_load_section(const char *filename, const char *section, bool allow_duplicates)
Definition registry_ini.c:596
secfile_lookup_bool_default
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
Definition registry_ini.c:1902
secfile_lookup_int_default
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
Definition registry_ini.c:2004
secfile_lookup_str_default
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Definition registry_ini.c:2210
server_scan_get_list
struct srv_list * server_scan_get_list(struct server_scan *scan)
Definition servers.c:866
server_scan_finish
void server_scan_finish(struct server_scan *scan)
Definition servers.c:879
server_scan_begin
struct server_scan * server_scan_begin(enum server_scan_type type, ServerScanErrorFunc error_func)
Definition servers.c:755
server_scan_get_type
enum server_scan_type server_scan_get_type(const struct server_scan *scan)
Definition servers.c:809
server_scan_poll
enum server_scan_status server_scan_poll(struct server_scan *scan)
Definition servers.c:832
servers.h
server_list_iterate_end
#define server_list_iterate_end
Definition servers.h:57
server_scan_status
server_scan_status
Definition servers.h:79
SCAN_STATUS_PARTIAL
@ SCAN_STATUS_PARTIAL
Definition servers.h:82
SCAN_STATUS_ERROR
@ SCAN_STATUS_ERROR
Definition servers.h:80
SCAN_STATUS_DONE
@ SCAN_STATUS_DONE
Definition servers.h:83
server_list_iterate
#define server_list_iterate(serverlist, pserver)
Definition servers.h:55
server_scan_type
server_scan_type
Definition servers.h:67
SERVER_SCAN_LOCAL
@ SERVER_SCAN_LOCAL
Definition servers.h:68
SERVER_SCAN_GLOBAL
@ SERVER_SCAN_GLOBAL
Definition servers.h:69
level
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:190
get_scenario_dirs
const struct strvec * get_scenario_dirs(void)
Definition shared.c:971
get_save_dirs
const struct strvec * get_save_dirs(void)
Definition shared.c:934
skip_to_basename
char * skip_to_basename(char *filepath)
Definition shared.c:1750
fileinfolist_infix
struct fileinfo_list * fileinfolist_infix(const struct strvec *dirs, const char *infix, bool nodups)
Definition shared.c:1204
shared.h
fileinfo_list_iterate
#define fileinfo_list_iterate(list, pnode)
Definition shared.h:182
FC_PTR_TO_INT
#define FC_PTR_TO_INT(p)
Definition shared.h:95
fileinfo_list_iterate_end
#define fileinfo_list_iterate_end
Definition shared.h:184
FC_INT_TO_PTR
#define FC_INT_TO_PTR(i)
Definition shared.h:94
size
size_t size
Definition specvec.h:72
y
struct sprite int int y
Definition sprite_g.h:31
scale
struct sprite int int int int struct sprite int int float scale
Definition sprite_g.h:33
x
struct sprite int x
Definition sprite_g.h:31
get_sprite_dimensions
struct sprite int int int int struct sprite int int float bool smooth get_sprite_dimensions
Definition sprite_g.h:36
aifill
const char * aifill(int amount)
Definition srv_main.c:2505
action
Definition actions.h:106
civ_game::est_connections
struct conn_list * est_connections
Definition game.h:97
civ_game::info
struct packet_game_info info
Definition game.h:89
civclient::conn
struct connection conn
Definition client_main.h:96
color
Definition colors.h:21
connection
Definition connection.h:136
connection::playing
struct player * playing
Definition connection.h:151
connection::access_level
enum cmdlevel access_level
Definition connection.h:177
connection::id
int id
Definition connection.h:137
connection::used
bool used
Definition connection.h:139
entry
Definition registry_ini.c:193
message
Definition messagewin_common.h:29
option
Definition options.c:514
packet_authentication_reply
Definition packets_gen.h:66
packet_game_info::is_new_game
bool is_new_game
Definition packets_gen.h:190
player
Definition player.h:249
player::team
struct team * team
Definition player.h:261
player::is_ready
bool is_ready
Definition player.h:262
save_dialog
Definition pages.c:373
save_dialog::action
save_dialog_action_fn_t action
Definition pages.c:377
save_dialog::entry
GtkEntry * entry
Definition pages.c:376
save_dialog::tree_view
GtkTreeView * tree_view
Definition pages.c:375
save_dialog::shell
GtkDialog * shell
Definition pages.c:374
save_dialog::files
save_dialog_files_fn_t files
Definition pages.c:378
section_file
Definition section_file.h:36
server_scan_timer_data
Definition pages.c:81
server_scan_timer_data::scan
struct server_scan * scan
Definition pages.c:82
server_scan_timer_data::timer
guint timer
Definition pages.c:83
server_scan
Definition servers.c:84
server
Definition servers.h:29
sprite
Definition sprite.h:22
srv_list
Definition servers.h:62
srv_list::mutex
fc_mutex mutex
Definition servers.h:64
srv_list::servers
struct server_list * servers
Definition servers.h:63
team_slot
Definition team.c:31
team
Definition team.c:40
tileset
Definition tilespec.c:482
video_mode
Definition options.h:46
view
Definition mapview_common.h:36
widget
Definition widget.h:112
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
cat_snprintf
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:986
fc_remove
int fc_remove(const char *filename)
Definition support.c:555
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
sz_strlcat
#define sz_strlcat(dest, src)
Definition support.h:190
fc_strncmp
#define fc_strncmp(_s1_, _s2_, _len_)
Definition support.h:154
team_name_translation
const char * team_name_translation(const struct team *pteam)
Definition team.c:420
team_slot_get_team
struct team * team_slot_get_team(const struct team_slot *tslot)
Definition team.c:150
team_slot_name_translation
const char * team_slot_name_translation(const struct team_slot *tslot)
Definition team.c:253
team_number
int team_number(const struct team *pteam)
Definition team.c:391
team_slot_index
int team_slot_index(const struct team_slot *tslot)
Definition team.c:138
team_members
const struct player_list * team_members(const struct team *pteam)
Definition team.c:456
team_slot_is_used
bool team_slot_is_used(const struct team_slot *tslot)
Definition team.c:162
team_slot_rule_name
const char * team_slot_rule_name(const struct team_slot *tslot)
Definition team.c:233
team_slots_iterate_end
#define team_slots_iterate_end
Definition team.h:77
team_slots_iterate
#define team_slots_iterate(_tslot)
Definition team.h:72
tileset_main_intro_filename
const char * tileset_main_intro_filename(const struct tileset *t)
Definition tilespec.c:948
client_start_server_and_set_page
void client_start_server_and_set_page(enum client_pages page)
Definition update_queue.c:506
set_client_page
void set_client_page(enum client_pages page)
Definition update_queue.c:496
update_queue_connect_processing_finished
void update_queue_connect_processing_finished(int request_id, uq_callback_t callback, void *data)
Definition update_queue.c:450
get_client_page
enum client_pages get_client_page(void)
Definition update_queue.c:520
update_queue.h
fc_git_revision
const char * fc_git_revision(void)
Definition version.c:75
unstable_message
const char * unstable_message(void)
Definition version.c:160
word_version
const char * word_version(void)
Definition version.c:62
version.h