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