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

Freeciv-3.1

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