2 * Utilities to use when constructing dialogs
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
30 #include <gdk/gdkkeysyms.h>
33 #include <epan/filesystem.h>
40 #include "gtkglobals.h"
41 #include "gui_utils.h"
42 #include "dlg_utils.h"
43 #include "compat_macros.h"
55 dlg_activate (GtkWidget *widget, gpointer ok_button);
57 /* create a button for the button row (helper for dlg_button_row_new) */
59 dlg_button_new(GtkWidget *hbox, GtkWidget *button_hbox, const gchar *stock_id)
63 button = BUTTON_NEW_FROM_STOCK(stock_id);
64 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
65 OBJECT_SET_DATA(hbox, stock_id, button);
66 gtk_box_pack_end(GTK_BOX(button_hbox), button, FALSE, FALSE, 0);
67 gtk_widget_show(button);
72 * Set the focus and default for the nth item in a button row, with
73 * 0 being the first item.
75 #define BUTTON_HBOX_KEY "button_hbox"
77 dlg_button_focus_nth(GtkWidget *hbox, gint focus_item) {
78 GtkWidget *button_hbox, *button;
85 button_hbox = OBJECT_GET_DATA(hbox, BUTTON_HBOX_KEY);
86 children = gtk_container_get_children(GTK_CONTAINER(button_hbox));
89 if (cur_item == focus_item) {
90 button = children->data;
91 gtk_widget_grab_focus(button);
92 gtk_widget_grab_default(button);
95 children = g_list_next(children);
99 g_list_free(children);
102 /* create a button row for a dialog */
104 /* The purpose of this is, to have one place available, where all button rows
105 * from all dialogs are laid out. This will:
107 * a.) keep the button layout more consistent over the different dialogs
108 * b.) being able to switch between different button layouts, e.g.:
109 * GTK1 (e.g. win32) "OK" "Apply" "Cancel"
110 * GTK2 (e.g. GNOME) "Apply" "Cancel" "OK"
113 dlg_button_row_new(const gchar *stock_id_first, ...)
116 va_list stock_id_list;
117 const gchar *stock_id = stock_id_first;
119 GtkWidget *button_hbox;
120 GtkWidget *help_hbox;
123 const gchar *ok = NULL;
124 const gchar *apply = NULL;
125 const gchar *save = NULL;
126 const gchar *dont_save = NULL;
127 const gchar *cancel = NULL;
128 const gchar *close = NULL;
129 const gchar *clear = NULL;
130 const gchar *cap_start = NULL;
131 const gchar *cap_stop = NULL;
132 const gchar *stop = NULL;
133 const gchar *create_stat = NULL;
134 const gchar *help = NULL;
135 const gchar *print = NULL;
136 const gchar *find = NULL;
137 const gchar *jump = NULL;
138 const gchar *yes = NULL;
139 const gchar *no = NULL;
140 const gchar *filter_stream= NULL;
143 va_start(stock_id_list, stock_id_first);
145 /* get all buttons needed */
146 while(stock_id != NULL) {
147 if (strcmp(stock_id, GTK_STOCK_OK) == 0) {
149 } else if (strcmp(stock_id, WIRESHARK_STOCK_CREATE_STAT) == 0) {
150 create_stat = stock_id;
151 } else if (strcmp(stock_id, GTK_STOCK_APPLY) == 0) {
153 } else if (strcmp(stock_id, GTK_STOCK_SAVE) == 0) {
155 } else if (strcmp(stock_id, WIRESHARK_STOCK_DONT_SAVE) == 0) {
156 dont_save = stock_id;
157 } else if (strcmp(stock_id, GTK_STOCK_CANCEL) == 0) {
159 } else if (strcmp(stock_id, GTK_STOCK_CLOSE) == 0) {
161 } else if (strcmp(stock_id, GTK_STOCK_CLEAR) == 0) {
164 } else if (strcmp(stock_id, WIRESHARK_STOCK_CAPTURE_START) == 0) {
165 cap_start = stock_id;
166 } else if (strcmp(stock_id, WIRESHARK_STOCK_CAPTURE_STOP) == 0) {
168 #endif /* HAVE_LIBPCAP */
169 } else if (strcmp(stock_id, GTK_STOCK_STOP) == 0) {
171 } else if (strcmp(stock_id, GTK_STOCK_HELP) == 0) {
173 } else if (strcmp(stock_id, GTK_STOCK_PRINT) == 0) {
175 } else if (strcmp(stock_id, GTK_STOCK_FIND) == 0) {
177 } else if (strcmp(stock_id, GTK_STOCK_JUMP_TO) == 0) {
179 } else if (strcmp(stock_id, GTK_STOCK_YES) == 0) {
181 } else if (strcmp(stock_id, GTK_STOCK_NO) == 0) {
183 } else if (strcmp(stock_id, WIRESHARK_STOCK_FILTER_OUT_STREAM) == 0) {
184 filter_stream = stock_id;
186 /* we don't know that button! */
187 g_assert_not_reached();
190 stock_id = va_arg(stock_id_list, gchar *);
192 va_end(stock_id_list);
194 hbox = gtk_hbox_new(FALSE, 0);
195 gtk_widget_show(hbox);
197 button_hbox = gtk_hbutton_box_new();
198 gtk_box_pack_end(GTK_BOX(hbox), button_hbox, TRUE, TRUE, 0);
199 OBJECT_SET_DATA(hbox, BUTTON_HBOX_KEY, button_hbox);
200 gtk_widget_show(button_hbox);
202 help_hbox = gtk_hbutton_box_new();
203 gtk_box_pack_end(GTK_BOX(hbox), help_hbox, FALSE, FALSE, 0);
204 gtk_widget_show(help_hbox);
207 /* if no buttons wanted, simply do nothing */
212 /* if only one button, simply put it in the middle (default) */
213 dlg_button_new(hbox, button_hbox, stock_id_first);
217 /* do we have a help button? -> special handling for it */
219 button = BUTTON_NEW_FROM_STOCK(help);
220 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
221 OBJECT_SET_DATA(hbox, help, button);
222 gtk_box_pack_start(GTK_BOX(help_hbox), button, FALSE, FALSE, 0);
223 gtk_widget_show(button);
227 /* if more than one button, sort buttons from left to right */
228 /* (the whole button cluster will then be right aligned) */
229 gtk_button_box_set_layout (GTK_BUTTON_BOX(button_hbox), GTK_BUTTONBOX_END);
230 gtk_button_box_set_spacing(GTK_BUTTON_BOX(button_hbox), 5);
232 /* GTK+ 1.3 and later - on Win32, we use 1.3[.x] or 2.x, not 1.2[.x] */
233 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2
234 /* beware: sequence of buttons are important! */
236 /* XXX: this can be implemented more elegant of course, but it works as it should */
239 dlg_button_new(hbox, button_hbox, cancel);
240 dlg_button_new(hbox, button_hbox, ok);
243 if (print && cancel) {
244 dlg_button_new(hbox, button_hbox, cancel);
245 dlg_button_new(hbox, button_hbox, print);
248 if (find && cancel) {
249 dlg_button_new(hbox, button_hbox, cancel);
250 dlg_button_new(hbox, button_hbox, find);
253 if (jump && cancel) {
254 dlg_button_new(hbox, button_hbox, cancel);
255 dlg_button_new(hbox, button_hbox, jump);
258 if (save && cancel) {
259 dlg_button_new(hbox, button_hbox, cancel);
260 dlg_button_new(hbox, button_hbox, save);
264 dlg_button_new(hbox, button_hbox, clear);
265 dlg_button_new(hbox, button_hbox, ok);
269 dlg_button_new(hbox, button_hbox, close);
270 dlg_button_new(hbox, button_hbox, save);
273 if (create_stat && cancel) {
274 dlg_button_new(hbox, button_hbox, cancel);
275 dlg_button_new(hbox, button_hbox, create_stat);
278 if (cap_start && cancel) {
279 dlg_button_new(hbox, button_hbox, cancel);
280 dlg_button_new(hbox, button_hbox, cap_start);
283 if (cap_stop && cancel) {
284 dlg_button_new(hbox, button_hbox, cancel);
285 dlg_button_new(hbox, button_hbox, cap_stop);
290 if (ok && save && close) {
291 dlg_button_new(hbox, button_hbox, save);
292 dlg_button_new(hbox, button_hbox, close);
293 dlg_button_new(hbox, button_hbox, ok);
296 if (ok && apply && cancel) {
297 dlg_button_new(hbox, button_hbox, apply);
298 dlg_button_new(hbox, button_hbox, cancel);
299 dlg_button_new(hbox, button_hbox, ok);
302 if (apply && save && close) {
303 dlg_button_new(hbox, button_hbox, save);
304 dlg_button_new(hbox, button_hbox, close);
305 dlg_button_new(hbox, button_hbox, apply);
308 if (yes && no && cancel) {
309 dlg_button_new(hbox, button_hbox, no);
310 dlg_button_new(hbox, button_hbox, cancel);
311 dlg_button_new(hbox, button_hbox, yes);
314 if (save && dont_save && cancel) {
315 dlg_button_new(hbox, button_hbox, dont_save);
316 dlg_button_new(hbox, button_hbox, cancel);
317 dlg_button_new(hbox, button_hbox, save);
322 if (ok && apply && save && cancel) {
323 dlg_button_new(hbox, button_hbox, save);
324 dlg_button_new(hbox, button_hbox, apply);
325 dlg_button_new(hbox, button_hbox, cancel);
326 dlg_button_new(hbox, button_hbox, ok);
329 if (ok && apply && save && close) {
330 dlg_button_new(hbox, button_hbox, save);
331 dlg_button_new(hbox, button_hbox, apply);
332 dlg_button_new(hbox, button_hbox, close);
333 dlg_button_new(hbox, button_hbox, ok);
339 /* beware: sequence of buttons is important! */
340 if (ok != NULL) dlg_button_new(hbox, button_hbox, ok);
341 if (jump != NULL) dlg_button_new(hbox, button_hbox, jump);
342 if (find != NULL) dlg_button_new(hbox, button_hbox, find);
343 if (print != NULL) dlg_button_new(hbox, button_hbox, print);
344 if (create_stat != NULL) dlg_button_new(hbox, button_hbox, create_stat);
345 if (apply != NULL) dlg_button_new(hbox, button_hbox, apply);
346 if (yes != NULL) dlg_button_new(hbox, button_hbox, yes);
347 if (no != NULL) dlg_button_new(hbox, button_hbox, no);
348 if (save != NULL) dlg_button_new(hbox, button_hbox, save);
349 if (dont_save != NULL) dlg_button_new(hbox, button_hbox, dont_save);
350 if (cap_start != NULL) dlg_button_new(hbox, button_hbox, cap_start);
351 if (cap_stop != NULL) dlg_button_new(hbox, button_hbox, cap_stop);
352 if (stop != NULL) dlg_button_new(hbox, button_hbox, stop);
353 if (close != NULL) dlg_button_new(hbox, button_hbox, close);
354 if (clear != NULL) dlg_button_new(hbox, button_hbox, clear);
355 if (cancel != NULL) dlg_button_new(hbox, button_hbox, cancel);
356 if (filter_stream!= NULL) dlg_button_new(hbox, button_hbox, filter_stream);
358 /* GTK2: we don't know that button combination, add it to the above list! */
359 /* g_assert_not_reached(); */
364 /* this is called, when a dialog was closed */
365 static void dlg_destroy_cb(GtkWidget *dialog _U_, gpointer data _U_)
367 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4
369 /* bring main window back to front (workaround for a bug in win32 GTK2.x)
370 XXX - do this only on Windows? */
371 gtk_window_present(GTK_WINDOW(top_level));
377 /* Create a dialog box window that belongs to Wireshark's main window. */
379 dlg_window_new(const gchar *title)
383 #if GTK_MAJOR_VERSION < 2
384 win = window_new(GTK_WINDOW_DIALOG, title);
386 win = window_new(GTK_WINDOW_TOPLEVEL, title);
390 * XXX - if we're running in the capture child process, we can't easily
391 * make this window transient for the main process's window. We just
394 * Perhaps the child process should only capture packets, write them to
395 * a file, and somehow notify the parent process and let *it* do all
396 * the GUI work. If we can do that efficiently (so that we don't drop
397 * more packets), perhaps we can also do so even when we're *not* doing
398 * an "Update list of packets in real time" capture. That'd let the
399 * child process run set-UID on platforms where you need that in order
400 * to capture, and might also simplify the job of having the GUI main
401 * loop wait both for user input and packet arrival.
404 gtk_window_set_transient_for(GTK_WINDOW(win), GTK_WINDOW(top_level));
407 SIGNAL_CONNECT(win, "destroy", dlg_destroy_cb, NULL);
412 /* Set the "activate" signal for a widget to call a routine to
413 activate the "OK" button for a dialog box.
415 XXX - there should be a way to specify that a GtkEntry widget
416 shouldn't itself handle the Return key, but should let it be
417 passed on to the parent, so that you don't have to do this
418 by hand for every GtkEntry widget in a dialog box, but, alas,
419 there isn't. (Does this problem exist for other widgets?
420 I.e., are there any others that seize the Return key? */
422 dlg_set_activate(GtkWidget *widget, GtkWidget *ok_button)
424 SIGNAL_CONNECT(widget, "activate", dlg_activate, ok_button);
428 dlg_activate (GtkWidget *widget _U_, gpointer ok_button)
430 gtk_widget_activate(GTK_WIDGET(ok_button));
433 #if GTK_MAJOR_VERSION < 2
434 /* Sigh. GTK+ appears not to acknowledge that it should be possible
435 to attach mnemonics to anything other than menu items; provide
436 routines to create radio and check buttons with labels that
437 include mnemonics. */
440 GtkAccelGroup *accel_group;
444 dlg_fix_label_callback(GtkWidget *label_widget, gpointer data)
446 fix_label_args_t *args = data;
450 gtk_label_get(GTK_LABEL(label_widget), &label);
451 accel_key = gtk_label_parse_uline(GTK_LABEL(label_widget), label);
452 if (accel_key != GDK_VoidSymbol) {
453 /* Yes, we have a mnemonic. */
454 gtk_widget_add_accelerator(args->button, "clicked", args->accel_group,
455 accel_key, 0, GTK_ACCEL_LOCKED);
456 gtk_widget_add_accelerator(args->button, "clicked", args->accel_group,
457 accel_key, GDK_MOD1_MASK, GTK_ACCEL_LOCKED);
462 dlg_fix_button_label(GtkWidget *button, GtkAccelGroup *accel_group)
464 fix_label_args_t args;
466 args.button = button;
467 args.accel_group = accel_group;
468 gtk_container_foreach(GTK_CONTAINER(button), dlg_fix_label_callback, &args);
472 dlg_radio_button_new_with_label_with_mnemonic(GSList *group,
473 const gchar *label, GtkAccelGroup *accel_group)
475 GtkWidget *radio_button;
477 radio_button = gtk_radio_button_new_with_label (group, label);
478 dlg_fix_button_label(radio_button, accel_group);
483 dlg_check_button_new_with_label_with_mnemonic(const gchar *label,
484 GtkAccelGroup *accel_group)
486 GtkWidget *check_button;
488 check_button = gtk_check_button_new_with_label (label);
489 dlg_fix_button_label(check_button, accel_group);
494 dlg_toggle_button_new_with_label_with_mnemonic(const gchar *label,
495 GtkAccelGroup *accel_group)
497 GtkWidget *toggle_button;
499 toggle_button = gtk_toggle_button_new_with_label (label);
500 dlg_fix_button_label(toggle_button, accel_group);
501 return toggle_button;