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