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)
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include <gdk/gdkkeysyms.h>
34 #if GTK_CHECK_VERSION(3,0,0)
35 # include <gdk/gdkkeysyms-compat.h>
38 #include <epan/prefs.h>
39 #include "epan/epan.h"
41 #include <epan/packet_info.h>
43 #include "../../globals.h"
45 #include "ui/recent.h"
46 #include "ui/ui_util.h"
48 #include <wsutil/file_util.h>
50 #include "ui/gtk/gtkglobals.h"
51 #include "ui/gtk/gui_utils.h"
52 #include "ui/gtk/font_utils.h"
53 #include "ui/gtk/color_utils.h"
55 #include "ui/gtk/old-gtk-compat.h"
57 #include "image/wsicon16.xpm"
58 #include "image/wsicon32.xpm"
59 #include "image/wsicon48.xpm"
60 #include "image/wsicon64.xpm"
66 #define WINDOW_GEOM_KEY "window_geom"
68 /* Set our window icon. The GDK documentation doesn't provide any
69 actual documentation for gdk_window_set_icon(), so we'll steal
70 libgimp/gimpdialog.c:gimp_dialog_realize_callback() from the Gimp
71 sources and assume it's safe.
73 XXX - The current icon size is fixed at 16x16 pixels, which looks fine
74 with kwm (KDE 1.x's window manager), Sawfish (the "default" window
75 manager for GNOME?), and under Windows with Exceed putting X windows
76 on the Windows desktop, using Exceed as the window manager, as those
77 window managers put a 16x16 icon on the title bar.
79 The window managers in some windowing environments (e.g. dtwm in CDE)
80 and some stand-alone window managers have larger icon sizes (many window
81 managers put the window icon on the desktop, in the Windows 3.x style,
82 rather than in the titlebar, in the Windows 4.x style), so we need to
83 find a way to size our icon appropriately.
85 The X11 Inter-Client Communications Conventions Manual, Version 1.1,
86 in X11R5, specifies that "a window manager that wishes to place
87 constraints on the sizes of icon pixmaps and/or windows should
88 place a property called WM_ICON_SIZE on the root"; that property
89 contains minimum width and height, maximum width and height, and
90 width and height increment values. "XGetIconSizes()" retrieves
91 that property; unfortunately, I've yet to find a window manager
92 that sets it on the root window (kwm, AfterStep, and Exceed don't
95 The X Desktop Group's Window Manager Standard specifies, in the section
96 on Application Window Properties, an _NET_WM_ICON property, presumably
97 set by the window manager, which is an array of possible icon sizes
98 for the client. There's no API in GTK+ 1.2[.x] for this; there may
99 eventually be one either in GTK+ 2.0 or GNOME 2.0.
101 Some window managers can be configured to take the window name
102 specified by the WM_NAME property of a window or the resource
103 or class name specified by the WM_CLASS property and base the
104 choice of icon for the window on one of those; WM_CLASS for
105 Wireshark's windows has a resource name of "wireshark" and a class
106 name of "Wireshark". However, the way that's done is window-manager-
107 specific, and there's no way to determine what size a particular
108 window manager would want, so there's no way to automate this as
109 part of the installation of Wireshark.
112 window_icon_realize_cb(GtkWidget *win,
116 GList *ws_icon_list = NULL;
119 icon = gdk_pixbuf_new_from_xpm_data((const char **)wsicon16_xpm);
120 ws_icon_list = g_list_append(ws_icon_list, icon);
121 icon = gdk_pixbuf_new_from_xpm_data((const char **)wsicon32_xpm);
122 ws_icon_list = g_list_append(ws_icon_list, icon);
123 icon = gdk_pixbuf_new_from_xpm_data((const char **)wsicon48_xpm);
124 ws_icon_list = g_list_append(ws_icon_list, icon);
125 icon = gdk_pixbuf_new_from_xpm_data((const char **)wsicon64_xpm);
126 ws_icon_list = g_list_append(ws_icon_list, icon);
128 gtk_window_set_icon_list(GTK_WINDOW(win), ws_icon_list);
130 g_list_foreach(ws_icon_list, (GFunc)g_object_unref, NULL);
131 g_list_free(ws_icon_list);
133 /* set icon by name, this allows us to use even SVG icon if it is present */
134 gtk_window_set_icon_name(GTK_WINDOW(win), "wireshark");
139 /* Create a new window, of the specified type, with the specified title
140 (if any) and the Wireshark icon. */
142 window_new(GtkWindowType type,
147 win = gtk_window_new(type);
149 gtk_window_set_title(GTK_WINDOW(win), title);
150 g_signal_connect(win, "realize", G_CALLBACK(window_icon_realize_cb), NULL);
152 /* XXX - which one is the correct default policy? or use a preference for this? */
153 /* GTK_WIN_POS_NONE, GTK_WIN_POS_CENTER or GTK_WIN_POS_MOUSE */
154 /* a lot of people dislike GTK_WIN_POS_MOUSE */
156 /* set the initial position (must be done, before show is called!) */
157 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_NONE);
160 GdkScreen *default_screen;
163 /* Ideally, new windows would open on the same monitor where the main
164 * window is located, but this doesn't happen when the main window is
165 * not located on the primary monitor. So, if there's more than 1
166 * monitor and Wireshark's main window isn't located on the primary
167 * one, attempt to improve the situation by at least displaying the new
168 * window somewhere on the same monitor, even if it won't be positioned
169 * the same way as it would be when it's on the primary monitor. Don't
170 * attempt to influence the placement on the primary monitor though,
171 * because that's probably the preferred placement strategy. But how
172 * to make window placement behave the same way on any monitor?
174 default_screen = gdk_screen_get_default();
175 n = gdk_screen_get_n_monitors(default_screen);
177 gtk_window_get_position(GTK_WINDOW(top_level), &x, &y);
178 n = gdk_screen_get_monitor_at_point(default_screen, x, y);
180 gtk_window_move(GTK_WINDOW(win), x + 40, y + 30);
188 /* Same as window_new(), but will keep its geometry values (size, position, ...).
189 * Be sure to use window_present() and window_destroy() appropriately! */
191 window_new_with_geom(GtkWindowType type,
193 const gchar *geom_name)
195 window_geometry_t geom;
196 GtkWidget *win = window_new(type, title);
198 g_object_set_data(G_OBJECT(win), WINDOW_GEOM_KEY, (gpointer)g_strdup(geom_name));
200 /* do we have a previously saved size and position of this window? */
202 /* It's a good idea to set the position and size of the window already here,
203 * as it's still invisible and won't "flicker the screen" while initially resizing. */
204 if(window_geom_load(geom_name, &geom)) {
205 /* XXX - use prefs to select which values to set? */
207 geom.set_size = TRUE;
208 geom.set_maximized = FALSE; /* don't maximize until window is shown */
209 window_set_geometry(win, &geom);
217 /* Create a new window for a splash screen; it's a main window, without decoration,
218 positioned in the center of the screen. */
220 splash_window_new(void)
224 win = window_new(GTK_WINDOW_TOPLEVEL, "Wireshark");
225 gtk_window_set_decorated(GTK_WINDOW(win), FALSE);
227 /* set the initial position (must be done, before show is called!) */
228 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
234 /* Present the created window on the screen. */
236 window_present(GtkWidget *win)
238 window_geometry_t geom;
241 /* present this window */
242 gtk_window_present(GTK_WINDOW(win));
244 /* do we have a previously saved size and position of this window? */
245 name = (const gchar *)g_object_get_data(G_OBJECT(win), WINDOW_GEOM_KEY);
247 if(window_geom_load(name, &geom)) {
248 /* XXX - use prefs to select which values to set? */
250 geom.set_size = TRUE;
251 geom.set_maximized = TRUE;
252 window_set_geometry(win, &geom);
259 window_key_press_cb(GtkWidget *widget,
261 gpointer cancel_button)
263 g_return_val_if_fail(widget != NULL, FALSE);
264 g_return_val_if_fail(event != NULL, FALSE);
266 if (event->keyval == GDK_Escape) {
267 gtk_widget_activate(GTK_WIDGET(cancel_button));
275 /* Set the "key_press_event" signal for a top-level dialog window to
276 call a routine to activate the "Cancel" button for a dialog box if
277 the key being pressed is the <Esc> key.
279 XXX - there should be a GTK+ widget that'll do that for you, and
280 let you specify a "Cancel" button. It should also not impose
281 a requirement that there be a separator in the dialog box, as
282 the GtkDialog widget does; the visual convention that there's
283 such a separator between the rest of the dialog boxes and buttons
284 such as "OK" and "Cancel" is, for better or worse, not universal
285 (not even in GTK+ - look at the GtkFileSelection dialog!). */
287 window_set_cancel(GtkWidget *widget,
288 GtkWidget *cancel_button)
290 g_signal_connect(widget, "key_press_event", G_CALLBACK(window_key_press_cb), cancel_button);
294 /* set the actions needed for the cancel "Close"/"Ok"/"Cancel" button that closes the window */
296 window_set_cancel_button(GtkWidget *win,
298 window_cancel_button_fct cb)
301 g_signal_connect(bt, "clicked", G_CALLBACK(cb), win);
303 gtk_widget_grab_default(bt);
305 window_set_cancel(win, bt);
309 /* default callback handler for cancel button "clicked" signal */
311 window_cancel_button_cb(GtkWidget *w _U_,
314 window_destroy(GTK_WIDGET(data));
318 /* default callback handler: the window managers X of the window was clicked (delete_event) */
320 window_delete_event_cb(GtkWidget *win,
322 gpointer user_data _U_)
326 /* event handled, don't do anything else */
331 /* get the geometry of a window from window_new() */
333 window_get_geometry(GtkWidget *widget,
334 window_geometry_t *geom)
336 GdkWindowState state;
337 GdkWindow *widget_window;
339 /* Try to grab our geometry.
341 GTK+ provides two routines to get a window's position relative
342 to the X root window. If I understand the documentation correctly,
343 gdk_window_get_deskrelative_origin applies mainly to Enlightenment
344 and gdk_window_get_root_origin applies for all other WMs.
346 The code below tries both routines, and picks the one that returns
347 the upper-left-most coordinates.
351 http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
352 http://www.gtk.org/faq/#AEN606
354 As gdk_window_get_deskrelative_origin() is deprecated it has been removed 2011-07-24.
357 memset(geom, 0, sizeof(window_geometry_t));
359 widget_window = gtk_widget_get_window(widget);
361 gdk_window_get_root_origin(widget_window,
365 /* XXX - Is this the "approved" method? */
366 #if GTK_CHECK_VERSION(2,24,0)
367 geom->width = gdk_window_get_width(widget_window);
368 geom->height = gdk_window_get_height(widget_window);
370 gdk_drawable_get_size(widget_window,
374 state = gdk_window_get_state(widget_window);
375 geom->maximized = ((state & GDK_WINDOW_STATE_MAXIMIZED) != 0);
379 /* set the geometry of a window from window_new() */
381 window_set_geometry(GtkWidget *widget,
382 window_geometry_t *geom)
384 GdkScreen *default_screen;
385 GdkRectangle viewable_area;
388 /* as we now have the geometry from the recent file, set it */
389 /* if the window was minimized, x and y are -32000 (at least on Win32) */
390 if (geom->set_pos && geom->x != -32000 && geom->y != -32000) {
391 /* Per Wireshark bug #553, GTK has a problem on MS Windows
392 * where the upper-left corner of the window may appear off
393 * screen when when a single desktop spans multiple monitors
394 * of different resolutions and positions relative to each
397 * If the requested (x,y) position isn't within the monitor's
398 * viewable area, change it to the viewable area's (x,y). */
399 default_screen = gdk_screen_get_default();
400 monitor_num = gdk_screen_get_monitor_at_point(default_screen,
402 gdk_screen_get_monitor_geometry(default_screen, monitor_num,
404 if(geom->x < viewable_area.x || geom->x > (viewable_area.x + viewable_area.width))
405 geom->x = viewable_area.x;
407 if(geom->y < viewable_area.y || geom->y > (viewable_area.y + viewable_area.height))
408 geom->y = viewable_area.y;
410 gtk_window_move(GTK_WINDOW(widget),
415 if (geom->set_size) {
416 gtk_window_resize(GTK_WINDOW(widget),
417 /*gtk_widget_set_size_request(widget,*/
422 if(geom->set_maximized) {
423 if (geom->maximized) {
424 gdk_window_maximize(gtk_widget_get_window(widget));
426 gdk_window_unmaximize(gtk_widget_get_window(widget));
432 window_destroy(GtkWidget *win)
434 window_geometry_t geom;
440 /* get_geometry must be done *before* destroy is running, as the window geometry
441 * cannot be retrieved at destroy time (so don't use event "destroy" for this) */
442 /* ...and don't do this at all, if we currently have no GdkWindow (e.g. if the
443 * GtkWidget is hidden) */
444 if(gtk_widget_get_has_window(win) && gtk_widget_get_visible(win)) {
445 window_get_geometry(win, &geom);
447 name = (const gchar *)g_object_get_data(G_OBJECT(win), WINDOW_GEOM_KEY);
449 window_geom_save(name, &geom);
450 g_free((gpointer)name);
454 gtk_widget_destroy(win);
458 /* Do we need this one ? */
459 /* convert an xpm to a GtkWidget, using the window settings from its parent */
460 /* (be sure that the parent window is already being displayed) */
462 xpm_to_widget_from_parent(GtkWidget *parent,
470 pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
471 gdk_pixbuf_render_pixmap_and_mask_for_colormap(pixbuf, gtk_widget_get_colormap(parent), &pixmap, &bitmap, 128);
473 return gtk_image_new_from_pixmap(pixmap, bitmap);
478 _gtk_image_new_from_pixbuf_unref(GdkPixbuf *pixbuf) {
481 widget = gtk_image_new_from_pixbuf(pixbuf);
482 g_object_unref(pixbuf);
486 /* convert an xpm to a GtkWidget */
488 xpm_to_widget(const char **xpm) {
491 pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
492 return _gtk_image_new_from_pixbuf_unref(pixbuf);
495 /* Convert an pixbuf data to a GtkWidget */
496 /* Data should be created with "gdk-pixbuf-csource --raw" */
498 pixbuf_to_widget(const char *pb_data) {
501 pixbuf = gdk_pixbuf_new_from_inline(-1, pb_data, FALSE, NULL);
502 return _gtk_image_new_from_pixbuf_unref(pixbuf);
506 * Alert box for an invalid display filter expression.
507 * Assumes "dfilter_error_msg" has been set by "dfilter_compile()" to the
508 * error message for the filter.
510 * XXX - should this have a "Help" button that pops up the display filter
514 bad_dfilter_alert_box(GtkWidget *parent,
517 GtkWidget *msg_dialog;
519 msg_dialog = gtk_message_dialog_new(GTK_WINDOW(parent),
520 GTK_DIALOG_DESTROY_WITH_PARENT,
523 "The filter expression \"%s\" isn't a valid display filter. (%s)",
524 dftext, dfilter_error_msg);
525 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog),
526 "See the help for a description of the display filter syntax.");
527 gtk_dialog_run(GTK_DIALOG(msg_dialog));
528 gtk_widget_destroy(msg_dialog);
531 /* update the main window */
533 main_window_update(void)
535 while (gtk_events_pending())
536 gtk_main_iteration();
539 /* exit the main window */
541 main_window_exit(void)
548 /* quit a nested main window */
550 main_window_nested_quit(void)
552 if (gtk_main_level() > 0)
556 /* quit the main window */
558 main_window_quit(void)
565 typedef struct pipe_input_tag {
569 pipe_input_cb_t input_cb;
579 /* The timer has expired, see if there's stuff to read from the pipe,
580 if so, do the callback */
582 pipe_timer_cb(gpointer data)
588 pipe_input_t *pipe_input = data;
592 /* try to read data from the pipe only 5 times, to avoid blocking */
593 while(iterations < 5) {
594 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/
596 /* Oddly enough although Named pipes don't work on win9x,
597 PeekNamedPipe does !!! */
598 handle = (HANDLE)_get_osfhandle(pipe_input->source);
599 result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
601 /* Get the child process exit status */
602 GetExitCodeProcess((HANDLE)*(pipe_input->child_process), &childstatus);
604 /* If the Peek returned an error, or there are bytes to be read
605 or the childwatcher thread has terminated then call the normal
607 if (!result || avail > 0 || childstatus != STILL_ACTIVE) {
609 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/
611 if(pipe_input->pipe_input_id != 0) {
612 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: stop timer");*/
613 /* avoid reentrancy problems and stack overflow */
614 g_source_remove(pipe_input->pipe_input_id);
615 pipe_input->pipe_input_id = 0;
618 /* And call the real handler */
619 if (!pipe_input->input_cb(pipe_input->source, pipe_input->user_data)) {
620 g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations);
621 /* pipe closed, return false so that the old timer is not run again */
626 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/
627 /* No data, stop now */
634 if(pipe_input->pipe_input_id == 0) {
635 /* restore pipe handler */
636 pipe_input->pipe_input_id = g_timeout_add(200, pipe_timer_cb, data);
637 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, new timer", iterations);*/
639 /* Return false so that the old timer is not run again */
642 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, old timer", iterations);*/
644 /* we didn't stopped the old timer, so let it run */
651 /* There's stuff to read from the sync pipe, meaning the child has sent
652 us a message, or the sync pipe has closed, meaning the child has
653 closed it (perhaps because it exited). */
655 pipe_input_cb(GIOChannel *source _U_,
656 GIOCondition condition _U_,
659 pipe_input_t *pipe_input = (pipe_input_t *)data;
662 /* avoid reentrancy problems and stack overflow */
663 g_source_remove(pipe_input->pipe_input_id);
665 if (pipe_input->input_cb(pipe_input->source, pipe_input->user_data)) {
666 /* restore pipe handler */
667 pipe_input->pipe_input_id = g_io_add_watch_full(pipe_input->channel,
669 G_IO_IN|G_IO_ERR|G_IO_HUP,
679 pipe_input_set_handler(gint source,
682 pipe_input_cb_t input_cb)
684 static pipe_input_t pipe_input;
686 pipe_input.source = source;
687 pipe_input.child_process = child_process;
688 pipe_input.user_data = user_data;
689 pipe_input.input_cb = input_cb;
692 /* Tricky to use pipes in win9x, as no concept of wait. NT can
693 do this but that doesn't cover all win32 platforms. GTK can do
694 this but doesn't seem to work over processes. Attempt to do
695 something similar here, start a timer and check for data on every
697 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/
698 pipe_input.pipe_input_id = g_timeout_add(200, pipe_timer_cb, &pipe_input);
700 pipe_input.channel = g_io_channel_unix_new(source);
701 g_io_channel_set_encoding(pipe_input.channel, NULL, NULL);
702 pipe_input.pipe_input_id = g_io_add_watch_full(pipe_input.channel,
704 G_IO_IN|G_IO_ERR|G_IO_HUP,
712 #endif /* HAVE_LIBPCAP */
714 /* Given a pointer to a GtkWidget for a top-level window, raise it and
715 de-iconify it. This routine is used if the user has done something to
716 ask that a window of a certain type be popped up when there can be only
717 one such window and such a window has already been popped up - we
718 pop up the existing one rather than creating a new one.
720 XXX - we should request that it be given the input focus, too. Alas,
721 GDK has nothing to do that, e.g. by calling "XSetInputFocus()" in a
722 window in X. Besides, using "XSetInputFocus()" doesn't work anyway,
723 apparently due to the way GTK+/GDK manages the input focus.
725 The X Desktop Group's Window Manager Standard specifies, in the section
726 on Root Window Properties, an _NET_ACTIVE_WINDOW client message that
727 can be sent to the root window, containing the window ID of the
728 window to activate; I infer that this might be the way to give the
729 window the input focus - I assume that means it's also de-iconified,
730 but I wouldn't assume it'd raise it.
732 XXX - will this do the right thing on window systems other than X? */
734 reactivate_window(GtkWidget *win)
736 GdkWindow *win_window;
738 win_window = gtk_widget_get_window(win);
740 gdk_window_show(win_window);
741 gdk_window_raise(win_window);
744 /* List of all GtkScrolledWindows, so we can globally set the scrollbar
745 placement of all of them. */
746 static GList *scrolled_windows;
748 static void setup_scrolled_window(GtkWidget *scrollw);
749 static void forget_scrolled_window(GtkWidget *scrollw, gpointer data);
751 /* Create a GtkScrolledWindow, set its scrollbar placement appropriately,
754 scrolled_window_new(GtkAdjustment *hadjustment,
755 GtkAdjustment *vadjustment)
759 scrollw = gtk_scrolled_window_new(hadjustment, vadjustment);
760 setup_scrolled_window(scrollw);
764 /* Set a GtkScrolledWindow's scrollbar placement and add it to the list
765 of GtkScrolledWindows. */
767 setup_scrolled_window(GtkWidget *scrollw)
769 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw),
770 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
772 scrolled_windows = g_list_append(scrolled_windows, scrollw);
774 /* Catch the "destroy" event on the widget, so that we remove it from
775 the list when it's destroyed. */
776 g_signal_connect(scrollw, "destroy", G_CALLBACK(forget_scrolled_window), NULL);
779 /* Remove a GtkScrolledWindow from the list of GtkScrolledWindows. */
781 forget_scrolled_window(GtkWidget *scrollw,
784 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
787 /* List of all CTrees/TreeViews, so we can globally set the line and
788 * expander style of all of them. */
791 static void setup_tree(GtkWidget *tree);
792 static void forget_tree(GtkWidget *tree, gpointer data);
793 static void set_tree_styles(GtkWidget *tree);
794 static gboolean tree_view_key_pressed_cb(GtkWidget *tree, GdkEventKey *event, gpointer user_data _U_);
796 /* Create a Tree, give it the right styles, and remember it. */
798 tree_view_new(GtkTreeModel *model)
802 tree = gtk_tree_view_new_with_model(model);
807 /* Set a Tree's styles and add it to the list of Trees. */
809 setup_tree(GtkWidget *tree)
811 set_tree_styles(tree);
813 trees = g_list_append(trees, tree);
815 /* Catch the "destroy" event on the widget, so that we remove it from
816 the list when it's destroyed. */
817 g_signal_connect(tree, "destroy", G_CALLBACK(forget_tree), NULL);
818 g_signal_connect(tree, "key-press-event", G_CALLBACK(tree_view_key_pressed_cb), NULL );
821 /* Remove a Tree from the list of Trees. */
823 forget_tree(GtkWidget *tree,
826 trees = g_list_remove(trees, tree);
829 /* Set the styles of a Tree based upon user preferences. */
831 set_tree_styles(GtkWidget *tree)
833 g_assert(prefs.gui_altern_colors >= 0 && prefs.gui_altern_colors <= 1);
834 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree),
835 prefs.gui_altern_colors);
839 set_tree_styles_cb(gpointer data,
840 gpointer user_data _U_)
842 set_tree_styles((GtkWidget *)data);
845 /* Set the styles of all Trees based upon style values. */
847 set_tree_styles_all(void)
849 g_list_foreach(trees, set_tree_styles_cb, NULL);
852 /* Move the currently-selected item in a list store up or down one position. */
854 tree_view_list_store_move_selection(GtkTreeView *tree,
857 GtkTreeIter from, to;
859 GtkTreeSelection *sel;
860 GtkTreePath *path_from, *path_to;
862 sel = gtk_tree_view_get_selection(tree);
863 if (!gtk_tree_selection_get_selected(sel, &model, &from)) {
867 path_from = gtk_tree_model_get_path(model, &from);
872 path_to = gtk_tree_path_copy(path_from);
873 /* XXX - Why does one return void and the other return a gboolean? */
875 gtk_tree_path_prev(path_to);
877 gtk_tree_path_next(path_to);
880 if (gtk_tree_path_compare(path_from, path_to) == 0) {
881 gtk_tree_path_free(path_from);
882 gtk_tree_path_free(path_to);
886 gtk_tree_model_get_iter(model, &to, path_to);
887 gtk_list_store_swap(GTK_LIST_STORE(model), &from, &to);
888 gtk_tree_path_free(path_from);
889 gtk_tree_path_free(path_to);
893 /* Find the selected row number in a list store. */
895 tree_view_list_store_get_selected_row(GtkTreeView *tree) {
898 GtkTreeSelection *sel;
903 sel = gtk_tree_view_get_selection(tree);
904 if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
908 path = gtk_tree_model_get_path(model, &iter);
913 path_str = gtk_tree_path_to_string(path);
914 gtk_tree_path_free(path);
916 row = (gint)strtol(path_str, NULL, 10);
922 /* append a row to the simple list */
923 /* use it like: simple_list_append(list, 0, "first", 1, "second", -1) */
925 simple_list_append(GtkWidget *list,
934 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
935 gtk_list_store_append(store, &iter);
936 gtk_list_store_set_valist(store, &iter, ap);
940 /* create a simple list widget */
942 simple_list_new(gint cols,
943 const gchar **titles) {
944 GtkWidget *plugins_list;
947 GtkCellRenderer *renderer;
948 GtkTreeViewColumn *column;
951 g_assert(cols <= 10);
952 store = gtk_list_store_new(cols,
953 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
954 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
955 plugins_list = tree_view_new(GTK_TREE_MODEL(store));
956 g_object_unref(G_OBJECT(store));
957 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(plugins_list), (titles != NULL));
958 for(i=0; i<cols; i++) {
959 renderer = gtk_cell_renderer_text_new();
960 column = gtk_tree_view_column_new_with_attributes(titles ? titles[i] : "", renderer,
962 gtk_tree_view_column_set_sort_column_id(column, i);
963 gtk_tree_view_append_column(GTK_TREE_VIEW(plugins_list), column);
970 render_as_url(GtkCellRenderer *cell)
972 g_object_set(cell, "foreground", "blue", NULL);
973 g_object_set(cell, "foreground-set", TRUE, NULL);
975 g_object_set(cell, "underline", PANGO_UNDERLINE_SINGLE, NULL);
976 g_object_set(cell, "underline-set", TRUE, NULL);
980 simple_list_url_col(GtkWidget *list,
983 GtkTreeViewColumn *ul_column;
984 GList *renderers_list;
985 GtkCellRenderer *ul_renderer;
987 /* make the column look like a link ... */
988 ul_column = gtk_tree_view_get_column(GTK_TREE_VIEW(list), col);
990 renderers_list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(ul_column));
992 if(renderers_list != NULL) {
993 /* it is simple list - there should be only one renderer */
994 ul_renderer = (GtkCellRenderer*)renderers_list->data;
996 render_as_url(ul_renderer);
998 g_list_free(renderers_list);
1004 copy_to_clipboard(GString *str)
1008 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
1009 gtk_clipboard_set_text(cb, str->str, -1); /* Copy the byte data into the clipboard */
1013 typedef struct _copy_binary_t {
1018 static copy_binary_t *
1019 create_copy_binary_t(const guint8 *data,
1022 copy_binary_t* copy_data;
1025 copy_data = g_new(copy_binary_t,1);
1026 copy_data->data = g_new(guint8,len);
1027 copy_data->len = len;
1028 memcpy(copy_data->data,data,len * sizeof(guint8));
1033 destroy_copy_binary_t(copy_binary_t *copy_data) {
1034 g_free(copy_data->data);
1039 copy_binary_free_cb(GtkClipboard *clipboard _U_,
1040 gpointer user_data_or_owner)
1042 destroy_copy_binary_t((copy_binary_t*)user_data_or_owner);
1046 copy_binary_get_cb(GtkClipboard *clipboard _U_,
1047 GtkSelectionData *selection_data,
1049 gpointer user_data_or_owner)
1051 copy_binary_t* copy_data;
1053 copy_data = (copy_binary_t*)user_data_or_owner;
1055 /* Just do a dumb set as binary data */
1056 gtk_selection_data_set(selection_data, GDK_NONE, 8, copy_data->data, copy_data->len);
1060 copy_binary_to_clipboard(const guint8 *data_p,
1063 static GtkTargetEntry target_entry[] = {
1064 {(char *)"application/octet-stream", 0, 0}};
1065 /* XXX - this is not understood by most applications,
1066 * but can be pasted into the better hex editors - is
1067 * there something better that we can do?
1071 copy_binary_t *copy_data;
1075 return; /* XXX would it be better to clear the clipboard? */
1077 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
1078 copy_data = create_copy_binary_t(data_p,len);
1080 ret = gtk_clipboard_set_with_data(cb,target_entry,1,
1081 copy_binary_get_cb, copy_binary_free_cb,copy_data);
1084 destroy_copy_binary_t(copy_data);
1089 * Create a new window title string with user-defined title preference.
1090 * (Or ignore it if unspecified).
1093 create_user_window_title(const gchar *caption)
1096 if (caption == NULL)
1097 return g_strdup("");
1099 /* no user-defined title specified */
1100 if ((prefs.gui_window_title == NULL) || (*prefs.gui_window_title == '\0'))
1101 return g_strdup(caption);
1103 return g_strdup_printf("%s [%s]", caption, prefs.gui_window_title);
1107 * Set the title of a window based on a supplied caption and the
1108 * display name for the capture file.
1110 * XXX - should this include the user preference as well?
1113 set_window_title(GtkWidget *win,
1114 const gchar *caption)
1119 display_name = cf_get_display_name(&cfile);
1120 title = g_strdup_printf("%s: %s", caption, display_name);
1121 g_free(display_name);
1122 gtk_window_set_title(GTK_WINDOW(win), title);
1127 * This callback is invoked when keyboard focus is within either
1128 * the packetlist view or the detail view. The keystrokes processed
1129 * within this callback are attempting to modify the detail view.
1130 * Within the detail view we special case the Left Arrow, Backspace
1131 * and Enter keys depending on the state of the expander (if any)
1132 * for the item in focus.
1134 * Returning FALSE allows processing of the original key_press_event
1135 * by other callbacks. Left/Right scrolling of the packetlist
1136 * view and expanding/collapsing of the detail view lists is
1137 * handled by the default GtkTreeView key-press-event call back.
1139 * XXX - Would an improved version of this callback test to see which
1140 * of the two GtkTreeView lists has focus? Left/Right scrolling of
1141 * the packetlist is currently not optimal. It will take several
1142 * right or left keypress events before the packetlist responds.
1143 * The problem appears to be that the focus is on a particular cell
1144 * within the highlighted row cell (like a spreadsheet). Scrolling
1145 * of the view right or left will not occur until the focus is
1146 * moved to a cell off the left or right edge of the packet list
1147 * view. Also TAB/SHIFT-TAB events can move keyboard focus to
1148 * the packetlist header where there is currently visual hint
1149 * a header cell has focus.
1152 tree_view_key_pressed_cb(GtkWidget *tree,
1154 gpointer user_data _U_)
1156 GtkTreeSelection* selection;
1159 GtkTreeModel* model;
1161 gboolean expanded, expandable;
1164 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1169 if(!gtk_tree_selection_get_selected(selection, &model, &iter)) {
1173 path = gtk_tree_model_get_path(model, &iter);
1178 /* Always FALSE when we're in the packet list (at least until we add sub-packets) */
1179 expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree), path);
1180 expandable = gtk_tree_model_iter_has_child(model, &iter);
1182 switch (event->keyval) {
1185 /* Subtree is expanded. Collapse it. */
1186 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree), path);
1190 /* No break - fall through to jumping to the parent */
1193 /* subtree is already collapsed, jump to parent node */
1194 if(! gtk_tree_model_iter_parent(model, &parent, &iter)) {
1198 gtk_tree_path_free(path);
1199 path = gtk_tree_model_get_path(model, &parent);
1203 gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree), path,
1204 NULL /* focus_column */,
1205 FALSE /* !start_editing */);
1212 /* We have a subtree. Try to expand it. */
1213 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), path, FALSE /* !open_all */);
1222 /* Reverse the current state. */
1224 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree), path);
1226 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), path, FALSE /* !open_all */);
1232 gtk_tree_path_free(path);
1238 switch_to_fixed_col(GtkTreeView *view)
1241 GtkTreeViewColumn *column;
1242 GList *columns, *list;
1244 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
1247 column = (GtkTreeViewColumn *)columns->data;
1248 size = gtk_tree_view_column_get_width(column);
1249 gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_FIXED);
1250 if (size > gtk_tree_view_column_get_fixed_width(column))
1251 gtk_tree_view_column_set_fixed_width(column, size);
1252 columns = g_list_next(columns);
1256 gtk_tree_view_set_fixed_height_mode(view, TRUE);
1260 get_default_col_size(GtkWidget *view,
1263 PangoLayout *layout;
1266 layout = gtk_widget_create_pango_layout(view, str);
1267 pango_layout_get_pixel_size(layout,
1268 &col_width, /* width */
1270 g_object_unref(G_OBJECT(layout));
1271 /* Add a single character's width to get some spacing between columns */
1272 return col_width + (pango_font_description_get_size(user_font_get_regular()) / PANGO_SCALE);
1277 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1278 * the user data must be the column number.
1279 * Present floats with two decimals
1282 float_data_func(GtkTreeViewColumn *column _U_,
1283 GtkCellRenderer *renderer,
1284 GtkTreeModel *model,
1292 /* the col to get data from is in userdata */
1293 gint float_col = GPOINTER_TO_INT(user_data);
1295 gtk_tree_model_get(model, iter, float_col, &float_val, -1);
1297 /* save the current locale */
1298 savelocale = setlocale(LC_NUMERIC, NULL);
1299 /* switch to "C" locale to avoid problems with localized decimal separators
1300 * in g_snprintf("%f") functions
1302 setlocale(LC_NUMERIC, "C");
1304 g_snprintf(buf, sizeof(buf), "%.2f", float_val);
1305 /* restore previous locale setting */
1306 setlocale(LC_NUMERIC, savelocale);
1308 g_object_set(renderer, "text", buf, NULL);
1312 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1313 * the user data must be the column number.
1314 * Present value as hexadecimal.
1317 present_as_hex_func(GtkTreeViewColumn *column _U_,
1318 GtkCellRenderer *renderer,
1319 GtkTreeModel *model,
1326 /* the col to get data from is in userdata */
1327 gint col = GPOINTER_TO_INT(user_data);
1329 gtk_tree_model_get(model, iter, col, &val, -1);
1331 g_snprintf(buf, sizeof(buf), "0x%02x", val);
1333 g_object_set(renderer, "text", buf, NULL);
1337 u64_data_func(GtkTreeViewColumn *column _U_,
1338 GtkCellRenderer *renderer,
1339 GtkTreeModel *model,
1348 /* the col to get data from is in userdata */
1349 gint col = GPOINTER_TO_INT(user_data);
1351 gtk_tree_model_get(model, iter, col, &val, -1);
1356 *--bp = (gchar)(val % 10) +'0';
1360 } while ((val /= 10) != 0 && bp > buf);
1361 g_object_set(renderer, "text", bp, NULL);
1365 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1366 * The user data must be the column number.
1367 * Renders the const static string whose pointer is stored.
1370 str_ptr_data_func(GtkTreeViewColumn *column _U_,
1371 GtkCellRenderer *renderer,
1372 GtkTreeModel *model,
1376 const gchar *str = NULL;
1378 /* The col to get data from is in userdata */
1379 gint data_column = GPOINTER_TO_INT(user_data);
1381 gtk_tree_model_get(model, iter, data_column, &str, -1);
1382 /* XXX should we check that str is non NULL and print a warning or do assert? */
1384 g_object_set(renderer, "text", str, NULL);
1388 str_ptr_sort_func(GtkTreeModel *model,
1393 const gchar *str_a = NULL;
1394 const gchar *str_b = NULL;
1397 /* The col to get data from is in userdata */
1398 gint data_column = GPOINTER_TO_INT(user_data);
1400 gtk_tree_model_get(model, a, data_column, &str_a, -1);
1401 gtk_tree_model_get(model, b, data_column, &str_b, -1);
1403 if (str_a == str_b) {
1404 /* it's worth testing because a lot of rows point to the same data */
1407 else if (str_a == NULL || str_b == NULL) {
1408 ret = (str_a == NULL) ? -1 : 1;
1411 ret = g_ascii_strcasecmp(str_a,str_b);
1416 /** --------------------------------------------------
1417 * ws_combo_box_text_and_pointer convenience functions
1418 * (Code adapted from GtkComboBox.c)
1422 * ws_combo_box_new_text_and_pointer_full:
1424 * Convenience function which constructs a new "text and pointer" combo box, which
1425 * is a #GtkComboBox just displaying strings and storing a pointer associated with
1426 * each combo_box entry; The pointer can be retrieved when an entry is selected.
1427 * Also: optionally returns the cell renderer for the combo box.
1428 * If you use this function to create a text_and_pointer combo_box,
1429 * you should only manipulate its data source with the
1430 * following convenience functions:
1431 * ws_combo_box_append_text_and_pointer()
1432 * ws_combo_box_append_text_and_pointer_full()
1434 * @param cell_p pointer to return the 'GtkCellRenderer *' for the combo box (or NULL).
1435 * @return A pointer to a new text_and_pointer combo_box.
1439 * GtkComboBox style property: "appears-as-list":
1440 * Default: 0: ie: displays as menus
1441 * Wireshark Windows gtkrc: 1: ie: displays as lists (treeview)
1444 ws_combo_box_new_text_and_pointer_full(GtkCellRenderer **cell_p) {
1445 GtkWidget *combo_box;
1446 GtkCellRenderer *cell;
1447 GtkTreeStore *store;
1449 /* The Tree store for the GtkComboBox has 3 columns:
1450 0: text string for display in GtkComboBox list;
1451 1: pointer (data) associated with the entry;
1452 2: True/False depending upon whether this entry is selectable ("sensitive" attribute).
1455 store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
1456 combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
1457 g_object_unref(store);
1458 cell = gtk_cell_renderer_text_new();
1459 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), cell, TRUE);
1460 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell,
1461 "text", 0, "sensitive", 2,
1463 if (cell_p != NULL) {
1470 * ws_combo_box_new_text_and_pointer:
1472 * Convenience function which constructs a new "text and pointer" combo box, which
1473 * is a #GtkComboBox just displaying strings and storing a pointer associated with
1474 * each combo_box entry; The pointer can be retrieved when an entry is selected.
1475 * If you use this function to create a text_and_pointer combo_box,
1476 * you should only manipulate its data source with the
1477 * following convenience functions:
1478 * ws_combo_box_append_text_and_pointer()
1479 * ws_combo_box_append_text_and_pointer_full()
1481 * @return A pointer to a new text_and_pointer combo_box.
1485 ws_combo_box_new_text_and_pointer(void) {
1486 return ws_combo_box_new_text_and_pointer_full(NULL);
1491 * ws_combo_box_clear_text_and_pointer:
1492 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1494 * Clears all the text_and_pointer entries in the text_and_pointer combo_box.
1495 * Note: A "changed" signal will be emitted after the clear if there was
1496 * an active (selected) entry before the clear.
1497 * You should use this function only with combo boxes constructed with
1498 * ws_combo_box_new_text_and_pointer().
1501 ws_combo_box_clear_text_and_pointer(GtkComboBox *combo_box)
1503 gtk_tree_store_clear(GTK_TREE_STORE(gtk_combo_box_get_model(combo_box)));
1507 * ws_combo_box_append_text_and_pointer_full:
1508 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1509 * @param parent_iter Parent row for apending; NULL if appending to tree top-level;
1510 * @param text A string to be displayed as an entry in the dropdown list of the combo_box
1511 * @param ptr A pointer to be associated with this entry of the combo_box
1512 * @param sensitive TRUE/FALSE to set sensitivity of the entry
1513 * @return A GtkTreeIter pointing to the appended GtkVomboBox entry.
1515 * Appends text and ptr to the list of strings and pointers stored in combo_box.
1516 * The text and ptr can be appended to any existing level of the tree_store.
1517 * The sensitivity of the row will be set as requested.
1518 * Note that you can only use this function with combo boxes constructed with
1519 * ws_combo_box_new_text_and_pointer().
1522 ws_combo_box_append_text_and_pointer_full(GtkComboBox *combo_box,
1523 GtkTreeIter *parent_iter,
1526 const gboolean sensitive)
1529 GtkTreeStore *store;
1531 store = GTK_TREE_STORE(gtk_combo_box_get_model(combo_box));
1533 gtk_tree_store_append(store, &iter, parent_iter);
1534 gtk_tree_store_set(store, &iter, 0, text, 1, ptr, 2, sensitive, -1);
1540 * ws_combo_box_append_text_and_pointer:
1541 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1542 * @param text A string to be displayed as an entry in the dropdown list of the combo_box
1543 * @param ptr A pointer to be associated with this entry of the combo_box
1544 * @return A GtkTreeIter pointing to the appended GtkComboBox entry.
1546 * Appends text and ptr to the list of strings and pointers stored in combo_box. Note that
1547 * you can only use this function with combo boxes constructed with
1548 * ws_combo_box_new_text_and_pointer().
1551 ws_combo_box_append_text_and_pointer(GtkComboBox *combo_box,
1555 return ws_combo_box_append_text_and_pointer_full(combo_box, NULL, text, ptr, TRUE);
1560 * ws_combo_box_get_active_pointer:
1561 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1562 * @param ptr A pointer to a location in which to store the pointer associated with the active entry
1563 * @return TRUE if an entry is selected (i.e: an active entry exists); FALSE otherwise
1565 * You can only use this function with combo boxes constructed with
1566 * ws_combo_box_new_text_and_pointer().
1569 ws_combo_box_get_active_pointer(GtkComboBox *combo_box,
1572 GtkTreeStore *store;
1577 if (gtk_combo_box_get_active_iter(combo_box, &iter)) {
1578 store = GTK_TREE_STORE(gtk_combo_box_get_model(combo_box));
1579 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1587 * ws_combo_box_get_active:
1588 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1589 * @return Index of the active entry; -1 if no entry is selected;
1590 * Note: If the active item is not an immediate child of root of the tree then
1591 * the index returned is that of the top-level for the acftive entry.
1594 ws_combo_box_get_active(GtkComboBox *combo_box)
1596 return gtk_combo_box_get_active(combo_box);
1600 * ws_combo_box_set_active:
1601 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1602 * @param idx of the entry which is to be set as active (ie: selected).
1603 * Index refers to the immediate children of the tree.
1606 ws_combo_box_set_active(GtkComboBox *combo_box,
1609 gtk_combo_box_set_active(combo_box, idx);
1613 * ws_combo_box_set_active_iter:
1614 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1615 * @param iter of the entry which is to be set as active (ie: selected).
1618 ws_combo_box_set_active_iter(GtkComboBox *combo_box, GtkTreeIter *iter)
1620 gtk_combo_box_set_active_iter(combo_box, iter);
1624 /* 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 */
1625 #if GTK_CHECK_VERSION(2,22,0)
1626 #if !GTK_CHECK_VERSION(3,0,0)
1627 static cairo_format_t
1628 gdk_cairo_format_for_content(cairo_content_t content)
1632 case CAIRO_CONTENT_COLOR:
1633 return CAIRO_FORMAT_RGB24;
1634 case CAIRO_CONTENT_ALPHA:
1635 return CAIRO_FORMAT_A8;
1636 case CAIRO_CONTENT_COLOR_ALPHA:
1638 return CAIRO_FORMAT_ARGB32;
1642 static cairo_surface_t *
1643 gdk_cairo_surface_coerce_to_image(cairo_surface_t *surface,
1644 cairo_content_t content,
1650 cairo_surface_t *copy;
1653 copy = cairo_image_surface_create(gdk_cairo_format_for_content(content),
1657 cr = cairo_create(copy);
1658 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1659 cairo_set_source_surface(cr, surface, -src_x, -src_y);
1667 convert_alpha(guchar *dest_data,
1678 src_data += src_stride * src_y + src_x * 4;
1680 for (y = 0; y < height; y++) {
1681 guint32 *src = (guint32 *)src_data;
1683 for (x = 0; x < width; x++) {
1684 guint alpha = src[x] >> 24;
1688 dest_data[x * 4 + 0] = 0;
1689 dest_data[x * 4 + 1] = 0;
1690 dest_data[x * 4 + 2] = 0;
1694 dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
1695 dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
1696 dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
1698 dest_data[x * 4 + 3] = alpha;
1701 src_data += src_stride;
1702 dest_data += dest_stride;
1707 convert_no_alpha(guchar *dest_data,
1718 src_data += src_stride * src_y + src_x * 4;
1720 for (y = 0; y < height; y++) {
1721 guint32 *src = (guint32 *)src_data;
1723 for (x = 0; x < width; x++) {
1724 dest_data[x * 3 + 0] = src[x] >> 16;
1725 dest_data[x * 3 + 1] = src[x] >> 8;
1726 dest_data[x * 3 + 2] = src[x];
1729 src_data += src_stride;
1730 dest_data += dest_stride;
1735 * gdk_pixbuf_get_from_surface:
1736 * @surface: surface to copy from
1737 * @src_x: Source X coordinate within @surface
1738 * @src_y: Source Y coordinate within @surface
1739 * @width: Width in pixels of region to get
1740 * @height: Height in pixels of region to get
1742 * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
1743 * representation inside a #GdkPixbuf. This allows you to efficiently read
1744 * individual pixels from cairo surfaces. For #GdkWindows, use
1745 * gdk_pixbuf_get_from_window() instead.
1747 * This function will create an RGB pixbuf with 8 bits per channel.
1748 * The pixbuf will contain an alpha channel if the @surface contains one.
1750 * Return value: (transfer full): A newly-created pixbuf with a reference
1751 * count of 1, or %NULL on error
1754 gdk_pixbuf_get_from_surface(cairo_surface_t *surface,
1760 cairo_content_t content;
1763 /* General sanity checks */
1764 g_return_val_if_fail(surface != NULL, NULL);
1765 g_return_val_if_fail(width > 0 && height > 0, NULL);
1767 content = cairo_surface_get_content(surface) | CAIRO_CONTENT_COLOR;
1768 dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
1769 !!(content & CAIRO_CONTENT_ALPHA),
1773 surface = gdk_cairo_surface_coerce_to_image(surface, content,
1776 cairo_surface_flush(surface);
1777 if (cairo_surface_status(surface) || dest == NULL)
1779 cairo_surface_destroy(surface);
1783 if (gdk_pixbuf_get_has_alpha(dest))
1784 convert_alpha(gdk_pixbuf_get_pixels(dest),
1785 gdk_pixbuf_get_rowstride(dest),
1786 cairo_image_surface_get_data(surface),
1787 cairo_image_surface_get_stride(surface),
1791 convert_no_alpha(gdk_pixbuf_get_pixels(dest),
1792 gdk_pixbuf_get_rowstride(dest),
1793 cairo_image_surface_get_data(surface),
1794 cairo_image_surface_get_stride(surface),
1798 cairo_surface_destroy(surface);
1801 #endif /* !GTK_CHECK_VERSION(3,0,0) */
1802 #endif /* GTK_CHECK_VERSION(2,22,0) */
1806 ws_gtk_box_new(GtkOrientation orientation,
1808 gboolean homogeneous)
1810 #if !GTK_CHECK_VERSION(3,0,0)
1811 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1812 return gtk_hbox_new(homogeneous, spacing);
1814 return gtk_vbox_new(homogeneous, spacing);
1818 widget = gtk_box_new(orientation, spacing);
1819 gtk_box_set_homogeneous(GTK_BOX(widget), homogeneous);
1822 #endif /* GTK_CHECK_VERSION(3,0,0) */
1825 #if !GTK_CHECK_VERSION(3,0,0)
1827 gtk_button_box_new(GtkOrientation orientation)
1829 if (orientation == GTK_ORIENTATION_HORIZONTAL) {
1830 return gtk_hbutton_box_new();
1832 return gtk_vbutton_box_new();
1837 gtk_scrollbar_new(GtkOrientation orientation,
1838 GtkAdjustment *adjustment)
1840 if (orientation == GTK_ORIENTATION_HORIZONTAL) {
1841 return gtk_hscrollbar_new(adjustment);
1843 return gtk_vscrollbar_new(adjustment);
1848 gtk_paned_new(GtkOrientation orientation)
1850 if(orientation == GTK_ORIENTATION_HORIZONTAL) {
1851 return gtk_hpaned_new();
1853 return gtk_vpaned_new();
1858 gtk_separator_new(GtkOrientation orientation)
1860 if (orientation == GTK_ORIENTATION_HORIZONTAL) {
1861 return gtk_hseparator_new();
1863 return gtk_vseparator_new();
1866 #endif /* GTK_CHECK_VERSION(3,0,0) */
1869 frame_new(const gchar *title) {
1870 GtkWidget *frame, *frame_lb;
1871 GString *mu_title = g_string_new("");
1873 frame = gtk_frame_new(NULL);
1874 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
1876 #if !defined(_WIN32) && !defined(__APPLE__)
1877 g_string_printf(mu_title, "%s", title);
1879 g_string_printf(mu_title, "<b>%s</b>", title);
1881 frame_lb = gtk_label_new(NULL);
1882 gtk_label_set_markup(GTK_LABEL(frame_lb), mu_title->str);
1883 gtk_frame_set_label_widget(GTK_FRAME(frame), frame_lb);
1885 g_string_free(mu_title, TRUE);
1891 /* ---------------------------------
1892 * ws_gtk_grid...() wrappers
1896 #if !GTK_CHECK_VERSION(3,0,0)
1900 ws_gtk_grid_attach_defaults(GtkGrid *grid, GtkWidget *child, gint left, gint top, gint width, gint height)
1902 /* Use defaults for [x|y]options and [x|y]padding which match those for gtk_table_attach_defaults() */
1903 ws_gtk_grid_attach_extended(grid, child, left, top, width, height, GTK_EXPAND|GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
1907 ws_gtk_grid_attach_extended(GtkGrid *grid, GtkWidget *child,
1908 gint left, gint top, gint width, gint height,
1909 GtkAttachOptions xoptions, GtkAttachOptions yoptions,
1910 guint xpadding, guint ypadding)
1912 gtk_grid_attach(grid, child, left, top, width, height);
1914 /* XXX: On Gtk3, there's Some trickyness about EXPAND which I probably don't
1915 * really understand.
1917 * Default for EXPAND is "not set".
1918 * In this case "computed expand" based on any child(ren) of this widget will
1919 * affect this widget.
1920 * If EXPAND is set (either TRUE or FALSE) then the value overrides any effect
1924 /* Note: widget defaults are FALSE */
1925 if (xoptions & GTK_EXPAND)
1926 gtk_widget_set_hexpand(child, TRUE);
1927 if (yoptions & GTK_EXPAND)
1928 gtk_widget_set_vexpand(child, TRUE);
1930 /* Note: widget default is GTK_FILL */
1931 /* XXX: Is an 'align' ignored if the corresponding 'fill; is FALSE ? */
1932 /* XXX: don't set FILL(since is dedault) but just clear if not set ?? */
1933 /* ToDo: review effect of explicit set/clear vs explict clear only */
1934 gtk_widget_set_halign(child, (xoptions & GTK_FILL) ? GTK_ALIGN_FILL : GTK_ALIGN_CENTER);
1935 gtk_widget_set_valign(child, (yoptions & GTK_FILL) ? GTK_ALIGN_FILL : GTK_ALIGN_CENTER);
1937 if (xpadding != 0) {
1938 gtk_widget_set_margin_left(child, xpadding);
1939 gtk_widget_set_margin_right(child, xpadding);
1941 if (ypadding != 0) {
1942 gtk_widget_set_margin_top(child, ypadding);
1943 gtk_widget_set_margin_bottom(child, ypadding);
1948 ws_gtk_grid_set_homogeneous(GtkGrid *grid, gboolean homogeneous)
1950 gtk_grid_set_row_homogeneous(grid, homogeneous);
1951 gtk_grid_set_column_homogeneous(grid, homogeneous);
1953 #endif /* !GTK_CHECK_VERSION(3,0,0) */
1956 * Wrap gdk_cairo_set_source_color() with the GTK 3 equivalent
1957 * to be used in GTK2
1959 #if !GTK_CHECK_VERSION(3,0,0)
1961 gdk_cairo_set_source_rgba(cairo_t *cr, const GdkRGBA *rgba)
1965 gdkRGBAcolor_to_GdkColor(&color, rgba);
1967 gdk_cairo_set_source_color(cr, &color);
1970 #endif /* GTK_CHECK_VERSION(3,0,0) */