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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include "ui/gtk/gtkglobals.h"
32 #include "ui/gtk/gui_utils.h"
33 #include "ui/gtk/dlg_utils.h"
34 #include "ui/gtk/stock_icons.h"
35 #include "ui/gtk/old-gtk-compat.h"
37 #include "epan/filesystem.h"
41 dlg_activate (GtkWidget
*widget
, gpointer ok_button
);
43 /* create a button for the button row (helper for dlg_button_row_new) */
45 dlg_button_new(GtkWidget
*hbox
, GtkWidget
*button_hbox
, const gchar
*stock_id
)
49 button
= gtk_button_new_from_stock(stock_id
);
50 gtk_widget_set_can_default(button
, TRUE
);
51 g_object_set_data(G_OBJECT(hbox
), stock_id
, button
);
52 gtk_box_pack_end(GTK_BOX(button_hbox
), button
, FALSE
, FALSE
, 0);
53 gtk_widget_show(button
);
58 * Set the focus and default for the nth item in a button row, with
59 * 0 being the first item.
61 #define BUTTON_HBOX_KEY "button_hbox"
63 dlg_button_focus_nth(GtkWidget
*hbox
, gint focus_item
) {
64 GtkWidget
*button_hbox
, *button
;
71 button_hbox
= (GtkWidget
*)g_object_get_data(G_OBJECT(hbox
), BUTTON_HBOX_KEY
);
72 children
= gtk_container_get_children(GTK_CONTAINER(button_hbox
));
75 if (cur_item
== focus_item
) {
76 button
= (GtkWidget
*)children
->data
;
77 gtk_widget_grab_focus(button
);
78 gtk_widget_grab_default(button
);
81 children
= g_list_next(children
);
85 g_list_free(children
);
88 /* create a button row for a dialog */
90 /* The purpose of this is, to have one place available, where all button rows
91 * from all dialogs are laid out. This will:
93 * a.) keep the button layout more consistent over the different dialogs
94 * b.) being able to switch between different button layouts, e.g.:
95 * e.g. Win32: "OK" "Apply" "Cancel"
96 * e.g. GNOME: "Apply" "Cancel" "OK"
99 dlg_button_row_new(const gchar
*stock_id_first
, ...)
102 va_list stock_id_list
;
103 const gchar
*stock_id
= stock_id_first
;
105 GtkWidget
*button_hbox
;
106 GtkWidget
*help_hbox
;
109 const gchar
*apply
= NULL
;
110 const gchar
*cancel
= NULL
;
111 const gchar
*cap_start
= NULL
;
112 const gchar
*cap_stop
= NULL
;
113 const gchar
*cap_options
= NULL
;
115 const gchar
*cap_details
= NULL
;
117 const gchar
*clear
= NULL
;
118 const gchar
*closex
= NULL
;
119 const gchar
*copy
= NULL
;
120 const gchar
*create_stat
= NULL
;
121 const gchar
*delete_id
= NULL
;
122 const gchar
*dont_save
= NULL
;
123 const gchar
*filter_stream
= NULL
;
124 const gchar
*find
= NULL
;
125 const gchar
*help
= NULL
;
126 const gchar
*jump
= NULL
;
127 const gchar
*no
= NULL
;
128 const gchar
*ok
= NULL
;
129 const gchar
*print
= NULL
;
130 const gchar
*save
= NULL
;
131 const gchar
*save_as
= NULL
;
132 const gchar
*save_all
= NULL
;
133 const gchar
*stop
= NULL
;
134 const gchar
*yes
= NULL
;
135 const gchar
*refresh
= NULL
;
136 const gchar
*add
= NULL
;
138 const gchar
*map
= NULL
;
139 #endif /* HAVE_GEOIP */
140 const gchar
*follow_stream
= NULL
;
141 const gchar
*graph_a_b
= NULL
;
142 const gchar
*graph_b_a
= NULL
;
145 va_start(stock_id_list
, stock_id_first
);
147 /* get all buttons needed */
148 while(stock_id
!= NULL
) {
149 if (strcmp(stock_id
, GTK_STOCK_OK
) == 0) {
151 } else if (strcmp(stock_id
, WIRESHARK_STOCK_CREATE_STAT
) == 0) {
152 create_stat
= stock_id
;
153 } else if (strcmp(stock_id
, GTK_STOCK_APPLY
) == 0) {
155 } else if (strcmp(stock_id
, GTK_STOCK_SAVE
) == 0) {
157 } else if (strcmp(stock_id
, GTK_STOCK_SAVE_AS
) == 0) {
159 } else if (strcmp(stock_id
, WIRESHARK_STOCK_SAVE_ALL
) == 0) {
161 } else if (strcmp(stock_id
, WIRESHARK_STOCK_DONT_SAVE
) == 0) {
162 dont_save
= stock_id
;
163 } else if (strcmp(stock_id
, WIRESHARK_STOCK_QUIT_DONT_SAVE
) == 0) {
164 dont_save
= stock_id
;
165 } else if (strcmp(stock_id
, GTK_STOCK_CANCEL
) == 0) {
167 } else if (strcmp(stock_id
, GTK_STOCK_CLOSE
) == 0) {
169 } else if (strcmp(stock_id
, GTK_STOCK_CLEAR
) == 0) {
171 } else if (strcmp(stock_id
, GTK_STOCK_REFRESH
) == 0) {
173 } else if (strcmp(stock_id
, GTK_STOCK_ADD
) == 0) {
176 } else if (strcmp(stock_id
, WIRESHARK_STOCK_CAPTURE_START
) == 0) {
177 cap_start
= stock_id
;
178 } else if (strcmp(stock_id
, WIRESHARK_STOCK_CAPTURE_STOP
) == 0) {
180 } else if (strcmp(stock_id
, WIRESHARK_STOCK_CAPTURE_OPTIONS
) == 0) {
181 cap_options
= stock_id
;
183 } else if (strcmp(stock_id
, WIRESHARK_STOCK_CAPTURE_DETAILS
) == 0) {
184 cap_details
= stock_id
;
186 #endif /* HAVE_LIBPCAP */
188 } else if (strcmp(stock_id
, WIRESHARK_STOCK_MAP
) == 0) {
190 #endif /* HAVE_GEOIP */
191 } else if (strcmp(stock_id
, WIRESHARK_STOCK_FOLLOW_STREAM
) == 0) {
192 follow_stream
= stock_id
;
193 } else if (strcmp(stock_id
, GTK_STOCK_STOP
) == 0) {
195 } else if (strcmp(stock_id
, GTK_STOCK_HELP
) == 0) {
197 } else if (strcmp(stock_id
, GTK_STOCK_PRINT
) == 0) {
199 } else if (strcmp(stock_id
, GTK_STOCK_FIND
) == 0) {
201 } else if (strcmp(stock_id
, GTK_STOCK_JUMP_TO
) == 0) {
203 } else if (strcmp(stock_id
, GTK_STOCK_YES
) == 0) {
205 } else if (strcmp(stock_id
, GTK_STOCK_NO
) == 0) {
207 } else if (strcmp(stock_id
, WIRESHARK_STOCK_FILTER_OUT_STREAM
) == 0) {
208 filter_stream
= stock_id
;
209 } else if (strcmp(stock_id
, GTK_STOCK_DELETE
) == 0) {
210 delete_id
= stock_id
;
211 } else if (strcmp(stock_id
, GTK_STOCK_COPY
) == 0) {
213 } else if (strcmp(stock_id
, WIRESHARK_STOCK_GRAPH_A_B
) == 0) {
214 graph_a_b
= stock_id
;
215 } else if (strcmp(stock_id
, WIRESHARK_STOCK_GRAPH_B_A
) == 0) {
216 graph_b_a
= stock_id
;
218 /* we don't know that button! */
219 g_assert_not_reached();
222 stock_id
= va_arg(stock_id_list
, gchar
*);
224 va_end(stock_id_list
);
226 hbox
= ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, DLG_BUTTON_SPACING
, FALSE
);
227 gtk_widget_show(hbox
);
229 button_hbox
= gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL
);
230 gtk_box_pack_end(GTK_BOX(hbox
), button_hbox
, TRUE
, TRUE
, 0);
231 g_object_set_data(G_OBJECT(hbox
), BUTTON_HBOX_KEY
, button_hbox
);
232 gtk_widget_show(button_hbox
);
233 gtk_box_set_spacing(GTK_BOX(button_hbox
), DLG_BUTTON_SPACING
);
235 help_hbox
= gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL
);
236 gtk_box_pack_end(GTK_BOX(hbox
), help_hbox
, FALSE
, FALSE
, 0);
237 gtk_widget_show(help_hbox
);
238 gtk_box_set_spacing(GTK_BOX(help_hbox
), DLG_BUTTON_SPACING
);
241 /* if no buttons wanted, simply do nothing */
246 /* if only one button, simply put it in the middle (default) */
247 dlg_button_new(hbox
, button_hbox
, stock_id_first
);
251 /* do we have a help button? -> special handling for it */
253 button
= gtk_button_new_from_stock(help
);
254 gtk_widget_set_can_default(button
, TRUE
);
255 g_object_set_data(G_OBJECT(hbox
), help
, button
);
256 gtk_box_pack_start(GTK_BOX(help_hbox
), button
, FALSE
, FALSE
, 0);
257 gtk_widget_show(button
);
261 /* do we have a copy button? -> special handling for it */
263 button
= gtk_button_new_from_stock(copy
);
264 gtk_widget_set_can_default(button
, TRUE
);
265 g_object_set_data(G_OBJECT(hbox
), copy
, button
);
266 gtk_box_pack_start(GTK_BOX(help_hbox
), button
, FALSE
, FALSE
, 0);
267 gtk_widget_show(button
);
271 /* do we have a refresh button? -> special handling for it */
273 button
= gtk_button_new_from_stock(refresh
);
274 g_object_set_data(G_OBJECT(hbox
), refresh
, button
);
275 gtk_box_pack_start(GTK_BOX(help_hbox
), button
, FALSE
, FALSE
, 0);
276 gtk_widget_show(button
);
280 /* do we have an add button? -> special handling for it */
282 button
= gtk_button_new_from_stock(add
);
283 g_object_set_data(G_OBJECT(hbox
), add
, button
);
284 gtk_box_pack_start(GTK_BOX(help_hbox
), button
, FALSE
, FALSE
, 0);
285 gtk_widget_show(button
);
290 /* do we have a map button? -> special handling for it */
292 button
= gtk_button_new_from_stock(map
);
293 gtk_widget_set_can_default(button
, TRUE
);
294 g_object_set_data(G_OBJECT(hbox
), map
, button
);
295 gtk_box_pack_start(GTK_BOX(help_hbox
), button
, FALSE
, FALSE
, 0);
296 gtk_widget_show(button
);
299 #endif /* HAVE_GEOIP */
301 /* if more than one button, sort buttons from left to right */
302 /* (the whole button cluster will then be right aligned) */
303 gtk_button_box_set_layout (GTK_BUTTON_BOX(button_hbox
), GTK_BUTTONBOX_END
);
306 /* beware: sequence of buttons are important! */
308 /* XXX: this can be implemented more elegant of course, but it works as it should */
311 dlg_button_new(hbox
, button_hbox
, cancel
);
312 dlg_button_new(hbox
, button_hbox
, ok
);
315 if (print
&& cancel
) {
316 dlg_button_new(hbox
, button_hbox
, cancel
);
317 dlg_button_new(hbox
, button_hbox
, print
);
320 if (find
&& cancel
) {
321 dlg_button_new(hbox
, button_hbox
, cancel
);
322 dlg_button_new(hbox
, button_hbox
, find
);
325 if (jump
&& cancel
) {
326 dlg_button_new(hbox
, button_hbox
, cancel
);
327 dlg_button_new(hbox
, button_hbox
, jump
);
330 if (save
&& cancel
) {
331 dlg_button_new(hbox
, button_hbox
, cancel
);
332 dlg_button_new(hbox
, button_hbox
, save
);
336 dlg_button_new(hbox
, button_hbox
, clear
);
337 dlg_button_new(hbox
, button_hbox
, ok
);
340 if (save
&& closex
) {
341 dlg_button_new(hbox
, button_hbox
, closex
);
342 dlg_button_new(hbox
, button_hbox
, save
);
345 if (create_stat
&& cancel
) {
346 dlg_button_new(hbox
, button_hbox
, cancel
);
347 dlg_button_new(hbox
, button_hbox
, create_stat
);
350 if (cap_start
&& cancel
) {
351 dlg_button_new(hbox
, button_hbox
, cancel
);
352 dlg_button_new(hbox
, button_hbox
, cap_start
);
355 if (cap_stop
&& cancel
) {
356 dlg_button_new(hbox
, button_hbox
, cancel
);
357 dlg_button_new(hbox
, button_hbox
, cap_stop
);
360 if (delete_id
&& cancel
) {
361 dlg_button_new(hbox
, button_hbox
, cancel
);
362 dlg_button_new(hbox
, button_hbox
, delete_id
);
367 if (ok
&& save
&& closex
) {
368 dlg_button_new(hbox
, button_hbox
, save
);
369 dlg_button_new(hbox
, button_hbox
, closex
);
370 dlg_button_new(hbox
, button_hbox
, ok
);
373 if (ok
&& apply
&& cancel
) {
374 dlg_button_new(hbox
, button_hbox
, apply
);
375 dlg_button_new(hbox
, button_hbox
, cancel
);
376 dlg_button_new(hbox
, button_hbox
, ok
);
379 if (apply
&& save
&& closex
) {
380 dlg_button_new(hbox
, button_hbox
, save
);
381 dlg_button_new(hbox
, button_hbox
, closex
);
382 dlg_button_new(hbox
, button_hbox
, apply
);
385 if (yes
&& no
&& cancel
) {
386 dlg_button_new(hbox
, button_hbox
, no
);
387 dlg_button_new(hbox
, button_hbox
, cancel
);
388 dlg_button_new(hbox
, button_hbox
, yes
);
391 if (save
&& dont_save
&& cancel
) {
392 dlg_button_new(hbox
, button_hbox
, dont_save
);
393 dlg_button_new(hbox
, button_hbox
, cancel
);
394 dlg_button_new(hbox
, button_hbox
, save
);
399 if (ok
&& apply
&& save
&& cancel
) {
400 dlg_button_new(hbox
, button_hbox
, save
);
401 dlg_button_new(hbox
, button_hbox
, apply
);
402 dlg_button_new(hbox
, button_hbox
, cancel
);
403 dlg_button_new(hbox
, button_hbox
, ok
);
406 if (ok
&& apply
&& save
&& closex
) {
407 dlg_button_new(hbox
, button_hbox
, save
);
408 dlg_button_new(hbox
, button_hbox
, apply
);
409 dlg_button_new(hbox
, button_hbox
, closex
);
410 dlg_button_new(hbox
, button_hbox
, ok
);
416 /* beware: sequence of buttons is important! */
417 if (ok
!= NULL
) dlg_button_new(hbox
, button_hbox
, ok
);
418 if (delete_id
!= NULL
) dlg_button_new(hbox
, button_hbox
, delete_id
);
419 if (jump
!= NULL
) dlg_button_new(hbox
, button_hbox
, jump
);
420 if (find
!= NULL
) dlg_button_new(hbox
, button_hbox
, find
);
421 if (print
!= NULL
) dlg_button_new(hbox
, button_hbox
, print
);
422 if (create_stat
!= NULL
) dlg_button_new(hbox
, button_hbox
, create_stat
);
423 if (apply
!= NULL
) dlg_button_new(hbox
, button_hbox
, apply
);
424 if (yes
!= NULL
) dlg_button_new(hbox
, button_hbox
, yes
);
425 if (no
!= NULL
) dlg_button_new(hbox
, button_hbox
, no
);
426 if (save
!= NULL
) dlg_button_new(hbox
, button_hbox
, save
);
427 if (save_as
!= NULL
) dlg_button_new(hbox
, button_hbox
, save_as
);
428 if (save_all
!= NULL
) dlg_button_new(hbox
, button_hbox
, save_all
);
429 if (dont_save
!= NULL
) dlg_button_new(hbox
, button_hbox
, dont_save
);
430 if (cap_start
!= NULL
) dlg_button_new(hbox
, button_hbox
, cap_start
);
431 if (cap_stop
!= NULL
) dlg_button_new(hbox
, button_hbox
, cap_stop
);
432 if (cap_options
!= NULL
) dlg_button_new(hbox
, button_hbox
, cap_options
);
434 if (cap_details
!= NULL
) dlg_button_new(hbox
, button_hbox
, cap_details
);
436 if (stop
!= NULL
) dlg_button_new(hbox
, button_hbox
, stop
);
437 if (clear
!= NULL
) dlg_button_new(hbox
, button_hbox
, clear
);
438 if (filter_stream
!= NULL
) dlg_button_new(hbox
, button_hbox
, filter_stream
);
439 if (follow_stream
!= NULL
) dlg_button_new(hbox
, button_hbox
, follow_stream
);
440 if (graph_a_b
!= NULL
) dlg_button_new(hbox
, button_hbox
, graph_a_b
);
441 if (graph_b_a
!= NULL
) dlg_button_new(hbox
, button_hbox
, graph_b_a
);
442 if (closex
!= NULL
) dlg_button_new(hbox
, button_hbox
, closex
);
443 if (cancel
!= NULL
) dlg_button_new(hbox
, button_hbox
, cancel
);
449 /* Create a dialog box window that belongs to Wireshark's main window. */
451 dlg_window_new(const gchar
*title
)
455 win
= window_new(GTK_WINDOW_TOPLEVEL
, title
);
458 * On Windows, making the dialogs transient to top_level behaves strangely.
459 * It is not possible any more to bring the top level window to front easily.
460 * So we don't do this on Windows.
462 * XXX: Note well: This means that *on Windows* any code which creates a
463 * window using dlg_window_new() and then calls
464 * gtk_widget_destroy_with_parent() will *not* get the desired effect
465 * since the dialog window actually has has no parent.
469 gtk_window_set_transient_for(GTK_WINDOW(win
), GTK_WINDOW(top_level
));
476 /* Create a configuration dialog box window that belongs to Wireshark's
477 * main window and add the name of the current profile name to its title bar
480 dlg_conf_window_new(const gchar
*title
)
482 const char *profile_name
;
487 * Set window title to reflect which preferences profile we are
490 profile_name
= get_profile_name();
492 win_name
= g_strdup_printf("%s - Profile: %s", title
, profile_name
);
493 win
= dlg_window_new(win_name
);
500 /* Set the "activate" signal for a widget to call a routine to
501 activate the "OK" button for a dialog box.
503 XXX - there should be a way to specify that a GtkEntry widget
504 shouldn't itself handle the Return key, but should let it be
505 passed on to the parent, so that you don't have to do this
506 by hand for every GtkEntry widget in a dialog box, but, alas,
507 there isn't. (Does this problem exist for other widgets?
508 I.e., are there any others that seize the Return key? */
510 dlg_set_activate(GtkWidget
*widget
, GtkWidget
*ok_button
)
512 g_signal_connect(widget
, "activate", G_CALLBACK(dlg_activate
), ok_button
);
516 dlg_activate (GtkWidget
*widget _U_
, gpointer ok_button
)
518 gtk_widget_activate(GTK_WIDGET(ok_button
));