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