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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 #include <gdk/gdkkeysyms.h>
36 #if GTK_CHECK_VERSION(3,0,0)
37 # include <gdk/gdkkeysyms-compat.h>
40 #include <epan/prefs.h>
41 #include "epan/epan.h"
43 #include <epan/packet_info.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"
54 #include "ui/gtk/old-gtk-compat.h"
56 #include "image/wsicon16.xpm"
57 #include "image/wsicon32.xpm"
58 #include "image/wsicon48.xpm"
59 #include "image/wsicon64.xpm"
61 #include "../version_info.h"
67 #define WINDOW_GEOM_KEY "window_geom"
70 /* load the geometry values for a window from previously saved values */
71 static gboolean window_geom_load(const gchar *name, window_geometry_t *geom);
75 /* Set our window icon. The GDK documentation doesn't provide any
76 actual documentation for gdk_window_set_icon(), so we'll steal
77 libgimp/gimpdialog.c:gimp_dialog_realize_callback() from the Gimp
78 sources and assume it's safe.
80 XXX - The current icon size is fixed at 16x16 pixels, which looks fine
81 with kwm (KDE 1.x's window manager), Sawfish (the "default" window
82 manager for GNOME?), and under Windows with Exceed putting X windows
83 on the Windows desktop, using Exceed as the window manager, as those
84 window managers put a 16x16 icon on the title bar.
86 The window managers in some windowing environments (e.g. dtwm in CDE)
87 and some stand-alone window managers have larger icon sizes (many window
88 managers put the window icon on the desktop, in the Windows 3.x style,
89 rather than in the titlebar, in the Windows 4.x style), so we need to
90 find a way to size our icon appropriately.
92 The X11 Inter-Client Communications Conventions Manual, Version 1.1,
93 in X11R5, specifies that "a window manager that wishes to place
94 constraints on the sizes of icon pixmaps and/or windows should
95 place a property called WM_ICON_SIZE on the root"; that property
96 contains minimum width and height, maximum width and height, and
97 width and height increment values. "XGetIconSizes()" retrieves
98 that property; unfortunately, I've yet to find a window manager
99 that sets it on the root window (kwm, AfterStep, and Exceed don't
102 The X Desktop Group's Window Manager Standard specifies, in the section
103 on Application Window Properties, an _NET_WM_ICON property, presumably
104 set by the window manager, which is an array of possible icon sizes
105 for the client. There's no API in GTK+ 1.2[.x] for this; there may
106 eventually be one either in GTK+ 2.0 or GNOME 2.0.
108 Some window managers can be configured to take the window name
109 specified by the WM_NAME property of a window or the resource
110 or class name specified by the WM_CLASS property and base the
111 choice of icon for the window on one of those; WM_CLASS for
112 Wireshark's windows has a resource name of "wireshark" and a class
113 name of "Wireshark". However, the way that's done is window-manager-
114 specific, and there's no way to determine what size a particular
115 window manager would want, so there's no way to automate this as
116 part of the installation of Wireshark.
119 window_icon_realize_cb (GtkWidget *win, gpointer data _U_)
122 GList *ws_icon_list=NULL;
126 icon = gdk_pixbuf_new_from_xpm_data ((const char **) wsicon16_xpm);
127 ws_icon_list = g_list_append (ws_icon_list, icon);
128 icon = gdk_pixbuf_new_from_xpm_data ((const char **) wsicon32_xpm);
129 ws_icon_list = g_list_append (ws_icon_list, icon);
130 icon = gdk_pixbuf_new_from_xpm_data ((const char **) wsicon48_xpm);
131 ws_icon_list = g_list_append (ws_icon_list, icon);
132 icon = gdk_pixbuf_new_from_xpm_data ((const char **) wsicon64_xpm);
133 ws_icon_list = g_list_append (ws_icon_list, icon);
134 gtk_window_set_icon_list(GTK_WINDOW(win), ws_icon_list);
135 /* set icon by name, this allows us to use even SVG icon if it is present */
136 gtk_window_set_icon_name(GTK_WINDOW(win), "wireshark");
143 /* Create a new window, of the specified type, with the specified title
144 (if any) and the Wireshark icon. */
146 window_new(GtkWindowType type, const gchar *title)
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_CENTER_ON_PARENT);*/
161 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_NONE);
167 /* Same as window_new(), but will keep its geometry values (size, position, ...).
168 * Be sure to use window_present() and window_destroy() appropriately! */
170 window_new_with_geom(GtkWindowType type, const gchar *title, const gchar *geom_name)
172 window_geometry_t geom;
173 GtkWidget *win = window_new(type, title);
175 g_object_set_data(G_OBJECT(win), WINDOW_GEOM_KEY, (gpointer)g_strdup(geom_name));
177 /* do we have a previously saved size and position of this window? */
179 /* It's a good idea to set the position and size of the window already here,
180 * as it's still invisible and won't "flicker the screen" while initially resizing. */
181 if(window_geom_load(geom_name, &geom)) {
182 /* XXX - use prefs to select which values to set? */
184 geom.set_size = TRUE;
185 geom.set_maximized = FALSE; /* don't maximize until window is shown */
186 window_set_geometry(win, &geom);
194 /* Create a new window for a splash screen; it's a main window, without decoration,
195 positioned in the center of the screen. */
197 splash_window_new(void)
201 win = window_new(GTK_WINDOW_TOPLEVEL, "Wireshark");
202 gtk_window_set_decorated(GTK_WINDOW(win), FALSE);
204 /* set the initial position (must be done, before show is called!) */
205 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
211 /* Present the created window on the screen. */
213 window_present(GtkWidget *win)
215 window_geometry_t geom;
218 /* present this window */
219 gtk_window_present(GTK_WINDOW(win));
221 /* do we have a previously saved size and position of this window? */
222 name = g_object_get_data(G_OBJECT(win), WINDOW_GEOM_KEY);
224 if(window_geom_load(name, &geom)) {
225 /* XXX - use prefs to select which values to set? */
227 geom.set_size = TRUE;
228 geom.set_maximized = TRUE;
229 window_set_geometry(win, &geom);
236 window_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer cancel_button)
238 g_return_val_if_fail (widget != NULL, FALSE);
239 g_return_val_if_fail (event != NULL, FALSE);
241 if (event->keyval == GDK_Escape) {
242 gtk_widget_activate(GTK_WIDGET(cancel_button));
250 /* Set the "key_press_event" signal for a top-level dialog window to
251 call a routine to activate the "Cancel" button for a dialog box if
252 the key being pressed is the <Esc> key.
254 XXX - there should be a GTK+ widget that'll do that for you, and
255 let you specify a "Cancel" button. It should also not impose
256 a requirement that there be a separator in the dialog box, as
257 the GtkDialog widget does; the visual convention that there's
258 such a separator between the rest of the dialog boxes and buttons
259 such as "OK" and "Cancel" is, for better or worse, not universal
260 (not even in GTK+ - look at the GtkFileSelection dialog!). */
262 window_set_cancel(GtkWidget *widget, GtkWidget *cancel_button)
264 g_signal_connect(widget, "key_press_event", G_CALLBACK(window_key_press_cb), cancel_button);
268 /* set the actions needed for the cancel "Close"/"Ok"/"Cancel" button that closes the window */
269 void window_set_cancel_button(GtkWidget *win, GtkWidget *bt, window_cancel_button_fct cb)
272 g_signal_connect(bt, "clicked", G_CALLBACK(cb), win);
274 gtk_widget_grab_default(bt);
276 window_set_cancel(win, bt);
280 /* default callback handler for cancel button "clicked" signal */
281 void window_cancel_button_cb(GtkWidget *w _U_, gpointer data)
283 window_destroy(GTK_WIDGET(data));
287 /* default callback handler: the window managers X of the window was clicked (delete_event) */
289 window_delete_event_cb(GtkWidget *win, GdkEvent *event _U_, gpointer user_data _U_)
293 /* event handled, don't do anything else */
298 /* get the geometry of a window from window_new() */
300 window_get_geometry(GtkWidget *widget, window_geometry_t *geom)
302 GdkWindowState state;
303 GdkWindow *widget_window;
305 /* Try to grab our geometry.
307 GTK+ provides two routines to get a window's position relative
308 to the X root window. If I understand the documentation correctly,
309 gdk_window_get_deskrelative_origin applies mainly to Enlightenment
310 and gdk_window_get_root_origin applies for all other WMs.
312 The code below tries both routines, and picks the one that returns
313 the upper-left-most coordinates.
317 http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
318 http://www.gtk.org/faq/#AEN606
320 As gdk_window_get_deskrelative_origin() is deprecated it has been removed 2011-07-24.
323 memset (geom, 0, sizeof (window_geometry_t));
325 widget_window = gtk_widget_get_window(widget);
327 gdk_window_get_root_origin(widget_window,
331 /* XXX - Is this the "approved" method? */
332 #if GTK_CHECK_VERSION(2,24,0)
333 geom->width = gdk_window_get_width(widget_window);
334 geom->height = gdk_window_get_height (widget_window);
336 gdk_drawable_get_size(widget_window,
340 state = gdk_window_get_state(widget_window);
341 geom->maximized = (state == GDK_WINDOW_STATE_MAXIMIZED);
345 /* set the geometry of a window from window_new() */
347 window_set_geometry(GtkWidget *widget, window_geometry_t *geom)
349 GdkScreen *default_screen;
350 GdkRectangle viewable_area;
353 /* as we now have the geometry from the recent file, set it */
354 /* if the window was minimized, x and y are -32000 (at least on Win32) */
355 if (geom->set_pos && geom->x != -32000 && geom->y != -32000) {
356 /* Per Wireshark bug #553, GTK has a problem on MS Windows
357 * where the upper-left corner of the window may appear off
358 * screen when when a single desktop spans multiple monitors
359 * of different resolutions and positions relative to each
362 * If the requested (x,y) position isn't within the monitor's
363 * viewable area, change it to the viewable area's (0,0). */
365 default_screen = gdk_screen_get_default();
366 monitor_num = gdk_screen_get_monitor_at_point(default_screen,
368 gdk_screen_get_monitor_geometry(default_screen, monitor_num,
371 if(geom->x < viewable_area.x || geom->x > viewable_area.width)
372 geom->x = viewable_area.x;
374 if(geom->y < viewable_area.y || geom->y > viewable_area.height)
375 geom->y = viewable_area.y;
377 gtk_window_move(GTK_WINDOW(widget),
382 if (geom->set_size) {
383 gtk_window_resize(GTK_WINDOW(widget),
384 /*gtk_widget_set_size_request(widget,*/
389 if(geom->set_maximized) {
390 if (geom->maximized) {
391 gdk_window_maximize(gtk_widget_get_window(widget));
393 gdk_window_unmaximize(gtk_widget_get_window(widget));
399 /* the geometry hashtable for all known window classes,
400 * the window name is the key, and the geometry struct is the value */
401 static GHashTable *window_geom_hash = NULL;
404 /* save the window and it's current geometry into the geometry hashtable */
406 window_geom_save(const gchar *name, window_geometry_t *geom)
409 window_geometry_t *work;
411 /* init hashtable, if not already done */
412 if(!window_geom_hash) {
413 window_geom_hash = g_hash_table_new (g_str_hash, g_str_equal);
415 /* if we have an old one, remove and free it first */
416 work = g_hash_table_lookup(window_geom_hash, name);
418 g_hash_table_remove(window_geom_hash, name);
423 /* g_malloc and insert the new one */
424 work = g_malloc(sizeof(*geom));
426 key = g_strdup(name);
428 g_hash_table_insert(window_geom_hash, key, work);
432 /* load the desired geometry for this window from the geometry hashtable */
434 window_geom_load(const gchar *name, window_geometry_t *geom)
436 window_geometry_t *p;
438 /* init hashtable, if not already done */
439 if(!window_geom_hash) {
440 window_geom_hash = g_hash_table_new (g_str_hash, g_str_equal);
443 p = g_hash_table_lookup(window_geom_hash, name);
453 /* read in a single key value pair from the recent file into the geometry hashtable */
455 window_geom_recent_read_pair(const char *name, const char *key, const char *value)
457 window_geometry_t geom;
460 /* find window geometry maybe already in hashtable */
461 if(!window_geom_load(name, &geom)) {
462 /* not in table, init geom with "basic" values */
463 geom.key = NULL; /* Will be set in window_geom_save () */
464 geom.set_pos = FALSE;
467 geom.set_size = FALSE;
471 geom.set_maximized = FALSE;/* this is valid in GTK2 only */
472 geom.maximized = FALSE; /* this is valid in GTK2 only */
475 if (strcmp(key, "x") == 0) {
476 geom.x = strtol(value, NULL, 10);
478 } else if (strcmp(key, "y") == 0) {
479 geom.y = strtol(value, NULL, 10);
481 } else if (strcmp(key, "width") == 0) {
482 geom.width = strtol(value, NULL, 10);
483 geom.set_size = TRUE;
484 } else if (strcmp(key, "height") == 0) {
485 geom.height = strtol(value, NULL, 10);
486 geom.set_size = TRUE;
487 } else if (strcmp(key, "maximized") == 0) {
488 if (g_ascii_strcasecmp(value, "true") == 0) {
489 geom.maximized = TRUE;
492 geom.maximized = FALSE;
494 geom.set_maximized = TRUE;
497 * Silently ignore the bogus key. We shouldn't abort here,
498 * as this could be due to a corrupt recent file.
500 * XXX - should we print a message about this?
505 /* save / replace geometry in hashtable */
506 window_geom_save(name, &geom);
510 /* write all geometry values of all windows from the hashtable to the recent file */
512 window_geom_recent_write_all(gpointer rf)
514 /* init hashtable, if not already done */
515 if(!window_geom_hash) {
516 window_geom_hash = g_hash_table_new (g_str_hash, g_str_equal);
519 g_hash_table_foreach(window_geom_hash, write_recent_geom, rf);
524 window_destroy(GtkWidget *win)
526 window_geometry_t geom;
532 /* get_geometry must be done *before* destroy is running, as the window geometry
533 * cannot be retrieved at destroy time (so don't use event "destroy" for this) */
534 /* ...and don't do this at all, if we currently have no GdkWindow (e.g. if the
535 * GtkWidget is hidden) */
536 if(gtk_widget_get_has_window (win) && gtk_widget_get_visible(win)) {
537 window_get_geometry(win, &geom);
539 name = g_object_get_data(G_OBJECT(win), WINDOW_GEOM_KEY);
541 window_geom_save(name, &geom);
542 g_free((gpointer)name);
546 gtk_widget_destroy(win);
550 /* Do we need this one ? */
551 /* convert an xpm to a GtkWidget, using the window settings from it's parent */
552 /* (be sure that the parent window is already being displayed) */
553 GtkWidget *xpm_to_widget_from_parent(GtkWidget *parent, const char ** xpm) {
559 pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
560 gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf, gtk_widget_get_colormap(parent), &pixmap, &bitmap, 128);
562 return gtk_image_new_from_pixmap (pixmap, bitmap);
566 /* convert an xpm to a GtkWidget */
567 GtkWidget *xpm_to_widget(const char ** xpm) {
570 pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
571 return gtk_image_new_from_pixbuf(pixbuf);
574 /* Convert an pixbuf data to a GtkWidget */
575 /* Data should be created with "gdk-pixbuf-csource --raw" */
576 GtkWidget *pixbuf_to_widget(const char * pb_data) {
579 pixbuf = gdk_pixbuf_new_from_inline (-1, pb_data, FALSE, NULL);
580 return gtk_image_new_from_pixbuf(pixbuf);
584 * Key to attach the "un-decorated" title to the window, so that if the
585 * user-specified decoration changes, we can correctly update the
588 #define MAIN_WINDOW_NAME_KEY "main_window_name"
590 /* Set the name of the top level main_window_name with the specified string and call
591 update_main_window_title() to construct the full title and display it in the main window
592 and its icon title. */
594 set_main_window_name(const gchar *window_name)
596 gchar *old_window_name;
598 /* Attach the new un-decorated window name to the window. */
599 old_window_name = g_object_get_data(G_OBJECT(top_level), MAIN_WINDOW_NAME_KEY);
600 g_free(old_window_name);
601 g_object_set_data(G_OBJECT(top_level), MAIN_WINDOW_NAME_KEY, g_strdup(window_name));
603 update_main_window_title();
606 /* Construct the main window's title with the current main_window_name, optionally appended
607 with the user-specified title and/or wireshark version. Display the result in the main
608 window title bar and in its icon title.
609 NOTE: The name was changed from '_name' to '_title' because main_window_name is actually
610 set in set_main_window_name() and is only one of the components of the title. */
612 update_main_window_title(void)
617 /* Get the current filename or other title set in set_main_window_name */
618 window_name = g_object_get_data(G_OBJECT(top_level), MAIN_WINDOW_NAME_KEY);
619 if (window_name != NULL) {
620 /* Optionally append the user-defined window title */
621 title = create_user_window_title(window_name);
623 /* Optionally append the version */
624 if (prefs.gui_version_in_start_page) {
625 gchar *old_title = title;
626 title = g_strdup_printf("%s [Wireshark %s %s]", title, VERSION, wireshark_svnversion);
629 gtk_window_set_title(GTK_WINDOW(top_level), title);
634 /* update the main window */
635 void main_window_update(void)
637 while (gtk_events_pending()) gtk_main_iteration();
640 /* exit the main window */
641 void main_window_exit(void)
648 /* quit a nested main window */
649 void main_window_nested_quit(void)
651 if (gtk_main_level() > 0)
655 /* quit the main window */
656 void main_window_quit(void)
663 typedef struct pipe_input_tag {
667 pipe_input_cb_t input_cb;
677 /* The timer has expired, see if there's stuff to read from the pipe,
678 if so, do the callback */
680 pipe_timer_cb(gpointer data)
684 gboolean result, result1;
686 pipe_input_t *pipe_input = data;
690 /* try to read data from the pipe only 5 times, to avoid blocking */
691 while(iterations < 5) {
692 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/
694 /* Oddly enough although Named pipes don't work on win9x,
695 PeekNamedPipe does !!! */
696 handle = (HANDLE) _get_osfhandle (pipe_input->source);
697 result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
699 /* Get the child process exit status */
700 result1 = GetExitCodeProcess((HANDLE)*(pipe_input->child_process),
703 /* If the Peek returned an error, or there are bytes to be read
704 or the childwatcher thread has terminated then call the normal
706 if (!result || avail > 0 || childstatus != STILL_ACTIVE) {
708 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/
710 if(pipe_input->pipe_input_id != 0) {
711 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: stop timer");*/
712 /* avoid reentrancy problems and stack overflow */
713 g_source_remove(pipe_input->pipe_input_id);
714 pipe_input->pipe_input_id = 0;
717 /* And call the real handler */
718 if (!pipe_input->input_cb(pipe_input->source, pipe_input->user_data)) {
719 g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations);
720 /* pipe closed, return false so that the old timer is not run again */
725 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/
726 /* No data, stop now */
733 if(pipe_input->pipe_input_id == 0) {
734 /* restore pipe handler */
735 pipe_input->pipe_input_id = g_timeout_add(200, pipe_timer_cb, data);
736 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, new timer", iterations);*/
738 /* Return false so that the old timer is not run again */
741 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, old timer", iterations);*/
743 /* we didn't stopped the old timer, so let it run */
750 /* There's stuff to read from the sync pipe, meaning the child has sent
751 us a message, or the sync pipe has closed, meaning the child has
752 closed it (perhaps because it exited). */
754 pipe_input_cb(GIOChannel *source _U_, GIOCondition condition _U_,
757 pipe_input_t *pipe_input = data;
760 /* avoid reentrancy problems and stack overflow */
761 g_source_remove(pipe_input->pipe_input_id);
763 if (pipe_input->input_cb(pipe_input->source, pipe_input->user_data)) {
764 /* restore pipe handler */
765 pipe_input->pipe_input_id = g_io_add_watch_full (pipe_input->channel,
767 G_IO_IN|G_IO_ERR|G_IO_HUP,
776 void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb)
778 static pipe_input_t pipe_input;
780 pipe_input.source = source;
781 pipe_input.child_process = child_process;
782 pipe_input.user_data = user_data;
783 pipe_input.input_cb = input_cb;
786 /* Tricky to use pipes in win9x, as no concept of wait. NT can
787 do this but that doesn't cover all win32 platforms. GTK can do
788 this but doesn't seem to work over processes. Attempt to do
789 something similar here, start a timer and check for data on every
791 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/
792 pipe_input.pipe_input_id = g_timeout_add(200, pipe_timer_cb, &pipe_input);
794 pipe_input.channel = g_io_channel_unix_new(source);
795 g_io_channel_set_encoding(pipe_input.channel, NULL, NULL);
796 pipe_input.pipe_input_id = g_io_add_watch_full(pipe_input.channel,
798 G_IO_IN|G_IO_ERR|G_IO_HUP,
806 #endif /* HAVE_LIBPCAP */
808 /* Given a pointer to a GtkWidget for a top-level window, raise it and
809 de-iconify it. This routine is used if the user has done something to
810 ask that a window of a certain type be popped up when there can be only
811 one such window and such a window has already been popped up - we
812 pop up the existing one rather than creating a new one.
814 XXX - we should request that it be given the input focus, too. Alas,
815 GDK has nothing to do that, e.g. by calling "XSetInputFocus()" in a
816 window in X. Besides, using "XSetInputFocus()" doesn't work anyway,
817 apparently due to the way GTK+/GDK manages the input focus.
819 The X Desktop Group's Window Manager Standard specifies, in the section
820 on Root Window Properties, an _NET_ACTIVE_WINDOW client message that
821 can be sent to the root window, containing the window ID of the
822 window to activate; I infer that this might be the way to give the
823 window the input focus - I assume that means it's also de-iconified,
824 but I wouldn't assume it'd raise it.
826 XXX - will this do the right thing on window systems other than X? */
828 reactivate_window(GtkWidget *win)
830 GdkWindow *win_window;
832 win_window = gtk_widget_get_window(win);
834 gdk_window_show(win_window);
835 gdk_window_raise(win_window);
838 /* List of all GtkScrolledWindows, so we can globally set the scrollbar
839 placement of all of them. */
840 static GList *scrolled_windows;
842 static void setup_scrolled_window(GtkWidget *scrollw);
843 static void forget_scrolled_window(GtkWidget *scrollw, gpointer data);
844 static void set_scrollbar_placement_scrollw(GtkWidget *scrollw);
846 /* Create a GtkScrolledWindow, set its scrollbar placement appropriately,
849 scrolled_window_new(GtkAdjustment *hadjustment, GtkAdjustment *vadjustment)
853 scrollw = gtk_scrolled_window_new(hadjustment, vadjustment);
854 setup_scrolled_window(scrollw);
858 /* Set a GtkScrolledWindow's scrollbar placement and add it to the list
859 of GtkScrolledWindows. */
861 setup_scrolled_window(GtkWidget *scrollw)
863 set_scrollbar_placement_scrollw(scrollw);
865 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw),
866 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
868 scrolled_windows = g_list_append(scrolled_windows, scrollw);
870 /* Catch the "destroy" event on the widget, so that we remove it from
871 the list when it's destroyed. */
872 g_signal_connect(scrollw, "destroy", G_CALLBACK(forget_scrolled_window), NULL);
875 /* Remove a GtkScrolledWindow from the list of GtkScrolledWindows. */
877 forget_scrolled_window(GtkWidget *scrollw, gpointer data _U_)
879 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
882 /* Set the scrollbar placement of a GtkScrolledWindow based upon user
885 set_scrollbar_placement_scrollw(GtkWidget *scrollw)
887 if (prefs.gui_scrollbar_on_right) {
888 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
889 GTK_CORNER_TOP_LEFT);
891 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
892 GTK_CORNER_TOP_RIGHT);
897 set_scrollbar_placement_cb(gpointer data, gpointer user_data _U_)
899 set_scrollbar_placement_scrollw((GtkWidget *)data);
902 /* Set the scrollbar placement of all GtkScrolledWindows based on
905 set_scrollbar_placement_all(void)
907 g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, NULL);
910 /* List of all CTrees/TreeViews, so we can globally set the line and
911 * expander style of all of them. */
914 static void setup_tree(GtkWidget *tree);
915 static void forget_tree(GtkWidget *tree, gpointer data);
916 static void set_tree_styles(GtkWidget *tree);
917 static gboolean tree_view_key_pressed_cb(GtkWidget *tree, GdkEventKey *event, gpointer user_data _U_);
919 /* Create a Tree, give it the right styles, and remember it. */
921 tree_view_new(GtkTreeModel *model)
925 tree = gtk_tree_view_new_with_model(model);
930 /* Set a Tree's styles and add it to the list of Trees. */
932 setup_tree(GtkWidget *tree)
934 set_tree_styles(tree);
936 trees = g_list_append(trees, tree);
938 /* Catch the "destroy" event on the widget, so that we remove it from
939 the list when it's destroyed. */
940 g_signal_connect(tree, "destroy", G_CALLBACK(forget_tree), NULL);
941 g_signal_connect(tree, "key-press-event", G_CALLBACK(tree_view_key_pressed_cb), NULL );
944 /* Remove a Tree from the list of Trees. */
946 forget_tree(GtkWidget *tree, gpointer data _U_)
948 trees = g_list_remove(trees, tree);
951 /* Set the styles of a Tree based upon user preferences. */
953 set_tree_styles(GtkWidget *tree)
955 g_assert(prefs.gui_altern_colors >= 0 && prefs.gui_altern_colors <= 1);
956 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree),
957 prefs.gui_altern_colors);
961 set_tree_styles_cb(gpointer data, gpointer user_data _U_)
963 set_tree_styles((GtkWidget *)data);
966 /* Set the styles of all Trees based upon style values. */
968 set_tree_styles_all(void)
970 g_list_foreach(trees, set_tree_styles_cb, NULL);
973 /* Move the currently-selected item in a list store up or down one position. */
975 tree_view_list_store_move_selection(GtkTreeView *tree, gboolean move_up)
977 GtkTreeIter from, to;
979 GtkTreeSelection *sel;
980 GtkTreePath *path_from, *path_to;
982 sel = gtk_tree_view_get_selection(tree);
983 if (! gtk_tree_selection_get_selected(sel, &model, &from)) {
987 path_from = gtk_tree_model_get_path(model, &from);
992 path_to = gtk_tree_path_copy(path_from);
993 /* XXX - Why does one return void and the other return a gboolean? */
995 gtk_tree_path_prev(path_to);
997 gtk_tree_path_next(path_to);
1000 if (gtk_tree_path_compare(path_from, path_to) == 0) {
1001 gtk_tree_path_free(path_from);
1002 gtk_tree_path_free(path_to);
1006 gtk_tree_model_get_iter(model, &to, path_to);
1007 gtk_list_store_swap(GTK_LIST_STORE(model), &from, &to);
1008 gtk_tree_path_free(path_from);
1009 gtk_tree_path_free(path_to);
1013 /* Find the selected row number in a list store. */
1015 tree_view_list_store_get_selected_row(GtkTreeView *tree) {
1017 GtkTreeModel *model;
1018 GtkTreeSelection *sel;
1023 sel = gtk_tree_view_get_selection(tree);
1024 if (! gtk_tree_selection_get_selected(sel, &model, &iter)) {
1028 path = gtk_tree_model_get_path(model, &iter);
1033 path_str = gtk_tree_path_to_string(path);
1034 gtk_tree_path_free(path);
1036 row = (gint) strtol(path_str, NULL, 10);
1042 /* append a row to the simple list */
1043 /* use it like: simple_list_append(list, 0, "first", 1, "second", -1) */
1045 simple_list_append(GtkWidget *list, ...)
1050 GtkListStore *store;
1053 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
1054 gtk_list_store_append(store, &iter);
1055 gtk_list_store_set_valist(store, &iter, ap);
1059 /* create a simple list widget */
1061 simple_list_new(gint cols, const gchar **titles) {
1062 GtkWidget *plugins_list;
1064 GtkListStore *store;
1065 GtkCellRenderer *renderer;
1066 GtkTreeViewColumn *column;
1069 g_assert(cols <= 10);
1070 store = gtk_list_store_new(cols,
1071 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
1072 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
1073 plugins_list = tree_view_new(GTK_TREE_MODEL(store));
1074 g_object_unref(G_OBJECT(store));
1075 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(plugins_list), (titles != NULL));
1076 for(i=0; i<cols; i++) {
1077 renderer = gtk_cell_renderer_text_new();
1078 column = gtk_tree_view_column_new_with_attributes(titles ? titles[i] : "", renderer,
1080 gtk_tree_view_column_set_sort_column_id(column, i);
1081 gtk_tree_view_append_column(GTK_TREE_VIEW(plugins_list), column);
1084 return plugins_list;
1087 void render_as_url(GtkCellRenderer *cell)
1089 g_object_set(cell, "foreground", "blue", NULL);
1090 g_object_set(cell, "foreground-set", TRUE, NULL);
1092 g_object_set(cell, "underline", PANGO_UNDERLINE_SINGLE, NULL);
1093 g_object_set(cell, "underline-set", TRUE, NULL);
1096 void simple_list_url_col(GtkWidget *list, gint col)
1098 GtkTreeViewColumn *ul_column;
1099 GList *renderers_list;
1100 GtkCellRenderer *ul_renderer;
1102 /* make the column look like a link ... */
1103 ul_column = gtk_tree_view_get_column(GTK_TREE_VIEW(list), col);
1105 renderers_list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(ul_column));
1107 if(renderers_list != NULL) {
1108 /* it is simple list - there should be only one renderer */
1109 ul_renderer = (GtkCellRenderer*)renderers_list->data;
1111 render_as_url(ul_renderer);
1113 g_list_free(renderers_list);
1119 copy_to_clipboard(GString *str)
1123 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
1124 gtk_clipboard_set_text(cb, str->str, -1); /* Copy the byte data into the clipboard */
1128 typedef struct _copy_binary_t {
1134 copy_binary_t* create_copy_binary_t(const guint8* data, int len)
1136 copy_binary_t* copy_data;
1139 copy_data = g_new(copy_binary_t,1);
1140 copy_data->data = g_new(guint8,len);
1141 copy_data->len = len;
1142 memcpy(copy_data->data,data,len * sizeof(guint8));
1146 static void destroy_copy_binary_t(copy_binary_t* copy_data) {
1147 g_free(copy_data->data);
1152 void copy_binary_free_cb(GtkClipboard *clipboard _U_, gpointer user_data_or_owner)
1154 copy_binary_t* copy_data;
1155 copy_data = user_data_or_owner;
1156 destroy_copy_binary_t(copy_data);
1160 void copy_binary_get_cb(GtkClipboard *clipboard _U_, GtkSelectionData *selection_data, guint info _U_, gpointer user_data_or_owner)
1162 copy_binary_t* copy_data;
1164 copy_data = user_data_or_owner;
1166 /* Just do a dumb set as binary data */
1167 gtk_selection_data_set(selection_data, GDK_NONE, 8, copy_data->data, copy_data->len);
1170 void copy_binary_to_clipboard(const guint8* data_p, int len)
1172 static GtkTargetEntry target_entry[] = {
1173 {"application/octet_stream", 0, 0}}; /* XXX - this not understood by most applications,
1174 * but can be pasted into the better hex editors - is
1175 * there something better that we can do?
1179 copy_binary_t* copy_data;
1183 return; /* XXX would it be better to clear the clipboard? */
1185 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
1186 copy_data = create_copy_binary_t(data_p,len);
1188 ret = gtk_clipboard_set_with_data(cb,target_entry,1,
1189 copy_binary_get_cb, copy_binary_free_cb,copy_data);
1192 destroy_copy_binary_t(copy_data);
1197 * Create a new window title string with user-defined title preference.
1198 * (Or ignore it if unspecified).
1201 create_user_window_title(const gchar *caption)
1204 if (caption == NULL)
1205 return g_strdup("");
1207 /* no user-defined title specified */
1208 if ((prefs.gui_window_title == NULL) || (*prefs.gui_window_title == '\0'))
1209 return g_strdup(caption);
1211 return g_strdup_printf("%s [%s]", caption, prefs.gui_window_title);
1214 /* XXX move toggle_tree over from proto_draw.c to handle GTK+ 1 */
1216 * This callback is invoked when keyboard focus is within either
1217 * the packetlist view or the detail view. The keystrokes processed
1218 * within this callback are attempting to modify the detail view.
1219 * Within the detail view we special case the Left Arrow, Backspace
1220 * and Enter keys depending on the state of the expander (if any)
1221 * for the item in focus.
1223 * Returning FALSE allows processing of the original key_press_event
1224 * by other callbacks. Left/Right scrolling of the packetlist
1225 * view and expanding/collapsing of the detail view lists is
1226 * handled by the default GtkTreeView key-press-event call back.
1228 * XXX - Would an improved version of this callback test to see which
1229 * of the two GtkTreeView lists has focus? Left/Right scrolling of
1230 * the packetlist is currently not optimal. It will take several
1231 * right or left keypress events before the packetlist responds.
1232 * The problem appears to be that the focus is on a particular cell
1233 * within the highlighted row cell (like a spreadsheet). Scrolling
1234 * of the view right or left will not occur until the focus is
1235 * moved to a cell off the left or right edge of the packet list
1236 * view. Also TAB/SHIFT-TAB events can move keyboard focus to
1237 * the packetlist header where there is currently visual hint
1238 * a header cell has focus.
1241 tree_view_key_pressed_cb(GtkWidget *tree, GdkEventKey *event, gpointer user_data _U_)
1243 GtkTreeSelection* selection;
1246 GtkTreeModel* model;
1248 gboolean expanded, expandable;
1251 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1256 if(!gtk_tree_selection_get_selected (selection, &model, &iter)) {
1260 path = gtk_tree_model_get_path(model, &iter);
1265 /* Always FALSE when we're in the packet list (at least until we add sub-packets) */
1266 expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree), path);
1267 expandable = gtk_tree_model_iter_has_child(model, &iter);
1269 switch (event->keyval) {
1272 /* Subtree is expanded. Collapse it. */
1273 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree), path);
1277 /* No break - fall through to jumping to the parent */
1280 /* subtree is already collapsed, jump to parent node */
1281 if(! gtk_tree_model_iter_parent(model, &parent, &iter)) {
1285 gtk_tree_path_free(path);
1286 path = gtk_tree_model_get_path(model, &parent);
1290 gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree), path,
1291 NULL /* focus_column */,
1292 FALSE /* !start_editing */);
1299 /* We have a subtree. Try to expand it. */
1300 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), path, FALSE /* !open_all */);
1309 /* Reverse the current state. */
1311 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree), path);
1313 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), path, FALSE /* !open_all */);
1319 gtk_tree_path_free(path);
1325 switch_to_fixed_col(GtkTreeView *view)
1328 GtkTreeViewColumn *column;
1329 GList *columns, *list;
1331 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(view));
1334 column = columns->data;
1335 size = gtk_tree_view_column_get_width (column);
1336 gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_FIXED);
1337 if (size > gtk_tree_view_column_get_fixed_width(column))
1338 gtk_tree_view_column_set_fixed_width(column, size);
1339 columns = g_list_next(columns);
1343 gtk_tree_view_set_fixed_height_mode(view, TRUE);
1347 get_default_col_size(GtkWidget *view, const gchar *str)
1349 PangoLayout *layout;
1352 layout = gtk_widget_create_pango_layout(view, str);
1353 pango_layout_get_pixel_size(layout,
1354 &col_width, /* width */
1356 g_object_unref(G_OBJECT(layout));
1357 /* Add a single character's width to get some spacing between columns */
1358 return col_width + (pango_font_description_get_size(user_font_get_regular()) / PANGO_SCALE);
1363 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1364 * the user data must be the colum number.
1365 * Present floats with two decimals
1368 float_data_func (GtkTreeViewColumn *column _U_,
1369 GtkCellRenderer *renderer,
1370 GtkTreeModel *model,
1378 /* the col to get data from is in userdata */
1379 gint float_col = GPOINTER_TO_INT(user_data);
1381 gtk_tree_model_get(model, iter, float_col, &float_val, -1);
1383 /* save the current locale */
1384 savelocale = setlocale(LC_NUMERIC, NULL);
1385 /* switch to "C" locale to avoid problems with localized decimal separators
1386 * in g_snprintf("%f") functions
1388 setlocale(LC_NUMERIC, "C");
1390 g_snprintf(buf, sizeof(buf), "%.2f", float_val);
1391 /* restore previous locale setting */
1392 setlocale(LC_NUMERIC, savelocale);
1394 g_object_set(renderer, "text", buf, NULL);
1398 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1399 * the user data must be the colum number.
1400 * Present value as hexadecimal.
1403 present_as_hex_func (GtkTreeViewColumn *column _U_,
1404 GtkCellRenderer *renderer,
1405 GtkTreeModel *model,
1412 /* the col to get data from is in userdata */
1413 gint col = GPOINTER_TO_INT(user_data);
1415 gtk_tree_model_get(model, iter, col, &val, -1);
1417 g_snprintf(buf, sizeof(buf), "0x%02x", val);
1419 g_object_set(renderer, "text", buf, NULL);
1423 u64_data_func (GtkTreeViewColumn *column _U_,
1424 GtkCellRenderer *renderer,
1425 GtkTreeModel *model,
1434 /* the col to get data from is in userdata */
1435 gint col = GPOINTER_TO_INT(user_data);
1437 gtk_tree_model_get(model, iter, col, &val, -1);
1442 *--bp = (gchar)(val % 10) +'0';
1446 } while ((val /= 10) != 0 && bp > buf);
1447 g_object_set(renderer, "text", bp, NULL);
1451 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1452 * The user data must be the column number.
1453 * Renders the const static string whose pointer is stored.
1456 str_ptr_data_func (GtkTreeViewColumn *column _U_,
1457 GtkCellRenderer *renderer,
1458 GtkTreeModel *model,
1462 const gchar *str = NULL;
1464 /* The col to get data from is in userdata */
1465 gint data_column = GPOINTER_TO_INT(user_data);
1467 gtk_tree_model_get(model, iter, data_column, &str, -1);
1468 /* XXX should we check that str is non NULL and print a warning or do assert? */
1470 g_object_set(renderer, "text", str, NULL);
1474 str_ptr_sort_func(GtkTreeModel *model,
1479 const gchar *str_a = NULL;
1480 const gchar *str_b = NULL;
1483 /* The col to get data from is in userdata */
1484 gint data_column = GPOINTER_TO_INT(user_data);
1486 gtk_tree_model_get(model, a, data_column, &str_a, -1);
1487 gtk_tree_model_get(model, b, data_column, &str_b, -1);
1489 if (str_a == str_b) {
1490 /* it's worth testing because a lot of rows point to the same data */
1493 else if (str_a == NULL || str_b == NULL) {
1494 ret = (str_a == NULL) ? -1 : 1;
1497 ret = g_ascii_strcasecmp(str_a,str_b);
1502 /** --------------------------------------------------
1503 * ws_combo_box_text_and_pointer convenience functions
1504 * (Code adapted from GtkComboBox.c)
1508 * ws_combo_box_new_text_and_pointer_full:
1510 * Convenience function which constructs a new "text and pointer" combo box, which
1511 * is a #GtkComboBox just displaying strings and storing a pointer associated with
1512 * each combo_box entry; The pointer can be retrieved when an entry is selected.
1513 * Also: optionally returns the cell renderer for the combo box.
1514 * If you use this function to create a text_and_pointer combo_box,
1515 * you should only manipulate its data source with the
1516 * following convenience functions:
1517 * ws_combo_box_append_text_and_pointer()
1518 * ws_combo_box_append_text_and_pointer_full()
1520 * @param cell_p pointer to return the 'GtkCellRenderer *' for the combo box (or NULL).
1521 * @return A pointer to a new text_and_pointer combo_box.
1525 * GtkComboBox style property: "appears-as-list":
1526 * Default: 0: ie: displays as menus
1527 * Wireshark Windows gtkrc: 1: ie: displays as lists (treeview)
1530 ws_combo_box_new_text_and_pointer_full(GtkCellRenderer **cell_p) {
1531 GtkWidget *combo_box;
1532 GtkCellRenderer *cell;
1533 GtkTreeStore *store;
1535 /* The Tree store for the GtkComboBox has 3 columns:
1536 0: text string for display in GtkComboBox list;
1537 1: pointer (data) associated with the entry;
1538 2: True/False depending upon whether this entry is selectable ("sensitive" attribute).
1541 store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
1542 combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL (store));
1543 g_object_unref(store);
1544 cell = gtk_cell_renderer_text_new();
1545 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), cell, TRUE);
1546 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell,
1547 "text", 0, "sensitive", 2,
1549 if (cell_p != NULL) {
1556 * ws_combo_box_new_text_and_pointer:
1558 * Convenience function which constructs a new "text and pointer" combo box, which
1559 * is a #GtkComboBox just displaying strings and storing a pointer associated with
1560 * each combo_box entry; The pointer can be retrieved when an entry is selected.
1561 * If you use this function to create a text_and_pointer combo_box,
1562 * you should only manipulate its data source with the
1563 * following convenience functions:
1564 * ws_combo_box_append_text_and_pointer()
1565 * ws_combo_box_append_text_and_pointer_full()
1567 * @return A pointer to a new text_and_pointer combo_box.
1571 ws_combo_box_new_text_and_pointer(void) {
1572 return ws_combo_box_new_text_and_pointer_full(NULL);
1577 * ws_combo_box_clear_text_and_pointer:
1578 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1580 * Clears all the text_and_pointer entries in the text_and_pointer combo_box.
1581 * Note: A "changed" signal will be emitted after the clear if there was
1582 * an active (selected) entry before the clear.
1583 * You should use this function only with combo boxes constructed with
1584 * ws_combo_box_new_text_and_pointer().
1587 ws_combo_box_clear_text_and_pointer(GtkComboBox *combo_box)
1589 gtk_tree_store_clear(GTK_TREE_STORE(gtk_combo_box_get_model(combo_box)));
1593 * ws_combo_box_append_text_and_pointer_full:
1594 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1595 * @param parent_iter Parent row for apending; NULL if appending to tree top-level;
1596 * @param text A string to be displayed as an entry in the dropdown list of the combo_box
1597 * @param ptr A pointer to be associated with this entry of the combo_box
1598 * @param sensitive TRUE/FALSE to set sensitivity of the entry
1599 * @return A GtkTreeIter pointing to the appended GtkVomboBox entry.
1601 * Appends text and ptr to the list of strings and pointers stored in combo_box.
1602 * The text and ptr can be appended to any existing level of the tree_store.
1603 * The sensitivity of the row will be set as requested.
1604 * Note that you can only use this function with combo boxes constructed with
1605 * ws_combo_box_new_text_and_pointer().
1608 ws_combo_box_append_text_and_pointer_full(GtkComboBox *combo_box,
1609 GtkTreeIter *parent_iter,
1612 const gboolean sensitive)
1615 GtkTreeStore *store;
1617 store = GTK_TREE_STORE(gtk_combo_box_get_model(combo_box));
1619 gtk_tree_store_append(store, &iter, parent_iter);
1620 gtk_tree_store_set(store, &iter, 0, text, 1, ptr, 2, sensitive, -1);
1626 * ws_combo_box_append_text_and_pointer:
1627 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1628 * @param text A string to be displayed as an entry in the dropdown list of the combo_box
1629 * @param ptr A pointer to be associated with this entry of the combo_box
1630 * @return A GtkTreeIter pointing to the appended GtkComboBox entry.
1632 * Appends text and ptr to the list of strings and pointers stored in combo_box. Note that
1633 * you can only use this function with combo boxes constructed with
1634 * ws_combo_box_new_text_and_pointer().
1637 ws_combo_box_append_text_and_pointer(GtkComboBox *combo_box,
1641 return ws_combo_box_append_text_and_pointer_full(combo_box, NULL, text, ptr, TRUE);
1646 * ws_combo_box_get_active_pointer:
1647 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1648 * @param ptr A pointer to a location in which to store the pointer associated with the active entry
1649 * @return TRUE if an entry is selected (i.e: an active entry exists); FALSE otherwise
1651 * You can only use this function with combo boxes constructed with
1652 * ws_combo_box_new_text_and_pointer().
1655 ws_combo_box_get_active_pointer(GtkComboBox *combo_box, gpointer *ptr)
1657 GtkTreeStore *store;
1662 if (gtk_combo_box_get_active_iter(combo_box, &iter)) {
1663 store = GTK_TREE_STORE(gtk_combo_box_get_model(combo_box));
1664 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1672 * ws_combo_box_get_active:
1673 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1674 * @return Index of the active entry; -1 if no entry is selected;
1675 * Note: If the active item is not an immediate child of root of the tree then
1676 * the index returned is that of the top-level for the acftive entry.
1679 ws_combo_box_get_active(GtkComboBox *combo_box)
1681 return gtk_combo_box_get_active(combo_box);
1685 * ws_combo_box_set_active:
1686 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1687 * @param idx of the entry which is to be set as active (ie: selected).
1688 * Index refers to the immediate children of the tree.
1691 ws_combo_box_set_active(GtkComboBox *combo_box, gint idx)
1693 gtk_combo_box_set_active(combo_box, idx);
1697 * ws_combo_box_set_active_iter:
1698 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1699 * @param iter of the entry which is to be set as active (ie: selected).
1702 ws_combo_box_set_active_iter(GtkComboBox *combo_box, GtkTreeIter *iter)
1704 gtk_combo_box_set_active_iter(combo_box, iter);
1708 /* 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 */
1709 #if GTK_CHECK_VERSION(2,22,0)
1710 #if !GTK_CHECK_VERSION(3,0,0)
1711 static cairo_format_t
1712 gdk_cairo_format_for_content (cairo_content_t content)
1716 case CAIRO_CONTENT_COLOR:
1717 return CAIRO_FORMAT_RGB24;
1718 case CAIRO_CONTENT_ALPHA:
1719 return CAIRO_FORMAT_A8;
1720 case CAIRO_CONTENT_COLOR_ALPHA:
1722 return CAIRO_FORMAT_ARGB32;
1726 static cairo_surface_t *
1727 gdk_cairo_surface_coerce_to_image (cairo_surface_t *surface,
1728 cairo_content_t content,
1734 cairo_surface_t *copy;
1737 copy = cairo_image_surface_create (gdk_cairo_format_for_content (content),
1741 cr = cairo_create (copy);
1742 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
1743 cairo_set_source_surface (cr, surface, -src_x, -src_y);
1751 convert_alpha (guchar *dest_data,
1762 src_data += src_stride * src_y + src_x * 4;
1764 for (y = 0; y < height; y++) {
1765 guint32 *src = (guint32 *) src_data;
1767 for (x = 0; x < width; x++) {
1768 guint alpha = src[x] >> 24;
1772 dest_data[x * 4 + 0] = 0;
1773 dest_data[x * 4 + 1] = 0;
1774 dest_data[x * 4 + 2] = 0;
1778 dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
1779 dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
1780 dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
1782 dest_data[x * 4 + 3] = alpha;
1785 src_data += src_stride;
1786 dest_data += dest_stride;
1791 convert_no_alpha (guchar *dest_data,
1802 src_data += src_stride * src_y + src_x * 4;
1804 for (y = 0; y < height; y++) {
1805 guint32 *src = (guint32 *) src_data;
1807 for (x = 0; x < width; x++) {
1808 dest_data[x * 3 + 0] = src[x] >> 16;
1809 dest_data[x * 3 + 1] = src[x] >> 8;
1810 dest_data[x * 3 + 2] = src[x];
1813 src_data += src_stride;
1814 dest_data += dest_stride;
1819 * gdk_pixbuf_get_from_surface:
1820 * @surface: surface to copy from
1821 * @src_x: Source X coordinate within @surface
1822 * @src_y: Source Y coordinate within @surface
1823 * @width: Width in pixels of region to get
1824 * @height: Height in pixels of region to get
1826 * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
1827 * representation inside a #GdkPixbuf. This allows you to efficiently read
1828 * individual pixels from cairo surfaces. For #GdkWindows, use
1829 * gdk_pixbuf_get_from_window() instead.
1831 * This function will create an RGB pixbuf with 8 bits per channel.
1832 * The pixbuf will contain an alpha channel if the @surface contains one.
1834 * Return value: (transfer full): A newly-created pixbuf with a reference
1835 * count of 1, or %NULL on error
1838 gdk_pixbuf_get_from_surface (cairo_surface_t *surface,
1844 cairo_content_t content;
1847 /* General sanity checks */
1848 g_return_val_if_fail (surface != NULL, NULL);
1849 g_return_val_if_fail (width > 0 && height > 0, NULL);
1851 content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
1852 dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1853 !!(content & CAIRO_CONTENT_ALPHA),
1857 surface = gdk_cairo_surface_coerce_to_image (surface, content,
1860 cairo_surface_flush (surface);
1861 if (cairo_surface_status (surface) || dest == NULL)
1863 cairo_surface_destroy (surface);
1867 if (gdk_pixbuf_get_has_alpha (dest))
1868 convert_alpha (gdk_pixbuf_get_pixels (dest),
1869 gdk_pixbuf_get_rowstride (dest),
1870 cairo_image_surface_get_data (surface),
1871 cairo_image_surface_get_stride (surface),
1875 convert_no_alpha (gdk_pixbuf_get_pixels (dest),
1876 gdk_pixbuf_get_rowstride (dest),
1877 cairo_image_surface_get_data (surface),
1878 cairo_image_surface_get_stride (surface),
1882 cairo_surface_destroy (surface);
1885 #endif /* !GTK_CHECK_VERSION(3,0,0) */
1886 #endif /* GTK_CHECK_VERSION(2,22,0) */
1889 GtkWidget * ws_gtk_box_new(GtkOrientation orientation, gint spacing, gboolean homogeneous)
1891 #if !GTK_CHECK_VERSION(3,0,0)
1892 if (orientation == GTK_ORIENTATION_HORIZONTAL){
1893 if(homogeneous == TRUE){
1894 return gtk_hbox_new(TRUE, spacing);
1896 return gtk_hbox_new(FALSE, spacing);
1899 if(homogeneous == TRUE){
1900 return gtk_vbox_new(TRUE, spacing);
1902 return gtk_vbox_new(FALSE, spacing);
1908 widget = gtk_box_new(rientation, spacing);
1909 gtk_box_set_homogeneous(GTK_BOX(widget), homogeneous);
1910 #endif /* GTK_CHECK_VERSION(3,0,0) */