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)
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 ***********************************************************************/
15 #include <fc_config.h>
24 #include <gdk/gdkkeysyms.h>
39 #include "gui_stuff.h"
42 static GList
*dialog_list
;
44 static GtkSizeGroup
*gui_action
;
47 /**************************************************************************
49 **************************************************************************/
50 void gtk_expose_now(GtkWidget
*w
)
52 gtk_widget_queue_draw(w
);
55 /**************************************************************************
56 Set widget position relative to reference widget
57 **************************************************************************/
58 void gtk_set_relative_position(GtkWidget
*ref
, GtkWidget
*w
, int px
, int py
)
60 gint x
, y
, width
, height
;
62 gtk_window_get_position(GTK_WINDOW(ref
), &x
, &y
);
63 gtk_window_get_size(GTK_WINDOW(ref
), &width
, &height
);
68 gtk_window_move(GTK_WINDOW(w
), x
, y
);
71 /**************************************************************************
72 Create new stock button
73 **************************************************************************/
74 GtkWidget
*gtk_stockbutton_new(const gchar
*stock
, const gchar
*label_text
)
82 button
= gtk_button_new();
84 label
= gtk_label_new_with_mnemonic(label_text
);
85 gtk_label_set_mnemonic_widget(GTK_LABEL(label
), button
);
86 g_object_set_data(G_OBJECT(button
), "label", label
);
88 image
= gtk_image_new_from_stock(stock
, GTK_ICON_SIZE_BUTTON
);
89 g_object_set_data(G_OBJECT(button
), "image", image
);
91 hbox
= gtk_hbox_new(FALSE
, 2);
93 align
= gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
95 gtk_box_pack_start(GTK_BOX (hbox
), image
, FALSE
, FALSE
, 0);
96 gtk_box_pack_end(GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
98 gtk_container_add(GTK_CONTAINER(button
), align
);
99 gtk_container_add(GTK_CONTAINER(align
), hbox
);
100 gtk_widget_show_all(align
);
104 /**************************************************************************
105 Changes the label (with mnemonic) on an existing stockbutton. See
107 **************************************************************************/
108 void gtk_stockbutton_set_label(GtkWidget
*button
, const gchar
*label_text
)
112 label
= g_object_get_data(G_OBJECT(button
), "label");
113 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label
), label_text
);
116 /**************************************************************************
117 Returns gettext-converted list of n strings. The individual strings
118 in the list are as returned by gettext(). In case of no NLS, the strings
119 will be the original strings, so caller should ensure that the originals
120 persist for as long as required. (For no NLS, still allocate the
121 list, for consistency.)
123 (This is not directly gui/gtk related, but it fits in here
124 because so far it is used for doing i18n for gtk titles...)
125 **************************************************************************/
126 void intl_slist(int n
, const char **s
, bool *done
)
139 /****************************************************************
140 Set itree to the beginning
141 *****************************************************************/
142 void itree_begin(GtkTreeModel
*model
, ITree
*it
)
145 it
->end
= !gtk_tree_model_get_iter_first(it
->model
, &it
->it
);
148 /****************************************************************
149 Return whether itree end has been reached
150 *****************************************************************/
151 gboolean
itree_end(ITree
*it
)
156 /****************************************************************
157 Make itree to go forward one step
158 *****************************************************************/
159 void itree_next(ITree
*it
)
161 it
->end
= !gtk_tree_model_iter_next(it
->model
, &it
->it
);
164 /****************************************************************
165 Store values to itree
166 *****************************************************************/
167 void itree_set(ITree
*it
, ...)
172 gtk_tree_store_set_valist(GTK_TREE_STORE(it
->model
), &it
->it
, ap
);
176 /****************************************************************
177 Get values from itree
178 *****************************************************************/
179 void itree_get(ITree
*it
, ...)
184 gtk_tree_model_get_valist(it
->model
, &it
->it
, ap
);
188 /****************************************************************
189 Append one item to the end of tree store
190 *****************************************************************/
191 void tstore_append(GtkTreeStore
*store
, ITree
*it
, ITree
*parent
)
193 it
->model
= GTK_TREE_MODEL(store
);
195 gtk_tree_store_append(GTK_TREE_STORE(it
->model
), &it
->it
, &parent
->it
);
197 gtk_tree_store_append(GTK_TREE_STORE(it
->model
), &it
->it
, NULL
);
201 /****************************************************************
202 Return whether current itree item is selected
203 *****************************************************************/
204 gboolean
itree_is_selected(GtkTreeSelection
*selection
, ITree
*it
)
206 return gtk_tree_selection_iter_is_selected(selection
, &it
->it
);
209 /****************************************************************
210 Add current itree item to selection
211 *****************************************************************/
212 void itree_select(GtkTreeSelection
*selection
, ITree
*it
)
214 gtk_tree_selection_select_iter(selection
, &it
->it
);
217 /****************************************************************
218 Remove current itree item from selection
219 *****************************************************************/
220 void itree_unselect(GtkTreeSelection
*selection
, ITree
*it
)
222 gtk_tree_selection_unselect_iter(selection
, &it
->it
);
225 /**************************************************************************
226 Return the selected row in a GtkTreeSelection.
227 If no row is selected return -1.
228 **************************************************************************/
229 gint
gtk_tree_selection_get_row(GtkTreeSelection
*selection
)
235 if (gtk_tree_selection_get_selected(selection
, &model
, &it
)) {
239 path
= gtk_tree_model_get_path(model
, &it
);
240 idx
= gtk_tree_path_get_indices(path
);
242 gtk_tree_path_free(path
);
247 /**************************************************************************
249 **************************************************************************/
250 void gtk_tree_view_focus(GtkTreeView
*view
)
256 if ((model
= gtk_tree_view_get_model(view
))
257 && gtk_tree_model_get_iter_first(model
, &iter
)
258 && (path
= gtk_tree_model_get_path(model
, &iter
))) {
259 gtk_tree_view_set_cursor(view
, path
, NULL
, FALSE
);
260 gtk_tree_path_free(path
);
261 gtk_widget_grab_focus(GTK_WIDGET(view
));
265 /**************************************************************************
266 Create an auxiliary menubar (i.e., not the main menubar at the top of
268 **************************************************************************/
269 GtkWidget
*gtk_aux_menu_bar_new(void) {
270 GtkWidget
*menubar
= gtk_menu_bar_new();
273 * Ubuntu Linux's Ayatana/Unity desktop environment likes to steal the
274 * application's main menu bar from its window and put it at the top of
275 * the screen. It needs a hint in order not to steal menu bars other
276 * than the main one. Gory details at
277 * https://bugs.launchpad.net/ubuntu/+source/freeciv/+bug/743265
279 if (g_object_class_find_property(
280 G_OBJECT_CLASS(GTK_MENU_BAR_GET_CLASS(menubar
)), "ubuntu-local")) {
281 g_object_set(G_OBJECT(menubar
), "ubuntu-local", TRUE
, NULL
);
287 /**************************************************************************
288 Generic close callback for all widgets
289 **************************************************************************/
290 static void close_callback(GtkDialog
*dialog
, gpointer data
)
292 gtk_widget_destroy(GTK_WIDGET(dialog
));
295 /**********************************************************************
296 This function handles new windows which are subwindows to the
297 toplevel window. It must be called on every dialog in the game,
298 so fullscreen windows are handled properly by the window manager.
299 ***********************************************************************/
300 void setup_dialog(GtkWidget
*shell
, GtkWidget
*parent
)
302 if (gui_options
.gui_gtk2_dialogs_on_top
|| gui_options
.gui_gtk2_fullscreen
) {
303 gtk_window_set_transient_for(GTK_WINDOW(shell
),
305 gtk_window_set_type_hint(GTK_WINDOW(shell
),
306 GDK_WINDOW_TYPE_HINT_DIALOG
);
308 gtk_window_set_type_hint(GTK_WINDOW(shell
),
309 GDK_WINDOW_TYPE_HINT_NORMAL
);
312 /* Close dialog window on Escape keypress. */
313 if (GTK_IS_DIALOG(shell
)) {
314 g_signal_connect_after(shell
, "close", G_CALLBACK(close_callback
), shell
);
318 /**************************************************************************
319 Emit a dialog response.
320 **************************************************************************/
321 static void gui_dialog_response(struct gui_dialog
*dlg
, int response
)
323 if (dlg
->response_callback
) {
324 (*dlg
->response_callback
)(dlg
, response
, dlg
->user_data
);
328 /**************************************************************************
329 Default dialog response handler. Destroys the dialog.
330 **************************************************************************/
331 static void gui_dialog_destroyed(struct gui_dialog
*dlg
, int response
,
334 gui_dialog_destroy(dlg
);
337 /**************************************************************************
338 Cleanups the leftovers after a dialog is destroyed.
339 **************************************************************************/
340 static void gui_dialog_destroy_handler(GtkWidget
*w
, struct gui_dialog
*dlg
)
342 if (dlg
->type
== GUI_DIALOG_TAB
) {
343 GtkWidget
*notebook
= dlg
->v
.tab
.notebook
;
344 gulong handler_id
= dlg
->v
.tab
.handler_id
;
346 g_signal_handler_disconnect(notebook
, handler_id
);
349 g_object_unref(dlg
->gui_button
);
351 if (*(dlg
->source
)) {
352 *(dlg
->source
) = NULL
;
355 dialog_list
= g_list_remove(dialog_list
, dlg
);
357 /* Raise the return dialog set by gui_dialog_set_return_dialog() */
358 if (dlg
->return_dialog_id
!= -1) {
360 for (it
= dialog_list
; it
; it
= g_list_next(it
)) {
361 struct gui_dialog
* adialog
= (struct gui_dialog
*)it
->data
;
362 if (adialog
->id
== dlg
->return_dialog_id
) {
363 gui_dialog_raise(adialog
);
376 /**************************************************************************
377 Emit a delete event response on dialog deletion in case the end-user
378 needs to know when a deletion took place.
380 **************************************************************************/
381 static gint
gui_dialog_delete_handler(GtkWidget
*widget
,
382 GdkEventAny
*ev
, gpointer data
)
384 struct gui_dialog
*dlg
= data
;
386 /* emit response signal. */
387 gui_dialog_response(dlg
, GTK_RESPONSE_DELETE_EVENT
);
389 /* do the destroy by default. */
393 /**************************************************************************
394 Emit a delete event response on dialog deletion in case the end-user
395 needs to know when a deletion took place.
397 **************************************************************************/
398 static gint
gui_dialog_delete_tab_handler(struct gui_dialog
* dlg
)
403 notebook
= dlg
->v
.tab
.notebook
;
404 n
= gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook
));
405 if (gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook
), n
)
406 != dlg
->v
.tab
.child
) {
407 gui_dialog_set_return_dialog(dlg
, NULL
);
410 /* emit response signal. */
411 gui_dialog_response(dlg
, GTK_RESPONSE_DELETE_EVENT
);
413 /* do the destroy by default. */
418 /**************************************************************************
419 Allow the user to close a dialog using Escape or CTRL+W.
420 **************************************************************************/
421 static gboolean
gui_dialog_key_press_handler(GtkWidget
*w
, GdkEventKey
*ev
,
424 struct gui_dialog
*dlg
= data
;
426 if (ev
->keyval
== GDK_Escape
427 || ((ev
->state
& GDK_CONTROL_MASK
) && ev
->keyval
== GDK_w
)) {
428 /* emit response signal. */
429 gui_dialog_response(dlg
, GTK_RESPONSE_DELETE_EVENT
);
432 /* propagate event further. */
436 /**************************************************************************
437 Resets tab colour on tab activation.
438 **************************************************************************/
439 static void gui_dialog_switch_page_handler(GtkNotebook
*notebook
,
440 GtkNotebookPage
*page
,
442 struct gui_dialog
*dlg
)
446 n
= gtk_notebook_page_num(GTK_NOTEBOOK(dlg
->v
.tab
.notebook
), dlg
->vbox
);
449 GtkRcStyle
*rc_style
= gtk_widget_get_modifier_style(dlg
->v
.tab
.label
);
451 rc_style
->color_flags
[GTK_STATE_ACTIVE
] &= ~GTK_RC_FG
;
452 gtk_widget_modify_style(dlg
->v
.tab
.label
, rc_style
);
456 /**************************************************************************
457 Changes a tab into a window.
458 **************************************************************************/
459 static void gui_dialog_detach(struct gui_dialog
* dlg
)
462 GtkWidget
*window
, *notebook
;
465 if (dlg
->type
!= GUI_DIALOG_TAB
) {
468 dlg
->type
= GUI_DIALOG_WINDOW
;
470 /* Create a new reference to the main widget, so it won't be
471 * destroyed in gtk_notebook_remove_page() */
472 g_object_ref(dlg
->vbox
);
474 /* Remove widget from the notebook */
475 notebook
= dlg
->v
.tab
.notebook
;
476 handler_id
= dlg
->v
.tab
.handler_id
;
477 g_signal_handler_disconnect(notebook
, handler_id
);
479 n
= gtk_notebook_page_num(GTK_NOTEBOOK(dlg
->v
.tab
.notebook
), dlg
->vbox
);
480 gtk_notebook_remove_page(GTK_NOTEBOOK(dlg
->v
.tab
.notebook
), n
);
483 /* Create window and put the widget inside */
484 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
485 gtk_window_set_title(GTK_WINDOW(window
), dlg
->title
);
486 setup_dialog(window
, toplevel
);
488 gtk_container_add(GTK_CONTAINER(window
), dlg
->vbox
);
489 dlg
->v
.window
= window
;
490 g_signal_connect(window
, "delete_event",
491 G_CALLBACK(gui_dialog_delete_handler
), dlg
);
493 gtk_window_set_default_size(GTK_WINDOW(dlg
->v
.window
),
495 dlg
->default_height
);
496 gtk_widget_show_all(window
);
499 /***************************************************************************
500 Someone has clicked on a label in a notebook
501 ***************************************************************************/
502 static gboolean
click_on_tab_callback(GtkWidget
* w
,
503 GdkEventButton
* button
,
506 if (button
->type
!= GDK_2BUTTON_PRESS
) {
509 if (button
->button
!= 1) {
512 gui_dialog_detach((struct gui_dialog
*) data
);
517 /**************************************************************************
518 Creates a new dialog. It will be a tab or a window depending on the
519 current user setting of 'gui_gtk2_enable_tabs'.
520 Sets pdlg to point to the dialog once it is create, Zeroes pdlg on
522 user_data will be passed through response function
523 check_top indicates if the layout deision should depend on the parent.
524 **************************************************************************/
525 void gui_dialog_new(struct gui_dialog
**pdlg
, GtkNotebook
*notebook
,
526 gpointer user_data
, bool check_top
)
528 struct gui_dialog
*dlg
;
529 GtkWidget
*vbox
, *action_area
;
530 static int dialog_id_counter
;
532 dlg
= fc_malloc(sizeof(*dlg
));
533 dialog_list
= g_list_prepend(dialog_list
, dlg
);
537 dlg
->user_data
= user_data
;
540 dlg
->default_width
= 200;
541 dlg
->default_height
= 300;
543 if (gui_options
.gui_gtk2_enable_tabs
) {
544 dlg
->type
= GUI_DIALOG_TAB
;
546 dlg
->type
= GUI_DIALOG_WINDOW
;
550 gui_action
= gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL
);
552 dlg
->gui_button
= gtk_size_group_new(GTK_SIZE_GROUP_BOTH
);
554 if (gui_options
.gui_gtk2_enable_tabs
555 && (check_top
&& notebook
!= GTK_NOTEBOOK(top_notebook
))
556 && !gui_options
.gui_gtk2_small_display_layout
) {
557 /* We expect this to be short (as opposed to tall); maximise usable
558 * height by putting buttons down the right hand side */
559 vbox
= gtk_hbox_new(FALSE
, 0);
560 action_area
= gtk_vbox_new(FALSE
, 2);
562 /* We expect this to be reasonably tall; maximise usable width by
563 * putting buttons along the bottom */
564 vbox
= gtk_vbox_new(FALSE
, 0);
565 action_area
= gtk_hbox_new(FALSE
, 2);
568 gtk_widget_show(vbox
);
569 gtk_box_pack_end(GTK_BOX(vbox
), action_area
, FALSE
, TRUE
, 0);
570 gtk_widget_show(action_area
);
572 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 2);
573 gtk_box_set_spacing(GTK_BOX(action_area
), 4);
574 gtk_container_set_border_width(GTK_CONTAINER(action_area
), 2);
577 case GUI_DIALOG_WINDOW
:
581 window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
582 gtk_widget_set_name(window
, "Freeciv");
583 gtk_window_set_position(GTK_WINDOW(window
), GTK_WIN_POS_MOUSE
);
584 setup_dialog(window
, toplevel
);
586 gtk_container_add(GTK_CONTAINER(window
), vbox
);
587 dlg
->v
.window
= window
;
588 g_signal_connect(window
, "delete_event",
589 G_CALLBACK(gui_dialog_delete_handler
), dlg
);
595 GtkWidget
*hbox
, *label
, *image
, *button
, *event_box
;
599 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU
, &w
, &h
);
601 hbox
= gtk_hbox_new(FALSE
, 0);
603 label
= gtk_label_new(NULL
);
604 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0.5);
605 gtk_misc_set_padding(GTK_MISC(label
), 4, 0);
606 gtk_box_pack_start(GTK_BOX(hbox
), label
, TRUE
, TRUE
, 0);
608 button
= gtk_button_new();
609 gtk_button_set_relief(GTK_BUTTON(button
), GTK_RELIEF_NONE
);
610 g_signal_connect_swapped(button
, "clicked",
611 G_CALLBACK(gui_dialog_delete_tab_handler
), dlg
);
613 buf
= g_strdup_printf(_("Close Tab:\n%s"), _("Ctrl+W"));
614 gtk_widget_set_tooltip_text(button
, buf
);
617 image
= gtk_image_new_from_stock(GTK_STOCK_CLOSE
, GTK_ICON_SIZE_MENU
);
618 gtk_widget_set_size_request(button
, w
, h
);
619 gtk_container_add(GTK_CONTAINER(button
), image
);
621 gtk_box_pack_start(GTK_BOX(hbox
), button
, FALSE
, FALSE
, 0);
623 gtk_widget_show_all(hbox
);
625 event_box
= gtk_event_box_new();
626 gtk_container_add(GTK_CONTAINER(event_box
), hbox
);
628 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), vbox
, event_box
);
629 dlg
->v
.tab
.handler_id
=
630 g_signal_connect(notebook
, "switch-page",
631 G_CALLBACK(gui_dialog_switch_page_handler
), dlg
);
632 dlg
->v
.tab
.child
= vbox
;
634 dlg
->v
.tab
.label
= label
;
635 dlg
->v
.tab
.notebook
= GTK_WIDGET(notebook
);
637 gtk_widget_add_events(event_box
, GDK_BUTTON2_MOTION_MASK
);
638 g_signal_connect(event_box
, "button-press-event",
639 G_CALLBACK(click_on_tab_callback
), dlg
);
645 dlg
->action_area
= action_area
;
647 dlg
->response_callback
= gui_dialog_destroyed
;
649 dlg
->id
= dialog_id_counter
;
651 dlg
->return_dialog_id
= -1;
653 g_signal_connect(vbox
, "destroy",
654 G_CALLBACK(gui_dialog_destroy_handler
), dlg
);
655 g_signal_connect(vbox
, "key_press_event",
656 G_CALLBACK(gui_dialog_key_press_handler
), dlg
);
658 g_object_set_data(G_OBJECT(vbox
), "gui-dialog-data", dlg
);
661 /**************************************************************************
662 Called when a dialog button is activated.
663 **************************************************************************/
664 static void action_widget_activated(GtkWidget
*button
, GtkWidget
*vbox
)
666 struct gui_dialog
*dlg
=
667 g_object_get_data(G_OBJECT(vbox
), "gui-dialog-data");
669 g_object_get_data(G_OBJECT(button
), "gui-dialog-response-data");
671 gui_dialog_response(dlg
, GPOINTER_TO_INT(arg2
));
674 /**************************************************************************
675 Places a button into a dialog, taking care of setting up signals, etc.
676 **************************************************************************/
677 static void gui_dialog_pack_button(struct gui_dialog
*dlg
, GtkWidget
*button
,
682 fc_assert_ret(GTK_IS_BUTTON(button
));
684 g_object_set_data(G_OBJECT(button
), "gui-dialog-response-data",
685 GINT_TO_POINTER(response
));
687 if ((signal_id
= g_signal_lookup("clicked", GTK_TYPE_BUTTON
))) {
690 closure
= g_cclosure_new_object(G_CALLBACK(action_widget_activated
),
691 G_OBJECT(dlg
->vbox
));
692 g_signal_connect_closure_by_id(button
, signal_id
, 0, closure
, FALSE
);
695 gtk_box_pack_end(GTK_BOX(dlg
->action_area
), button
, FALSE
, TRUE
, 0);
696 gtk_size_group_add_widget(gui_action
, button
);
697 gtk_size_group_add_widget(dlg
->gui_button
, button
);
700 /**************************************************************************
701 Adds a button to a dialog, allowing the choice of a special stock item.
702 **************************************************************************/
703 GtkWidget
*gui_dialog_add_stockbutton(struct gui_dialog
*dlg
,
705 const char *text
, int response
)
709 button
= gtk_stockbutton_new(stock
, text
);
710 GTK_WIDGET_SET_FLAGS(button
, GTK_CAN_DEFAULT
);
711 gui_dialog_pack_button(dlg
, button
, response
);
716 /**************************************************************************
717 Adds a button to a dialog.
718 **************************************************************************/
719 GtkWidget
*gui_dialog_add_button(struct gui_dialog
*dlg
,
720 const char *text
, int response
)
724 button
= gtk_button_new_from_stock(text
);
725 GTK_WIDGET_SET_FLAGS(button
, GTK_CAN_DEFAULT
);
726 gui_dialog_pack_button(dlg
, button
, response
);
731 /**************************************************************************
732 Adds a widget to a dialog.
733 **************************************************************************/
734 GtkWidget
*gui_dialog_add_widget(struct gui_dialog
*dlg
,
737 gtk_box_pack_start(GTK_BOX(dlg
->action_area
), widget
, FALSE
, TRUE
, 0);
738 gtk_size_group_add_widget(gui_action
, widget
);
743 /**************************************************************************
744 Changes the default dialog response.
745 **************************************************************************/
746 void gui_dialog_set_default_response(struct gui_dialog
*dlg
, int response
)
751 children
= gtk_container_get_children(GTK_CONTAINER(dlg
->action_area
));
753 for (list
= children
; list
; list
= g_list_next(list
)) {
754 GtkWidget
*button
= list
->data
;
756 if (GTK_IS_BUTTON(button
)) {
757 gpointer data
= g_object_get_data(G_OBJECT(button
),
758 "gui-dialog-response-data");
760 if (response
== GPOINTER_TO_INT(data
)) {
761 gtk_widget_grab_default(button
);
766 g_list_free(children
);
769 /**************************************************************************
770 Change the sensitivity of a dialog button.
771 **************************************************************************/
772 void gui_dialog_set_response_sensitive(struct gui_dialog
*dlg
,
773 int response
, bool setting
)
778 children
= gtk_container_get_children(GTK_CONTAINER(dlg
->action_area
));
780 for (list
= children
; list
; list
= g_list_next(list
)) {
781 GtkWidget
*button
= list
->data
;
783 if (GTK_IS_BUTTON(button
)) {
784 gpointer data
= g_object_get_data(G_OBJECT(button
),
785 "gui-dialog-response-data");
787 if (response
== GPOINTER_TO_INT(data
)) {
788 gtk_widget_set_sensitive(button
, setting
);
793 g_list_free(children
);
796 /**************************************************************************
797 Get the dialog's toplevel window.
798 **************************************************************************/
799 GtkWidget
*gui_dialog_get_toplevel(struct gui_dialog
*dlg
)
801 return gtk_widget_get_toplevel(dlg
->vbox
);
804 /**************************************************************************
805 Show the dialog contents, but not the dialog per se.
806 **************************************************************************/
807 void gui_dialog_show_all(struct gui_dialog
*dlg
)
809 gtk_widget_show_all(dlg
->vbox
);
811 if (dlg
->type
== GUI_DIALOG_TAB
) {
814 gint num_visible
= 0;
816 children
= gtk_container_get_children(GTK_CONTAINER(dlg
->action_area
));
818 for (list
= children
; list
; list
= g_list_next(list
)) {
819 GtkWidget
*button
= list
->data
;
821 if (!GTK_IS_BUTTON(button
)) {
824 gpointer data
= g_object_get_data(G_OBJECT(button
),
825 "gui-dialog-response-data");
826 int response
= GPOINTER_TO_INT(data
);
828 if (response
!= GTK_RESPONSE_CLOSE
829 && response
!= GTK_RESPONSE_CANCEL
) {
832 gtk_widget_hide(button
);
836 g_list_free(children
);
838 if (num_visible
== 0) {
839 gtk_widget_hide(dlg
->action_area
);
844 /**************************************************************************
845 Notify the user the dialog has changed.
846 **************************************************************************/
847 void gui_dialog_present(struct gui_dialog
*dlg
)
849 fc_assert_ret(NULL
!= dlg
);
852 case GUI_DIALOG_WINDOW
:
853 gtk_widget_show(dlg
->v
.window
);
857 GtkNotebook
*notebook
= GTK_NOTEBOOK(dlg
->v
.tab
.notebook
);
860 current
= gtk_notebook_get_current_page(notebook
);
861 n
= gtk_notebook_page_num(notebook
, dlg
->vbox
);
864 GtkWidget
*label
= dlg
->v
.tab
.label
;
865 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
866 GdkColor color
= {.red
= 255 << 8, .green
= 0, .blue
= 0};
868 gdk_rgb_find_color(cmap
, &color
);
869 gtk_widget_modify_fg(label
, GTK_STATE_ACTIVE
, &color
);
876 /**************************************************************************
878 **************************************************************************/
879 void gui_dialog_raise(struct gui_dialog
*dlg
)
881 fc_assert_ret(NULL
!= dlg
);
884 case GUI_DIALOG_WINDOW
:
885 gtk_window_present(GTK_WINDOW(dlg
->v
.window
));
889 GtkNotebook
*notebook
= GTK_NOTEBOOK(dlg
->v
.tab
.notebook
);
892 n
= gtk_notebook_page_num(notebook
, dlg
->vbox
);
893 gtk_notebook_set_current_page(notebook
, n
);
899 /**************************************************************************
900 Alert the user to an important event.
901 **************************************************************************/
902 void gui_dialog_alert(struct gui_dialog
*dlg
)
904 fc_assert_ret(NULL
!= dlg
);
907 case GUI_DIALOG_WINDOW
:
911 GtkNotebook
*notebook
= GTK_NOTEBOOK(dlg
->v
.tab
.notebook
);
914 current
= gtk_notebook_get_current_page(notebook
);
915 n
= gtk_notebook_page_num(notebook
, dlg
->vbox
);
918 GtkWidget
*label
= dlg
->v
.tab
.label
;
919 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
920 GdkColor color
= {.red
= 0, .green
= 0, .blue
= 255 << 8};
922 gdk_rgb_find_color(cmap
, &color
);
923 gtk_widget_modify_fg(label
, GTK_STATE_ACTIVE
, &color
);
930 /**************************************************************************
931 Sets the dialog's default size (applies to toplevel windows only).
932 **************************************************************************/
933 void gui_dialog_set_default_size(struct gui_dialog
*dlg
, int width
, int height
)
935 dlg
->default_width
= width
;
936 dlg
->default_height
= height
;
938 case GUI_DIALOG_WINDOW
:
939 gtk_window_set_default_size(GTK_WINDOW(dlg
->v
.window
), width
, height
);
946 /**************************************************************************
947 Changes a dialog's title.
948 **************************************************************************/
949 void gui_dialog_set_title(struct gui_dialog
*dlg
, const char *title
)
954 dlg
->title
= fc_strdup(title
);
956 case GUI_DIALOG_WINDOW
:
957 gtk_window_set_title(GTK_WINDOW(dlg
->v
.window
), title
);
960 gtk_label_set_text_with_mnemonic(GTK_LABEL(dlg
->v
.tab
.label
), title
);
965 /**************************************************************************
967 **************************************************************************/
968 void gui_dialog_destroy(struct gui_dialog
*dlg
)
971 case GUI_DIALOG_WINDOW
:
972 gtk_widget_destroy(dlg
->v
.window
);
978 n
= gtk_notebook_page_num(GTK_NOTEBOOK(dlg
->v
.tab
.notebook
), dlg
->vbox
);
979 gtk_notebook_remove_page(GTK_NOTEBOOK(dlg
->v
.tab
.notebook
), n
);
985 /**************************************************************************
987 **************************************************************************/
988 void gui_dialog_destroy_all(void)
992 for (it
= dialog_list
; it
; it
= it_next
) {
993 it_next
= g_list_next(it
);
995 gui_dialog_destroy((struct gui_dialog
*)it
->data
);
999 /**************************************************************************
1000 Set the response callback for a dialog.
1001 **************************************************************************/
1002 void gui_dialog_response_set_callback(struct gui_dialog
*dlg
,
1003 GUI_DIALOG_RESPONSE_FUN fun
)
1005 dlg
->response_callback
= fun
;
1008 /**************************************************************************
1009 When the dlg dialog is destroyed the return_dialog will be raised
1010 **************************************************************************/
1011 void gui_dialog_set_return_dialog(struct gui_dialog
*dlg
,
1012 struct gui_dialog
*return_dialog
)
1014 if (return_dialog
== NULL
) {
1015 dlg
->return_dialog_id
= -1;
1017 dlg
->return_dialog_id
= return_dialog
->id
;
1021 /**************************************************************************
1022 Updates a gui font style.
1023 **************************************************************************/
1024 void gui_update_font(const char *font_name
, const char *font_value
)
1028 fc_snprintf(str
, sizeof(str
),
1029 "style \"ext-%s\" {\n"
1030 " font_name = \"%s\"\n"
1033 "widget \"Freeciv*.%s\" style \"ext-%s\"",
1034 font_name
, font_value
, font_name
, font_name
);
1036 gtk_rc_parse_string(str
);
1039 /****************************************************************************
1040 Update a font option which is not attached to a widget.
1041 ****************************************************************************/
1042 void gui_update_font_full(const char *font_name
, const char *font_value
,
1045 GtkSettings
*settings
;
1050 gui_update_font(font_name
, font_value
);
1052 screen
= gdk_screen_get_default();
1053 settings
= gtk_settings_get_for_screen(screen
);
1055 fc_snprintf(buf
, sizeof(buf
), "Freeciv*.%s", font_name
);
1056 style
= gtk_rc_get_style_by_paths(settings
, buf
, NULL
, G_TYPE_NONE
);
1059 g_object_ref(style
);
1061 style
= gtk_style_new();
1065 g_object_unref(*pstyle
);
1070 /****************************************************************************
1071 Temporarily disable signal invocation of the given callback for the given
1072 GObject. Re-enable the signal with enable_gobject_callback.
1073 ****************************************************************************/
1074 void disable_gobject_callback(GObject
*obj
, GCallback cb
)
1082 hid
= g_signal_handler_find(obj
, G_SIGNAL_MATCH_FUNC
,
1083 0, 0, NULL
, cb
, NULL
);
1084 g_signal_handler_block(obj
, hid
);
1087 /****************************************************************************
1088 Re-enable a signal callback blocked by disable_gobject_callback.
1089 ****************************************************************************/
1090 void enable_gobject_callback(GObject
*obj
, GCallback cb
)
1098 hid
= g_signal_handler_find(obj
, G_SIGNAL_MATCH_FUNC
,
1099 0, 0, NULL
, cb
, NULL
);
1100 g_signal_handler_unblock(obj
, hid
);
1103 /**************************************************************************
1104 Convenience function to add a column to a GtkTreeView. Returns the added
1105 column, or NULL if an error occurred.
1106 **************************************************************************/
1107 GtkTreeViewColumn
*add_treeview_column(GtkWidget
*view
, const char *title
,
1108 GType gtype
, int model_index
)
1110 GtkTreeViewColumn
*col
;
1111 GtkCellRenderer
*rend
;
1114 fc_assert_ret_val(view
!= NULL
, NULL
);
1115 fc_assert_ret_val(GTK_IS_TREE_VIEW(view
), NULL
);
1116 fc_assert_ret_val(title
!= NULL
, NULL
);
1118 if (gtype
== G_TYPE_BOOLEAN
) {
1119 rend
= gtk_cell_renderer_toggle_new();
1121 } else if (gtype
== GDK_TYPE_PIXBUF
) {
1122 rend
= gtk_cell_renderer_pixbuf_new();
1125 rend
= gtk_cell_renderer_text_new();
1129 col
= gtk_tree_view_column_new_with_attributes(title
, rend
, attr
,
1131 gtk_tree_view_append_column(GTK_TREE_VIEW(view
), col
);