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