Freeciv-3.1: /fast/freeciv/nightly/S3_1/client/gui-gtk-4.0/pages.c Source File

Freeciv-3.1

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