Freeciv-3.1
Loading...
Searching...
No Matches
gui_main.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#ifdef AUDIO_SDL
19/* Though it would happily compile without this include,
20 * it is needed for sound to work.
21 * It defines "main" macro to rename our main() so that
22 * it can install SDL's own. */
23#ifdef SDL2_PLAIN_INCLUDE
24#include <SDL.h>
25#else /* PLAIN_INCLUDE */
26#include <SDL2/SDL.h>
27#endif /* PLAIN_INCLUDE */
28#endif /* AUDIO_SDL */
29
30#ifdef HAVE_LOCALE_H
31#include <locale.h>
32#endif
33#include <stdarg.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <time.h>
38
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42
43#include <gtk/gtk.h>
44#include <gdk/gdkkeysyms.h>
45
46/* utility */
47#include "fc_cmdline.h"
48#include "fciconv.h"
49#include "fcintl.h"
50#include "log.h"
51#include "mem.h"
52#include "support.h"
53
54/* common */
55#include "dataio.h"
56#include "featured_text.h"
57#include "game.h"
58#include "government.h"
59#include "map.h"
60#include "unitlist.h"
61#include "version.h"
62
63/* client */
64#include "client_main.h"
65#include "climisc.h"
66#include "clinet.h"
67#include "colors.h"
68#include "connectdlg_common.h"
69#include "control.h"
70#include "editor.h"
71#include "options.h"
72#include "text.h"
73#include "tilespec.h"
74#include "zoom.h"
75
76/* client/gui-gtk-3.22 */
77#include "chatline.h"
78#include "citizensinfo.h"
79#include "connectdlg.h"
80#include "cma_fe.h"
81#include "dialogs.h"
82#include "diplodlg.h"
83#include "editgui.h"
84#include "gotodlg.h"
85#include "graphics.h"
86#include "gui_stuff.h"
87#include "happiness.h"
88#include "helpdlg.h"
89#include "inteldlg.h"
90#include "mapctrl.h"
91#include "mapview.h"
92#include "menu.h"
93#include "messagewin.h"
94#include "optiondlg.h"
95#include "pages.h"
96#include "plrdlg.h"
97#include "luaconsole.h"
98#include "spaceshipdlg.h"
99#include "repodlgs.h"
100#include "voteinfo_bar.h"
101
102#include "gui_main.h"
103
105
106GtkWidget *map_canvas; /* GtkDrawingArea */
109
110GtkWidget *overview_canvas; /* GtkDrawingArea */
111GtkWidget *overview_scrolled_window; /* GtkScrolledWindow */
112/* The two values below define the width and height of the map overview. The
113 * first set of values (2*62, 2*46) define the size for a netbook display. For
114 * bigger displays the values are doubled (default). */
115#define OVERVIEW_CANVAS_STORE_WIDTH_NETBOOK (2 * 64)
116#define OVERVIEW_CANVAS_STORE_HEIGHT_NETBOOK (2 * 46)
117#define OVERVIEW_CANVAS_STORE_WIDTH \
118 (2 * OVERVIEW_CANVAS_STORE_WIDTH_NETBOOK)
119#define OVERVIEW_CANVAS_STORE_HEIGHT \
120 (2 * OVERVIEW_CANVAS_STORE_HEIGHT_NETBOOK)
123
124GtkWidget *toplevel;
125GdkWindow *root_window;
126GtkWidget *toplevel_tabs;
127GtkWidget *top_vbox;
129GtkWidget *map_widget;
130static GtkWidget *bottom_hpaned;
131
132PangoFontDescription *city_names_style = NULL;
133PangoFontDescription *city_productions_style = NULL;
134PangoFontDescription *reqtree_text_style = NULL;
135
138
139GtkWidget *avbox, *ahbox, *conn_box;
140GtkWidget* scroll_panel;
141
142GtkWidget *econ_label[10];
143GtkWidget *bulb_label;
144GtkWidget *sun_label;
145GtkWidget *flake_label;
147GtkWidget *timeout_label;
149
151GtkWidget *unit_info_box;
153
154GtkWidget *econ_ebox;
155GtkWidget *bulb_ebox;
156GtkWidget *sun_ebox;
157GtkWidget *flake_ebox;
159
160const char *const gui_character_encoding = "UTF-8";
162
163static GtkWidget *main_menubar;
164static GtkWidget *unit_image_table;
165static GtkWidget *unit_image;
166static GtkWidget *unit_image_button;
169static GtkWidget *more_arrow_pixmap;
170static GtkWidget *more_arrow_pixmap_button;
172
173static int unit_id_top;
174static int unit_ids[MAX_NUM_UNITS_BELOW]; /* ids of the units icons in
175 * information display: (or 0) */
176GtkTextView *main_message_area;
177GtkTextBuffer *message_buffer = NULL;
179
180static gint timer_id; /* ditto */
181static GIOChannel *srv_channel;
182static guint srv_id;
184
185static bool gui_up = FALSE;
186
187static struct video_mode vmode = { -1, -1 };
188
189static void set_g_log_callbacks(void);
190
191static gboolean show_info_button_release(GtkWidget *w, GdkEventButton *ev, gpointer data);
192static gboolean show_info_popup(GtkWidget *w, GdkEventButton *ev, gpointer data);
193
194static void end_turn_callback(GtkWidget *w, gpointer data);
195static gboolean get_net_input(GIOChannel *source, GIOCondition condition,
196 gpointer data);
197static void set_wait_for_writable_socket(struct connection *pc,
198 bool socket_writable);
199
200static void print_usage(void);
201static bool parse_options(int argc, char **argv);
202static gboolean toplevel_key_press_handler(GtkWidget *w, GdkEventKey *ev, gpointer data);
203static gboolean toplevel_key_release_handler(GtkWidget *w, GdkEventKey *ev, gpointer data);
204static gboolean mouse_scroll_mapcanvas(GtkWidget *w, GdkEventScroll *ev);
205
206static void tearoff_callback(GtkWidget *b, gpointer data);
207static GtkWidget *detached_widget_new(void);
208static GtkWidget *detached_widget_fill(GtkWidget *tearbox);
209
210static gboolean select_unit_image_callback(GtkWidget *w, GdkEvent *ev,
211 gpointer data);
212static gboolean select_more_arrow_pixmap_callback(GtkWidget *w, GdkEvent *ev,
213 gpointer data);
214static gboolean quit_dialog_callback(void);
215
216static void allied_chat_button_toggled(GtkToggleButton *button,
217 gpointer user_data);
218
219static void free_unit_table(void);
220
221static void adjust_default_options(void);
222
223/**********************************************************************/
226static void log_callback_utf8(enum log_level level, const char *message,
227 bool file_too)
228{
229 if (!file_too || level <= LOG_FATAL) {
230 fc_fprintf(stderr, "%d: %s\n", level, message);
231 }
232}
233
234/**********************************************************************/
238static gboolean timer_callback(gpointer data)
239{
240 double seconds = real_timer_callback();
241
242 timer_id = g_timeout_add(seconds * 1000, timer_callback, NULL);
243
244 return FALSE;
245}
246
247/**********************************************************************/
251static void print_usage(void)
252{
253 /* add client-specific usage information here */
254 fc_fprintf(stderr,
255 _("This client accepts the standard Gtk command-line options\n"
256 "after '--'. See the Gtk documentation.\n\n"));
257
258 fc_fprintf(stderr,
259 _("Other gui-specific options are:\n"));
260
261 fc_fprintf(stderr,
262 _("-r, --resolution WIDTHxHEIGHT\tAssume given resolution "
263 "screen\n"));
264
265 fc_fprintf(stderr, "\n");
266
267 /* TRANS: No full stop after the URL, could cause confusion. */
268 fc_fprintf(stderr, _("Report bugs at %s\n"), BUG_URL);
269}
270
271/**********************************************************************/
274static bool parse_options(int argc, char **argv)
275{
276 int i = 1;
277
278 while (i < argc) {
279 char *option = NULL;
280
281 if (is_option("--help", argv[i])) {
282 print_usage();
283
284 return FALSE;
285 } else if ((option = get_option_malloc("--resolution", argv, &i, argc, FALSE))) {
287 fc_fprintf(stderr, _("Illegal video mode '%s'\n"), option);
288 exit(EXIT_FAILURE);
289 }
290 free(option);
291 }
292 /* Can't check against unknown options, as those might be gtk options */
293
294 i++;
295 }
296
297 return TRUE;
298}
299
300/**********************************************************************/
303static gboolean toplevel_focus(GtkWidget *w, GtkDirectionType arg)
304{
305 switch (arg) {
306 case GTK_DIR_TAB_FORWARD:
307 case GTK_DIR_TAB_BACKWARD:
308
309 if (!gtk_widget_get_can_focus(w)) {
310 return FALSE;
311 }
312
313 if (!gtk_widget_is_focus(w)) {
314 gtk_widget_grab_focus(w);
315 return TRUE;
316 }
317 break;
318
319 default:
320 break;
321 }
322 return FALSE;
323}
324
325/**********************************************************************/
331 GtkAllocation *allocation,
332 gpointer data)
333{
334 static int old_width = 0, old_height = 0;
335
336 if (allocation->width != old_width
337 || allocation->height != old_height) {
339 old_width = allocation->width;
340 old_height = allocation->height;
341 }
342}
343
344/**********************************************************************/
347gboolean map_canvas_focus(void)
348{
349 gtk_window_present(GTK_WINDOW(toplevel));
350 gtk_notebook_set_current_page(GTK_NOTEBOOK(top_notebook), 0);
351 gtk_widget_grab_focus(map_canvas);
352 return TRUE;
353}
354
355/**********************************************************************/
364static gboolean toplevel_handler(GtkWidget *w, GdkEvent *ev, gpointer data)
365{
366 GtkWidget *focus;
367
368 focus = gtk_window_get_focus(GTK_WINDOW(toplevel));
369 if (focus) {
370 if (GTK_IS_ENTRY(focus)
371 || (GTK_IS_TEXT_VIEW(focus)
372 && gtk_text_view_get_editable(GTK_TEXT_VIEW(focus)))) {
373 /* Propagate event to currently focused entry widget. */
374 if (gtk_widget_event(focus, ev)) {
375 /* Do not propagate event to our children. */
376 return TRUE;
377 }
378 }
379 }
380
381 /* Continue propagating event to our children. */
382 return FALSE;
383}
384
385/**********************************************************************/
388static gboolean key_press_map_canvas(GtkWidget *w, GdkEventKey *ev,
389 gpointer data)
390{
391 if ((ev->state & GDK_SHIFT_MASK)) {
392 switch (ev->keyval) {
393
394 case GDK_KEY_Left:
395 scroll_mapview(DIR8_WEST);
396 return TRUE;
397
398 case GDK_KEY_Right:
399 scroll_mapview(DIR8_EAST);
400 return TRUE;
401
402 case GDK_KEY_Up:
403 scroll_mapview(DIR8_NORTH);
404 return TRUE;
405
406 case GDK_KEY_Down:
407 scroll_mapview(DIR8_SOUTH);
408 return TRUE;
409
410 case GDK_KEY_Home:
412 return TRUE;
413
414 case GDK_KEY_Page_Up:
415 g_signal_emit_by_name(main_message_area, "move_cursor",
416 GTK_MOVEMENT_PAGES, -1, FALSE);
417 return TRUE;
418
419 case GDK_KEY_Page_Down:
420 g_signal_emit_by_name(main_message_area, "move_cursor",
421 GTK_MOVEMENT_PAGES, 1, FALSE);
422 return TRUE;
423
424 default:
425 break;
426 }
427 } else if (!(ev->state & GDK_CONTROL_MASK)) {
428 switch (ev->keyval) {
429 default:
430 break;
431 }
432 }
433
434 if (ev->state & GDK_SHIFT_MASK) {
435 bool volchange = FALSE;
436
437 switch (ev->keyval) {
438 case GDK_KEY_plus:
439 case GDK_KEY_KP_Add:
441 volchange = TRUE;
442 break;
443
444 case GDK_KEY_minus:
445 case GDK_KEY_KP_Subtract:
447 volchange = TRUE;
448 break;
449
450 default:
451 break;
452 }
453
454 if (volchange) {
455 struct option *poption = optset_option_by_name(client_optset, "sound_effects_volume");
456
458 option_changed(poption);
459
460 return TRUE;
461 }
462 } else if (!(ev->state & GDK_CONTROL_MASK)) {
463 switch (ev->keyval) {
464 case GDK_KEY_plus:
465 case GDK_KEY_KP_Add:
466 zoom_step_up();
467 return TRUE;
468
469 case GDK_KEY_minus:
470 case GDK_KEY_KP_Subtract:
472 return TRUE;
473
474 default:
475 break;
476 }
477 }
478
479 /* Return here if observer */
480 if (client_is_observer()) {
481 return FALSE;
482 }
483
484 switch (ev->keyval) {
485
486 case GDK_KEY_KP_Up:
487 case GDK_KEY_KP_8:
488 case GDK_KEY_Up:
489 case GDK_KEY_8:
490 key_unit_move(DIR8_NORTH);
491 return TRUE;
492
493 case GDK_KEY_KP_Page_Up:
494 case GDK_KEY_KP_9:
495 case GDK_KEY_Page_Up:
496 case GDK_KEY_9:
497 key_unit_move(DIR8_NORTHEAST);
498 return TRUE;
499
500 case GDK_KEY_KP_Right:
501 case GDK_KEY_KP_6:
502 case GDK_KEY_Right:
503 case GDK_KEY_6:
504 key_unit_move(DIR8_EAST);
505 return TRUE;
506
507 case GDK_KEY_KP_Page_Down:
508 case GDK_KEY_KP_3:
509 case GDK_KEY_Page_Down:
510 case GDK_KEY_3:
511 key_unit_move(DIR8_SOUTHEAST);
512 return TRUE;
513
514 case GDK_KEY_KP_Down:
515 case GDK_KEY_KP_2:
516 case GDK_KEY_Down:
517 case GDK_KEY_2:
518 key_unit_move(DIR8_SOUTH);
519 return TRUE;
520
521 case GDK_KEY_KP_End:
522 case GDK_KEY_KP_1:
523 case GDK_KEY_End:
524 case GDK_KEY_1:
525 key_unit_move(DIR8_SOUTHWEST);
526 return TRUE;
527
528 case GDK_KEY_KP_Left:
529 case GDK_KEY_KP_4:
530 case GDK_KEY_Left:
531 case GDK_KEY_4:
532 key_unit_move(DIR8_WEST);
533 return TRUE;
534
535 case GDK_KEY_KP_Home:
536 case GDK_KEY_KP_7:
537 case GDK_KEY_Home:
538 case GDK_KEY_7:
539 key_unit_move(DIR8_NORTHWEST);
540 return TRUE;
541
542 case GDK_KEY_KP_Begin:
543 case GDK_KEY_KP_5:
544 case GDK_KEY_5:
546 return TRUE;
547
548 case GDK_KEY_Escape:
550 return TRUE;
551
552 case GDK_KEY_b:
555 return TRUE;
556 }
557 break;
558
559 default:
560 break;
561 };
562
563 return FALSE;
564}
565
566/**********************************************************************/
569static gboolean toplevel_key_release_handler(GtkWidget *w, GdkEventKey *ev,
570 gpointer data)
571{
572 /* inputline history code */
573 if (!gtk_widget_get_mapped(top_vbox) || inputline_has_focus()) {
574 return FALSE;
575 }
576
577 if (editor_is_active()) {
578 return handle_edit_key_release(ev);
579 }
580
581 return FALSE;
582}
583
584/**********************************************************************/
587static gboolean toplevel_key_press_handler(GtkWidget *w, GdkEventKey *ev,
588 gpointer data)
589{
590 if (inputline_has_focus()) {
591 return FALSE;
592 }
593
594 if (ev->keyval == GDK_KEY_apostrophe) {
595 /* Allow this even if not in main map view; chatline is present on
596 * some other pages too */
597
598 /* Make the chatline visible if it's not currently.
599 * FIXME: should find the correct window, even when detached, from any
600 * other window; should scroll to the bottom automatically showing the
601 * latest text from other players; MUST NOT make spurious text windows
602 * at the bottom of other dialogs. */
603 if (gtk_widget_get_mapped(top_vbox)) {
604 /* The main game view is visible. May need to switch notebook. */
605 if (GUI_GTK_OPTION(message_chat_location) == GUI_GTK_MSGCHAT_MERGED) {
606 gtk_notebook_set_current_page(GTK_NOTEBOOK(top_notebook), 1);
607 } else {
608 gtk_notebook_set_current_page(GTK_NOTEBOOK(bottom_notebook), 0);
609 }
610 }
611
612 /* If the chatline is (now) visible, focus it. */
613 if (inputline_is_visible()) {
615 return TRUE;
616 }
617 }
618
619 if (!gtk_widget_get_mapped(top_vbox)
621 return FALSE;
622 }
623
624 if (editor_is_active()) {
625 if (handle_edit_key_press(ev)) {
626 return TRUE;
627 }
628 }
629
630 if (ev->state & GDK_SHIFT_MASK) {
631 switch (ev->keyval) {
632
633 case GDK_KEY_Return:
634 case GDK_KEY_KP_Enter:
635 key_end_turn();
636 return TRUE;
637
638 default:
639 break;
640 }
641 }
642
643 if (0 == gtk_notebook_get_current_page(GTK_NOTEBOOK(top_notebook))) {
644 /* 0 means the map view is focused. */
645 return key_press_map_canvas(w, ev, data);
646 }
647
648#if 0
649 /* We are focused some other dialog, tab, or widget. */
650 if ((ev->state & GDK_CONTROL_MASK)) {
651 } else if ((ev->state & GDK_SHIFT_MASK)) {
652 } else {
653 switch (ev->keyval) {
654
655 case GDK_KEY_F4:
657 return TRUE;
658
659 default:
660 break;
661 };
662 }
663#endif /* 0 */
664
665 return FALSE;
666}
667
668/**********************************************************************/
671static gboolean mouse_scroll_mapcanvas(GtkWidget *w, GdkEventScroll *ev)
672{
673 int scroll_x, scroll_y, xstep, ystep;
674
675 if (!can_client_change_view()) {
676 return FALSE;
677 }
678
679 get_mapview_scroll_pos(&scroll_x, &scroll_y);
680 get_mapview_scroll_step(&xstep, &ystep);
681
682 switch (ev->direction) {
683 case GDK_SCROLL_UP:
684 scroll_y -= ystep*2;
685 break;
686 case GDK_SCROLL_DOWN:
687 scroll_y += ystep*2;
688 break;
689 case GDK_SCROLL_RIGHT:
690 scroll_x += xstep*2;
691 break;
692 case GDK_SCROLL_LEFT:
693 scroll_x -= xstep*2;
694 break;
695 default:
696 return FALSE;
697 };
698
699 set_mapview_scroll_pos(scroll_x, scroll_y, mouse_zoom);
700
701 /* Emulating mouse move now */
702 if (!gtk_widget_has_focus(map_canvas)) {
703 gtk_widget_grab_focus(map_canvas);
704 }
705
706 update_line(ev->x, ev->y);
707 if (rbutton_down && (ev->state & GDK_BUTTON3_MASK)) {
708 update_selection_rectangle(ev->x, ev->y);
709 }
710
713 }
714
716
717 return TRUE;
718}
719
720/**********************************************************************/
723static void tearoff_destroy(GtkWidget *w, gpointer data)
724{
725 GtkWidget *p, *b, *box;
726 GtkWidget *old_parent;
727
728 box = GTK_WIDGET(data);
729 old_parent = gtk_widget_get_parent(box);
730 p = g_object_get_data(G_OBJECT(w), "parent");
731 b = g_object_get_data(G_OBJECT(w), "toggle");
732 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b), FALSE);
733
734 gtk_widget_hide(w);
735
736 g_object_ref(box); /* Make sure reference count stays above 0
737 * during the transition to new parent. */
738 gtk_container_remove(GTK_CONTAINER(old_parent), box);
739 gtk_container_add(GTK_CONTAINER(p), box);
740 g_object_unref(box);
741}
742
743/**********************************************************************/
746static gboolean propagate_keypress(GtkWidget *w, GdkEvent *ev)
747{
748 gtk_widget_event(toplevel, ev);
749
750 return FALSE;
751}
752
753/**********************************************************************/
757static void tearoff_callback(GtkWidget *b, gpointer data)
758{
759 GtkWidget *box = GTK_WIDGET(data);
760
761 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b))) {
762 GtkWidget *old_parent;
763 GtkWidget *w;
764 GtkWidget *temp_hide;
765
766 old_parent = gtk_widget_get_parent(box);
767 w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
769 gtk_widget_set_name(w, "Freeciv");
770 gtk_window_set_title(GTK_WINDOW(w), _("Freeciv"));
771 gtk_window_set_position(GTK_WINDOW(w), GTK_WIN_POS_MOUSE);
772 g_signal_connect(w, "destroy", G_CALLBACK(tearoff_destroy), box);
773 g_signal_connect(w, "key_press_event",
774 G_CALLBACK(propagate_keypress), NULL);
775
776 g_object_set_data(G_OBJECT(w), "parent", gtk_widget_get_parent(box));
777 g_object_set_data(G_OBJECT(w), "toggle", b);
778
779 temp_hide = g_object_get_data(G_OBJECT(box), "hide-over-reparent");
780 if (temp_hide != NULL) {
781 gtk_widget_hide(temp_hide);
782 }
783
784 g_object_ref(box); /* Make sure reference count stays above 0
785 * during the transition to new parent. */
786 gtk_container_remove(GTK_CONTAINER(old_parent), box);
787 gtk_container_add(GTK_CONTAINER(w), box);
788 g_object_unref(box);
789 gtk_widget_show(w);
790
791 if (temp_hide != NULL) {
792 gtk_widget_show(temp_hide);
793 }
794 } else {
795 gtk_widget_destroy(gtk_widget_get_parent(box));
796 }
797}
798
799/**********************************************************************/
802static GtkWidget *detached_widget_new(void)
803{
804 GtkWidget *hgrid = gtk_grid_new();
805 gtk_grid_set_column_spacing(GTK_GRID(hgrid), 2);
806 return hgrid;
807}
808
809/**********************************************************************/
813static GtkWidget *detached_widget_fill(GtkWidget *tearbox)
814{
815 GtkWidget *b, *fillbox;
816 static GtkCssProvider *detach_button_provider = NULL;
817
818 if (detach_button_provider == NULL) {
819 detach_button_provider = gtk_css_provider_new();
820
821 /* These toggle buttons run vertically down the side of many UI
822 * elements, so they need to be thin horizontally. */
823 gtk_css_provider_load_from_data(detach_button_provider,
824 ".detach_button {\n"
825 " padding: 0px 0px 0px 0px;\n"
826 " min-width: 6px;\n"
827 "}",
828 -1, NULL);
829 }
830
831 b = gtk_toggle_button_new();
832 gtk_style_context_add_provider(gtk_widget_get_style_context(b),
833 GTK_STYLE_PROVIDER(detach_button_provider),
834 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
835 gtk_style_context_add_class(gtk_widget_get_style_context(b),
836 "detach_button");
837 gtk_widget_set_tooltip_text(b, _("Detach/Attach the pane."));
838
839 gtk_container_add(GTK_CONTAINER(tearbox), b);
840 g_signal_connect(b, "toggled", G_CALLBACK(tearoff_callback), tearbox);
841
842 fillbox = gtk_grid_new();
843 gtk_orientable_set_orientation(GTK_ORIENTABLE(fillbox),
844 GTK_ORIENTATION_VERTICAL);
845
846 gtk_container_add(GTK_CONTAINER(tearbox), fillbox);
847
848 return fillbox;
849}
850
851/**********************************************************************/
859{
860 int i, width;
861 GtkWidget *table = unit_image_table;
862 GdkPixbuf *pix;
863 int ttw;
864
865 /* Get width of the overview window */
869
871
872 if (GUI_GTK_OPTION(small_display_layout)) {
873 /* We want arrow to appear if there is other units in addition
874 to active one in tile. Active unit is not counted, so there
875 can be 0 other units to not to display arrow. */
876 num_units_below = 1 - 1;
877 } else {
878 num_units_below = width / ttw;
880 }
881
882 /* Top row: the active unit. */
883 /* Note, we ref this and other widgets here so that we can unref them
884 * in reset_unit_table. */
885 unit_image = gtk_image_new();
886 gtk_widget_add_events(unit_image, GDK_BUTTON_PRESS_MASK);
887 g_object_ref(unit_image);
888 unit_image_button = gtk_event_box_new();
889 gtk_widget_set_size_request(unit_image_button, ttw, -1);
890 gtk_event_box_set_visible_window(GTK_EVENT_BOX(unit_image_button), FALSE);
891 g_object_ref(unit_image_button);
892 gtk_container_add(GTK_CONTAINER(unit_image_button), unit_image);
893 gtk_grid_attach(GTK_GRID(table), unit_image_button, 0, 0, 1, 1);
894 g_signal_connect(unit_image_button, "button_press_event",
895 G_CALLBACK(select_unit_image_callback),
896 GINT_TO_POINTER(-1));
897
898 if (!GUI_GTK_OPTION(small_display_layout)) {
899 /* Bottom row: other units in the same tile. */
900 for (i = 0; i < num_units_below; i++) {
901 unit_below_image[i] = gtk_image_new();
902 g_object_ref(unit_below_image[i]);
903 gtk_widget_add_events(unit_below_image[i], GDK_BUTTON_PRESS_MASK);
904 unit_below_image_button[i] = gtk_event_box_new();
905 g_object_ref(unit_below_image_button[i]);
906 gtk_widget_set_size_request(unit_below_image_button[i], ttw, -1);
907 gtk_event_box_set_visible_window(GTK_EVENT_BOX(unit_below_image_button[i]),
908 FALSE);
909 gtk_container_add(GTK_CONTAINER(unit_below_image_button[i]),
911 g_signal_connect(unit_below_image_button[i],
912 "button_press_event",
913 G_CALLBACK(select_unit_image_callback),
914 GINT_TO_POINTER(i));
915
916 gtk_grid_attach(GTK_GRID(table), unit_below_image_button[i],
917 i, 1, 1, 1);
918 }
919 }
920
921 /* Create arrow (popup for all units on the selected tile) */
923 more_arrow_pixmap = gtk_image_new_from_pixbuf(pix);
924 g_object_ref(more_arrow_pixmap);
925 more_arrow_pixmap_button = gtk_event_box_new();
926 g_object_ref(more_arrow_pixmap_button);
927 gtk_event_box_set_visible_window(GTK_EVENT_BOX(more_arrow_pixmap_button),
928 FALSE);
929 gtk_container_add(GTK_CONTAINER(more_arrow_pixmap_button),
931 g_signal_connect(more_arrow_pixmap_button,
932 "button_press_event",
933 G_CALLBACK(select_more_arrow_pixmap_callback), NULL);
934 /* An extra layer so that we can hide the clickable button but keep
935 * an explicit size request to avoid the layout jumping around */
936 more_arrow_pixmap_container = gtk_frame_new(NULL);
937 gtk_frame_set_shadow_type(GTK_FRAME(more_arrow_pixmap_container), GTK_SHADOW_NONE);
938 gtk_widget_set_halign(more_arrow_pixmap_container, GTK_ALIGN_CENTER);
939 gtk_widget_set_valign(more_arrow_pixmap_container, GTK_ALIGN_CENTER);
940 g_object_ref(more_arrow_pixmap_container);
941 gtk_container_add(GTK_CONTAINER(more_arrow_pixmap_container),
943 gtk_widget_set_size_request(more_arrow_pixmap_container,
944 gdk_pixbuf_get_width(pix), -1);
945 g_object_unref(G_OBJECT(pix));
946
947 if (!GUI_GTK_OPTION(small_display_layout)) {
948 /* Display on bottom row. */
949 gtk_grid_attach(GTK_GRID(table), more_arrow_pixmap_container,
950 num_units_below, 1, 1, 1);
951 } else {
952 /* Display on top row (there is no bottom row). */
953 gtk_grid_attach(GTK_GRID(table), more_arrow_pixmap_container,
954 1, 0, 1, 1);
955 }
956
957 gtk_widget_show_all(table);
958}
959
960/**********************************************************************/
963static void free_unit_table(void)
964{
965 if (unit_image_button) {
966 gtk_container_remove(GTK_CONTAINER(unit_image_table),
968 g_object_unref(unit_image);
969 g_object_unref(unit_image_button);
970 if (!GUI_GTK_OPTION(small_display_layout)) {
971 int i;
972
973 for (i = 0; i < num_units_below; i++) {
974 gtk_container_remove(GTK_CONTAINER(unit_image_table),
976 g_object_unref(unit_below_image[i]);
977 g_object_unref(unit_below_image_button[i]);
978 }
979 }
980 gtk_container_remove(GTK_CONTAINER(unit_image_table),
982 g_object_unref(more_arrow_pixmap);
983 g_object_unref(more_arrow_pixmap_button);
984 g_object_unref(more_arrow_pixmap_container);
985 }
986}
987
988/**********************************************************************/
992{
993 /* Unreference all of the widgets that we're about to reallocate, thus
994 * avoiding a memory leak. Remove them from the container first, just
995 * to be safe. Note, the widgets are ref'd in
996 * populate_unit_image_table. */
998
1000
1001 /* We have to force a redraw of the units. And we explicitly have
1002 * to force a redraw of the focus unit, which is normally only
1003 * redrawn when the focus changes. We also have to force the 'more'
1004 * arrow to go away, both by expicitly hiding it and telling it to
1005 * do so (this will be reset immediately afterwards if necessary,
1006 * but we have to make the *internal* state consistent). */
1007 gtk_widget_hide(more_arrow_pixmap_button);
1009 if (get_num_units_in_focus() == 1) {
1011 } else {
1012 set_unit_icon(-1, NULL);
1013 }
1015}
1016
1017/**********************************************************************/
1021{
1022 if (enable) {
1024 /* Ensure the menus are really created before performing any operations
1025 * on them. */
1026 while (gtk_events_pending()) {
1027 gtk_main_iteration();
1028 }
1029 gtk_grid_attach_next_to(GTK_GRID(top_vbox), main_menubar, NULL, GTK_POS_TOP, 1, 1);
1030 menus_init();
1031 gtk_widget_show_all(main_menubar);
1032 } else {
1033 gtk_widget_destroy(main_menubar);
1034 }
1035}
1036
1037/**********************************************************************/
1043static gboolean right_notebook_button_release(GtkWidget *widget,
1044 GdkEventButton *event)
1045{
1046 if (event->type != GDK_BUTTON_RELEASE) {
1047 return FALSE;
1048 }
1049
1050 if (!GTK_IS_NOTEBOOK(widget)
1051 || -1 == gtk_notebook_get_current_page(GTK_NOTEBOOK(widget))) {
1052 /* Make sure the default gtk handler
1053 * does NOT get called in this case. */
1054 return TRUE;
1055 }
1056
1057 return FALSE;
1058}
1059
1060/**********************************************************************/
1063#if 0
1064static void setup_canvas_color_for_state(GtkStateFlags state)
1065{
1066 gtk_widget_override_background_color(GTK_WIDGET(overview_canvas), state,
1067 &get_color(tileset, COLOR_OVERVIEW_UNKNOWN)->color);
1068 gtk_widget_override_background_color(GTK_WIDGET(map_canvas), state,
1069 &get_color(tileset, COLOR_OVERVIEW_UNKNOWN)->color);
1070}
1071#endif
1072
1073/**********************************************************************/
1077{
1078 struct option *opt = optset_option_by_name(server_optset, "fixedlength");
1079
1080 if (opt != NULL && option_bool_get(opt)) {
1081 gtk_widget_set_tooltip_text(turn_done_button,
1082 _("Fixed length turns"));
1083 } else {
1084 char buf[256];
1085
1086 fc_snprintf(buf, sizeof(buf), "%s:\n%s",
1087 _("Turn Done"), _("Shift+Return"));
1088 gtk_widget_set_tooltip_text(turn_done_button, buf);
1089 }
1090}
1091
1092/**********************************************************************/
1095static void setup_widgets(void)
1096{
1097 GtkWidget *page, *ebox, *hgrid, *hgrid2, *label;
1098 GtkWidget *frame, *table, *table2, *paned, *sw, *text;
1099 GtkWidget *button, *view, *vgrid, *right_vbox = NULL;
1100 int i;
1101 GtkWidget *notebook, *statusbar;
1102 GtkWidget *dtach_lowbox = NULL;
1103 struct sprite *spr;
1104
1105 message_buffer = gtk_text_buffer_new(NULL);
1106
1107 notebook = gtk_notebook_new();
1108
1109 /* Stop mouse wheel notebook page switching. */
1110 g_signal_connect(notebook, "scroll_event",
1111 G_CALLBACK(gtk_true), NULL);
1112
1113 toplevel_tabs = notebook;
1114 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
1115 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
1116 vgrid = gtk_grid_new();
1117 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1118 GTK_ORIENTATION_VERTICAL);
1119 gtk_grid_set_row_spacing(GTK_GRID(vgrid), 4);
1120 gtk_container_add(GTK_CONTAINER(toplevel), vgrid);
1121 gtk_container_add(GTK_CONTAINER(vgrid), notebook);
1123 gtk_container_add(GTK_CONTAINER(vgrid), statusbar);
1124
1125 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1126 create_main_page(), NULL);
1127 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1128 create_start_page(), NULL);
1129 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1130 create_scenario_page(), NULL);
1131 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1132 create_load_page(), NULL);
1133 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
1134 create_network_page(), NULL);
1135
1137
1139 g_object_set(ingame_votebar, "margin", 2, NULL);
1140
1141 /* *** everything in the top *** */
1142
1143 page = gtk_scrolled_window_new(NULL, NULL);
1144 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(page),
1145 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1146 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(page),
1147 GTK_SHADOW_ETCHED_IN);
1148 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, NULL);
1149
1150 top_vbox = gtk_grid_new();
1151 gtk_orientable_set_orientation(GTK_ORIENTABLE(top_vbox),
1152 GTK_ORIENTATION_VERTICAL);
1153 gtk_grid_set_row_spacing(GTK_GRID(top_vbox), 5);
1154 hgrid = gtk_grid_new();
1155
1156 if (GUI_GTK_OPTION(small_display_layout)) {
1157 /* The window is divided into two horizontal panels: overview +
1158 * civinfo + unitinfo, main view + message window. */
1159 right_vbox = gtk_grid_new();
1160 gtk_orientable_set_orientation(GTK_ORIENTABLE(right_vbox),
1161 GTK_ORIENTATION_VERTICAL);
1162 gtk_container_add(GTK_CONTAINER(hgrid), right_vbox);
1163
1164 paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
1165 gtk_container_add(GTK_CONTAINER(page), top_vbox);
1166 gtk_container_add(GTK_CONTAINER(top_vbox), hgrid);
1167 gtk_container_add(GTK_CONTAINER(right_vbox), paned);
1168 gtk_container_add(GTK_CONTAINER(right_vbox), ingame_votebar);
1169
1170 /* Overview size designed for small displays (netbooks). */
1173 } else {
1174 /* The window is divided into two vertical panes: overview +
1175 * + civinfo + unitinfo + main view, message window. */
1176 paned = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
1177 gtk_container_add(GTK_CONTAINER(page), paned);
1178 gtk_paned_pack1(GTK_PANED(paned), top_vbox, TRUE, FALSE);
1179 gtk_container_add(GTK_CONTAINER(top_vbox), hgrid);
1180
1181 /* Overview size designed for big displays (desktops). */
1184 }
1185
1186 /* this holds the overview canvas, production info, etc. */
1187 vgrid = gtk_grid_new();
1188 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1189 GTK_ORIENTATION_VERTICAL);
1190 gtk_grid_set_column_spacing(GTK_GRID(vgrid), 3);
1191 /* Put vgrid to the left of anything else in hgrid -- right_vbox is either
1192 * the chat/messages pane, or NULL which is OK */
1193 gtk_grid_attach_next_to(GTK_GRID(hgrid), vgrid, right_vbox,
1194 GTK_POS_LEFT, 1, 1);
1195
1196 /* Overview canvas */
1198 gtk_widget_set_hexpand(ahbox, FALSE);
1199 gtk_widget_set_vexpand(ahbox, FALSE);
1200 gtk_container_add(GTK_CONTAINER(vgrid), ahbox);
1202
1203 overview_scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1204 gtk_container_set_border_width(GTK_CONTAINER (overview_scrolled_window), 1);
1205 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (overview_scrolled_window),
1206 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1207
1208 overview_canvas = gtk_drawing_area_new();
1209 gtk_widget_set_halign(overview_canvas, GTK_ALIGN_CENTER);
1210 gtk_widget_set_valign(overview_canvas, GTK_ALIGN_CENTER);
1211 gtk_widget_set_size_request(overview_canvas, overview_canvas_store_width,
1213 gtk_widget_set_size_request(overview_scrolled_window, overview_canvas_store_width,
1215 gtk_widget_set_hexpand(overview_canvas, TRUE);
1216 gtk_widget_set_vexpand(overview_canvas, TRUE);
1217
1218 gtk_widget_add_events(overview_canvas, GDK_EXPOSURE_MASK
1219 |GDK_BUTTON_PRESS_MASK
1220 |GDK_POINTER_MOTION_MASK);
1221 gtk_container_add(GTK_CONTAINER(avbox), overview_scrolled_window);
1222
1223 gtk_container_add(GTK_CONTAINER(overview_scrolled_window),
1225
1226 g_signal_connect(overview_canvas, "draw",
1227 G_CALLBACK(overview_canvas_draw), NULL);
1228
1229 g_signal_connect(overview_canvas, "motion_notify_event",
1230 G_CALLBACK(move_overviewcanvas), NULL);
1231
1232 g_signal_connect(overview_canvas, "button_press_event",
1233 G_CALLBACK(butt_down_overviewcanvas), NULL);
1234
1235 /* The rest */
1236
1238 gtk_container_add(GTK_CONTAINER(vgrid), ahbox);
1239 gtk_widget_set_hexpand(ahbox, FALSE);
1241 gtk_widget_set_vexpand(avbox, TRUE);
1242 gtk_widget_set_valign(avbox, GTK_ALIGN_FILL);
1243
1244 /* Info on player's civilization, when game is running. */
1245 frame = gtk_frame_new("");
1246 gtk_container_add(GTK_CONTAINER(avbox), frame);
1247
1248 main_frame_civ_name = frame;
1249
1250 vgrid = gtk_grid_new();
1251 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1252 GTK_ORIENTATION_VERTICAL);
1253 gtk_container_add(GTK_CONTAINER(frame), vgrid);
1254 gtk_widget_set_hexpand(vgrid, TRUE);
1255
1256 ebox = gtk_event_box_new();
1257 gtk_widget_add_events(ebox, GDK_BUTTON_PRESS_MASK);
1258 gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
1259 g_signal_connect(ebox, "button_press_event",
1260 G_CALLBACK(show_info_popup), NULL);
1261 gtk_container_add(GTK_CONTAINER(vgrid), ebox);
1262
1263 label = gtk_label_new(NULL);
1264 gtk_widget_set_halign(label, GTK_ALIGN_START);
1265 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
1266 gtk_widget_set_margin_start(label, 2);
1267 gtk_widget_set_margin_end(label, 2);
1268 gtk_widget_set_margin_top(label, 2);
1269 gtk_widget_set_margin_bottom(label, 2);
1270 gtk_container_add(GTK_CONTAINER(ebox), label);
1271 main_label_info = label;
1272
1273 /* Production status */
1274 table = gtk_grid_new();
1275 gtk_widget_set_halign(table, GTK_ALIGN_CENTER);
1276 gtk_grid_set_column_homogeneous(GTK_GRID(table), TRUE);
1277 gtk_container_add(GTK_CONTAINER(avbox), table);
1278
1279 /* Citizens for taxrates */
1280 ebox = gtk_event_box_new();
1281 gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
1282 gtk_grid_attach(GTK_GRID(table), ebox, 0, 0, 10, 1);
1283 econ_ebox = ebox;
1284
1285 table2 = gtk_grid_new();
1286 gtk_container_add(GTK_CONTAINER(ebox), table2);
1287
1288 for (i = 0; i < 10; i++) {
1289 ebox = gtk_event_box_new();
1290 gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
1291 gtk_widget_add_events(ebox, GDK_BUTTON_PRESS_MASK);
1292
1293 gtk_grid_attach(GTK_GRID(table2), ebox, i, 0, 1, 1);
1294
1295 g_signal_connect(ebox, "button_press_event",
1296 G_CALLBACK(taxrates_callback), GINT_TO_POINTER(i));
1297
1299 econ_label[i] = gtk_image_new_from_surface(spr->surface);
1300 gtk_container_add(GTK_CONTAINER(ebox), econ_label[i]);
1301 }
1302
1303 /* Science, environmental, govt, timeout */
1304 spr = client_research_sprite();
1305 if (spr != NULL) {
1306 bulb_label = gtk_image_new_from_surface(spr->surface);
1307 } else {
1308 bulb_label = gtk_image_new();
1309 }
1310
1311 spr = client_warming_sprite();
1312 if (spr != NULL) {
1313 sun_label = gtk_image_new_from_surface(spr->surface);
1314 } else {
1315 sun_label = gtk_image_new();
1316 }
1317
1318 spr = client_cooling_sprite();
1319 if (spr != NULL) {
1320 flake_label = gtk_image_new_from_surface(spr->surface);
1321 } else {
1322 flake_label = gtk_image_new();
1323 }
1324
1326 if (spr != NULL) {
1327 government_label = gtk_image_new_from_surface(spr->surface);
1328 } else {
1329 government_label = gtk_image_new();
1330 }
1331
1332 for (i = 0; i < 4; i++) {
1333 GtkWidget *w;
1334
1335 ebox = gtk_event_box_new();
1336 gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
1337
1338 switch (i) {
1339 case 0:
1340 w = bulb_label;
1341 bulb_ebox = ebox;
1342 break;
1343 case 1:
1344 w = sun_label;
1345 sun_ebox = ebox;
1346 break;
1347 case 2:
1348 w = flake_label;
1349 flake_ebox = ebox;
1350 break;
1351 default:
1352 case 3:
1353 w = government_label;
1354 government_ebox = ebox;
1355 break;
1356 }
1357
1358 gtk_widget_set_halign(w, GTK_ALIGN_START);
1359 gtk_widget_set_valign(w, GTK_ALIGN_START);
1360 gtk_widget_set_margin_start(w, 0);
1361 gtk_widget_set_margin_end(w, 0);
1362 gtk_widget_set_margin_top(w, 0);
1363 gtk_widget_set_margin_bottom(w, 0);
1364 gtk_container_add(GTK_CONTAINER(ebox), w);
1365 gtk_grid_attach(GTK_GRID(table), ebox, i, 1, 1, 1);
1366 }
1367
1368 timeout_label = gtk_label_new("");
1369
1370 frame = gtk_frame_new(NULL);
1371 gtk_grid_attach(GTK_GRID(table), frame, 4, 1, 6, 1);
1372 gtk_container_add(GTK_CONTAINER(frame), timeout_label);
1373
1374
1375 /* Turn done */
1376 turn_done_button = gtk_button_new_with_label(_("Turn Done"));
1377
1378 gtk_grid_attach(GTK_GRID(table), turn_done_button, 0, 2, 10, 1);
1379
1380 g_signal_connect(turn_done_button, "clicked",
1381 G_CALLBACK(end_turn_callback), NULL);
1383
1384 /* Selected unit status */
1385
1386 unit_info_box = gtk_grid_new();
1387 gtk_widget_set_hexpand(unit_info_box, FALSE);
1388 gtk_orientable_set_orientation(GTK_ORIENTABLE(unit_info_box),
1389 GTK_ORIENTATION_VERTICAL);
1390 gtk_container_add(GTK_CONTAINER(avbox), unit_info_box);
1391
1392 /* In edit mode the unit_info_box widget is replaced by the
1393 * editinfobox, so we need to add a ref here so that it is
1394 * not destroyed when removed from its container.
1395 * See editinfobox_refresh(). */
1396 g_object_ref(unit_info_box);
1397
1398 unit_info_frame = gtk_frame_new("");
1399 gtk_container_add(GTK_CONTAINER(unit_info_box), unit_info_frame);
1400
1401 sw = gtk_scrolled_window_new(NULL, NULL);
1402 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1403 GTK_SHADOW_OUT);
1404 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1405 GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
1406 gtk_container_add(GTK_CONTAINER(unit_info_frame), sw);
1407
1408 label = gtk_label_new(NULL);
1409 gtk_widget_set_hexpand(label, TRUE);
1410 gtk_widget_set_halign(label, GTK_ALIGN_START);
1411 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
1412 gtk_widget_set_margin_start(label, 2);
1413 gtk_widget_set_margin_end(label, 2);
1414 gtk_widget_set_margin_top(label, 2);
1415 gtk_widget_set_margin_bottom(label, 2);
1416 gtk_container_add(GTK_CONTAINER(sw), label);
1417 unit_info_label = label;
1418
1419 hgrid2 = gtk_grid_new();
1420 gtk_container_add(GTK_CONTAINER(unit_info_box), hgrid2);
1421
1422 table = gtk_grid_new();
1423 g_object_set(table, "margin", 5, NULL);
1424 gtk_container_add(GTK_CONTAINER(hgrid2), table);
1425
1426 gtk_grid_set_row_spacing(GTK_GRID(table), 2);
1427 gtk_grid_set_column_spacing(GTK_GRID(table), 2);
1428
1429 unit_image_table = table;
1430
1431 /* Map canvas, editor toolbar, and scrollbars */
1432
1433 /* The top notebook containing the map view and dialogs. */
1434
1435 top_notebook = gtk_notebook_new();
1436 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(top_notebook), GTK_POS_BOTTOM);
1437 gtk_notebook_set_scrollable(GTK_NOTEBOOK(top_notebook), TRUE);
1438
1439
1440 if (GUI_GTK_OPTION(small_display_layout)) {
1441 gtk_paned_pack1(GTK_PANED(paned), top_notebook, TRUE, FALSE);
1442 } else if (GUI_GTK_OPTION(message_chat_location) == GUI_GTK_MSGCHAT_MERGED) {
1443 right_vbox = gtk_grid_new();
1444 gtk_orientable_set_orientation(GTK_ORIENTABLE(right_vbox),
1445 GTK_ORIENTATION_VERTICAL);
1446
1447 gtk_container_add(GTK_CONTAINER(right_vbox), top_notebook);
1448 gtk_container_add(GTK_CONTAINER(right_vbox), ingame_votebar);
1449 gtk_container_add(GTK_CONTAINER(hgrid), right_vbox);
1450 } else {
1451 gtk_container_add(GTK_CONTAINER(hgrid), top_notebook);
1452 }
1453
1454 map_widget = gtk_grid_new();
1455
1456 vgrid = gtk_grid_new();
1457 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1458 GTK_ORIENTATION_VERTICAL);
1459 gtk_container_add(GTK_CONTAINER(vgrid), map_widget);
1460
1461 gtk_container_add(GTK_CONTAINER(vgrid), editgui_get_editbar()->widget);
1462 g_object_set(editgui_get_editbar()->widget, "margin", 4, NULL);
1463
1464 label = gtk_label_new(Q_("?noun:View"));
1465 gtk_notebook_append_page(GTK_NOTEBOOK(top_notebook), vgrid, label);
1466
1467 frame = gtk_frame_new(NULL);
1468 gtk_grid_attach(GTK_GRID(map_widget), frame, 0, 0, 1, 1);
1469
1470 map_canvas = gtk_drawing_area_new();
1471 gtk_widget_set_hexpand(map_canvas, TRUE);
1472 gtk_widget_set_vexpand(map_canvas, TRUE);
1473 gtk_widget_set_size_request(map_canvas, 300, 300);
1474 gtk_widget_set_can_focus(map_canvas, TRUE);
1475
1476#if 0
1477 setup_canvas_color_for_state(GTK_STATE_FLAG_NORMAL);
1478 setup_canvas_color_for_state(GTK_STATE_FLAG_ACTIVE);
1479 setup_canvas_color_for_state(GTK_STATE_FLAG_PRELIGHT);
1480 setup_canvas_color_for_state(GTK_STATE_FLAG_SELECTED);
1481 setup_canvas_color_for_state(GTK_STATE_FLAG_INSENSITIVE);
1482 setup_canvas_color_for_state(GTK_STATE_FLAG_INCONSISTENT);
1483 setup_canvas_color_for_state(GTK_STATE_FLAG_FOCUSED);
1484 setup_canvas_color_for_state(GTK_STATE_FLAG_BACKDROP);
1485#endif /* 0 */
1486
1487 gtk_widget_add_events(map_canvas, GDK_EXPOSURE_MASK
1488 |GDK_BUTTON_PRESS_MASK
1489 |GDK_BUTTON_RELEASE_MASK
1490 |GDK_KEY_PRESS_MASK
1491 |GDK_POINTER_MOTION_MASK
1492 |GDK_SCROLL_MASK);
1493
1494 gtk_container_add(GTK_CONTAINER(frame), map_canvas);
1495
1497 gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, NULL);
1498 gtk_grid_attach(GTK_GRID(map_widget), map_horizontal_scrollbar, 0, 1, 1, 1);
1499
1501 gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, NULL);
1502 gtk_grid_attach(GTK_GRID(map_widget), map_vertical_scrollbar, 1, 0, 1, 1);
1503
1504 g_signal_connect(map_canvas, "draw",
1505 G_CALLBACK(map_canvas_draw), NULL);
1506
1507 g_signal_connect(map_canvas, "configure_event",
1508 G_CALLBACK(map_canvas_configure), NULL);
1509
1510 g_signal_connect(map_canvas, "motion_notify_event",
1511 G_CALLBACK(move_mapcanvas), NULL);
1512
1513 g_signal_connect(toplevel, "enter_notify_event",
1514 G_CALLBACK(leave_mapcanvas), NULL);
1515
1516 g_signal_connect(map_canvas, "button_press_event",
1517 G_CALLBACK(butt_down_mapcanvas), NULL);
1518
1519 g_signal_connect(map_canvas, "button_release_event",
1520 G_CALLBACK(butt_release_mapcanvas), NULL);
1521
1522 g_signal_connect(map_canvas, "scroll_event",
1523 G_CALLBACK(mouse_scroll_mapcanvas), NULL);
1524
1525 g_signal_connect(toplevel, "key_press_event",
1526 G_CALLBACK(toplevel_key_press_handler), NULL);
1527
1528 g_signal_connect(toplevel, "key_release_event",
1529 G_CALLBACK(toplevel_key_release_handler), NULL);
1530
1531 /* *** The message window -- this is a detachable widget *** */
1532
1533 if (GUI_GTK_OPTION(message_chat_location) == GUI_GTK_MSGCHAT_MERGED) {
1534 bottom_hpaned = paned;
1536 } else {
1537 GtkWidget *hpaned;
1538
1539 dtach_lowbox = detached_widget_new();
1540 gtk_paned_pack2(GTK_PANED(paned), dtach_lowbox, FALSE, TRUE);
1541 avbox = detached_widget_fill(dtach_lowbox);
1542
1543 vgrid = gtk_grid_new();
1544 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1545 GTK_ORIENTATION_VERTICAL);
1546 if (!GUI_GTK_OPTION(small_display_layout)) {
1547 gtk_container_add(GTK_CONTAINER(vgrid), ingame_votebar);
1548 }
1549 gtk_container_add(GTK_CONTAINER(avbox), vgrid);
1550
1551 if (GUI_GTK_OPTION(small_display_layout)) {
1552 hpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
1553 } else {
1554 hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
1555 }
1556 gtk_container_add(GTK_CONTAINER(vgrid), hpaned);
1557 g_object_set(hpaned, "margin", 4, NULL);
1558 bottom_hpaned = hpaned;
1559
1560 bottom_notebook = gtk_notebook_new();
1561 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(bottom_notebook), GTK_POS_TOP);
1562 gtk_notebook_set_scrollable(GTK_NOTEBOOK(bottom_notebook), TRUE);
1563 gtk_paned_pack1(GTK_PANED(hpaned), bottom_notebook, TRUE, TRUE);
1564
1565 right_notebook = gtk_notebook_new();
1566 g_object_ref(right_notebook);
1567 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(right_notebook), GTK_POS_TOP);
1568 gtk_notebook_set_scrollable(GTK_NOTEBOOK(right_notebook), TRUE);
1569 g_signal_connect(right_notebook, "button-release-event",
1570 G_CALLBACK(right_notebook_button_release), NULL);
1571 if (GUI_GTK_OPTION(message_chat_location) == GUI_GTK_MSGCHAT_SPLIT) {
1572 gtk_paned_pack2(GTK_PANED(hpaned), right_notebook, TRUE, TRUE);
1573 }
1574 }
1575
1576 vgrid = gtk_grid_new();
1577 gtk_orientable_set_orientation(GTK_ORIENTABLE(vgrid),
1578 GTK_ORIENTATION_VERTICAL);
1579
1580 sw = gtk_scrolled_window_new(NULL, NULL);
1581 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1582 GTK_SHADOW_ETCHED_IN);
1583 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC,
1584 GTK_POLICY_ALWAYS);
1585 gtk_container_add(GTK_CONTAINER(vgrid), sw);
1586
1587 label = gtk_label_new(_("Chat"));
1588 gtk_notebook_append_page(GTK_NOTEBOOK(bottom_notebook), vgrid, label);
1589
1590 text = gtk_text_view_new_with_buffer(message_buffer);
1591 gtk_widget_set_hexpand(text, TRUE);
1592 gtk_widget_set_vexpand(text, TRUE);
1594 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
1595 gtk_container_add(GTK_CONTAINER(sw), text);
1596 g_signal_connect(text, "size-allocate",
1597 G_CALLBACK(main_message_area_size_allocate), NULL);
1598
1599 gtk_widget_set_name(text, "chatline");
1600
1601 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
1602 gtk_widget_realize(text);
1603 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 5);
1604
1605 main_message_area = GTK_TEXT_VIEW(text);
1606 if (dtach_lowbox != NULL) {
1607 g_object_set_data(G_OBJECT(dtach_lowbox), "hide-over-reparent", main_message_area);
1608 }
1609
1611
1612 /* the chat line */
1614 gtk_container_add(GTK_CONTAINER(vgrid), view);
1615 g_object_set(view, "margin", 3, NULL);
1616
1617 button = gtk_check_button_new_with_label(_("Allies Only"));
1618 gtk_widget_set_focus_on_click(button, FALSE);
1619 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
1620 GUI_GTK_OPTION(allied_chat_only));
1621 g_signal_connect(button, "toggled",
1622 G_CALLBACK(allied_chat_button_toggled), NULL);
1625
1626 button = gtk_button_new_with_label(_("Clear links"));
1627 g_signal_connect(button, "clicked",
1628 G_CALLBACK(link_marks_clear_all), NULL);
1630
1631 /* Other things to take care of */
1632
1633 gtk_widget_show_all(gtk_bin_get_child(GTK_BIN(toplevel)));
1634
1635 if (GUI_GTK_OPTION(enable_tabs)) {
1637 }
1638
1639 gtk_notebook_set_current_page(GTK_NOTEBOOK(top_notebook), 0);
1640 gtk_notebook_set_current_page(GTK_NOTEBOOK(bottom_notebook), 0);
1641
1642 if (!GUI_GTK_OPTION(map_scrollbars)) {
1643 gtk_widget_hide(map_horizontal_scrollbar);
1644 gtk_widget_hide(map_vertical_scrollbar);
1645 }
1646}
1647
1648/**********************************************************************/
1651static void g_log_to_freelog_cb(const gchar *log_domain,
1652 GLogLevelFlags log_level,
1653 const gchar *message,
1654 gpointer user_data)
1655{
1656 enum log_level fllvl = LOG_ERROR;
1657
1658 switch (log_level) {
1659 case G_LOG_LEVEL_DEBUG:
1660 fllvl = LOG_DEBUG;
1661 break;
1662 case G_LOG_LEVEL_WARNING:
1663 fllvl = LOG_WARN;
1664 break;
1665 default:
1666 break;
1667 }
1668
1669 if (log_domain != NULL) {
1670 log_base(fllvl, "%s: %s", log_domain, message);
1671 } else {
1672 log_base(fllvl, "%s", message);
1673 }
1674}
1675
1676/**********************************************************************/
1679static GLogWriterOutput g_log_writer_to_freelog_cb(GLogLevelFlags log_level,
1680 const GLogField *fields,
1681 gsize n_fields,
1682 gpointer user_data)
1683{
1684 /* No need to have formatter of our own - let's use glib's default one. */
1685 gchar *out = g_log_writer_format_fields(log_level, fields, n_fields, FALSE);
1686
1687 g_log_to_freelog_cb(NULL, log_level, out, NULL);
1688
1689 return G_LOG_WRITER_HANDLED;
1690}
1691
1692/**********************************************************************/
1695static void set_g_log_callback_domain(const char *domain)
1696{
1697 g_log_set_handler(domain,
1698 G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING
1699 | G_LOG_LEVEL_MASK
1700 | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
1701 g_log_to_freelog_cb, NULL);
1702}
1703
1704/**********************************************************************/
1707static void set_g_log_callbacks(void)
1708{
1709 /* Old API, still used by many log producers */
1710 g_log_set_default_handler(g_log_to_freelog_cb, NULL);
1711
1715
1716 /* glib >= 2.50 API */
1717 g_log_set_writer_func(g_log_writer_to_freelog_cb, NULL, NULL);
1718}
1719
1720/**********************************************************************/
1729
1730/**********************************************************************/
1733int main(int argc, char **argv)
1734{
1735 return client_main(argc, argv, FALSE);
1736}
1737
1738/**********************************************************************/
1742{
1743 log_normal(_("Migrating options from gtk2 to gtk3 client"));
1744
1745#define MIGRATE_OPTION(opt) gui_options.gui_gtk3_##opt = gui_options.gui_gtk2_##opt;
1746#define MIGRATE_STR_OPTION(opt) \
1747 strncpy(gui_options.gui_gtk3_##opt, gui_options.gui_gtk2_##opt, \
1748 sizeof(gui_options.gui_gtk3_##opt));
1749
1750 /* Default theme name is never migrated */
1751 /* 'fullscreen', 'small_display_layout', and 'message_chat_location'
1752 * not migrated, as (unlike Gtk2), Gtk3-client tries to pick better
1753 * defaults for these in fresh installations based on screen size (see
1754 * adjust_default_options()); so user is probably better served by
1755 * getting these adaptive defaults than whatever they had for Gtk2.
1756 * Since 'fullscreen' isn't migrated, we don't need to worry about
1757 * preserving gui_gtk2_migrated_from_2_5 either. */
1758 MIGRATE_OPTION(map_scrollbars);
1759 MIGRATE_OPTION(dialogs_on_top);
1760 MIGRATE_OPTION(show_task_icons);
1761 MIGRATE_OPTION(enable_tabs);
1762 MIGRATE_OPTION(show_chat_message_time);
1763 MIGRATE_OPTION(new_messages_go_to_top);
1764 MIGRATE_OPTION(show_message_window_buttons);
1765 MIGRATE_OPTION(metaserver_tab_first);
1766 MIGRATE_OPTION(allied_chat_only);
1767 MIGRATE_OPTION(mouse_over_map_focus);
1768 MIGRATE_OPTION(chatline_autocompletion);
1769 MIGRATE_OPTION(citydlg_xsize);
1770 MIGRATE_OPTION(citydlg_ysize);
1771 MIGRATE_OPTION(popup_tech_help);
1772
1773 MIGRATE_STR_OPTION(font_city_label);
1774 MIGRATE_STR_OPTION(font_notify_label);
1775 MIGRATE_STR_OPTION(font_spaceship_label);
1776 MIGRATE_STR_OPTION(font_help_label);
1777 MIGRATE_STR_OPTION(font_help_link);
1778 MIGRATE_STR_OPTION(font_help_text);
1779 MIGRATE_STR_OPTION(font_chatline);
1780 MIGRATE_STR_OPTION(font_beta_label);
1781 MIGRATE_STR_OPTION(font_small);
1782 MIGRATE_STR_OPTION(font_comment_label);
1783 MIGRATE_STR_OPTION(font_city_names);
1784 MIGRATE_STR_OPTION(font_city_productions);
1785 MIGRATE_STR_OPTION(font_reqtree_text);
1786
1787#undef MIGRATE_OPTION
1788#undef MIGRATE_STR_OPTION
1789
1791}
1792
1793/**********************************************************************/
1797{
1798 log_normal(_("Migrating options from gtk3 to gtk3.22 client"));
1799
1800#define MIGRATE_OPTION(opt) GUI_GTK_OPTION(opt) = gui_options.gui_gtk3_##opt;
1801#define MIGRATE_STR_OPTION(opt) \
1802 strncpy(GUI_GTK_OPTION(opt), gui_options.gui_gtk3_##opt, \
1803 sizeof(GUI_GTK_OPTION(opt)));
1804
1805 /* Default theme name is never migrated */
1806
1807 /* Simulate gui-gtk3's migrate_options_from_2_5() */
1809 log_normal(_("Migrating gtk3-client options from freeciv-2.5 options."));
1812 }
1813
1814 MIGRATE_OPTION(fullscreen);
1815 MIGRATE_OPTION(map_scrollbars);
1816 MIGRATE_OPTION(dialogs_on_top);
1817 MIGRATE_OPTION(show_task_icons);
1818 MIGRATE_OPTION(enable_tabs);
1819 MIGRATE_OPTION(show_chat_message_time);
1820 MIGRATE_OPTION(new_messages_go_to_top);
1821 MIGRATE_OPTION(show_message_window_buttons);
1822 MIGRATE_OPTION(metaserver_tab_first);
1823 MIGRATE_OPTION(allied_chat_only);
1824 MIGRATE_OPTION(message_chat_location);
1825 MIGRATE_OPTION(small_display_layout);
1826 MIGRATE_OPTION(mouse_over_map_focus);
1827 MIGRATE_OPTION(chatline_autocompletion);
1828 MIGRATE_OPTION(citydlg_xsize);
1829 MIGRATE_OPTION(citydlg_ysize);
1830 MIGRATE_OPTION(popup_tech_help);
1831
1832 MIGRATE_STR_OPTION(font_city_label);
1833 MIGRATE_STR_OPTION(font_notify_label);
1834 MIGRATE_STR_OPTION(font_spaceship_label);
1835 MIGRATE_STR_OPTION(font_help_label);
1836 MIGRATE_STR_OPTION(font_help_link);
1837 MIGRATE_STR_OPTION(font_help_text);
1838 MIGRATE_STR_OPTION(font_chatline);
1839 MIGRATE_STR_OPTION(font_beta_label);
1840 MIGRATE_STR_OPTION(font_small);
1841 MIGRATE_STR_OPTION(font_comment_label);
1842 MIGRATE_STR_OPTION(font_city_names);
1843 MIGRATE_STR_OPTION(font_city_productions);
1844 MIGRATE_STR_OPTION(font_reqtree_text);
1845
1846#undef MIGRATE_OPTION
1847#undef MIGRATE_STR_OPTION
1848
1849 GUI_GTK_OPTION(migrated_from_gtk3) = TRUE;
1850}
1851
1852/**********************************************************************/
1855int ui_main(int argc, char **argv)
1856{
1857 PangoFontDescription *toplevel_font_name;
1858 guint sig;
1859
1860 if (parse_options(argc, argv)) {
1861 char window_name[1024];
1862
1863 /* The locale has already been set in init_nls() and the windows-specific
1864 * locale logic in gtk_init() causes problems with zh_CN (see PR#39475) */
1865 gtk_disable_setlocale();
1866
1867 /* GTK withdraw gtk options. Process GTK arguments */
1868 if (!gtk_init_check(&argc, &argv)) {
1869 log_fatal(_("Failed to open graphical mode."));
1870 exit(EXIT_FAILURE);
1871 }
1872
1874
1876
1877 toplevel = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1878 gtk_window_set_position(GTK_WINDOW(toplevel), GTK_WIN_POS_CENTER);
1879 if (vmode.width > 0 && vmode.height > 0) {
1880 gtk_window_resize(GTK_WINDOW(toplevel), vmode.width, vmode.height);
1881 }
1882 g_signal_connect(toplevel, "key_press_event",
1883 G_CALLBACK(toplevel_handler), NULL);
1884
1885 gtk_window_set_role(GTK_WINDOW(toplevel), "toplevel");
1886 gtk_widget_realize(toplevel);
1887 gtk_widget_set_name(toplevel, "Freeciv");
1888 root_window = gtk_widget_get_window(toplevel);
1889
1890 if (gui_options.first_boot) {
1892 /* We're using fresh defaults for this version of this client,
1893 * so prevent any future migrations from other clients / versions */
1894 GUI_GTK_OPTION(migrated_from_gtk3) = TRUE;
1895 /* Avoid also marking gtk3 as migrated, so that it can have its own
1896 * run of its adjust_default_options() if it is ever run (as a
1897 * side effect of Gtk2->Gtk3 migration). */
1898 } else {
1899 if (!GUI_GTK_OPTION(migrated_from_gtk3)) {
1902 /* We want a fresh look at screen-size-related options after Gtk2 */
1904 /* We don't ever want to consider pre-2.6 fullscreen option again
1905 * (even for gui-gtk3) */
1907 }
1909 }
1910 }
1911
1912 if (GUI_GTK_OPTION(fullscreen)) {
1913 gtk_window_fullscreen(GTK_WINDOW(toplevel));
1914 }
1915
1916 fc_snprintf(window_name, sizeof(window_name), _("Freeciv (%s)"), GUI_NAME_SHORT);
1917 gtk_window_set_title(GTK_WINDOW(toplevel), window_name);
1918
1919 g_signal_connect(toplevel, "delete_event",
1920 G_CALLBACK(quit_dialog_callback), NULL);
1921
1922 /* Disable GTK+ cursor key focus movement */
1923 sig = g_signal_lookup("focus", GTK_TYPE_WIDGET);
1924 g_signal_handlers_disconnect_matched(toplevel, G_SIGNAL_MATCH_ID, sig,
1925 0, 0, 0, 0);
1926 g_signal_connect(toplevel, "focus", G_CALLBACK(toplevel_focus), NULL);
1927
1928 options_iterate(client_optset, poption) {
1929 if (OT_FONT == option_type(poption)) {
1930 /* Force to call the appropriate callback. */
1931 option_changed(poption);
1932 }
1934
1935 toplevel_font_name = pango_context_get_font_description(
1936 gtk_widget_get_pango_context(toplevel));
1937
1938 if (NULL == city_names_style) {
1939 city_names_style = pango_font_description_copy(toplevel_font_name);
1940 log_error("city_names_style should have been set by options.");
1941 }
1942 if (NULL == city_productions_style) {
1943 city_productions_style = pango_font_description_copy(toplevel_font_name);
1944 log_error("city_productions_style should have been set by options.");
1945 }
1946 if (NULL == reqtree_text_style) {
1947 reqtree_text_style = pango_font_description_copy(toplevel_font_name);
1948 log_error("reqtree_text_style should have been set by options.");
1949 }
1950
1953
1954 /* Keep the icon of the executable on Windows (see PR#36491) */
1955#ifndef FREECIV_MSWINDOWS
1956 {
1958
1959 /* Only call this after tileset_load_tiles is called. */
1960 gtk_window_set_icon(GTK_WINDOW(toplevel), pixbuf);
1961 g_object_unref(pixbuf);
1962 }
1963#endif /* FREECIV_MSWINDOWS */
1964
1965 setup_widgets();
1966 load_cursors();
1967 cma_fe_init();
1974 chatline_init();
1976
1978
1979 gtk_widget_show(toplevel);
1980
1981 /* Assumes toplevel showing */
1983
1984 /* Assumes client_state is set */
1985 timer_id = g_timeout_add(TIMER_INTERVAL, timer_callback, NULL);
1986
1987 gui_up = TRUE;
1988 gtk_main();
1989 gui_up = FALSE;
1990
1999 cma_fe_done();
2001
2002 /* We have extra ref for unit_info_box that has protected
2003 * it from getting destroyed when editinfobox_refresh()
2004 * moves widgets around. Free that extra ref here. */
2005 g_object_unref(unit_info_box);
2006
2007 editgui_free();
2008 gtk_widget_destroy(toplevel_tabs);
2009 gtk_widget_destroy(toplevel);
2010 menus_free();
2011 message_buffer = NULL; /* Result of destruction of everything */
2013 }
2014
2015 return EXIT_SUCCESS;
2016}
2017
2018/**********************************************************************/
2021bool is_gui_up(void)
2022{
2023 return gui_up;
2024}
2025
2026/**********************************************************************/
2029void ui_exit(void)
2030{
2031 if (message_buffer != NULL) {
2032 g_object_unref(message_buffer);
2033 message_buffer = NULL;
2034 }
2035}
2036
2037/**********************************************************************/
2040enum gui_type get_gui_type(void)
2041{
2042 return GUI_GTK3_22;
2043}
2044
2045/**********************************************************************/
2048void sound_bell(void)
2049{
2050 gdk_display_beep(gdk_display_get_default());
2051}
2052
2053/**********************************************************************/
2059void set_unit_icon(int idx, struct unit *punit)
2060{
2061 GtkWidget *w;
2062
2063 fc_assert_ret(idx >= -1 && idx < num_units_below);
2064
2065 if (idx == -1) {
2066 w = unit_image;
2067 unit_id_top = punit ? punit->id : 0;
2068 } else {
2069 w = unit_below_image[idx];
2070 unit_ids[idx] = punit ? punit->id : 0;
2071 }
2072
2073 if (!w) {
2074 return;
2075 }
2076
2077 if (punit) {
2078 put_unit_image(punit, GTK_IMAGE(w), -1);
2079 } else {
2080 gtk_image_clear(GTK_IMAGE(w));
2081 }
2082}
2083
2084/**********************************************************************/
2090{
2091 static bool showing = FALSE;
2092
2094 return;
2095 }
2096
2097 if (onoff && !showing) {
2098 gtk_widget_show(more_arrow_pixmap_button);
2099 showing = TRUE;
2100 } else if (!onoff && showing) {
2101 gtk_widget_hide(more_arrow_pixmap_button);
2102 showing = FALSE;
2103 }
2104}
2105
2106/**********************************************************************/
2116
2117/**********************************************************************/
2121static gboolean select_unit_image_callback(GtkWidget *w, GdkEvent *ev,
2122 gpointer data)
2123{
2124 int i = GPOINTER_TO_INT(data);
2125 struct unit *punit;
2126
2127 if (i == -1) {
2129 if (punit && unit_is_in_focus(punit)) {
2130 /* Clicking on the currently selected unit will center it. */
2132 }
2133 return TRUE;
2134 }
2135
2136 if (unit_ids[i] == 0) /* no unit displayed at this place */
2137 return TRUE;
2138
2140 if (NULL != punit && unit_owner(punit) == client.conn.playing) {
2141 /* Unit shouldn't be NULL but may be owned by an ally. */
2143 }
2144
2145 return TRUE;
2146}
2147
2148/**********************************************************************/
2152static gboolean select_more_arrow_pixmap_callback(GtkWidget *w, GdkEvent *ev,
2153 gpointer data)
2154{
2156
2157 if (punit) {
2159 }
2160
2161 return TRUE;
2162}
2163
2164/**********************************************************************/
2167static gboolean show_info_button_release(GtkWidget *w, GdkEventButton *ev,
2168 gpointer data)
2169{
2170 gtk_grab_remove(w);
2171 gdk_seat_ungrab(gdk_device_get_seat(ev->device));
2172 gtk_widget_destroy(w);
2173
2174 return FALSE;
2175}
2176
2177/**********************************************************************/
2180static gboolean show_info_popup(GtkWidget *w, GdkEventButton *ev, gpointer data)
2181{
2182 if (ev->button == 1) {
2183 GtkWidget *p;
2184
2185 p = gtk_window_new(GTK_WINDOW_POPUP);
2186 gtk_container_set_border_width(GTK_CONTAINER(p), 4);
2187 gtk_window_set_transient_for(GTK_WINDOW(p), GTK_WINDOW(toplevel));
2188 gtk_window_set_position(GTK_WINDOW(p), GTK_WIN_POS_MOUSE);
2189
2190 gtk_widget_new(GTK_TYPE_LABEL, "GtkWidget::parent", p,
2191 "GtkLabel::label", get_info_label_text_popup(),
2192 "GtkWidget::visible", TRUE,
2193 NULL);
2194 gtk_widget_show(p);
2195
2196 gdk_seat_grab(gdk_device_get_seat(ev->device), gtk_widget_get_window(p),
2197 GDK_SEAT_CAPABILITY_ALL_POINTING,
2198 TRUE, NULL, (GdkEvent *)ev, NULL, NULL);
2199 gtk_grab_add(p);
2200
2201 g_signal_connect_after(p, "button_release_event",
2202 G_CALLBACK(show_info_button_release), NULL);
2203 }
2204
2205 return TRUE;
2206}
2207
2208/**********************************************************************/
2211static void end_turn_callback(GtkWidget *w, gpointer data)
2212{
2213 gtk_widget_set_sensitive(turn_done_button, FALSE);
2215}
2216
2217/**********************************************************************/
2220static gboolean get_net_input(GIOChannel *source, GIOCondition condition,
2221 gpointer data)
2222{
2223 input_from_server(g_io_channel_unix_get_fd(source));
2224
2225 return TRUE;
2226}
2227
2228/**********************************************************************/
2232 bool socket_writable)
2233{
2234 static bool previous_state = FALSE;
2235
2236 fc_assert_ret(pc == &client.conn);
2237
2238 if (previous_state == socket_writable)
2239 return;
2240
2241 log_debug("set_wait_for_writable_socket(%d)", socket_writable);
2242
2243 g_source_remove(srv_id);
2244 srv_id = g_io_add_watch(srv_channel,
2245 G_IO_IN | (socket_writable ? G_IO_OUT : 0) | G_IO_ERR,
2247 NULL);
2248
2249 previous_state = socket_writable;
2250}
2251
2252/**********************************************************************/
2256void add_net_input(int sock)
2257{
2258#ifdef FREECIV_MSWINDOWS
2259 srv_channel = g_io_channel_win32_new_socket(sock);
2260#else
2261 srv_channel = g_io_channel_unix_new(sock);
2262#endif
2263 srv_id = g_io_add_watch(srv_channel,
2264 G_IO_IN | G_IO_ERR,
2266 NULL);
2268}
2269
2270/**********************************************************************/
2275{
2276 g_source_remove(srv_id);
2277 g_io_channel_unref(srv_channel);
2278 gdk_window_set_cursor(root_window, NULL);
2279}
2280
2281/**********************************************************************/
2285static void quit_dialog_response(GtkWidget *dialog, gint response)
2286{
2287 gtk_widget_destroy(dialog);
2288 if (response == GTK_RESPONSE_YES) {
2290 if (client.conn.used) {
2292 }
2293 quit_gtk_main();
2294 }
2295}
2296
2297/**********************************************************************/
2301{
2302 /* Quit gtk main loop. After this it will return to finish
2303 * ui_main() */
2304
2305 gtk_main_quit();
2306}
2307
2308/**********************************************************************/
2313{
2314 static GtkWidget *dialog;
2315
2316 if (!dialog) {
2317 dialog = gtk_message_dialog_new(NULL,
2318 0,
2319 GTK_MESSAGE_WARNING,
2320 GTK_BUTTONS_YES_NO,
2321 _("Are you sure you want to quit?"));
2322 setup_dialog(dialog, toplevel);
2323
2324 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
2325
2326 g_signal_connect(dialog, "response",
2327 G_CALLBACK(quit_dialog_response), NULL);
2328 g_signal_connect(dialog, "destroy",
2329 G_CALLBACK(gtk_widget_destroyed), &dialog);
2330 }
2331
2332 gtk_window_present(GTK_WINDOW(dialog));
2333}
2334
2335/**********************************************************************/
2338static gboolean quit_dialog_callback(void)
2339{
2341 /* Stop emission of event. */
2342 return TRUE;
2343}
2344
2345struct callback {
2346 void (*callback)(void *data);
2347 void *data;
2348};
2349
2350/**********************************************************************/
2353static gboolean idle_callback_wrapper(gpointer data)
2354{
2355 struct callback *cb = data;
2356
2357 (cb->callback)(cb->data);
2358 free(cb);
2359
2360 return FALSE;
2361}
2362
2363/**********************************************************************/
2368void add_idle_callback(void (callback)(void *), void *data)
2369{
2370 struct callback *cb = fc_malloc(sizeof(*cb));
2371
2372 cb->callback = callback;
2373 cb->data = data;
2374 g_idle_add(idle_callback_wrapper, cb);
2375}
2376
2377/**********************************************************************/
2381static void allied_chat_only_callback(struct option *poption)
2382{
2383 GtkWidget *button;
2384
2386 fc_assert_ret(button != NULL);
2387 fc_assert_ret(GTK_IS_TOGGLE_BUTTON(button));
2388
2389 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
2390 option_bool_get(poption));
2391}
2392
2393/**********************************************************************/
2396void fullscreen_opt_refresh(struct option *poption)
2397{
2398 if (GUI_GTK_OPTION(fullscreen)) {
2399 gtk_window_fullscreen(GTK_WINDOW(toplevel));
2400 } else {
2401 gtk_window_unfullscreen(GTK_WINDOW(toplevel));
2402 }
2403}
2404
2405/**********************************************************************/
2408static void apply_city_names_font(struct option *poption)
2409{
2411 option_font_get(poption),
2414}
2415
2416/**********************************************************************/
2419static void apply_city_productions_font(struct option *poption)
2420{
2422 option_font_get(poption),
2425}
2426
2427/**********************************************************************/
2430static void apply_reqtree_text_font(struct option *poption)
2431{
2433 option_font_get(poption),
2436}
2437
2438/**********************************************************************/
2443{
2444
2445 struct option *poption;
2446
2447#define option_var_set_callback(var, callback) \
2448 if ((poption = optset_option_by_name(client_optset, GUI_GTK_OPTION_STR(var)))) { \
2449 option_set_changed_callback(poption, callback); \
2450 } else { \
2451 log_error("Didn't find option %s!", GUI_GTK_OPTION_STR(var)); \
2452 }
2453
2454 option_var_set_callback(allied_chat_only,
2456 option_var_set_callback(fullscreen,
2458
2459 option_var_set_callback(font_city_names,
2461 option_var_set_callback(font_city_productions,
2463 option_var_set_callback(font_reqtree_text,
2465#undef option_var_set_callback
2466}
2467
2468/**********************************************************************/
2473{
2474 GtkWidget *button;
2475
2477 fc_assert_ret(button != NULL);
2478 fc_assert_ret(GTK_IS_TOGGLE_BUTTON(button));
2479
2480 /* Hide the "Allies Only" button for local games. */
2481 if (is_server_running()) {
2482 gtk_widget_hide(button);
2483 } else {
2484 gtk_widget_show(button);
2485 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
2486 GUI_GTK_OPTION(allied_chat_only));
2487 }
2488}
2489
2490/**********************************************************************/
2493static void allied_chat_button_toggled(GtkToggleButton *button,
2494 gpointer user_data)
2495{
2496 GUI_GTK_OPTION(allied_chat_only) = gtk_toggle_button_get_active(button);
2497}
2498
2499/**********************************************************************/
2502void insert_client_build_info(char *outbuf, size_t outlen)
2503{
2504 cat_snprintf(outbuf, outlen, _("\nBuilt against gtk+ %d.%d.%d, using %d.%d.%d"
2505 "\nBuilt against glib %d.%d.%d, using %d.%d.%d"),
2506 GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION,
2507 gtk_get_major_version(), gtk_get_minor_version(), gtk_get_micro_version(),
2508 GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION,
2509 glib_major_version, glib_minor_version, glib_micro_version);
2510}
2511
2512/**********************************************************************/
2516static bool monitor_size(GdkRectangle *rect_p)
2517{
2518 GdkDisplay *display;
2519 GdkMonitor *monitor;
2520
2521 display = gdk_display_get_default();
2522 if (!display) {
2523 return FALSE;
2524 }
2525
2526 monitor = gdk_display_get_primary_monitor(display);
2527 if (!monitor) {
2528 return FALSE;
2529 }
2530
2531 gdk_monitor_get_geometry(monitor, rect_p);
2532 return TRUE;
2533}
2534
2535/**********************************************************************/
2539{
2540 GdkRectangle rect;
2541
2542 if (vmode.width > 0) {
2543 return vmode.width;
2544 }
2545
2546 if (monitor_size(&rect)) {
2547 return rect.width;
2548 } else {
2549 return 0;
2550 }
2551}
2552
2553/**********************************************************************/
2557{
2558 GdkRectangle rect;
2559
2560 if (vmode.height > 0) {
2561 return vmode.height;
2562 }
2563
2564 if (monitor_size(&rect)) {
2565 return rect.height;
2566 } else {
2567 return 0;
2568 }
2569}
2570
2571/**********************************************************************/
2575{
2576 if (vmode.width > 0 && vmode.height > 0) {
2577 return &vmode;
2578 }
2579
2580 return NULL;
2581}
2582
2583/**********************************************************************/
2586static void adjust_default_options(void)
2587{
2588 int scr_height = screen_height();
2589
2590 if (scr_height > 0) {
2591 /* Adjust these options only if we do know the screen height. */
2592
2593 if (scr_height <= 480) {
2594 /* Freeciv is practically unusable outside fullscreen mode in so
2595 * small display */
2596 log_verbose("Changing default to fullscreen due to very small screen");
2597 GUI_GTK_OPTION(fullscreen) = TRUE;
2598 }
2599 if (scr_height < 1024) {
2600 /* This is a small display */
2601 log_verbose("Defaulting to small widget layout due to small screen");
2602 GUI_GTK_OPTION(small_display_layout) = TRUE;
2603 log_verbose("Defaulting to merged messages/chat due to small screen");
2604 GUI_GTK_OPTION(message_chat_location) = GUI_GTK_MSGCHAT_MERGED;
2605 }
2606 }
2607}
struct canvas int int struct sprite int int int width
Definition canvas_g.h:44
void chat_welcome_message(bool gui_has_copying_mitem)
bool client_is_observer(void)
double real_timer_callback(void)
int client_main(int argc, char *argv[], bool postpone_tileset)
void user_ended_turn(void)
struct civclient client
void start_quitting(void)
void set_client_state(enum client_states newstate)
bool can_client_change_view(void)
#define TIMER_INTERVAL
Definition client_main.h:30
@ C_S_DISCONNECTED
Definition client_main.h:45
void buy_production_in_selected_cities(void)
Definition climisc.c:1310
struct sprite * client_warming_sprite(void)
Definition climisc.c:371
struct sprite * client_cooling_sprite(void)
Definition climisc.c:388
struct sprite * client_research_sprite(void)
Definition climisc.c:348
struct sprite * client_government_sprite(void)
Definition climisc.c:406
void input_from_server(int fd)
Definition clinet.c:406
void disconnect_from_server(void)
Definition clinet.c:305
struct color * get_color(const struct tileset *t, enum color_std stdcolor)
bool is_server_running(void)
void key_recall_previous_focus_unit(void)
Definition control.c:3161
bool unit_is_in_focus(const struct unit *punit)
Definition control.c:389
void key_cancel_action(void)
Definition control.c:3100
int num_units_below
Definition control.c:76
void unit_focus_set(struct unit *punit)
Definition control.c:507
struct unit_list * get_units_in_focus(void)
Definition control.c:177
void key_end_turn(void)
Definition control.c:3153
void update_unit_pix_label(struct unit_list *punitlist)
Definition control.c:984
void key_unit_move(enum direction8 gui_dir)
Definition control.c:3182
enum cursor_hover_state hover_state
Definition control.c:89
struct unit * head_of_units_in_focus(void)
Definition control.c:411
int get_num_units_in_focus(void)
Definition control.c:185
void control_mouse_cursor(struct tile *ptile)
Definition control.c:1214
void key_center_capital(void)
Definition control.c:3136
#define MAX_NUM_UNITS_BELOW
Definition control.h:285
@ HOVER_NONE
Definition control.h:26
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:73
bool editor_is_active(void)
Definition editor.c:346
enum event_type event
Definition events.c:81
bool is_option(const char *option_name, char *option)
Definition fc_cmdline.c:112
char * get_option_malloc(const char *option_name, char **argv, int *i, int argc, bool gc)
Definition fc_cmdline.c:50
@ O_SCIENCE
Definition fc_types.h:91
@ O_GOLD
Definition fc_types.h:91
void fc_fprintf(FILE *stream, const char *format,...) fc__attribute((__format__(__printf__
#define Q_(String)
Definition fcintl.h:70
#define _(String)
Definition fcintl.h:67
struct unit * game_unit_by_number(int id)
Definition game.c:111
bool inputline_has_focus(void)
Definition chatline.c:71
void inputline_toolkit_view_append_button(GtkWidget *toolkit_view, GtkWidget *button)
Definition chatline.c:1288
GtkWidget * inputline_toolkit_view_new(void)
Definition chatline.c:1266
void set_message_buffer_view_link_handlers(GtkWidget *view)
Definition chatline.c:744
bool inputline_is_visible(void)
Definition chatline.c:87
void chatline_init(void)
Definition chatline.c:1298
void inputline_grab_focus(void)
Definition chatline.c:79
void chatline_scroll_to_bottom(bool delayed)
Definition chatline.c:1006
void citizens_dialog_init(void)
void citizens_dialog_done(void)
void cma_fe_init(void)
Definition cma_fe.c:88
void cma_fe_done(void)
Definition cma_fe.c:96
void unit_select_dialog_popup(struct tile *ptile)
Definition dialogs.c:382
gboolean taxrates_callback(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition dialogs.c:1434
void diplomacy_dialog_init(void)
Definition diplodlg.c:1175
void diplomacy_dialog_done(void)
Definition diplodlg.c:1184
gboolean handle_edit_key_release(GdkEventKey *ev)
Definition editgui.c:1779
gboolean handle_edit_key_press(GdkEventKey *ev)
Definition editgui.c:1661
void editgui_create_widgets(void)
Definition editgui.c:1821
struct editbar * editgui_get_editbar(void)
Definition editgui.c:1787
void editgui_free(void)
Definition editgui.c:1834
void goto_dialog_focus_units_changed(void)
Definition gotodlg.c:540
static GtkWidget * source
Definition gotodlg.c:58
void load_cursors(void)
Definition graphics.c:78
GtkWidget * map_vertical_scrollbar
Definition gui_main.c:108
int ui_main(int argc, char **argv)
Definition gui_main.c:1702
const char * client_string
Definition gui_main.c:104
GtkTextBuffer * message_buffer
Definition gui_main.c:177
static void quit_dialog_response(GtkWidget *dialog, gint response)
Definition gui_main.c:2127
void real_focus_units_changed(void)
Definition gui_main.c:1955
void set_unit_icons_more_arrow(bool onoff)
Definition gui_main.c:1932
static void print_usage(void)
Definition gui_main.c:249
#define OVERVIEW_CANVAS_STORE_WIDTH_NETBOOK
Definition gui_main.c:115
#define option_var_set_callback(var, callback)
static gboolean select_unit_image_callback(GtkWidget *w, GdkEvent *ev, gpointer data)
Definition gui_main.c:1964
static gboolean quit_dialog_callback(void)
Definition gui_main.c:2180
static GIOChannel * srv_channel
Definition gui_main.c:181
GtkWidget * main_label_info
Definition gui_main.c:137
GtkWidget * bottom_notebook
Definition gui_main.c:128
GtkWidget * unit_info_label
Definition gui_main.c:150
static gboolean timer_callback(gpointer data)
Definition gui_main.c:236
struct video_mode * resolution_request_get(void)
Definition gui_main.c:2396
void set_unit_icon(int idx, struct unit *punit)
Definition gui_main.c:1902
static int unit_ids[MAX_NUM_UNITS_BELOW]
Definition gui_main.c:174
GtkWidget * timeout_label
Definition gui_main.c:147
static bool gui_up
Definition gui_main.c:185
static guint srv_id
Definition gui_main.c:182
static gboolean mouse_scroll_mapcanvas(GtkWidget *w, GdkEventScroll *ev)
Definition gui_main.c:690
PangoFontDescription * city_productions_style
Definition gui_main.c:133
GtkWidget * overview_scrolled_window
Definition gui_main.c:111
static GtkWidget * more_arrow_pixmap
Definition gui_main.c:169
static GtkWidget * detached_widget_fill(GtkWidget *tearbox)
Definition gui_main.c:817
void enable_menus(bool enable)
Definition gui_main.c:1001
static gboolean select_more_arrow_pixmap_callback(GtkWidget *w, GdkEvent *ev, gpointer data)
Definition gui_main.c:1995
GtkWidget * top_notebook
Definition gui_main.c:128
static gboolean propagate_keypress(GtkWidget *w, GdkEvent *ev)
Definition gui_main.c:758
#define MIGRATE_STR_OPTION(opt)
GtkWidget * econ_ebox
Definition gui_main.c:154
GtkWidget * unit_info_box
Definition gui_main.c:151
void ui_exit(void)
Definition gui_main.c:1872
enum gui_type get_gui_type(void)
Definition gui_main.c:1883
static GtkWidget * detached_widget_new(void)
Definition gui_main.c:805
gint cur_y
Definition gui_main.c:183
int main(int argc, char **argv)
Definition gui_main.c:1627
void fullscreen_opt_refresh(struct option *poption)
Definition gui_main.c:2238
static void main_message_area_size_allocate(GtkWidget *widget, GtkAllocation *allocation, gpointer data)
Definition gui_main.c:349
static gboolean toplevel_handler(GtkWidget *w, GdkEvent *ev, gpointer data)
Definition gui_main.c:383
void ui_init(void)
Definition gui_main.c:1618
static GtkWidget * unit_below_image_button[MAX_NUM_UNITS_BELOW]
Definition gui_main.c:168
static void free_unit_table(void)
Definition gui_main.c:944
static gboolean idle_callback_wrapper(gpointer data)
Definition gui_main.c:2195
static void apply_city_names_font(struct option *poption)
Definition gui_main.c:2250
static void apply_city_productions_font(struct option *poption)
Definition gui_main.c:2261
static GtkWidget * unit_below_image[MAX_NUM_UNITS_BELOW]
Definition gui_main.c:167
static void tearoff_destroy(GtkWidget *w, gpointer data)
Definition gui_main.c:742
GtkWidget * government_label
Definition gui_main.c:146
GtkWidget * sun_label
Definition gui_main.c:144
PangoFontDescription * city_names_style
Definition gui_main.c:132
void refresh_chat_buttons(void)
Definition gui_main.c:2313
gboolean map_canvas_focus(void)
Definition gui_main.c:366
GtkWidget * turn_done_button
Definition gui_main.c:148
static GtkWidget * bottom_hpaned
Definition gui_main.c:130
static gint timer_id
Definition gui_main.c:180
static GtkWidget * main_menubar
Definition gui_main.c:163
int screen_width(void)
Definition gui_main.c:2356
GtkWidget * scroll_panel
Definition gui_main.c:140
static void end_turn_callback(GtkWidget *w, gpointer data)
Definition gui_main.c:2052
#define OVERVIEW_CANVAS_STORE_HEIGHT_NETBOOK
Definition gui_main.c:116
static void log_callback_utf8(enum log_level level, const char *message, bool file_too)
Definition gui_main.c:224
void add_idle_callback(void(callback)(void *), void *data)
Definition gui_main.c:2210
static gboolean show_info_popup(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition gui_main.c:2021
void reset_unit_table(void)
Definition gui_main.c:972
static gboolean key_press_map_canvas(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition gui_main.c:407
GtkWidget * unit_info_frame
Definition gui_main.c:152
void options_extra_init(void)
Definition gui_main.c:2284
GtkWidget * top_vbox
Definition gui_main.c:127
static void allied_chat_only_callback(struct option *poption)
Definition gui_main.c:2223
GdkWindow * root_window
Definition gui_main.c:125
static void adjust_default_options(void)
Definition gui_main.c:2408
static void set_wait_for_writable_socket(struct connection *pc, bool socket_writable)
Definition gui_main.c:2072
static GtkWidget * more_arrow_pixmap_button
Definition gui_main.c:170
GtkWidget * ahbox
Definition gui_main.c:139
static void apply_reqtree_text_font(struct option *poption)
Definition gui_main.c:2272
static gboolean show_info_button_release(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition gui_main.c:2010
bool is_gui_up(void)
Definition gui_main.c:1864
static gboolean toplevel_focus(GtkWidget *w, GtkDirectionType arg)
Definition gui_main.c:322
PangoFontDescription * reqtree_text_style
Definition gui_main.c:134
GtkWidget * sun_ebox
Definition gui_main.c:156
GtkWidget * bulb_ebox
Definition gui_main.c:155
GtkWidget * flake_label
Definition gui_main.c:145
GtkWidget * avbox
Definition gui_main.c:139
gint cur_x
Definition gui_main.c:183
void insert_client_build_info(char *outbuf, size_t outlen)
Definition gui_main.c:2343
static GtkWidget * unit_image_button
Definition gui_main.c:166
static GtkWidget * unit_image_table
Definition gui_main.c:164
static gboolean right_notebook_button_release(GtkWidget *widget, GdkEventButton *event)
Definition gui_main.c:1024
GtkWidget * bulb_label
Definition gui_main.c:143
GtkWidget * overview_canvas
Definition gui_main.c:110
GtkWidget * toplevel
Definition gui_main.c:124
static void setup_widgets(void)
Definition gui_main.c:1074
#define OVERVIEW_CANVAS_STORE_WIDTH
Definition gui_main.c:117
static gboolean toplevel_key_release_handler(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition gui_main.c:588
void remove_net_input(void)
Definition gui_main.c:2116
GtkWidget * map_horizontal_scrollbar
Definition gui_main.c:107
static void setup_canvas_color_for_state(GtkStateFlags state)
Definition gui_main.c:1044
GtkWidget * map_canvas
Definition gui_main.c:106
static gboolean toplevel_key_press_handler(GtkWidget *w, GdkEventKey *ev, gpointer data)
Definition gui_main.c:606
void sound_bell(void)
Definition gui_main.c:1891
static void migrate_options_from_gtk2(void)
Definition gui_main.c:1635
GtkWidget * econ_label[10]
Definition gui_main.c:142
GtkWidget * government_ebox
Definition gui_main.c:158
void popup_quit_dialog(void)
Definition gui_main.c:2154
const char *const gui_character_encoding
Definition gui_main.c:160
static int unit_id_top
Definition gui_main.c:173
static gboolean get_net_input(GIOChannel *source, GIOCondition condition, gpointer data)
Definition gui_main.c:2061
static GtkWidget * more_arrow_pixmap_container
Definition gui_main.c:171
GtkWidget * map_widget
Definition gui_main.c:129
GtkWidget * right_notebook
Definition gui_main.c:128
void quit_gtk_main(void)
Definition gui_main.c:2142
static void allied_chat_button_toggled(GtkToggleButton *button, gpointer user_data)
Definition gui_main.c:2334
static struct video_mode vmode
Definition gui_main.c:187
void add_net_input(int sock)
Definition gui_main.c:2098
GtkWidget * toplevel_tabs
Definition gui_main.c:126
static GtkWidget * allied_chat_toggle_button
Definition gui_main.c:178
GtkWidget * flake_ebox
Definition gui_main.c:157
int overview_canvas_store_width
Definition gui_main.c:121
void update_turn_done_tooltip(void)
Definition gui_main.c:1055
static void tearoff_callback(GtkWidget *b, gpointer data)
Definition gui_main.c:769
static GtkWidget * unit_image
Definition gui_main.c:165
GtkTextView * main_message_area
Definition gui_main.c:176
int overview_canvas_store_height
Definition gui_main.c:122
int screen_height(void)
Definition gui_main.c:2376
static bool parse_options(int argc, char **argv)
Definition gui_main.c:286
GtkWidget * conn_box
Definition gui_main.c:139
#define OVERVIEW_CANVAS_STORE_HEIGHT
Definition gui_main.c:119
GtkWidget * main_frame_civ_name
Definition gui_main.c:136
#define MIGRATE_OPTION(opt)
const bool gui_use_transliteration
Definition gui_main.c:161
static void populate_unit_image_table(void)
Definition gui_main.c:842
#define GUI_NAME_FULL
Definition gui_main.h:22
#define GUI_NAME_SHORT
Definition gui_main.h:23
#define GUI_GTK_OPTION(optname)
Definition gui_main.h:25
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:281
void gui_update_font_full(const char *font_name, const char *font_value, PangoFontDescription **font_desc)
Definition gui_stuff.c:1070
void happiness_dialog_init(void)
Definition happiness.c:86
void happiness_dialog_done(void)
Definition happiness.c:94
void help_system_init(void)
Definition helpdlg.c:156
void intel_dialog_done(void)
Definition inteldlg.c:127
void intel_dialog_init(void)
Definition inteldlg.c:118
void luaconsole_dialog_init(void)
Definition luaconsole.c:83
void luaconsole_dialog_done(void)
Definition luaconsole.c:101
gboolean butt_release_mapcanvas(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition mapctrl.c:216
gboolean move_overviewcanvas(GtkWidget *w, GdkEventMotion *ev, gpointer data)
Definition mapctrl.c:458
gboolean butt_down_overviewcanvas(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition mapctrl.c:467
gboolean butt_down_mapcanvas(GtkWidget *w, GdkEventButton *ev, gpointer data)
Definition mapctrl.c:237
gboolean move_mapcanvas(GtkWidget *w, GdkEventMotion *ev, gpointer data)
Definition mapctrl.c:400
gboolean leave_mapcanvas(GtkWidget *widget, GdkEventCrossing *event)
Definition mapctrl.c:429
void update_city_descriptions(void)
Definition mapview.c:470
gboolean map_canvas_draw(GtkWidget *w, cairo_t *cr, gpointer data)
Definition mapview.c:407
gboolean map_canvas_configure(GtkWidget *w, GdkEventConfigure *ev, gpointer data)
Definition mapview.c:386
void put_unit_image(struct unit *punit, GtkImage *p, int height)
Definition mapview.c:478
gboolean overview_canvas_draw(GtkWidget *w, cairo_t *cr, gpointer data)
Definition mapview.c:339
GtkWidget * setup_menus(GtkWidget *window)
Definition menu.c:2115
void menus_free(void)
Definition menu.c:3143
void meswin_dialog_popup(bool raise)
Definition messagewin.c:416
GtkWidget * create_start_page(void)
Definition pages.c:2621
GtkWidget * create_network_page(void)
Definition pages.c:1199
GtkWidget * create_scenario_page(void)
Definition pages.c:3184
static GtkWidget * statusbar
Definition pages.c:89
void destroy_server_scans(void)
Definition pages.c:767
GtkWidget * create_load_page(void)
Definition pages.c:2902
GtkWidget * create_statusbar(void)
Definition pages.c:908
GtkWidget * create_main_page(void)
Definition pages.c:231
void science_report_dialog_redraw(void)
Definition repodlgs.c:761
void spaceship_dialog_init(void)
void spaceship_dialog_done(void)
GdkPixbuf * sprite_get_pixbuf(struct sprite *sprite)
Definition sprite.c:402
GtkWidget * ingame_votebar
GtkWidget * voteinfo_bar_new(bool split_bar)
static bool monitor_size(GdkRectangle *rect_p)
Definition gui_main.c:2516
static void set_g_log_callbacks(void)
Definition gui_main.c:1707
static void g_log_to_freelog_cb(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
Definition gui_main.c:1651
static void set_g_log_callback_domain(const char *domain)
Definition gui_main.c:1695
static void migrate_options_from_gtk3(void)
Definition gui_main.c:1796
static GLogWriterOutput g_log_writer_to_freelog_cb(GLogLevelFlags log_level, const GLogField *fields, gsize n_fields, gpointer user_data)
Definition gui_main.c:1679
void dlg_tab_provider_prepare(void)
Definition gui_stuff.c:1151
log_callback_fn log_set_callback(log_callback_fn callback)
Definition log.c:290
#define fc_assert_ret(condition)
Definition log.h:191
#define log_verbose(message,...)
Definition log.h:109
#define log_fatal(message,...)
Definition log.h:100
#define log_debug(message,...)
Definition log.h:115
#define log_normal(message,...)
Definition log.h:107
#define log_base(level, message,...)
Definition log.h:94
log_level
Definition log.h:28
@ LOG_ERROR
Definition log.h:30
@ LOG_DEBUG
Definition log.h:34
@ LOG_FATAL
Definition log.h:29
@ LOG_WARN
Definition log.h:31
#define log_error(message,...)
Definition log.h:103
void update_line(int canvas_x, int canvas_y)
void maybe_activate_keyboardless_goto(int canvas_x, int canvas_y)
bool rbutton_down
bool tiles_hilited_cities
void scroll_mapview(enum direction8 gui_dir)
bool keyboardless_goto_button_down
void update_selection_rectangle(float canvas_x, float canvas_y)
void init_mapcanvas_and_overview(void)
struct tile * canvas_pos_to_tile(float canvas_x, float canvas_y, float zoom)
void free_mapcanvas_and_overview(void)
void get_mapview_scroll_pos(int *scroll_x, int *scroll_y)
void get_mapview_scroll_step(int *xstep, int *ystep)
void set_mapview_scroll_pos(int scroll_x, int scroll_y, float zoom)
void center_tile_mapcanvas(const struct tile *ptile)
void set_frame_by_frame_animation(void)
void link_marks_clear_all(void)
#define fc_malloc(sz)
Definition mem.h:34
void menus_init(void)
void option_changed(struct option *poption)
Definition options.c:723
const struct option_set * server_optset
Definition options.c:4009
const struct option_set * client_optset
Definition options.c:1255
bool option_bool_get(const struct option *poption)
Definition options.c:772
enum option_type option_type(const struct option *poption)
Definition options.c:633
const char * option_font_target(const struct option *poption)
Definition options.c:1138
bool string_to_video_mode(const char *buf, struct video_mode *mode)
Definition options.c:6453
struct client_options gui_options
Definition options.c:71
const char * option_font_get(const struct option *poption)
Definition options.c:1116
struct option * optset_option_by_name(const struct option_set *poptset, const char *name)
Definition options.c:406
#define GUI_GTK_OVERVIEW_MIN_XSIZE
Definition options.h:574
#define options_iterate(poptset, poption)
Definition options.h:527
@ GUI_GTK_MSGCHAT_MERGED
Definition options.h:68
@ GUI_GTK_MSGCHAT_SPLIT
Definition options.h:66
#define options_iterate_end
Definition options.h:532
const char * get_info_label_text_popup(void)
Definition text.c:1002
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:183
#define CLIP(lower, current, upper)
Definition shared.h:57
void * data
Definition gui_main.c:2189
void(* callback)(void *data)
Definition gui_main.c:2188
struct connection conn
Definition client_main.h:96
bool gui_gtk3_migrated_from_2_5
Definition options.h:134
int sound_effects_volume
Definition options.h:183
bool first_boot
Definition options.h:124
bool gui_gtk3_fullscreen
Definition options.h:261
bool migrate_fullscreen
Definition options.h:138
bool gui_gtk3_migrated_from_gtk2
Definition options.h:129
Definition colors.h:20
struct player * playing
Definition connection.h:156
void(* notify_of_writable_data)(struct connection *pc, bool data_available_and_socket_full)
Definition connection.h:186
cairo_surface_t * surface
Definition sprite.h:23
Definition unit.h:138
int id
Definition unit.h:145
int height
Definition options.h:47
int width
Definition options.h:46
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:995
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
void tileset_load_tiles(struct tileset *t)
Definition tilespec.c:3448
void tileset_free_tiles(struct tileset *t)
Definition tilespec.c:6342
void tileset_use_preferred_theme(const struct tileset *t)
Definition tilespec.c:6764
struct sprite * get_icon_sprite(const struct tileset *t, enum icon_type icon)
Definition tilespec.c:6674
void tileset_init(struct tileset *t)
Definition tilespec.c:6823
struct sprite * get_arrow_sprite(const struct tileset *t, enum arrow_type arrow)
Definition tilespec.c:6564
struct sprite * get_tax_sprite(const struct tileset *t, Output_type_id otype)
Definition tilespec.c:6575
int tileset_tile_width(const struct tileset *t)
Definition tilespec.c:716
@ ARROW_RIGHT
Definition tilespec.h:199
@ ICON_FREECIV
Definition tilespec.h:310
#define unit_tile(_pu)
Definition unit.h:395
#define unit_owner(_pu)
Definition unit.h:394
#define enable(id)
Definition widget.h:223
float mouse_zoom
Definition zoom.c:28
void zoom_step_down(void)
Definition zoom.c:130
void zoom_step_up(void)
Definition zoom.c:106