Use gtk1/gtk2 compatibility macros to reduce #ifdefs.
[obnox/wireshark/wip.git] / gtk / dlg_utils.c
1 /* dlg_utils.c
2  * Utilities to use when constructing dialogs
3  *
4  * $Id: dlg_utils.c,v 1.10 2002/11/10 11:00:29 oabad Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31 #include <gdk/gdkkeysyms.h>
32
33 #include "gtkglobals.h"
34 #include "ui_util.h"
35 #include "compat_macros.h"
36
37 static void
38 dlg_activate (GtkWidget *widget, gpointer ok_button);
39
40 static gint
41 dlg_key_press (GtkWidget *widget, GdkEventKey *event, gpointer cancel_button);
42
43 /* Create a dialog box window that belongs to Ethereal's main window. */
44 GtkWidget *
45 dlg_window_new(const gchar *title)
46 {
47         GtkWidget *win;
48
49 #if GTK_MAJOR_VERSION < 2
50         win = gtk_window_new(GTK_WINDOW_DIALOG);
51 #else
52         win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
53 #endif
54         gtk_window_set_transient_for(GTK_WINDOW(win), GTK_WINDOW(top_level));
55         gtk_window_set_title(GTK_WINDOW(win), title);
56         SIGNAL_CONNECT(win, "realize", window_icon_realize_cb, NULL);
57         return win;
58 }
59
60 /* Set the "activate" signal for a widget to call a routine to
61    activate the "OK" button for a dialog box.
62
63    XXX - there should be a way to specify that a GtkEntry widget
64    shouldn't itself handle the Return key, but should let it be
65    passed on to the parent, so that you don't have to do this
66    by hand for every GtkEntry widget in a dialog box, but, alas,
67    there isn't.  (Does this problem exist for other widgets?
68    I.e., are there any others that seize the Return key? */
69 void
70 dlg_set_activate(GtkWidget *widget, GtkWidget *ok_button)
71 {
72   SIGNAL_CONNECT(widget, "activate", dlg_activate, ok_button);
73 }
74
75 static void
76 dlg_activate (GtkWidget *widget _U_, gpointer ok_button)
77 {
78   gtk_widget_activate(GTK_WIDGET(ok_button));
79 }
80
81 /* Set the "key_press_event" signal for a top-level dialog window to
82    call a routine to activate the "Cancel" button for a dialog box if
83    the key being pressed is the <Esc> key.
84
85    XXX - there should be a GTK+ widget that'll do that for you, and
86    let you specify a "Cancel" button.  It should also not impose
87    a requirement that there be a separator in the dialog box, as
88    the GtkDialog widget does; the visual convention that there's
89    such a separator between the rest of the dialog boxes and buttons
90    such as "OK" and "Cancel" is, for better or worse, not universal
91    (not even in GTK+ - look at the GtkFileSelection dialog!). */
92 void
93 dlg_set_cancel(GtkWidget *widget, GtkWidget *cancel_button)
94 {
95   SIGNAL_CONNECT(widget, "key_press_event", dlg_key_press, cancel_button);
96 }
97
98 static gint
99 dlg_key_press (GtkWidget *widget, GdkEventKey *event, gpointer cancel_button)
100 {
101   g_return_val_if_fail (widget != NULL, FALSE);
102   g_return_val_if_fail (event != NULL, FALSE);
103
104   if (event->keyval == GDK_Escape) {
105     gtk_widget_activate(GTK_WIDGET(cancel_button));
106     return TRUE;
107   }
108
109   return FALSE;
110 }
111
112 #if GTK_MAJOR_VERSION < 2
113 /* Sigh.  GTK+ appears not to acknowledge that it should be possible
114    to attach mnemonics to anything other than menu items; provide
115    routines to create radio and check buttons with labels that
116    include mnemonics.  */
117 typedef struct {
118         GtkWidget *button;
119         GtkAccelGroup *accel_group;
120 } fix_label_args_t;
121
122 static void
123 dlg_fix_label_callback(GtkWidget *label_widget, gpointer data)
124 {
125   fix_label_args_t *args = data;
126   gchar *label;
127   guint accel_key;
128
129   gtk_label_get(GTK_LABEL(label_widget), &label);
130   accel_key = gtk_label_parse_uline(GTK_LABEL(label_widget), label);
131   if (accel_key != GDK_VoidSymbol) {
132     /* Yes, we have a mnemonic. */
133     gtk_widget_add_accelerator(args->button, "clicked", args->accel_group,
134                                 accel_key, 0, GTK_ACCEL_LOCKED);
135     gtk_widget_add_accelerator(args->button, "clicked", args->accel_group,
136                                 accel_key, GDK_MOD1_MASK, GTK_ACCEL_LOCKED);
137   }
138 }
139
140 static void
141 dlg_fix_button_label(GtkWidget *button, GtkAccelGroup *accel_group)
142 {
143   fix_label_args_t args;
144
145   args.button = button;
146   args.accel_group = accel_group;
147   gtk_container_foreach(GTK_CONTAINER(button), dlg_fix_label_callback, &args);
148 }
149
150 GtkWidget *
151 dlg_radio_button_new_with_label_with_mnemonic(GSList *group,
152                 const gchar *label, GtkAccelGroup *accel_group)
153 {
154   GtkWidget *radio_button;
155
156   radio_button = gtk_radio_button_new_with_label (group, label);
157   dlg_fix_button_label(radio_button, accel_group);
158   return radio_button;
159 }
160
161 GtkWidget *
162 dlg_check_button_new_with_label_with_mnemonic(const gchar *label,
163                         GtkAccelGroup *accel_group)
164 {
165   GtkWidget *check_button;
166
167   check_button = gtk_check_button_new_with_label (label);
168   dlg_fix_button_label(check_button, accel_group);
169   return check_button;
170 }
171 #endif