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.
33 #include "gtk/gtkglobals.h"
34 #include "gtk/gui_utils.h"
35 #include "gtk/dlg_utils.h"
36 #include "gtk/stock_icons.h"
38 #include "epan/filesystem.h"
42 dlg_activate (GtkWidget *widget, gpointer ok_button);
44 /* create a button for the button row (helper for dlg_button_row_new) */
46 dlg_button_new(GtkWidget *hbox, GtkWidget *button_hbox, const gchar *stock_id)
50 button = gtk_button_new_from_stock(stock_id);
51 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
52 g_object_set_data(G_OBJECT(hbox), stock_id, button);
53 gtk_box_pack_end(GTK_BOX(button_hbox), button, FALSE, FALSE, 0);
54 gtk_widget_show(button);
59 * Set the focus and default for the nth item in a button row, with
60 * 0 being the first item.
62 #define BUTTON_HBOX_KEY "button_hbox"
64 dlg_button_focus_nth(GtkWidget *hbox, gint focus_item) {
65 GtkWidget *button_hbox, *button;
72 button_hbox = g_object_get_data(G_OBJECT(hbox), BUTTON_HBOX_KEY);
73 children = gtk_container_children(GTK_CONTAINER(button_hbox));
76 if (cur_item == focus_item) {
77 button = children->data;
78 gtk_widget_grab_focus(button);
79 gtk_widget_grab_default(button);
82 children = g_list_next(children);
86 g_list_free(children);
89 /* create a button row for a dialog */
91 /* The purpose of this is, to have one place available, where all button rows
92 * from all dialogs are laid out. This will:
94 * a.) keep the button layout more consistent over the different dialogs
95 * b.) being able to switch between different button layouts, e.g.:
96 * e.g. Win32: "OK" "Apply" "Cancel"
97 * e.g. GNOME: "Apply" "Cancel" "OK"
100 dlg_button_row_new(const gchar *stock_id_first, ...)
103 va_list stock_id_list;
104 const gchar *stock_id = stock_id_first;
106 GtkWidget *button_hbox;
107 GtkWidget *help_hbox;
110 const gchar *apply = NULL;
111 const gchar *cancel = NULL;
112 const gchar *cap_start = NULL;
113 const gchar *cap_stop = NULL;
114 const gchar *clear = NULL;
115 const gchar *close = NULL;
116 const gchar *copy = NULL;
117 const gchar *create_stat = NULL;
118 const gchar *delete = NULL;
119 const gchar *dont_save = NULL;
120 const gchar *filter_stream= NULL;
121 const gchar *find = NULL;
122 const gchar *help = NULL;
123 const gchar *jump = NULL;
124 const gchar *no = NULL;
125 const gchar *ok = NULL;
126 const gchar *print = NULL;
127 const gchar *save = NULL;
128 const gchar *stop = NULL;
129 const gchar *yes = NULL;
132 va_start(stock_id_list, stock_id_first);
134 /* get all buttons needed */
135 while(stock_id != NULL) {
136 if (strcmp(stock_id, GTK_STOCK_OK) == 0) {
138 } else if (strcmp(stock_id, WIRESHARK_STOCK_CREATE_STAT) == 0) {
139 create_stat = stock_id;
140 } else if (strcmp(stock_id, GTK_STOCK_APPLY) == 0) {
142 } else if (strcmp(stock_id, GTK_STOCK_SAVE) == 0) {
144 } else if (strcmp(stock_id, WIRESHARK_STOCK_DONT_SAVE) == 0) {
145 dont_save = stock_id;
146 } else if (strcmp(stock_id, GTK_STOCK_CANCEL) == 0) {
148 } else if (strcmp(stock_id, GTK_STOCK_CLOSE) == 0) {
150 } else if (strcmp(stock_id, GTK_STOCK_CLEAR) == 0) {
153 } else if (strcmp(stock_id, WIRESHARK_STOCK_CAPTURE_START) == 0) {
154 cap_start = stock_id;
155 } else if (strcmp(stock_id, WIRESHARK_STOCK_CAPTURE_STOP) == 0) {
157 #endif /* HAVE_LIBPCAP */
158 } else if (strcmp(stock_id, GTK_STOCK_STOP) == 0) {
160 } else if (strcmp(stock_id, GTK_STOCK_HELP) == 0) {
162 } else if (strcmp(stock_id, GTK_STOCK_PRINT) == 0) {
164 } else if (strcmp(stock_id, GTK_STOCK_FIND) == 0) {
166 } else if (strcmp(stock_id, GTK_STOCK_JUMP_TO) == 0) {
168 } else if (strcmp(stock_id, GTK_STOCK_YES) == 0) {
170 } else if (strcmp(stock_id, GTK_STOCK_NO) == 0) {
172 } else if (strcmp(stock_id, WIRESHARK_STOCK_FILTER_OUT_STREAM) == 0) {
173 filter_stream = stock_id;
174 } else if (strcmp(stock_id, GTK_STOCK_DELETE) == 0) {
176 } else if (strcmp(stock_id, GTK_STOCK_COPY) == 0) {
179 /* we don't know that button! */
180 g_assert_not_reached();
183 stock_id = va_arg(stock_id_list, gchar *);
185 va_end(stock_id_list);
187 hbox = gtk_hbox_new(FALSE, 0);
188 gtk_widget_show(hbox);
190 button_hbox = gtk_hbutton_box_new();
191 gtk_box_pack_end(GTK_BOX(hbox), button_hbox, TRUE, TRUE, 0);
192 g_object_set_data(G_OBJECT(hbox), BUTTON_HBOX_KEY, button_hbox);
193 gtk_widget_show(button_hbox);
195 help_hbox = gtk_hbutton_box_new();
196 gtk_box_pack_end(GTK_BOX(hbox), help_hbox, FALSE, FALSE, 0);
197 gtk_widget_show(help_hbox);
200 /* if no buttons wanted, simply do nothing */
205 /* if only one button, simply put it in the middle (default) */
206 dlg_button_new(hbox, button_hbox, stock_id_first);
210 /* do we have a help button? -> special handling for it */
212 button = gtk_button_new_from_stock(help);
213 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
214 g_object_set_data(G_OBJECT(hbox), help, button);
215 gtk_box_pack_start(GTK_BOX(help_hbox), button, FALSE, FALSE, 0);
216 gtk_widget_show(button);
220 /* do we have a copy button? -> special handling for it */
222 button = gtk_button_new_from_stock(copy);
223 GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
224 g_object_set_data(G_OBJECT(hbox), copy, button);
225 gtk_box_pack_start(GTK_BOX(help_hbox), button, FALSE, FALSE, 0);
226 gtk_widget_show(button);
230 /* if more than one button, sort buttons from left to right */
231 /* (the whole button cluster will then be right aligned) */
232 gtk_button_box_set_layout (GTK_BUTTON_BOX(button_hbox), GTK_BUTTONBOX_END);
233 gtk_button_box_set_spacing(GTK_BUTTON_BOX(button_hbox), 5);
235 /* GTK+ 1.3 and later - on Win32, we use 1.3[.x] or 2.x, not 1.2[.x] */
237 /* beware: sequence of buttons are important! */
239 /* XXX: this can be implemented more elegant of course, but it works as it should */
242 dlg_button_new(hbox, button_hbox, cancel);
243 dlg_button_new(hbox, button_hbox, ok);
246 if (print && cancel) {
247 dlg_button_new(hbox, button_hbox, cancel);
248 dlg_button_new(hbox, button_hbox, print);
251 if (find && cancel) {
252 dlg_button_new(hbox, button_hbox, cancel);
253 dlg_button_new(hbox, button_hbox, find);
256 if (jump && cancel) {
257 dlg_button_new(hbox, button_hbox, cancel);
258 dlg_button_new(hbox, button_hbox, jump);
261 if (save && cancel) {
262 dlg_button_new(hbox, button_hbox, cancel);
263 dlg_button_new(hbox, button_hbox, save);
267 dlg_button_new(hbox, button_hbox, clear);
268 dlg_button_new(hbox, button_hbox, ok);
272 dlg_button_new(hbox, button_hbox, close);
273 dlg_button_new(hbox, button_hbox, save);
276 if (create_stat && cancel) {
277 dlg_button_new(hbox, button_hbox, cancel);
278 dlg_button_new(hbox, button_hbox, create_stat);
281 if (cap_start && cancel) {
282 dlg_button_new(hbox, button_hbox, cancel);
283 dlg_button_new(hbox, button_hbox, cap_start);
286 if (cap_stop && cancel) {
287 dlg_button_new(hbox, button_hbox, cancel);
288 dlg_button_new(hbox, button_hbox, cap_stop);
291 if (delete && cancel) {
292 dlg_button_new(hbox, button_hbox, cancel);
293 dlg_button_new(hbox, button_hbox, delete);
298 if (ok && save && close) {
299 dlg_button_new(hbox, button_hbox, save);
300 dlg_button_new(hbox, button_hbox, close);
301 dlg_button_new(hbox, button_hbox, ok);
304 if (ok && apply && cancel) {
305 dlg_button_new(hbox, button_hbox, apply);
306 dlg_button_new(hbox, button_hbox, cancel);
307 dlg_button_new(hbox, button_hbox, ok);
310 if (apply && save && close) {
311 dlg_button_new(hbox, button_hbox, save);
312 dlg_button_new(hbox, button_hbox, close);
313 dlg_button_new(hbox, button_hbox, apply);
316 if (yes && no && cancel) {
317 dlg_button_new(hbox, button_hbox, no);
318 dlg_button_new(hbox, button_hbox, cancel);
319 dlg_button_new(hbox, button_hbox, yes);
322 if (save && dont_save && cancel) {
323 dlg_button_new(hbox, button_hbox, dont_save);
324 dlg_button_new(hbox, button_hbox, cancel);
325 dlg_button_new(hbox, button_hbox, save);
330 if (ok && apply && save && cancel) {
331 dlg_button_new(hbox, button_hbox, save);
332 dlg_button_new(hbox, button_hbox, apply);
333 dlg_button_new(hbox, button_hbox, cancel);
334 dlg_button_new(hbox, button_hbox, ok);
337 if (ok && apply && save && close) {
338 dlg_button_new(hbox, button_hbox, save);
339 dlg_button_new(hbox, button_hbox, apply);
340 dlg_button_new(hbox, button_hbox, close);
341 dlg_button_new(hbox, button_hbox, ok);
347 /* beware: sequence of buttons is important! */
348 if (ok != NULL) dlg_button_new(hbox, button_hbox, ok);
349 if (delete != NULL) dlg_button_new(hbox, button_hbox, delete);
350 if (jump != NULL) dlg_button_new(hbox, button_hbox, jump);
351 if (find != NULL) dlg_button_new(hbox, button_hbox, find);
352 if (print != NULL) dlg_button_new(hbox, button_hbox, print);
353 if (create_stat != NULL) dlg_button_new(hbox, button_hbox, create_stat);
354 if (apply != NULL) dlg_button_new(hbox, button_hbox, apply);
355 if (yes != NULL) dlg_button_new(hbox, button_hbox, yes);
356 if (no != NULL) dlg_button_new(hbox, button_hbox, no);
357 if (save != NULL) dlg_button_new(hbox, button_hbox, save);
358 if (dont_save != NULL) dlg_button_new(hbox, button_hbox, dont_save);
359 if (cap_start != NULL) dlg_button_new(hbox, button_hbox, cap_start);
360 if (cap_stop != NULL) dlg_button_new(hbox, button_hbox, cap_stop);
361 if (stop != NULL) dlg_button_new(hbox, button_hbox, stop);
362 if (clear != NULL) dlg_button_new(hbox, button_hbox, clear);
363 if (filter_stream!= NULL) dlg_button_new(hbox, button_hbox, filter_stream);
364 if (close != NULL) dlg_button_new(hbox, button_hbox, close);
365 if (cancel != NULL) dlg_button_new(hbox, button_hbox, cancel);
367 /* GTK2: we don't know that button combination, add it to the above list! */
368 /* g_assert_not_reached(); */
373 /* this is called, when a dialog was closed */
374 static void dlg_destroy_cb(GtkWidget *dialog _U_, gpointer data _U_)
376 #if !GTK_CHECK_VERSION(2,4,0)
378 /* bring main window back to front (workaround for a bug in win32 GTK2.x)
379 XXX - do this only on Windows? */
380 gtk_window_present(GTK_WINDOW(top_level));
386 /* Create a dialog box window that belongs to Wireshark's main window. */
388 dlg_window_new(const gchar *title)
392 win = window_new(GTK_WINDOW_TOPLEVEL, title);
395 * XXX - if we're running in the capture child process, we can't easily
396 * make this window transient for the main process's window. We just
399 * Perhaps the child process should only capture packets, write them to
400 * a file, and somehow notify the parent process and let *it* do all
401 * the GUI work. If we can do that efficiently (so that we don't drop
402 * more packets), perhaps we can also do so even when we're *not* doing
403 * an "Update list of packets in real time" capture. That'd let the
404 * child process run set-UID on platforms where you need that in order
405 * to capture, and might also simplify the job of having the GUI main
406 * loop wait both for user input and packet arrival.
409 gtk_window_set_transient_for(GTK_WINDOW(win), GTK_WINDOW(top_level));
412 g_signal_connect(win, "destroy", G_CALLBACK(dlg_destroy_cb), NULL);
417 /* Create a configuration dialog box window that belongs to Wireshark's
418 * main window and add the name of the current profile name to it's title bar
421 dlg_conf_window_new(const gchar *title)
423 const char *profile_name;
428 * Set window title to reflect which preferences profile we are
431 profile_name = get_profile_name();
433 win_name = g_strdup_printf("%s - Profile: %s", title, profile_name);
434 win = dlg_window_new(win_name);
441 /* Set the "activate" signal for a widget to call a routine to
442 activate the "OK" button for a dialog box.
444 XXX - there should be a way to specify that a GtkEntry widget
445 shouldn't itself handle the Return key, but should let it be
446 passed on to the parent, so that you don't have to do this
447 by hand for every GtkEntry widget in a dialog box, but, alas,
448 there isn't. (Does this problem exist for other widgets?
449 I.e., are there any others that seize the Return key? */
451 dlg_set_activate(GtkWidget *widget, GtkWidget *ok_button)
453 g_signal_connect(widget, "activate", G_CALLBACK(dlg_activate), ok_button);
457 dlg_activate (GtkWidget *widget _U_, gpointer ok_button)
459 gtk_widget_activate(GTK_WIDGET(ok_button));