2 * UI utility routines, some GTK+-specific (declared in gtk/gui_utils.h)
3 * and some with GUI-independent APIs, with this file containing the GTK+
4 * implementations of them (declared in ui_util.h)
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.
32 #include <gdk/gdkkeysyms.h>
33 #if GTK_CHECK_VERSION(3,0,0)
34 # include <gdk/gdkkeysyms-compat.h>
37 #include <epan/prefs.h>
38 #include "epan/epan.h"
40 #include <epan/packet_info.h>
42 #include "../../globals.h"
44 #include "ui/recent.h"
45 #include "ui/ui_util.h"
47 #include <wsutil/file_util.h>
49 #include "ui/gtk/gtkglobals.h"
50 #include "ui/gtk/gui_utils.h"
51 #include "ui/gtk/font_utils.h"
52 #include "ui/gtk/color_utils.h"
53 #include "ui/gtk/old-gtk-compat.h"
54 #ifndef HAVE_GRESOURCE
55 #include "ui/gtk/pixbuf-csource.h"
62 #define WINDOW_GEOM_KEY "window_geom"
64 /* Set our window icon. The GDK documentation doesn't provide any
65 actual documentation for gdk_window_set_icon(), so we'll steal
66 libgimp/gimpdialog.c:gimp_dialog_realize_callback() from the Gimp
67 sources and assume it's safe.
69 XXX - The current icon size is fixed at 16x16 pixels, which looks fine
70 with kwm (KDE 1.x's window manager), Sawfish (the "default" window
71 manager for GNOME?), and under Windows with Exceed putting X windows
72 on the Windows desktop, using Exceed as the window manager, as those
73 window managers put a 16x16 icon on the title bar.
75 The window managers in some windowing environments (e.g. dtwm in CDE)
76 and some stand-alone window managers have larger icon sizes (many window
77 managers put the window icon on the desktop, in the Windows 3.x style,
78 rather than in the titlebar, in the Windows 4.x style), so we need to
79 find a way to size our icon appropriately.
81 The X11 Inter-Client Communications Conventions Manual, Version 1.1,
82 in X11R5, specifies that "a window manager that wishes to place
83 constraints on the sizes of icon pixmaps and/or windows should
84 place a property called WM_ICON_SIZE on the root"; that property
85 contains minimum width and height, maximum width and height, and
86 width and height increment values. "XGetIconSizes()" retrieves
87 that property; unfortunately, I've yet to find a window manager
88 that sets it on the root window (kwm, AfterStep, and Exceed don't
91 The X Desktop Group's Window Manager Standard specifies, in the section
92 on Application Window Properties, an _NET_WM_ICON property, presumably
93 set by the window manager, which is an array of possible icon sizes
94 for the client. There's no API in GTK+ 1.2[.x] for this; there may
95 eventually be one either in GTK+ 2.0 or GNOME 2.0.
97 Some window managers can be configured to take the window name
98 specified by the WM_NAME property of a window or the resource
99 or class name specified by the WM_CLASS property and base the
100 choice of icon for the window on one of those; WM_CLASS for
101 Wireshark's windows has a resource name of "wireshark" and a class
102 name of "Wireshark". However, the way that's done is window-manager-
103 specific, and there's no way to determine what size a particular
104 window manager would want, so there's no way to automate this as
105 part of the installation of Wireshark.
108 window_icon_realize_cb(GtkWidget *win,
112 GList *ws_icon_list = NULL;
113 GdkPixbuf *icon16, *icon32, *icon48, *icon64;
115 #ifdef HAVE_GRESOURCE
116 icon16 = ws_gdk_pixbuf_new_from_resource("/org/wireshark/image/wsicon16.png");
117 icon32 = ws_gdk_pixbuf_new_from_resource("/org/wireshark/image/wsicon32.png");
118 icon48 = ws_gdk_pixbuf_new_from_resource("/org/wireshark/image/wsicon48.png");
119 icon64 = ws_gdk_pixbuf_new_from_resource("/org/wireshark/image/wsicon64.png");
121 icon16 = gdk_pixbuf_new_from_inline(-1, wsicon_16_pb_data, FALSE, NULL);
122 icon32 = gdk_pixbuf_new_from_inline(-1, wsicon_32_pb_data, FALSE, NULL);
123 icon48 = gdk_pixbuf_new_from_inline(-1, wsicon_48_pb_data, FALSE, NULL);
124 icon64 = gdk_pixbuf_new_from_inline(-1, wsicon_64_pb_data, FALSE, NULL);
126 ws_icon_list = g_list_append(ws_icon_list, icon16);
127 ws_icon_list = g_list_append(ws_icon_list, icon32);
128 ws_icon_list = g_list_append(ws_icon_list, icon48);
129 ws_icon_list = g_list_append(ws_icon_list, icon64);
131 gtk_window_set_icon_list(GTK_WINDOW(win), ws_icon_list);
133 g_list_foreach(ws_icon_list, (GFunc)g_object_unref, NULL);
134 g_list_free(ws_icon_list);
136 /* set icon by name, this allows us to use even SVG icon if it is present */
137 gtk_window_set_icon_name(GTK_WINDOW(win), "wireshark");
142 /* Create a new window, of the specified type, with the specified title
143 (if any) and the Wireshark icon. */
145 window_new(GtkWindowType type,
150 win = gtk_window_new(type);
152 gtk_window_set_title(GTK_WINDOW(win), title);
153 g_signal_connect(win, "realize", G_CALLBACK(window_icon_realize_cb), NULL);
155 /* XXX - which one is the correct default policy? or use a preference for this? */
156 /* GTK_WIN_POS_NONE, GTK_WIN_POS_CENTER or GTK_WIN_POS_MOUSE */
157 /* a lot of people dislike GTK_WIN_POS_MOUSE */
159 /* set the initial position (must be done, before show is called!) */
160 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_NONE);
163 GdkScreen *default_screen;
166 /* Ideally, new windows would open on the same monitor where the main
167 * window is located, but this doesn't happen when the main window is
168 * not located on the primary monitor. So, if there's more than 1
169 * monitor and Wireshark's main window isn't located on the primary
170 * one, attempt to improve the situation by at least displaying the new
171 * window somewhere on the same monitor, even if it won't be positioned
172 * the same way as it would be when it's on the primary monitor. Don't
173 * attempt to influence the placement on the primary monitor though,
174 * because that's probably the preferred placement strategy. But how
175 * to make window placement behave the same way on any monitor?
177 default_screen = gdk_screen_get_default();
178 n = gdk_screen_get_n_monitors(default_screen);
180 gtk_window_get_position(GTK_WINDOW(top_level), &x, &y);
181 n = gdk_screen_get_monitor_at_point(default_screen, x, y);
183 gtk_window_move(GTK_WINDOW(win), x + 40, y + 30);
191 /* Same as window_new(), but will keep its geometry values (size, position, ...).
192 * Be sure to use window_present() and window_destroy() appropriately! */
194 window_new_with_geom(GtkWindowType type,
196 const gchar *geom_name,
197 GtkWindowPosition pos)
199 window_geometry_t geom;
200 GtkWidget *win = window_new(type, title);
202 g_object_set_data(G_OBJECT(win), WINDOW_GEOM_KEY, (gpointer)g_strdup(geom_name));
204 /* do we have a previously saved size and position of this window? */
206 /* It's a good idea to set the position and size of the window already here,
207 * as it's still invisible and won't "flicker the screen" while initially resizing. */
208 if(window_geom_load(geom_name, &geom)) {
209 /* XXX - use prefs to select which values to set? */
211 geom.set_size = TRUE;
212 geom.set_maximized = FALSE; /* don't maximize until window is shown */
213 window_set_geometry(win, &geom);
214 } else if (pos != GTK_WIN_POS_NONE) {
216 /* Testing using GTK+ 2.24.10 shows that
217 * GTK_WIN_POS_CENTER_ON_PARENT doesn't seem to work on Windows, so
218 * use the next best thing. Is this a problem for all OS's though,
219 * or just Windows? Unknown. (Tested with Windows XP SP3 32-bit)
221 if (pos == GTK_WIN_POS_CENTER_ON_PARENT)
222 pos = GTK_WIN_POS_CENTER;
224 gtk_window_set_position(GTK_WINDOW(win), pos);
232 /* Create a new window for a splash screen; it's a main window, without decoration,
233 positioned in the center of the screen. */
235 splash_window_new(void)
239 win = window_new(GTK_WINDOW_TOPLEVEL, "Wireshark");
240 gtk_window_set_decorated(GTK_WINDOW(win), FALSE);
242 /* set the initial position (must be done, before show is called!) */
243 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
249 /* Present the created window on the screen. */
251 window_present(GtkWidget *win)
253 window_geometry_t geom;
256 /* present this window */
257 gtk_window_present(GTK_WINDOW(win));
259 /* do we have a previously saved size and position of this window? */
260 name = (const gchar *)g_object_get_data(G_OBJECT(win), WINDOW_GEOM_KEY);
262 if(window_geom_load(name, &geom)) {
263 /* XXX - use prefs to select which values to set? */
265 geom.set_size = TRUE;
266 geom.set_maximized = TRUE;
267 window_set_geometry(win, &geom);
274 window_key_press_cb(GtkWidget *widget,
276 gpointer cancel_button)
278 g_return_val_if_fail(widget != NULL, FALSE);
279 g_return_val_if_fail(event != NULL, FALSE);
281 if (event->keyval == GDK_Escape) {
282 gtk_widget_activate(GTK_WIDGET(cancel_button));
290 /* Set the "key_press_event" signal for a top-level dialog window to
291 call a routine to activate the "Cancel" button for a dialog box if
292 the key being pressed is the <Esc> key.
294 XXX - there should be a GTK+ widget that'll do that for you, and
295 let you specify a "Cancel" button. It should also not impose
296 a requirement that there be a separator in the dialog box, as
297 the GtkDialog widget does; the visual convention that there's
298 such a separator between the rest of the dialog boxes and buttons
299 such as "OK" and "Cancel" is, for better or worse, not universal
300 (not even in GTK+ - look at the GtkFileSelection dialog!). */
302 window_set_cancel(GtkWidget *widget,
303 GtkWidget *cancel_button)
305 g_signal_connect(widget, "key_press_event", G_CALLBACK(window_key_press_cb), cancel_button);
309 /* set the actions needed for the cancel "Close"/"Ok"/"Cancel" button that closes the window */
311 window_set_cancel_button(GtkWidget *win,
313 window_cancel_button_fct cb)
316 g_signal_connect(bt, "clicked", G_CALLBACK(cb), win);
318 gtk_widget_grab_default(bt);
320 window_set_cancel(win, bt);
324 /* default callback handler for cancel button "clicked" signal */
326 window_cancel_button_cb(GtkWidget *w _U_,
329 window_destroy(GTK_WIDGET(data));
333 /* default callback handler: the window managers X of the window was clicked (delete_event) */
335 window_delete_event_cb(GtkWidget *win,
337 gpointer user_data _U_)
341 /* event handled, don't do anything else */
346 /* get the geometry of a window from window_new() */
348 window_get_geometry(GtkWidget *widget,
349 window_geometry_t *geom)
351 GdkWindowState state;
352 GdkWindow *widget_window;
354 /* Try to grab our geometry.
356 GTK+ provides two routines to get a window's position relative
357 to the X root window. If I understand the documentation correctly,
358 gdk_window_get_deskrelative_origin applies mainly to Enlightenment
359 and gdk_window_get_root_origin applies for all other WMs.
361 The code below tries both routines, and picks the one that returns
362 the upper-left-most coordinates.
366 http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
367 http://www.gtk.org/faq/#AEN606
369 As gdk_window_get_deskrelative_origin() is deprecated it has been removed 2011-07-24.
372 memset(geom, 0, sizeof(window_geometry_t));
374 widget_window = gtk_widget_get_window(widget);
376 gdk_window_get_root_origin(widget_window,
380 /* XXX - Is this the "approved" method? */
381 #if GTK_CHECK_VERSION(2,24,0)
382 geom->width = gdk_window_get_width(widget_window);
383 geom->height = gdk_window_get_height(widget_window);
385 gdk_drawable_get_size(widget_window,
389 state = gdk_window_get_state(widget_window);
390 geom->maximized = ((state & GDK_WINDOW_STATE_MAXIMIZED) != 0);
395 /* Ensure Wireshark isn't obscured by the system taskbar (or other desktop toolbars).
396 * Resolves https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=3034 */
398 window_adjust_if_obscured(window_geometry_t *geom)
400 MONITORINFO MonitorInfo;
403 DWORD dwFlags = MONITOR_DEFAULTTONEAREST; /* MONITOR_DEFAULTTOPRIMARY? */
406 * Get the virtual screen's top-left coordinates so we can reliably
407 * determine which monitor we're dealing with. See also:
408 * http://msdn.microsoft.com/en-us/library/windows/desktop/dd145136%28v=vs.85%29.aspx
410 vs.x = GetSystemMetrics(SM_XVIRTUALSCREEN);
411 vs.y = GetSystemMetrics(SM_YVIRTUALSCREEN);
412 pt.x = geom->x + vs.x;
413 pt.y = geom->y + vs.y;
414 MonitorInfo.cbSize = sizeof(MONITORINFO);
415 hMonitor = MonitorFromPoint(pt, dwFlags);
416 if (GetMonitorInfo(hMonitor, &MonitorInfo)) {
417 if (pt.x < MonitorInfo.rcWork.left)
418 geom->x += MonitorInfo.rcWork.left - pt.x;
419 if (pt.y < MonitorInfo.rcWork.top)
420 geom->y += MonitorInfo.rcWork.top - pt.y;
425 /* set the geometry of a window from window_new() */
427 window_set_geometry(GtkWidget *widget,
428 window_geometry_t *geom)
430 GdkScreen *default_screen;
431 GdkRectangle viewable_area;
434 /* as we now have the geometry from the recent file, set it */
435 /* if the window was minimized, x and y are -32000 (at least on Win32) */
436 if (geom->set_pos && geom->x != -32000 && geom->y != -32000) {
437 /* Per Wireshark bug #553, GTK has a problem on MS Windows
438 * where the upper-left corner of the window may appear off
439 * screen when when a single desktop spans multiple monitors
440 * of different resolutions and positions relative to each
443 * If the requested (x,y) position isn't within the monitor's
444 * viewable area, change it to the viewable area's (x,y). */
445 default_screen = gdk_screen_get_default();
446 monitor_num = gdk_screen_get_monitor_at_point(default_screen,
448 gdk_screen_get_monitor_geometry(default_screen, monitor_num,
450 if(geom->x < viewable_area.x || geom->x > (viewable_area.x + viewable_area.width))
451 geom->x = viewable_area.x;
453 if(geom->y < viewable_area.y || geom->y > (viewable_area.y + viewable_area.height))
454 geom->y = viewable_area.y;
457 window_adjust_if_obscured(geom);
460 gtk_window_move(GTK_WINDOW(widget),
465 if (geom->set_size) {
466 gtk_window_resize(GTK_WINDOW(widget),
467 /*gtk_widget_set_size_request(widget,*/
472 if(geom->set_maximized) {
473 if (geom->maximized) {
474 gdk_window_maximize(gtk_widget_get_window(widget));
476 gdk_window_unmaximize(gtk_widget_get_window(widget));
482 window_destroy(GtkWidget *win)
484 window_geometry_t geom;
490 /* get_geometry must be done *before* destroy is running, as the window geometry
491 * cannot be retrieved at destroy time (so don't use event "destroy" for this) */
492 /* ...and don't do this at all, if we currently have no GdkWindow (e.g. if the
493 * GtkWidget is hidden) */
494 if(gtk_widget_get_has_window(win) && gtk_widget_get_visible(win)) {
495 window_get_geometry(win, &geom);
497 name = (const gchar *)g_object_get_data(G_OBJECT(win), WINDOW_GEOM_KEY);
499 window_geom_save(name, &geom);
500 g_free((gpointer)name);
504 gtk_widget_destroy(win);
508 _gtk_image_new_from_pixbuf_unref(GdkPixbuf *pixbuf) {
511 widget = gtk_image_new_from_pixbuf(pixbuf);
512 g_object_unref(pixbuf);
516 /* convert an xpm to a GtkWidget */
518 xpm_to_widget(const char **xpm) {
521 pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
522 return _gtk_image_new_from_pixbuf_unref(pixbuf);
525 /* Convert an pixbuf GResource to a GtkWidget */
527 #ifdef HAVE_GRESOURCE
528 pixbuf_to_widget(const char *pb_path) {
530 pixbuf_to_widget(const guint8 *pb_data) {
534 #ifdef HAVE_GRESOURCE
535 pixbuf = ws_gdk_pixbuf_new_from_resource(pb_path);
537 pixbuf = gdk_pixbuf_new_from_inline(-1, pb_data, FALSE, NULL);
539 return _gtk_image_new_from_pixbuf_unref(pixbuf);
543 * Alert box for an invalid display filter expression.
544 * Assumes "dfilter_error_msg" has been set by "dfilter_compile()" to the
545 * error message for the filter.
547 * XXX - should this have a "Help" button that pops up the display filter
551 bad_dfilter_alert_box(GtkWidget *parent,
555 GtkWidget *msg_dialog;
557 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(parent),
558 GTK_DIALOG_DESTROY_WITH_PARENT,
561 "The filter expression \"%s\" isn't a valid display filter. (%s)",
563 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
564 "See the help for a description of the display filter syntax.");
565 gtk_dialog_run(GTK_DIALOG(msg_dialog));
566 gtk_widget_destroy(msg_dialog);
569 /* update the main window */
571 main_window_update(void)
573 while (gtk_events_pending())
574 gtk_main_iteration();
579 /* quit a nested main window */
581 main_window_nested_quit(void)
583 if (gtk_main_level() > 0)
587 /* quit the main window */
589 main_window_quit(void)
594 typedef struct pipe_input_tag {
597 ws_process_id *child_process;
598 pipe_input_cb_t input_cb;
608 /* The timer has expired, see if there's stuff to read from the pipe,
609 if so, do the callback */
611 pipe_timer_cb(gpointer data)
617 pipe_input_t *pipe_input = data;
621 /* try to read data from the pipe only 5 times, to avoid blocking */
622 while(iterations < 5) {
623 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/
625 /* Oddly enough although Named pipes don't work on win9x,
626 PeekNamedPipe does !!! */
627 handle = (HANDLE)_get_osfhandle(pipe_input->source);
628 result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
630 /* Get the child process exit status */
631 GetExitCodeProcess((HANDLE)*(pipe_input->child_process), &childstatus);
633 /* If the Peek returned an error, or there are bytes to be read
634 or the childwatcher thread has terminated then call the normal
636 if (!result || avail > 0 || childstatus != STILL_ACTIVE) {
638 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/
640 if(pipe_input->pipe_input_id != 0) {
641 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: stop timer");*/
642 /* avoid reentrancy problems and stack overflow */
643 g_source_remove(pipe_input->pipe_input_id);
644 pipe_input->pipe_input_id = 0;
647 /* And call the real handler */
648 if (!pipe_input->input_cb(pipe_input->source, pipe_input->user_data)) {
649 g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations);
650 /* pipe closed, return false so that the old timer is not run again */
655 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/
656 /* No data, stop now */
663 if(pipe_input->pipe_input_id == 0) {
664 /* restore pipe handler */
665 pipe_input->pipe_input_id = g_timeout_add(200, pipe_timer_cb, data);
666 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, new timer", iterations);*/
668 /* Return false so that the old timer is not run again */
671 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, old timer", iterations);*/
673 /* we didn't stopped the old timer, so let it run */
680 /* There's stuff to read from the sync pipe, meaning the child has sent
681 us a message, or the sync pipe has closed, meaning the child has
682 closed it (perhaps because it exited). */
684 pipe_input_cb(GIOChannel *source _U_,
685 GIOCondition condition _U_,
688 pipe_input_t *pipe_input = (pipe_input_t *)data;
691 /* avoid reentrancy problems and stack overflow */
692 g_source_remove(pipe_input->pipe_input_id);
694 if (pipe_input->input_cb(pipe_input->source, pipe_input->user_data)) {
695 /* restore pipe handler */
696 pipe_input->pipe_input_id = g_io_add_watch_full(pipe_input->channel,
698 (GIOCondition)(G_IO_IN|G_IO_ERR|G_IO_HUP),
708 pipe_input_set_handler(gint source,
710 ws_process_id *child_process,
711 pipe_input_cb_t input_cb)
713 static pipe_input_t pipe_input;
715 pipe_input.source = source;
716 pipe_input.child_process = child_process;
717 pipe_input.user_data = user_data;
718 pipe_input.input_cb = input_cb;
721 /* Tricky to use pipes in win9x, as no concept of wait. NT can
722 do this but that doesn't cover all win32 platforms. GTK can do
723 this but doesn't seem to work over processes. Attempt to do
724 something similar here, start a timer and check for data on every
726 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/
727 pipe_input.pipe_input_id = g_timeout_add(200, pipe_timer_cb, &pipe_input);
729 pipe_input.channel = g_io_channel_unix_new(source);
730 g_io_channel_set_encoding(pipe_input.channel, NULL, NULL);
731 pipe_input.pipe_input_id = g_io_add_watch_full(pipe_input.channel,
733 (GIOCondition)(G_IO_IN|G_IO_ERR|G_IO_HUP),
741 #endif /* HAVE_LIBPCAP */
743 /* Given a pointer to a GtkWidget for a top-level window, raise it and
744 de-iconify it. This routine is used if the user has done something to
745 ask that a window of a certain type be popped up when there can be only
746 one such window and such a window has already been popped up - we
747 pop up the existing one rather than creating a new one.
749 XXX - we should request that it be given the input focus, too. Alas,
750 GDK has nothing to do that, e.g. by calling "XSetInputFocus()" in a
751 window in X. Besides, using "XSetInputFocus()" doesn't work anyway,
752 apparently due to the way GTK+/GDK manages the input focus.
754 The X Desktop Group's Window Manager Standard specifies, in the section
755 on Root Window Properties, an _NET_ACTIVE_WINDOW client message that
756 can be sent to the root window, containing the window ID of the
757 window to activate; I infer that this might be the way to give the
758 window the input focus - I assume that means it's also de-iconified,
759 but I wouldn't assume it'd raise it.
761 XXX - will this do the right thing on window systems other than X? */
763 reactivate_window(GtkWidget *win)
765 GdkWindow *win_window;
767 win_window = gtk_widget_get_window(win);
769 gdk_window_show(win_window);
770 gdk_window_raise(win_window);
773 /* List of all GtkScrolledWindows, so we can globally set the scrollbar
774 placement of all of them. */
775 static GList *scrolled_windows;
777 static void setup_scrolled_window(GtkWidget *scrollw);
778 static void forget_scrolled_window(GtkWidget *scrollw, gpointer data);
780 /* Create a GtkScrolledWindow, set its scrollbar placement appropriately,
783 scrolled_window_new(GtkAdjustment *hadjustment,
784 GtkAdjustment *vadjustment)
788 scrollw = gtk_scrolled_window_new(hadjustment, vadjustment);
789 setup_scrolled_window(scrollw);
793 /* Set a GtkScrolledWindow's scrollbar placement and add it to the list
794 of GtkScrolledWindows. */
796 setup_scrolled_window(GtkWidget *scrollw)
798 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw),
799 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
800 #if GTK_CHECK_VERSION(3,16,0)
801 gtk_scrolled_window_set_overlay_scrolling(GTK_SCROLLED_WINDOW(scrollw), FALSE);
802 #endif /* OVERLAY_SCROLLING */
804 scrolled_windows = g_list_append(scrolled_windows, scrollw);
806 /* Catch the "destroy" event on the widget, so that we remove it from
807 the list when it's destroyed. */
808 g_signal_connect(scrollw, "destroy", G_CALLBACK(forget_scrolled_window), NULL);
811 /* Remove a GtkScrolledWindow from the list of GtkScrolledWindows. */
813 forget_scrolled_window(GtkWidget *scrollw,
816 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
819 /* List of all CTrees/TreeViews, so we can globally set the line and
820 * expander style of all of them. */
823 static void setup_tree(GtkWidget *tree);
824 static void forget_tree(GtkWidget *tree, gpointer data);
825 static void set_tree_styles(GtkWidget *tree);
826 static gboolean tree_view_key_pressed_cb(GtkWidget *tree, GdkEventKey *event, gpointer user_data _U_);
828 /* Create a Tree, give it the right styles, and remember it. */
830 tree_view_new(GtkTreeModel *model)
834 tree = gtk_tree_view_new_with_model(model);
839 /* Set a Tree's styles and add it to the list of Trees. */
841 setup_tree(GtkWidget *tree)
843 set_tree_styles(tree);
845 trees = g_list_append(trees, tree);
847 /* Catch the "destroy" event on the widget, so that we remove it from
848 the list when it's destroyed. */
849 g_signal_connect(tree, "destroy", G_CALLBACK(forget_tree), NULL);
850 g_signal_connect(tree, "key-press-event", G_CALLBACK(tree_view_key_pressed_cb), NULL );
853 /* Remove a Tree from the list of Trees. */
855 forget_tree(GtkWidget *tree,
858 trees = g_list_remove(trees, tree);
861 /* Set the styles of a Tree based upon user preferences. */
863 set_tree_styles(GtkWidget *tree)
865 g_assert(prefs.gui_altern_colors >= 0 && prefs.gui_altern_colors <= 1);
866 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree),
867 prefs.gui_altern_colors);
871 set_tree_styles_cb(gpointer data,
872 gpointer user_data _U_)
874 set_tree_styles((GtkWidget *)data);
877 /* Set the styles of all Trees based upon style values. */
879 set_tree_styles_all(void)
881 g_list_foreach(trees, set_tree_styles_cb, NULL);
884 /* Move the currently-selected item in a list store up or down one position. */
886 tree_view_list_store_move_selection(GtkTreeView *tree,
889 GtkTreeIter from, to;
891 GtkTreeSelection *sel;
892 GtkTreePath *path_from, *path_to;
894 sel = gtk_tree_view_get_selection(tree);
895 if (!gtk_tree_selection_get_selected(sel, &model, &from)) {
899 path_from = gtk_tree_model_get_path(model, &from);
904 path_to = gtk_tree_path_copy(path_from);
905 /* XXX - Why does one return void and the other return a gboolean? */
907 gtk_tree_path_prev(path_to);
909 gtk_tree_path_next(path_to);
912 if (gtk_tree_path_compare(path_from, path_to) == 0) {
913 gtk_tree_path_free(path_from);
914 gtk_tree_path_free(path_to);
918 gtk_tree_model_get_iter(model, &to, path_to);
919 gtk_list_store_swap(GTK_LIST_STORE(model), &from, &to);
920 gtk_tree_path_free(path_from);
921 gtk_tree_path_free(path_to);
925 /* Find the selected row number in a list store. */
927 tree_view_list_store_get_selected_row(GtkTreeView *tree) {
930 GtkTreeSelection *sel;
935 sel = gtk_tree_view_get_selection(tree);
936 if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
940 path = gtk_tree_model_get_path(model, &iter);
945 path_str = gtk_tree_path_to_string(path);
946 gtk_tree_path_free(path);
948 row = (gint)strtol(path_str, NULL, 10);
954 /* append a row to the simple list */
955 /* use it like: simple_list_append(list, 0, "first", 1, "second", -1) */
957 simple_list_append(GtkWidget *list,
966 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
967 gtk_list_store_append(store, &iter);
968 gtk_list_store_set_valist(store, &iter, ap);
972 /* create a simple list widget */
974 simple_list_new(gint cols,
975 const gchar **titles) {
976 GtkWidget *plugins_list;
979 GtkCellRenderer *renderer;
980 GtkTreeViewColumn *column;
983 g_assert(cols <= 10);
984 store = gtk_list_store_new(cols,
985 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
986 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
987 plugins_list = tree_view_new(GTK_TREE_MODEL(store));
988 g_object_unref(G_OBJECT(store));
989 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(plugins_list), (titles != NULL));
990 for(i=0; i<cols; i++) {
991 renderer = gtk_cell_renderer_text_new();
992 column = gtk_tree_view_column_new_with_attributes(titles ? titles[i] : "", renderer,
994 gtk_tree_view_column_set_sort_column_id(column, i);
995 gtk_tree_view_append_column(GTK_TREE_VIEW(plugins_list), column);
1002 render_as_url(GtkCellRenderer *cell)
1004 g_object_set(cell, "foreground", "blue", NULL);
1005 g_object_set(cell, "foreground-set", TRUE, NULL);
1007 g_object_set(cell, "underline", PANGO_UNDERLINE_SINGLE, NULL);
1008 g_object_set(cell, "underline-set", TRUE, NULL);
1012 simple_list_url_col(GtkWidget *list,
1015 GtkTreeViewColumn *ul_column;
1016 GList *renderers_list;
1017 GtkCellRenderer *ul_renderer;
1019 /* make the column look like a link ... */
1020 ul_column = gtk_tree_view_get_column(GTK_TREE_VIEW(list), col);
1022 renderers_list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(ul_column));
1024 if(renderers_list != NULL) {
1025 /* it is simple list - there should be only one renderer */
1026 ul_renderer = (GtkCellRenderer*)renderers_list->data;
1028 render_as_url(ul_renderer);
1030 g_list_free(renderers_list);
1036 copy_to_clipboard(GString *str)
1040 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
1041 gtk_clipboard_set_text(cb, str->str, -1); /* Copy the byte data into the clipboard */
1045 typedef struct _copy_binary_t {
1050 static copy_binary_t *
1051 create_copy_binary_t(const guint8 *data,
1054 copy_binary_t* copy_data;
1057 copy_data = g_new(copy_binary_t,1);
1058 copy_data->data = g_new(guint8,len);
1059 copy_data->len = len;
1060 memcpy(copy_data->data,data,len * sizeof(guint8));
1065 destroy_copy_binary_t(copy_binary_t *copy_data) {
1066 g_free(copy_data->data);
1071 copy_binary_free_cb(GtkClipboard *clipboard _U_,
1072 gpointer user_data_or_owner)
1074 destroy_copy_binary_t((copy_binary_t*)user_data_or_owner);
1078 copy_binary_get_cb(GtkClipboard *clipboard _U_,
1079 GtkSelectionData *selection_data,
1081 gpointer user_data_or_owner)
1083 copy_binary_t* copy_data;
1085 copy_data = (copy_binary_t*)user_data_or_owner;
1087 /* Just do a dumb set as binary data */
1088 gtk_selection_data_set(selection_data, GDK_NONE, 8, copy_data->data, copy_data->len);
1092 copy_binary_to_clipboard(const guint8 *data_p,
1095 static GtkTargetEntry target_entry[] = {
1096 {(char *)"application/octet-stream", 0, 0}};
1097 /* XXX - this is not understood by most applications,
1098 * but can be pasted into the better hex editors - is
1099 * there something better that we can do?
1103 copy_binary_t *copy_data;
1107 return; /* XXX would it be better to clear the clipboard? */
1109 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
1110 copy_data = create_copy_binary_t(data_p,len);
1112 ret = gtk_clipboard_set_with_data(cb,target_entry,1,
1113 copy_binary_get_cb, copy_binary_free_cb,copy_data);
1116 destroy_copy_binary_t(copy_data);
1121 * Create a new window title string with user-defined title preference.
1122 * (Or ignore it if unspecified).
1125 create_user_window_title(const gchar *caption)
1128 if (caption == NULL)
1129 return g_strdup("");
1131 /* no user-defined title specified */
1132 if ((prefs.gui_window_title == NULL) || (*prefs.gui_window_title == '\0'))
1133 return g_strdup(caption);
1135 return g_strdup_printf("%s [%s]", caption, prefs.gui_window_title);
1139 * Set the title of a window based on a supplied caption and the
1140 * display name for the capture file.
1142 * XXX - should this include the user preference as well?
1145 set_window_title(GtkWidget *win,
1146 const gchar *caption)
1151 display_name = cf_get_display_name(&cfile);
1152 title = g_strdup_printf("%s: %s", caption, display_name);
1153 g_free(display_name);
1154 gtk_window_set_title(GTK_WINDOW(win), title);
1159 * Collapse row and his children
1162 tree_collapse_row_with_children(GtkTreeView *tree_view, GtkTreeModel *model, GtkTreePath *path,
1167 if (gtk_tree_view_row_expanded(tree_view, path)) {
1168 if (gtk_tree_model_iter_children(model, &child, iter)) {
1169 gtk_tree_path_down(path);
1173 if (gtk_tree_view_row_expanded(tree_view, path)) {
1174 tree_collapse_row_with_children(tree_view, model, path, &child);
1177 gtk_tree_path_next(path);
1178 } while (gtk_tree_model_iter_next(model, &child));
1180 gtk_tree_path_up(path);
1182 gtk_tree_view_collapse_row(tree_view, path);
1188 tree_collapse_path_all(GtkTreeView *tree_view, GtkTreePath *path)
1191 GtkTreeModel *model;
1193 model = gtk_tree_view_get_model(tree_view);
1194 gtk_tree_model_get_iter(model, &iter, path);
1196 tree_collapse_row_with_children(tree_view, model, path, &iter);
1200 * This callback is invoked when keyboard focus is within either
1201 * the packetlist view or the detail view. The keystrokes processed
1202 * within this callback are attempting to modify the detail view.
1203 * Within the detail view we special case the Left Arrow, Backspace
1204 * and Enter keys depending on the state of the expander (if any)
1205 * for the item in focus.
1207 * Returning FALSE allows processing of the original key_press_event
1208 * by other callbacks. Left/Right scrolling of the packetlist
1209 * view and expanding/collapsing of the detail view lists is
1210 * handled by the default GtkTreeView key-press-event call back.
1212 * XXX - Would an improved version of this callback test to see which
1213 * of the two GtkTreeView lists has focus? Left/Right scrolling of
1214 * the packetlist is currently not optimal. It will take several
1215 * right or left keypress events before the packetlist responds.
1216 * The problem appears to be that the focus is on a particular cell
1217 * within the highlighted row cell (like a spreadsheet). Scrolling
1218 * of the view right or left will not occur until the focus is
1219 * moved to a cell off the left or right edge of the packet list
1220 * view. Also TAB/SHIFT-TAB events can move keyboard focus to
1221 * the packetlist header where there is currently visual hint
1222 * a header cell has focus.
1225 tree_view_key_pressed_cb(GtkWidget *tree,
1227 gpointer user_data _U_)
1229 GtkTreeSelection *selection;
1232 GtkTreeModel *model;
1234 gboolean expanded, expandable;
1237 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1242 if(!gtk_tree_selection_get_selected(selection, &model, &iter)) {
1246 path = gtk_tree_model_get_path(model, &iter);
1251 /* Always FALSE when we're in the packet list (at least until we add sub-packets) */
1252 expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree), path);
1253 expandable = gtk_tree_model_iter_has_child(model, &iter);
1255 switch (event->keyval) {
1258 /* Subtree is expanded. Collapse it. */
1259 if (event->state & GDK_SHIFT_MASK)
1261 tree_collapse_row_with_children(GTK_TREE_VIEW(tree), model, path, &iter);
1264 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree), path);
1268 /* No break - fall through to jumping to the parent */
1271 /* subtree is already collapsed, jump to parent node */
1272 if(! gtk_tree_model_iter_parent(model, &parent, &iter)) {
1276 gtk_tree_path_free(path);
1277 path = gtk_tree_model_get_path(model, &parent);
1281 gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree), path,
1282 NULL /* focus_column */,
1283 FALSE /* !start_editing */);
1290 /* We have a subtree. Try to expand it. */
1291 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), path, FALSE /* !open_all */);
1300 /* Reverse the current state. */
1302 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree), path);
1304 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), path, FALSE /* !open_all */);
1310 gtk_tree_path_free(path);
1316 switch_to_fixed_col(GtkTreeView *view)
1319 GtkTreeViewColumn *column;
1320 GList *columns, *list;
1322 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
1325 column = (GtkTreeViewColumn *)columns->data;
1326 size = gtk_tree_view_column_get_width(column);
1327 gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_FIXED);
1328 if (size > gtk_tree_view_column_get_fixed_width(column))
1329 gtk_tree_view_column_set_fixed_width(column, size);
1330 columns = g_list_next(columns);
1334 gtk_tree_view_set_fixed_height_mode(view, TRUE);
1338 get_default_col_size(GtkWidget *view,
1341 PangoLayout *layout;
1344 layout = gtk_widget_create_pango_layout(view, str);
1345 pango_layout_get_pixel_size(layout,
1346 &col_width, /* width */
1348 g_object_unref(G_OBJECT(layout));
1349 /* Add a single character's width to get some spacing between columns */
1350 return col_width + (pango_font_description_get_size(user_font_get_regular()) / PANGO_SCALE);
1355 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1356 * the user data must be the column number.
1357 * Present floats with two decimals
1360 float_data_func(GtkTreeViewColumn *column _U_,
1361 GtkCellRenderer *renderer,
1362 GtkTreeModel *model,
1370 /* the col to get data from is in userdata */
1371 gint float_col = GPOINTER_TO_INT(user_data);
1373 gtk_tree_model_get(model, iter, float_col, &float_val, -1);
1375 /* save the current locale */
1376 savelocale = g_strdup(setlocale(LC_NUMERIC, NULL));
1377 /* switch to "C" locale to avoid problems with localized decimal separators
1378 * in g_snprintf("%f") functions
1380 setlocale(LC_NUMERIC, "C");
1382 g_snprintf(buf, sizeof(buf), "%.2f", float_val);
1383 /* restore previous locale setting */
1384 setlocale(LC_NUMERIC, savelocale);
1387 g_object_set(renderer, "text", buf, NULL);
1391 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1392 * the user data must be the column number.
1393 * Present value as hexadecimal.
1396 present_as_hex_func(GtkTreeViewColumn *column _U_,
1397 GtkCellRenderer *renderer,
1398 GtkTreeModel *model,
1405 /* the col to get data from is in userdata */
1406 gint col = GPOINTER_TO_INT(user_data);
1408 gtk_tree_model_get(model, iter, col, &val, -1);
1410 g_snprintf(buf, sizeof(buf), "0x%02x", val);
1412 g_object_set(renderer, "text", buf, NULL);
1416 u64_data_func(GtkTreeViewColumn *column _U_,
1417 GtkCellRenderer *renderer,
1418 GtkTreeModel *model,
1427 /* the col to get data from is in userdata */
1428 gint col = GPOINTER_TO_INT(user_data);
1430 gtk_tree_model_get(model, iter, col, &val, -1);
1435 *--bp = (gchar)(val % 10) +'0';
1439 } while ((val /= 10) != 0 && bp > buf);
1440 g_object_set(renderer, "text", bp, NULL);
1444 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1445 * The user data must be the column number.
1446 * Renders the const static string whose pointer is stored.
1449 str_ptr_data_func(GtkTreeViewColumn *column _U_,
1450 GtkCellRenderer *renderer,
1451 GtkTreeModel *model,
1455 const gchar *str = NULL;
1457 /* The col to get data from is in userdata */
1458 gint data_column = GPOINTER_TO_INT(user_data);
1460 gtk_tree_model_get(model, iter, data_column, &str, -1);
1461 /* XXX should we check that str is non NULL and print a warning or do assert? */
1463 g_object_set(renderer, "text", str, NULL);
1467 str_ptr_sort_func(GtkTreeModel *model,
1472 const gchar *str_a = NULL;
1473 const gchar *str_b = NULL;
1476 /* The col to get data from is in userdata */
1477 gint data_column = GPOINTER_TO_INT(user_data);
1479 gtk_tree_model_get(model, a, data_column, &str_a, -1);
1480 gtk_tree_model_get(model, b, data_column, &str_b, -1);
1482 if (str_a == str_b) {
1483 /* it's worth testing because a lot of rows point to the same data */
1486 else if (str_a == NULL || str_b == NULL) {
1487 ret = (str_a == NULL) ? -1 : 1;
1490 ret = g_ascii_strcasecmp(str_a,str_b);
1495 /** --------------------------------------------------
1496 * ws_combo_box_text_and_pointer convenience functions
1497 * (Code adapted from GtkComboBox.c)
1501 * ws_combo_box_new_text_and_pointer_full:
1503 * Convenience function which constructs a new "text and pointer" combo box, which
1504 * is a #GtkComboBox just displaying strings and storing a pointer associated with
1505 * each combo_box entry; The pointer can be retrieved when an entry is selected.
1506 * Also: optionally returns the cell renderer for the combo box.
1507 * If you use this function to create a text_and_pointer combo_box,
1508 * you should only manipulate its data source with the
1509 * following convenience functions:
1510 * ws_combo_box_append_text_and_pointer()
1511 * ws_combo_box_append_text_and_pointer_full()
1513 * @param cell_p pointer to return the 'GtkCellRenderer *' for the combo box (or NULL).
1514 * @return A pointer to a new text_and_pointer combo_box.
1518 * GtkComboBox style property: "appears-as-list":
1519 * Default: 0: ie: displays as menus
1520 * Wireshark Windows gtkrc: 1: ie: displays as lists (treeview)
1523 ws_combo_box_new_text_and_pointer_full(GtkCellRenderer **cell_p) {
1524 GtkWidget *combo_box;
1525 GtkCellRenderer *cell;
1526 GtkTreeStore *store;
1528 /* The Tree store for the GtkComboBox has 3 columns:
1529 0: text string for display in GtkComboBox list;
1530 1: pointer (data) associated with the entry;
1531 2: True/False depending upon whether this entry is selectable ("sensitive" attribute).
1534 store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
1535 combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
1536 g_object_unref(store);
1537 cell = gtk_cell_renderer_text_new();
1538 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), cell, TRUE);
1539 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell,
1540 "text", 0, "sensitive", 2,
1542 if (cell_p != NULL) {
1549 * ws_combo_box_new_text_and_pointer:
1551 * Convenience function which constructs a new "text and pointer" combo box, which
1552 * is a #GtkComboBox just displaying strings and storing a pointer associated with
1553 * each combo_box entry; The pointer can be retrieved when an entry is selected.
1554 * If you use this function to create a text_and_pointer combo_box,
1555 * you should only manipulate its data source with the
1556 * following convenience functions:
1557 * ws_combo_box_append_text_and_pointer()
1558 * ws_combo_box_append_text_and_pointer_full()
1560 * @return A pointer to a new text_and_pointer combo_box.
1564 ws_combo_box_new_text_and_pointer(void) {
1565 return ws_combo_box_new_text_and_pointer_full(NULL);
1570 * ws_combo_box_clear_text_and_pointer:
1571 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1573 * Clears all the text_and_pointer entries in the text_and_pointer combo_box.
1574 * Note: A "changed" signal will be emitted after the clear if there was
1575 * an active (selected) entry before the clear.
1576 * You should use this function only with combo boxes constructed with
1577 * ws_combo_box_new_text_and_pointer().
1580 ws_combo_box_clear_text_and_pointer(GtkComboBox *combo_box)
1582 gtk_tree_store_clear(GTK_TREE_STORE(gtk_combo_box_get_model(combo_box)));
1586 * ws_combo_box_append_text_and_pointer_full:
1587 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1588 * @param parent_iter Parent row for apending; NULL if appending to tree top-level;
1589 * @param text A string to be displayed as an entry in the dropdown list of the combo_box
1590 * @param ptr A pointer to be associated with this entry of the combo_box
1591 * @param sensitive TRUE/FALSE to set sensitivity of the entry
1592 * @return A GtkTreeIter pointing to the appended GtkVomboBox entry.
1594 * Appends text and ptr to the list of strings and pointers stored in combo_box.
1595 * The text and ptr can be appended to any existing level of the tree_store.
1596 * The sensitivity of the row will be set as requested.
1597 * Note that you can only use this function with combo boxes constructed with
1598 * ws_combo_box_new_text_and_pointer().
1601 ws_combo_box_append_text_and_pointer_full(GtkComboBox *combo_box,
1602 GtkTreeIter *parent_iter,
1605 const gboolean sensitive)
1608 GtkTreeStore *store;
1610 store = GTK_TREE_STORE(gtk_combo_box_get_model(combo_box));
1612 gtk_tree_store_append(store, &iter, parent_iter);
1613 gtk_tree_store_set(store, &iter, 0, text, 1, ptr, 2, sensitive, -1);
1619 * ws_combo_box_append_text_and_pointer:
1620 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1621 * @param text A string to be displayed as an entry in the dropdown list of the combo_box
1622 * @param ptr A pointer to be associated with this entry of the combo_box
1623 * @return A GtkTreeIter pointing to the appended GtkComboBox entry.
1625 * Appends text and ptr to the list of strings and pointers stored in combo_box. Note that
1626 * you can only use this function with combo boxes constructed with
1627 * ws_combo_box_new_text_and_pointer().
1630 ws_combo_box_append_text_and_pointer(GtkComboBox *combo_box,
1634 return ws_combo_box_append_text_and_pointer_full(combo_box, NULL, text, ptr, TRUE);
1639 * ws_combo_box_get_active_pointer:
1640 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1641 * @param ptr A pointer to a location in which to store the pointer associated with the active entry
1642 * @return TRUE if an entry is selected (i.e: an active entry exists); FALSE otherwise
1644 * You can only use this function with combo boxes constructed with
1645 * ws_combo_box_new_text_and_pointer().
1648 ws_combo_box_get_active_pointer(GtkComboBox *combo_box,
1651 GtkTreeStore *store;
1656 if (gtk_combo_box_get_active_iter(combo_box, &iter)) {
1657 store = GTK_TREE_STORE(gtk_combo_box_get_model(combo_box));
1658 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1666 * ws_combo_box_get_active:
1667 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1668 * @return Index of the active entry; -1 if no entry is selected;
1669 * Note: If the active item is not an immediate child of root of the tree then
1670 * the index returned is that of the top-level for the acftive entry.
1673 ws_combo_box_get_active(GtkComboBox *combo_box)
1675 return gtk_combo_box_get_active(combo_box);
1679 * ws_combo_box_set_active:
1680 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1681 * @param idx of the entry which is to be set as active (ie: selected).
1682 * Index refers to the immediate children of the tree.
1685 ws_combo_box_set_active(GtkComboBox *combo_box,
1688 gtk_combo_box_set_active(combo_box, idx);
1692 * ws_combo_box_set_active_iter:
1693 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1694 * @param iter of the entry which is to be set as active (ie: selected).
1697 ws_combo_box_set_active_iter(GtkComboBox *combo_box, GtkTreeIter *iter)
1699 gtk_combo_box_set_active_iter(combo_box, iter);
1703 /* Copy functions from GTK 3.0 to be used if GTK version is 2.22 or 2.24 to be able save Graphs to file */
1704 #if GTK_CHECK_VERSION(2,22,0)
1705 #if !GTK_CHECK_VERSION(3,0,0)
1706 static cairo_format_t
1707 gdk_cairo_format_for_content(cairo_content_t content)
1711 case CAIRO_CONTENT_COLOR:
1712 return CAIRO_FORMAT_RGB24;
1713 case CAIRO_CONTENT_ALPHA:
1714 return CAIRO_FORMAT_A8;
1715 case CAIRO_CONTENT_COLOR_ALPHA:
1717 return CAIRO_FORMAT_ARGB32;
1721 static cairo_surface_t *
1722 gdk_cairo_surface_coerce_to_image(cairo_surface_t *surface,
1723 cairo_content_t content,
1729 cairo_surface_t *copy;
1732 copy = cairo_image_surface_create(gdk_cairo_format_for_content(content),
1736 cr = cairo_create(copy);
1737 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1738 cairo_set_source_surface(cr, surface, -src_x, -src_y);
1746 convert_alpha(guchar *dest_data,
1757 src_data += src_stride * src_y + src_x * 4;
1759 for (y = 0; y < height; y++) {
1760 guint32 *src = (guint32 *)src_data;
1762 for (x = 0; x < width; x++) {
1763 guint alpha = src[x] >> 24;
1767 dest_data[x * 4 + 0] = 0;
1768 dest_data[x * 4 + 1] = 0;
1769 dest_data[x * 4 + 2] = 0;
1773 dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
1774 dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
1775 dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
1777 dest_data[x * 4 + 3] = alpha;
1780 src_data += src_stride;
1781 dest_data += dest_stride;
1786 convert_no_alpha(guchar *dest_data,
1797 src_data += src_stride * src_y + src_x * 4;
1799 for (y = 0; y < height; y++) {
1800 guint32 *src = (guint32 *)src_data;
1802 for (x = 0; x < width; x++) {
1803 dest_data[x * 3 + 0] = src[x] >> 16;
1804 dest_data[x * 3 + 1] = src[x] >> 8;
1805 dest_data[x * 3 + 2] = src[x];
1808 src_data += src_stride;
1809 dest_data += dest_stride;
1814 * gdk_pixbuf_get_from_surface:
1815 * @surface: surface to copy from
1816 * @src_x: Source X coordinate within @surface
1817 * @src_y: Source Y coordinate within @surface
1818 * @width: Width in pixels of region to get
1819 * @height: Height in pixels of region to get
1821 * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
1822 * representation inside a #GdkPixbuf. This allows you to efficiently read
1823 * individual pixels from cairo surfaces. For #GdkWindows, use
1824 * gdk_pixbuf_get_from_window() instead.
1826 * This function will create an RGB pixbuf with 8 bits per channel.
1827 * The pixbuf will contain an alpha channel if the @surface contains one.
1829 * Return value: (transfer full): A newly-created pixbuf with a reference
1830 * count of 1, or %NULL on error
1833 gdk_pixbuf_get_from_surface(cairo_surface_t *surface,
1839 cairo_content_t content;
1842 /* General sanity checks */
1843 g_return_val_if_fail(surface != NULL, NULL);
1844 g_return_val_if_fail(width > 0 && height > 0, NULL);
1846 content = (cairo_content_t)(cairo_surface_get_content(surface) | CAIRO_CONTENT_COLOR);
1847 dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
1848 !!(content & CAIRO_CONTENT_ALPHA),
1852 surface = gdk_cairo_surface_coerce_to_image(surface, content,
1855 cairo_surface_flush(surface);
1856 if (cairo_surface_status(surface) || dest == NULL)
1858 cairo_surface_destroy(surface);
1862 if (gdk_pixbuf_get_has_alpha(dest))
1863 convert_alpha(gdk_pixbuf_get_pixels(dest),
1864 gdk_pixbuf_get_rowstride(dest),
1865 cairo_image_surface_get_data(surface),
1866 cairo_image_surface_get_stride(surface),
1870 convert_no_alpha(gdk_pixbuf_get_pixels(dest),
1871 gdk_pixbuf_get_rowstride(dest),
1872 cairo_image_surface_get_data(surface),
1873 cairo_image_surface_get_stride(surface),
1877 cairo_surface_destroy(surface);
1880 #endif /* !GTK_CHECK_VERSION(3,0,0) */
1881 #endif /* GTK_CHECK_VERSION(2,22,0) */
1885 ws_gtk_box_new(GtkOrientation orientation,
1887 gboolean homogeneous)
1889 #if !GTK_CHECK_VERSION(3,0,0)
1890 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1891 return gtk_hbox_new(homogeneous, spacing);
1893 return gtk_vbox_new(homogeneous, spacing);
1897 widget = gtk_box_new(orientation, spacing);
1898 gtk_box_set_homogeneous(GTK_BOX(widget), homogeneous);
1901 #endif /* GTK_CHECK_VERSION(3,0,0) */
1904 #if !GTK_CHECK_VERSION(3,0,0)
1906 gtk_button_box_new(GtkOrientation orientation)
1908 if (orientation == GTK_ORIENTATION_HORIZONTAL) {
1909 return gtk_hbutton_box_new();
1911 return gtk_vbutton_box_new();
1916 gtk_scrollbar_new(GtkOrientation orientation,
1917 GtkAdjustment *adjustment)
1919 if (orientation == GTK_ORIENTATION_HORIZONTAL) {
1920 return gtk_hscrollbar_new(adjustment);
1922 return gtk_vscrollbar_new(adjustment);
1927 gtk_paned_new(GtkOrientation orientation)
1929 if(orientation == GTK_ORIENTATION_HORIZONTAL) {
1930 return gtk_hpaned_new();
1932 return gtk_vpaned_new();
1937 gtk_separator_new(GtkOrientation orientation)
1939 if (orientation == GTK_ORIENTATION_HORIZONTAL) {
1940 return gtk_hseparator_new();
1942 return gtk_vseparator_new();
1945 #endif /* GTK_CHECK_VERSION(3,0,0) */
1948 frame_new(const gchar *title) {
1949 GtkWidget *frame, *frame_lb;
1950 GString *mu_title = g_string_new("");
1952 frame = gtk_frame_new(NULL);
1953 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
1955 #if defined(_WIN32) || defined(__APPLE__)
1956 g_string_printf(mu_title, "%s", title);
1958 g_string_printf(mu_title, "<b>%s</b>", title);
1960 frame_lb = gtk_label_new(NULL);
1961 gtk_label_set_markup(GTK_LABEL(frame_lb), mu_title->str);
1962 gtk_frame_set_label_widget(GTK_FRAME(frame), frame_lb);
1964 g_string_free(mu_title, TRUE);
1970 /* ---------------------------------
1971 * ws_gtk_grid...() wrappers
1975 #if !GTK_CHECK_VERSION(3,0,0)
1979 ws_gtk_grid_attach_defaults(GtkGrid *grid, GtkWidget *child, gint left, gint top, gint width, gint height)
1981 /* Use defaults for [x|y]options and [x|y]padding which match those for gtk_table_attach_defaults() */
1982 ws_gtk_grid_attach_extended(grid, child, left, top, width, height,
1983 (GtkAttachOptions)(GTK_EXPAND|GTK_FILL), (GtkAttachOptions)(GTK_EXPAND|GTK_FILL), 0, 0);
1987 ws_gtk_grid_attach_extended(GtkGrid *grid, GtkWidget *child,
1988 gint left, gint top, gint width, gint height,
1989 GtkAttachOptions xoptions, GtkAttachOptions yoptions,
1990 guint xpadding, guint ypadding)
1992 gtk_grid_attach(grid, child, left, top, width, height);
1994 /* XXX: On Gtk3, there's Some trickyness about EXPAND which I probably don't
1995 * really understand.
1997 * Default for EXPAND is "not set".
1998 * In this case "computed expand" based on any child(ren) of this widget will
1999 * affect this widget.
2000 * If EXPAND is set (either TRUE or FALSE) then the value overrides any effect
2004 /* Note: widget defaults are FALSE */
2005 if (xoptions & GTK_EXPAND)
2006 gtk_widget_set_hexpand(child, TRUE);
2007 if (yoptions & GTK_EXPAND)
2008 gtk_widget_set_vexpand(child, TRUE);
2010 /* Note: widget default is GTK_FILL */
2011 /* XXX: Is an 'align' ignored if the corresponding 'fill; is FALSE ? */
2012 /* XXX: don't set FILL(since is dedault) but just clear if not set ?? */
2013 /* ToDo: review effect of explicit set/clear vs explict clear only */
2014 gtk_widget_set_halign(child, (xoptions & GTK_FILL) ? GTK_ALIGN_FILL : GTK_ALIGN_CENTER);
2015 gtk_widget_set_valign(child, (yoptions & GTK_FILL) ? GTK_ALIGN_FILL : GTK_ALIGN_CENTER);
2017 if (xpadding != 0) {
2018 gtk_widget_set_margin_left(child, xpadding);
2019 gtk_widget_set_margin_right(child, xpadding);
2021 if (ypadding != 0) {
2022 gtk_widget_set_margin_top(child, ypadding);
2023 gtk_widget_set_margin_bottom(child, ypadding);
2028 ws_gtk_grid_set_homogeneous(GtkGrid *grid, gboolean homogeneous)
2030 gtk_grid_set_row_homogeneous(grid, homogeneous);
2031 gtk_grid_set_column_homogeneous(grid, homogeneous);
2033 #endif /* !GTK_CHECK_VERSION(3,0,0) */
2036 * Wrap gdk_cairo_set_source_color() with the GTK 3 equivalent
2037 * to be used in GTK2
2039 #if !GTK_CHECK_VERSION(3,0,0)
2041 gdk_cairo_set_source_rgba(cairo_t *cr, const GdkRGBA *rgba)
2045 gdkRGBAcolor_to_GdkColor(&color, rgba);
2047 gdk_cairo_set_source_color(cr, &color);
2050 #endif /* GTK_CHECK_VERSION(3,0,0) */
2052 #ifdef HAVE_GRESOURCE
2054 ws_gdk_pixbuf_new_from_resource(const char *path)
2059 pixbuf = gdk_pixbuf_new_from_resource(path, &err);
2060 g_assert_no_error(err);
2063 #endif /* HAVE_GRESOURCE */
2066 * Editor modelines - http://www.wireshark.org/tools/modelines.html
2071 * indent-tabs-mode: nil
2074 * vi: set shiftwidth=4 tabstop=8 expandtab:
2075 * :indentSize=4:tabSize=8:noTabs=true: