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 "ui/gtk/wsicon.h"
63 #define WINDOW_GEOM_KEY "window_geom"
65 /* Set our window icon. The GDK documentation doesn't provide any
66 actual documentation for gdk_window_set_icon(), so we'll steal
67 libgimp/gimpdialog.c:gimp_dialog_realize_callback() from the Gimp
68 sources and assume it's safe.
70 XXX - The current icon size is fixed at 16x16 pixels, which looks fine
71 with kwm (KDE 1.x's window manager), Sawfish (the "default" window
72 manager for GNOME?), and under Windows with Exceed putting X windows
73 on the Windows desktop, using Exceed as the window manager, as those
74 window managers put a 16x16 icon on the title bar.
76 The window managers in some windowing environments (e.g. dtwm in CDE)
77 and some stand-alone window managers have larger icon sizes (many window
78 managers put the window icon on the desktop, in the Windows 3.x style,
79 rather than in the titlebar, in the Windows 4.x style), so we need to
80 find a way to size our icon appropriately.
82 The X11 Inter-Client Communications Conventions Manual, Version 1.1,
83 in X11R5, specifies that "a window manager that wishes to place
84 constraints on the sizes of icon pixmaps and/or windows should
85 place a property called WM_ICON_SIZE on the root"; that property
86 contains minimum width and height, maximum width and height, and
87 width and height increment values. "XGetIconSizes()" retrieves
88 that property; unfortunately, I've yet to find a window manager
89 that sets it on the root window (kwm, AfterStep, and Exceed don't
92 The X Desktop Group's Window Manager Standard specifies, in the section
93 on Application Window Properties, an _NET_WM_ICON property, presumably
94 set by the window manager, which is an array of possible icon sizes
95 for the client. There's no API in GTK+ 1.2[.x] for this; there may
96 eventually be one either in GTK+ 2.0 or GNOME 2.0.
98 Some window managers can be configured to take the window name
99 specified by the WM_NAME property of a window or the resource
100 or class name specified by the WM_CLASS property and base the
101 choice of icon for the window on one of those; WM_CLASS for
102 Wireshark's windows has a resource name of "wireshark" and a class
103 name of "Wireshark". However, the way that's done is window-manager-
104 specific, and there's no way to determine what size a particular
105 window manager would want, so there's no way to automate this as
106 part of the installation of Wireshark.
109 window_icon_realize_cb(GtkWidget
*win
,
113 GList
*ws_icon_list
= NULL
;
116 icon
= gdk_pixbuf_new_from_inline(-1, wsicon_16_pb_data
, FALSE
, NULL
);
117 ws_icon_list
= g_list_append(ws_icon_list
, icon
);
118 icon
= gdk_pixbuf_new_from_inline(-1, wsicon_32_pb_data
, FALSE
, NULL
);
119 ws_icon_list
= g_list_append(ws_icon_list
, icon
);
120 icon
= gdk_pixbuf_new_from_inline(-1, wsicon_48_pb_data
, FALSE
, NULL
);
121 ws_icon_list
= g_list_append(ws_icon_list
, icon
);
122 icon
= gdk_pixbuf_new_from_inline(-1, wsicon_64_pb_data
, FALSE
, NULL
);
123 ws_icon_list
= g_list_append(ws_icon_list
, icon
);
125 gtk_window_set_icon_list(GTK_WINDOW(win
), ws_icon_list
);
127 g_list_foreach(ws_icon_list
, (GFunc
)g_object_unref
, NULL
);
128 g_list_free(ws_icon_list
);
130 /* set icon by name, this allows us to use even SVG icon if it is present */
131 gtk_window_set_icon_name(GTK_WINDOW(win
), "wireshark");
136 /* Create a new window, of the specified type, with the specified title
137 (if any) and the Wireshark icon. */
139 window_new(GtkWindowType type
,
144 win
= gtk_window_new(type
);
146 gtk_window_set_title(GTK_WINDOW(win
), title
);
147 g_signal_connect(win
, "realize", G_CALLBACK(window_icon_realize_cb
), NULL
);
149 /* XXX - which one is the correct default policy? or use a preference for this? */
150 /* GTK_WIN_POS_NONE, GTK_WIN_POS_CENTER or GTK_WIN_POS_MOUSE */
151 /* a lot of people dislike GTK_WIN_POS_MOUSE */
153 /* set the initial position (must be done, before show is called!) */
154 gtk_window_set_position(GTK_WINDOW(win
), GTK_WIN_POS_NONE
);
157 GdkScreen
*default_screen
;
160 /* Ideally, new windows would open on the same monitor where the main
161 * window is located, but this doesn't happen when the main window is
162 * not located on the primary monitor. So, if there's more than 1
163 * monitor and Wireshark's main window isn't located on the primary
164 * one, attempt to improve the situation by at least displaying the new
165 * window somewhere on the same monitor, even if it won't be positioned
166 * the same way as it would be when it's on the primary monitor. Don't
167 * attempt to influence the placement on the primary monitor though,
168 * because that's probably the preferred placement strategy. But how
169 * to make window placement behave the same way on any monitor?
171 default_screen
= gdk_screen_get_default();
172 n
= gdk_screen_get_n_monitors(default_screen
);
174 gtk_window_get_position(GTK_WINDOW(top_level
), &x
, &y
);
175 n
= gdk_screen_get_monitor_at_point(default_screen
, x
, y
);
177 gtk_window_move(GTK_WINDOW(win
), x
+ 40, y
+ 30);
185 /* Same as window_new(), but will keep its geometry values (size, position, ...).
186 * Be sure to use window_present() and window_destroy() appropriately! */
188 window_new_with_geom(GtkWindowType type
,
190 const gchar
*geom_name
)
192 window_geometry_t geom
;
193 GtkWidget
*win
= window_new(type
, title
);
195 g_object_set_data(G_OBJECT(win
), WINDOW_GEOM_KEY
, (gpointer
)g_strdup(geom_name
));
197 /* do we have a previously saved size and position of this window? */
199 /* It's a good idea to set the position and size of the window already here,
200 * as it's still invisible and won't "flicker the screen" while initially resizing. */
201 if(window_geom_load(geom_name
, &geom
)) {
202 /* XXX - use prefs to select which values to set? */
204 geom
.set_size
= TRUE
;
205 geom
.set_maximized
= FALSE
; /* don't maximize until window is shown */
206 window_set_geometry(win
, &geom
);
214 /* Create a new window for a splash screen; it's a main window, without decoration,
215 positioned in the center of the screen. */
217 splash_window_new(void)
221 win
= window_new(GTK_WINDOW_TOPLEVEL
, "Wireshark");
222 gtk_window_set_decorated(GTK_WINDOW(win
), FALSE
);
224 /* set the initial position (must be done, before show is called!) */
225 gtk_window_set_position(GTK_WINDOW(win
), GTK_WIN_POS_CENTER
);
231 /* Present the created window on the screen. */
233 window_present(GtkWidget
*win
)
235 window_geometry_t geom
;
238 /* present this window */
239 gtk_window_present(GTK_WINDOW(win
));
241 /* do we have a previously saved size and position of this window? */
242 name
= (const gchar
*)g_object_get_data(G_OBJECT(win
), WINDOW_GEOM_KEY
);
244 if(window_geom_load(name
, &geom
)) {
245 /* XXX - use prefs to select which values to set? */
247 geom
.set_size
= TRUE
;
248 geom
.set_maximized
= TRUE
;
249 window_set_geometry(win
, &geom
);
256 window_key_press_cb(GtkWidget
*widget
,
258 gpointer cancel_button
)
260 g_return_val_if_fail(widget
!= NULL
, FALSE
);
261 g_return_val_if_fail(event
!= NULL
, FALSE
);
263 if (event
->keyval
== GDK_Escape
) {
264 gtk_widget_activate(GTK_WIDGET(cancel_button
));
272 /* Set the "key_press_event" signal for a top-level dialog window to
273 call a routine to activate the "Cancel" button for a dialog box if
274 the key being pressed is the <Esc> key.
276 XXX - there should be a GTK+ widget that'll do that for you, and
277 let you specify a "Cancel" button. It should also not impose
278 a requirement that there be a separator in the dialog box, as
279 the GtkDialog widget does; the visual convention that there's
280 such a separator between the rest of the dialog boxes and buttons
281 such as "OK" and "Cancel" is, for better or worse, not universal
282 (not even in GTK+ - look at the GtkFileSelection dialog!). */
284 window_set_cancel(GtkWidget
*widget
,
285 GtkWidget
*cancel_button
)
287 g_signal_connect(widget
, "key_press_event", G_CALLBACK(window_key_press_cb
), cancel_button
);
291 /* set the actions needed for the cancel "Close"/"Ok"/"Cancel" button that closes the window */
293 window_set_cancel_button(GtkWidget
*win
,
295 window_cancel_button_fct cb
)
298 g_signal_connect(bt
, "clicked", G_CALLBACK(cb
), win
);
300 gtk_widget_grab_default(bt
);
302 window_set_cancel(win
, bt
);
306 /* default callback handler for cancel button "clicked" signal */
308 window_cancel_button_cb(GtkWidget
*w _U_
,
311 window_destroy(GTK_WIDGET(data
));
315 /* default callback handler: the window managers X of the window was clicked (delete_event) */
317 window_delete_event_cb(GtkWidget
*win
,
319 gpointer user_data _U_
)
323 /* event handled, don't do anything else */
328 /* get the geometry of a window from window_new() */
330 window_get_geometry(GtkWidget
*widget
,
331 window_geometry_t
*geom
)
333 GdkWindowState state
;
334 GdkWindow
*widget_window
;
336 /* Try to grab our geometry.
338 GTK+ provides two routines to get a window's position relative
339 to the X root window. If I understand the documentation correctly,
340 gdk_window_get_deskrelative_origin applies mainly to Enlightenment
341 and gdk_window_get_root_origin applies for all other WMs.
343 The code below tries both routines, and picks the one that returns
344 the upper-left-most coordinates.
348 http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
349 http://www.gtk.org/faq/#AEN606
351 As gdk_window_get_deskrelative_origin() is deprecated it has been removed 2011-07-24.
354 memset(geom
, 0, sizeof(window_geometry_t
));
356 widget_window
= gtk_widget_get_window(widget
);
358 gdk_window_get_root_origin(widget_window
,
362 /* XXX - Is this the "approved" method? */
363 #if GTK_CHECK_VERSION(2,24,0)
364 geom
->width
= gdk_window_get_width(widget_window
);
365 geom
->height
= gdk_window_get_height(widget_window
);
367 gdk_drawable_get_size(widget_window
,
371 state
= gdk_window_get_state(widget_window
);
372 geom
->maximized
= ((state
& GDK_WINDOW_STATE_MAXIMIZED
) != 0);
377 /* Ensure Wireshark isn't obscured by the system taskbar (or other desktop toolbars).
378 * Resolves https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=3034 */
380 window_adjust_if_obscured(window_geometry_t
*geom
)
382 MONITORINFO MonitorInfo
;
385 DWORD dwFlags
= MONITOR_DEFAULTTONEAREST
; /* MONITOR_DEFAULTTOPRIMARY? */
388 * Get the virtual screen's top-left coordinates so we can reliably
389 * determine which monitor we're dealing with. See also:
390 * http://msdn.microsoft.com/en-us/library/windows/desktop/dd145136%28v=vs.85%29.aspx
392 vs
.x
= GetSystemMetrics(SM_XVIRTUALSCREEN
);
393 vs
.y
= GetSystemMetrics(SM_YVIRTUALSCREEN
);
394 pt
.x
= geom
->x
+ vs
.x
;
395 pt
.y
= geom
->y
+ vs
.y
;
396 MonitorInfo
.cbSize
= sizeof(MONITORINFO
);
397 hMonitor
= MonitorFromPoint(pt
, dwFlags
);
398 if (GetMonitorInfo(hMonitor
, &MonitorInfo
)) {
399 if (pt
.x
< MonitorInfo
.rcWork
.left
)
400 geom
->x
+= MonitorInfo
.rcWork
.left
- pt
.x
;
401 if (pt
.y
< MonitorInfo
.rcWork
.top
)
402 geom
->y
+= MonitorInfo
.rcWork
.top
- pt
.y
;
407 /* set the geometry of a window from window_new() */
409 window_set_geometry(GtkWidget
*widget
,
410 window_geometry_t
*geom
)
412 GdkScreen
*default_screen
;
413 GdkRectangle viewable_area
;
416 /* as we now have the geometry from the recent file, set it */
417 /* if the window was minimized, x and y are -32000 (at least on Win32) */
418 if (geom
->set_pos
&& geom
->x
!= -32000 && geom
->y
!= -32000) {
419 /* Per Wireshark bug #553, GTK has a problem on MS Windows
420 * where the upper-left corner of the window may appear off
421 * screen when when a single desktop spans multiple monitors
422 * of different resolutions and positions relative to each
425 * If the requested (x,y) position isn't within the monitor's
426 * viewable area, change it to the viewable area's (x,y). */
427 default_screen
= gdk_screen_get_default();
428 monitor_num
= gdk_screen_get_monitor_at_point(default_screen
,
430 gdk_screen_get_monitor_geometry(default_screen
, monitor_num
,
432 if(geom
->x
< viewable_area
.x
|| geom
->x
> (viewable_area
.x
+ viewable_area
.width
))
433 geom
->x
= viewable_area
.x
;
435 if(geom
->y
< viewable_area
.y
|| geom
->y
> (viewable_area
.y
+ viewable_area
.height
))
436 geom
->y
= viewable_area
.y
;
439 window_adjust_if_obscured(geom
);
442 gtk_window_move(GTK_WINDOW(widget
),
447 if (geom
->set_size
) {
448 gtk_window_resize(GTK_WINDOW(widget
),
449 /*gtk_widget_set_size_request(widget,*/
454 if(geom
->set_maximized
) {
455 if (geom
->maximized
) {
456 gdk_window_maximize(gtk_widget_get_window(widget
));
458 gdk_window_unmaximize(gtk_widget_get_window(widget
));
464 window_destroy(GtkWidget
*win
)
466 window_geometry_t geom
;
472 /* get_geometry must be done *before* destroy is running, as the window geometry
473 * cannot be retrieved at destroy time (so don't use event "destroy" for this) */
474 /* ...and don't do this at all, if we currently have no GdkWindow (e.g. if the
475 * GtkWidget is hidden) */
476 if(gtk_widget_get_has_window(win
) && gtk_widget_get_visible(win
)) {
477 window_get_geometry(win
, &geom
);
479 name
= (const gchar
*)g_object_get_data(G_OBJECT(win
), WINDOW_GEOM_KEY
);
481 window_geom_save(name
, &geom
);
482 g_free((gpointer
)name
);
486 gtk_widget_destroy(win
);
490 _gtk_image_new_from_pixbuf_unref(GdkPixbuf
*pixbuf
) {
493 widget
= gtk_image_new_from_pixbuf(pixbuf
);
494 g_object_unref(pixbuf
);
498 /* convert an xpm to a GtkWidget */
500 xpm_to_widget(const char **xpm
) {
503 pixbuf
= gdk_pixbuf_new_from_xpm_data(xpm
);
504 return _gtk_image_new_from_pixbuf_unref(pixbuf
);
507 /* Convert an pixbuf data to a GtkWidget */
508 /* Data should be created with "gdk-pixbuf-csource --raw" */
510 pixbuf_to_widget(const guint8
*pb_data
) {
513 pixbuf
= gdk_pixbuf_new_from_inline(-1, pb_data
, FALSE
, NULL
);
514 return _gtk_image_new_from_pixbuf_unref(pixbuf
);
518 * Alert box for an invalid display filter expression.
519 * Assumes "dfilter_error_msg" has been set by "dfilter_compile()" to the
520 * error message for the filter.
522 * XXX - should this have a "Help" button that pops up the display filter
526 bad_dfilter_alert_box(GtkWidget
*parent
,
529 GtkWidget
*msg_dialog
;
531 msg_dialog
= gtk_message_dialog_new(GTK_WINDOW(parent
),
532 GTK_DIALOG_DESTROY_WITH_PARENT
,
535 "The filter expression \"%s\" isn't a valid display filter. (%s)",
536 dftext
, dfilter_error_msg
);
537 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msg_dialog
),
538 "See the help for a description of the display filter syntax.");
539 gtk_dialog_run(GTK_DIALOG(msg_dialog
));
540 gtk_widget_destroy(msg_dialog
);
543 /* update the main window */
545 main_window_update(void)
547 while (gtk_events_pending())
548 gtk_main_iteration();
553 /* quit a nested main window */
555 main_window_nested_quit(void)
557 if (gtk_main_level() > 0)
561 /* quit the main window */
563 main_window_quit(void)
568 typedef struct pipe_input_tag
{
572 pipe_input_cb_t input_cb
;
582 /* The timer has expired, see if there's stuff to read from the pipe,
583 if so, do the callback */
585 pipe_timer_cb(gpointer data
)
591 pipe_input_t
*pipe_input
= data
;
595 /* try to read data from the pipe only 5 times, to avoid blocking */
596 while(iterations
< 5) {
597 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/
599 /* Oddly enough although Named pipes don't work on win9x,
600 PeekNamedPipe does !!! */
601 handle
= (HANDLE
)_get_osfhandle(pipe_input
->source
);
602 result
= PeekNamedPipe(handle
, NULL
, 0, NULL
, &avail
, NULL
);
604 /* Get the child process exit status */
605 GetExitCodeProcess((HANDLE
)*(pipe_input
->child_process
), &childstatus
);
607 /* If the Peek returned an error, or there are bytes to be read
608 or the childwatcher thread has terminated then call the normal
610 if (!result
|| avail
> 0 || childstatus
!= STILL_ACTIVE
) {
612 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/
614 if(pipe_input
->pipe_input_id
!= 0) {
615 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: stop timer");*/
616 /* avoid reentrancy problems and stack overflow */
617 g_source_remove(pipe_input
->pipe_input_id
);
618 pipe_input
->pipe_input_id
= 0;
621 /* And call the real handler */
622 if (!pipe_input
->input_cb(pipe_input
->source
, pipe_input
->user_data
)) {
623 g_log(NULL
, G_LOG_LEVEL_DEBUG
, "pipe_timer_cb: input pipe closed, iterations: %u", iterations
);
624 /* pipe closed, return false so that the old timer is not run again */
629 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/
630 /* No data, stop now */
637 if(pipe_input
->pipe_input_id
== 0) {
638 /* restore pipe handler */
639 pipe_input
->pipe_input_id
= g_timeout_add(200, pipe_timer_cb
, data
);
640 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, new timer", iterations);*/
642 /* Return false so that the old timer is not run again */
645 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, old timer", iterations);*/
647 /* we didn't stopped the old timer, so let it run */
654 /* There's stuff to read from the sync pipe, meaning the child has sent
655 us a message, or the sync pipe has closed, meaning the child has
656 closed it (perhaps because it exited). */
658 pipe_input_cb(GIOChannel
*source _U_
,
659 GIOCondition condition _U_
,
662 pipe_input_t
*pipe_input
= (pipe_input_t
*)data
;
665 /* avoid reentrancy problems and stack overflow */
666 g_source_remove(pipe_input
->pipe_input_id
);
668 if (pipe_input
->input_cb(pipe_input
->source
, pipe_input
->user_data
)) {
669 /* restore pipe handler */
670 pipe_input
->pipe_input_id
= g_io_add_watch_full(pipe_input
->channel
,
672 (GIOCondition
)(G_IO_IN
|G_IO_ERR
|G_IO_HUP
),
682 pipe_input_set_handler(gint source
,
685 pipe_input_cb_t input_cb
)
687 static pipe_input_t pipe_input
;
689 pipe_input
.source
= source
;
690 pipe_input
.child_process
= child_process
;
691 pipe_input
.user_data
= user_data
;
692 pipe_input
.input_cb
= input_cb
;
695 /* Tricky to use pipes in win9x, as no concept of wait. NT can
696 do this but that doesn't cover all win32 platforms. GTK can do
697 this but doesn't seem to work over processes. Attempt to do
698 something similar here, start a timer and check for data on every
700 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/
701 pipe_input
.pipe_input_id
= g_timeout_add(200, pipe_timer_cb
, &pipe_input
);
703 pipe_input
.channel
= g_io_channel_unix_new(source
);
704 g_io_channel_set_encoding(pipe_input
.channel
, NULL
, NULL
);
705 pipe_input
.pipe_input_id
= g_io_add_watch_full(pipe_input
.channel
,
707 (GIOCondition
)(G_IO_IN
|G_IO_ERR
|G_IO_HUP
),
715 #endif /* HAVE_LIBPCAP */
717 /* Given a pointer to a GtkWidget for a top-level window, raise it and
718 de-iconify it. This routine is used if the user has done something to
719 ask that a window of a certain type be popped up when there can be only
720 one such window and such a window has already been popped up - we
721 pop up the existing one rather than creating a new one.
723 XXX - we should request that it be given the input focus, too. Alas,
724 GDK has nothing to do that, e.g. by calling "XSetInputFocus()" in a
725 window in X. Besides, using "XSetInputFocus()" doesn't work anyway,
726 apparently due to the way GTK+/GDK manages the input focus.
728 The X Desktop Group's Window Manager Standard specifies, in the section
729 on Root Window Properties, an _NET_ACTIVE_WINDOW client message that
730 can be sent to the root window, containing the window ID of the
731 window to activate; I infer that this might be the way to give the
732 window the input focus - I assume that means it's also de-iconified,
733 but I wouldn't assume it'd raise it.
735 XXX - will this do the right thing on window systems other than X? */
737 reactivate_window(GtkWidget
*win
)
739 GdkWindow
*win_window
;
741 win_window
= gtk_widget_get_window(win
);
743 gdk_window_show(win_window
);
744 gdk_window_raise(win_window
);
747 /* List of all GtkScrolledWindows, so we can globally set the scrollbar
748 placement of all of them. */
749 static GList
*scrolled_windows
;
751 static void setup_scrolled_window(GtkWidget
*scrollw
);
752 static void forget_scrolled_window(GtkWidget
*scrollw
, gpointer data
);
754 /* Create a GtkScrolledWindow, set its scrollbar placement appropriately,
757 scrolled_window_new(GtkAdjustment
*hadjustment
,
758 GtkAdjustment
*vadjustment
)
762 scrollw
= gtk_scrolled_window_new(hadjustment
, vadjustment
);
763 setup_scrolled_window(scrollw
);
767 /* Set a GtkScrolledWindow's scrollbar placement and add it to the list
768 of GtkScrolledWindows. */
770 setup_scrolled_window(GtkWidget
*scrollw
)
772 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw
),
773 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
775 scrolled_windows
= g_list_append(scrolled_windows
, scrollw
);
777 /* Catch the "destroy" event on the widget, so that we remove it from
778 the list when it's destroyed. */
779 g_signal_connect(scrollw
, "destroy", G_CALLBACK(forget_scrolled_window
), NULL
);
782 /* Remove a GtkScrolledWindow from the list of GtkScrolledWindows. */
784 forget_scrolled_window(GtkWidget
*scrollw
,
787 scrolled_windows
= g_list_remove(scrolled_windows
, scrollw
);
790 /* List of all CTrees/TreeViews, so we can globally set the line and
791 * expander style of all of them. */
794 static void setup_tree(GtkWidget
*tree
);
795 static void forget_tree(GtkWidget
*tree
, gpointer data
);
796 static void set_tree_styles(GtkWidget
*tree
);
797 static gboolean
tree_view_key_pressed_cb(GtkWidget
*tree
, GdkEventKey
*event
, gpointer user_data _U_
);
799 /* Create a Tree, give it the right styles, and remember it. */
801 tree_view_new(GtkTreeModel
*model
)
805 tree
= gtk_tree_view_new_with_model(model
);
810 /* Set a Tree's styles and add it to the list of Trees. */
812 setup_tree(GtkWidget
*tree
)
814 set_tree_styles(tree
);
816 trees
= g_list_append(trees
, tree
);
818 /* Catch the "destroy" event on the widget, so that we remove it from
819 the list when it's destroyed. */
820 g_signal_connect(tree
, "destroy", G_CALLBACK(forget_tree
), NULL
);
821 g_signal_connect(tree
, "key-press-event", G_CALLBACK(tree_view_key_pressed_cb
), NULL
);
824 /* Remove a Tree from the list of Trees. */
826 forget_tree(GtkWidget
*tree
,
829 trees
= g_list_remove(trees
, tree
);
832 /* Set the styles of a Tree based upon user preferences. */
834 set_tree_styles(GtkWidget
*tree
)
836 g_assert(prefs
.gui_altern_colors
>= 0 && prefs
.gui_altern_colors
<= 1);
837 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree
),
838 prefs
.gui_altern_colors
);
842 set_tree_styles_cb(gpointer data
,
843 gpointer user_data _U_
)
845 set_tree_styles((GtkWidget
*)data
);
848 /* Set the styles of all Trees based upon style values. */
850 set_tree_styles_all(void)
852 g_list_foreach(trees
, set_tree_styles_cb
, NULL
);
855 /* Move the currently-selected item in a list store up or down one position. */
857 tree_view_list_store_move_selection(GtkTreeView
*tree
,
860 GtkTreeIter from
, to
;
862 GtkTreeSelection
*sel
;
863 GtkTreePath
*path_from
, *path_to
;
865 sel
= gtk_tree_view_get_selection(tree
);
866 if (!gtk_tree_selection_get_selected(sel
, &model
, &from
)) {
870 path_from
= gtk_tree_model_get_path(model
, &from
);
875 path_to
= gtk_tree_path_copy(path_from
);
876 /* XXX - Why does one return void and the other return a gboolean? */
878 gtk_tree_path_prev(path_to
);
880 gtk_tree_path_next(path_to
);
883 if (gtk_tree_path_compare(path_from
, path_to
) == 0) {
884 gtk_tree_path_free(path_from
);
885 gtk_tree_path_free(path_to
);
889 gtk_tree_model_get_iter(model
, &to
, path_to
);
890 gtk_list_store_swap(GTK_LIST_STORE(model
), &from
, &to
);
891 gtk_tree_path_free(path_from
);
892 gtk_tree_path_free(path_to
);
896 /* Find the selected row number in a list store. */
898 tree_view_list_store_get_selected_row(GtkTreeView
*tree
) {
901 GtkTreeSelection
*sel
;
906 sel
= gtk_tree_view_get_selection(tree
);
907 if (!gtk_tree_selection_get_selected(sel
, &model
, &iter
)) {
911 path
= gtk_tree_model_get_path(model
, &iter
);
916 path_str
= gtk_tree_path_to_string(path
);
917 gtk_tree_path_free(path
);
919 row
= (gint
)strtol(path_str
, NULL
, 10);
925 /* append a row to the simple list */
926 /* use it like: simple_list_append(list, 0, "first", 1, "second", -1) */
928 simple_list_append(GtkWidget
*list
,
937 store
= GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list
)));
938 gtk_list_store_append(store
, &iter
);
939 gtk_list_store_set_valist(store
, &iter
, ap
);
943 /* create a simple list widget */
945 simple_list_new(gint cols
,
946 const gchar
**titles
) {
947 GtkWidget
*plugins_list
;
950 GtkCellRenderer
*renderer
;
951 GtkTreeViewColumn
*column
;
954 g_assert(cols
<= 10);
955 store
= gtk_list_store_new(cols
,
956 G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_STRING
,
957 G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_STRING
);
958 plugins_list
= tree_view_new(GTK_TREE_MODEL(store
));
959 g_object_unref(G_OBJECT(store
));
960 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(plugins_list
), (titles
!= NULL
));
961 for(i
=0; i
<cols
; i
++) {
962 renderer
= gtk_cell_renderer_text_new();
963 column
= gtk_tree_view_column_new_with_attributes(titles
? titles
[i
] : "", renderer
,
965 gtk_tree_view_column_set_sort_column_id(column
, i
);
966 gtk_tree_view_append_column(GTK_TREE_VIEW(plugins_list
), column
);
973 render_as_url(GtkCellRenderer
*cell
)
975 g_object_set(cell
, "foreground", "blue", NULL
);
976 g_object_set(cell
, "foreground-set", TRUE
, NULL
);
978 g_object_set(cell
, "underline", PANGO_UNDERLINE_SINGLE
, NULL
);
979 g_object_set(cell
, "underline-set", TRUE
, NULL
);
983 simple_list_url_col(GtkWidget
*list
,
986 GtkTreeViewColumn
*ul_column
;
987 GList
*renderers_list
;
988 GtkCellRenderer
*ul_renderer
;
990 /* make the column look like a link ... */
991 ul_column
= gtk_tree_view_get_column(GTK_TREE_VIEW(list
), col
);
993 renderers_list
= gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(ul_column
));
995 if(renderers_list
!= NULL
) {
996 /* it is simple list - there should be only one renderer */
997 ul_renderer
= (GtkCellRenderer
*)renderers_list
->data
;
999 render_as_url(ul_renderer
);
1001 g_list_free(renderers_list
);
1007 copy_to_clipboard(GString
*str
)
1011 cb
= gtk_clipboard_get(GDK_SELECTION_CLIPBOARD
); /* Get the default clipboard */
1012 gtk_clipboard_set_text(cb
, str
->str
, -1); /* Copy the byte data into the clipboard */
1016 typedef struct _copy_binary_t
{
1021 static copy_binary_t
*
1022 create_copy_binary_t(const guint8
*data
,
1025 copy_binary_t
* copy_data
;
1028 copy_data
= g_new(copy_binary_t
,1);
1029 copy_data
->data
= g_new(guint8
,len
);
1030 copy_data
->len
= len
;
1031 memcpy(copy_data
->data
,data
,len
* sizeof(guint8
));
1036 destroy_copy_binary_t(copy_binary_t
*copy_data
) {
1037 g_free(copy_data
->data
);
1042 copy_binary_free_cb(GtkClipboard
*clipboard _U_
,
1043 gpointer user_data_or_owner
)
1045 destroy_copy_binary_t((copy_binary_t
*)user_data_or_owner
);
1049 copy_binary_get_cb(GtkClipboard
*clipboard _U_
,
1050 GtkSelectionData
*selection_data
,
1052 gpointer user_data_or_owner
)
1054 copy_binary_t
* copy_data
;
1056 copy_data
= (copy_binary_t
*)user_data_or_owner
;
1058 /* Just do a dumb set as binary data */
1059 gtk_selection_data_set(selection_data
, GDK_NONE
, 8, copy_data
->data
, copy_data
->len
);
1063 copy_binary_to_clipboard(const guint8
*data_p
,
1066 static GtkTargetEntry target_entry
[] = {
1067 {(char *)"application/octet-stream", 0, 0}};
1068 /* XXX - this is not understood by most applications,
1069 * but can be pasted into the better hex editors - is
1070 * there something better that we can do?
1074 copy_binary_t
*copy_data
;
1078 return; /* XXX would it be better to clear the clipboard? */
1080 cb
= gtk_clipboard_get(GDK_SELECTION_CLIPBOARD
); /* Get the default clipboard */
1081 copy_data
= create_copy_binary_t(data_p
,len
);
1083 ret
= gtk_clipboard_set_with_data(cb
,target_entry
,1,
1084 copy_binary_get_cb
, copy_binary_free_cb
,copy_data
);
1087 destroy_copy_binary_t(copy_data
);
1092 * Create a new window title string with user-defined title preference.
1093 * (Or ignore it if unspecified).
1096 create_user_window_title(const gchar
*caption
)
1099 if (caption
== NULL
)
1100 return g_strdup("");
1102 /* no user-defined title specified */
1103 if ((prefs
.gui_window_title
== NULL
) || (*prefs
.gui_window_title
== '\0'))
1104 return g_strdup(caption
);
1106 return g_strdup_printf("%s [%s]", caption
, prefs
.gui_window_title
);
1110 * Set the title of a window based on a supplied caption and the
1111 * display name for the capture file.
1113 * XXX - should this include the user preference as well?
1116 set_window_title(GtkWidget
*win
,
1117 const gchar
*caption
)
1122 display_name
= cf_get_display_name(&cfile
);
1123 title
= g_strdup_printf("%s: %s", caption
, display_name
);
1124 g_free(display_name
);
1125 gtk_window_set_title(GTK_WINDOW(win
), title
);
1130 * Collapse row and his children
1133 tree_collapse_row_with_children(GtkTreeView
*tree_view
, GtkTreeModel
*model
, GtkTreePath
*path
,
1138 if (gtk_tree_view_row_expanded(tree_view
, path
)) {
1139 if (gtk_tree_model_iter_children(model
, &child
, iter
)) {
1140 gtk_tree_path_down(path
);
1144 if (gtk_tree_view_row_expanded(tree_view
, path
)) {
1145 tree_collapse_row_with_children(tree_view
, model
, path
, &child
);
1148 gtk_tree_path_next(path
);
1149 } while (gtk_tree_model_iter_next(model
, &child
));
1151 gtk_tree_path_up(path
);
1153 gtk_tree_view_collapse_row(tree_view
, path
);
1159 tree_collapse_path_all(GtkTreeView
*tree_view
, GtkTreePath
*path
)
1162 GtkTreeModel
*model
;
1164 model
= gtk_tree_view_get_model(tree_view
);
1165 gtk_tree_model_get_iter(model
, &iter
, path
);
1167 tree_collapse_row_with_children(tree_view
, model
, path
, &iter
);
1171 * This callback is invoked when keyboard focus is within either
1172 * the packetlist view or the detail view. The keystrokes processed
1173 * within this callback are attempting to modify the detail view.
1174 * Within the detail view we special case the Left Arrow, Backspace
1175 * and Enter keys depending on the state of the expander (if any)
1176 * for the item in focus.
1178 * Returning FALSE allows processing of the original key_press_event
1179 * by other callbacks. Left/Right scrolling of the packetlist
1180 * view and expanding/collapsing of the detail view lists is
1181 * handled by the default GtkTreeView key-press-event call back.
1183 * XXX - Would an improved version of this callback test to see which
1184 * of the two GtkTreeView lists has focus? Left/Right scrolling of
1185 * the packetlist is currently not optimal. It will take several
1186 * right or left keypress events before the packetlist responds.
1187 * The problem appears to be that the focus is on a particular cell
1188 * within the highlighted row cell (like a spreadsheet). Scrolling
1189 * of the view right or left will not occur until the focus is
1190 * moved to a cell off the left or right edge of the packet list
1191 * view. Also TAB/SHIFT-TAB events can move keyboard focus to
1192 * the packetlist header where there is currently visual hint
1193 * a header cell has focus.
1196 tree_view_key_pressed_cb(GtkWidget
*tree
,
1198 gpointer user_data _U_
)
1200 GtkTreeSelection
*selection
;
1203 GtkTreeModel
*model
;
1205 gboolean expanded
, expandable
;
1208 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(tree
));
1213 if(!gtk_tree_selection_get_selected(selection
, &model
, &iter
)) {
1217 path
= gtk_tree_model_get_path(model
, &iter
);
1222 /* Always FALSE when we're in the packet list (at least until we add sub-packets) */
1223 expanded
= gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree
), path
);
1224 expandable
= gtk_tree_model_iter_has_child(model
, &iter
);
1226 switch (event
->keyval
) {
1229 /* Subtree is expanded. Collapse it. */
1230 if (event
->state
& GDK_SHIFT_MASK
)
1232 tree_collapse_row_with_children(GTK_TREE_VIEW(tree
), model
, path
, &iter
);
1235 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree
), path
);
1239 /* No break - fall through to jumping to the parent */
1242 /* subtree is already collapsed, jump to parent node */
1243 if(! gtk_tree_model_iter_parent(model
, &parent
, &iter
)) {
1247 gtk_tree_path_free(path
);
1248 path
= gtk_tree_model_get_path(model
, &parent
);
1252 gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree
), path
,
1253 NULL
/* focus_column */,
1254 FALSE
/* !start_editing */);
1261 /* We have a subtree. Try to expand it. */
1262 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree
), path
, FALSE
/* !open_all */);
1271 /* Reverse the current state. */
1273 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree
), path
);
1275 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree
), path
, FALSE
/* !open_all */);
1281 gtk_tree_path_free(path
);
1287 switch_to_fixed_col(GtkTreeView
*view
)
1290 GtkTreeViewColumn
*column
;
1291 GList
*columns
, *list
;
1293 columns
= gtk_tree_view_get_columns(GTK_TREE_VIEW(view
));
1296 column
= (GtkTreeViewColumn
*)columns
->data
;
1297 size
= gtk_tree_view_column_get_width(column
);
1298 gtk_tree_view_column_set_sizing(column
,GTK_TREE_VIEW_COLUMN_FIXED
);
1299 if (size
> gtk_tree_view_column_get_fixed_width(column
))
1300 gtk_tree_view_column_set_fixed_width(column
, size
);
1301 columns
= g_list_next(columns
);
1305 gtk_tree_view_set_fixed_height_mode(view
, TRUE
);
1309 get_default_col_size(GtkWidget
*view
,
1312 PangoLayout
*layout
;
1315 layout
= gtk_widget_create_pango_layout(view
, str
);
1316 pango_layout_get_pixel_size(layout
,
1317 &col_width
, /* width */
1319 g_object_unref(G_OBJECT(layout
));
1320 /* Add a single character's width to get some spacing between columns */
1321 return col_width
+ (pango_font_description_get_size(user_font_get_regular()) / PANGO_SCALE
);
1326 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1327 * the user data must be the column number.
1328 * Present floats with two decimals
1331 float_data_func(GtkTreeViewColumn
*column _U_
,
1332 GtkCellRenderer
*renderer
,
1333 GtkTreeModel
*model
,
1341 /* the col to get data from is in userdata */
1342 gint float_col
= GPOINTER_TO_INT(user_data
);
1344 gtk_tree_model_get(model
, iter
, float_col
, &float_val
, -1);
1346 /* save the current locale */
1347 savelocale
= setlocale(LC_NUMERIC
, NULL
);
1348 /* switch to "C" locale to avoid problems with localized decimal separators
1349 * in g_snprintf("%f") functions
1351 setlocale(LC_NUMERIC
, "C");
1353 g_snprintf(buf
, sizeof(buf
), "%.2f", float_val
);
1354 /* restore previous locale setting */
1355 setlocale(LC_NUMERIC
, savelocale
);
1357 g_object_set(renderer
, "text", buf
, NULL
);
1361 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1362 * the user data must be the column number.
1363 * Present value as hexadecimal.
1366 present_as_hex_func(GtkTreeViewColumn
*column _U_
,
1367 GtkCellRenderer
*renderer
,
1368 GtkTreeModel
*model
,
1375 /* the col to get data from is in userdata */
1376 gint col
= GPOINTER_TO_INT(user_data
);
1378 gtk_tree_model_get(model
, iter
, col
, &val
, -1);
1380 g_snprintf(buf
, sizeof(buf
), "0x%02x", val
);
1382 g_object_set(renderer
, "text", buf
, NULL
);
1386 u64_data_func(GtkTreeViewColumn
*column _U_
,
1387 GtkCellRenderer
*renderer
,
1388 GtkTreeModel
*model
,
1397 /* the col to get data from is in userdata */
1398 gint col
= GPOINTER_TO_INT(user_data
);
1400 gtk_tree_model_get(model
, iter
, col
, &val
, -1);
1405 *--bp
= (gchar
)(val
% 10) +'0';
1409 } while ((val
/= 10) != 0 && bp
> buf
);
1410 g_object_set(renderer
, "text", bp
, NULL
);
1414 * This function can be called from gtk_tree_view_column_set_cell_data_func()
1415 * The user data must be the column number.
1416 * Renders the const static string whose pointer is stored.
1419 str_ptr_data_func(GtkTreeViewColumn
*column _U_
,
1420 GtkCellRenderer
*renderer
,
1421 GtkTreeModel
*model
,
1425 const gchar
*str
= NULL
;
1427 /* The col to get data from is in userdata */
1428 gint data_column
= GPOINTER_TO_INT(user_data
);
1430 gtk_tree_model_get(model
, iter
, data_column
, &str
, -1);
1431 /* XXX should we check that str is non NULL and print a warning or do assert? */
1433 g_object_set(renderer
, "text", str
, NULL
);
1437 str_ptr_sort_func(GtkTreeModel
*model
,
1442 const gchar
*str_a
= NULL
;
1443 const gchar
*str_b
= NULL
;
1446 /* The col to get data from is in userdata */
1447 gint data_column
= GPOINTER_TO_INT(user_data
);
1449 gtk_tree_model_get(model
, a
, data_column
, &str_a
, -1);
1450 gtk_tree_model_get(model
, b
, data_column
, &str_b
, -1);
1452 if (str_a
== str_b
) {
1453 /* it's worth testing because a lot of rows point to the same data */
1456 else if (str_a
== NULL
|| str_b
== NULL
) {
1457 ret
= (str_a
== NULL
) ? -1 : 1;
1460 ret
= g_ascii_strcasecmp(str_a
,str_b
);
1465 /** --------------------------------------------------
1466 * ws_combo_box_text_and_pointer convenience functions
1467 * (Code adapted from GtkComboBox.c)
1471 * ws_combo_box_new_text_and_pointer_full:
1473 * Convenience function which constructs a new "text and pointer" combo box, which
1474 * is a #GtkComboBox just displaying strings and storing a pointer associated with
1475 * each combo_box entry; The pointer can be retrieved when an entry is selected.
1476 * Also: optionally returns the cell renderer for the combo box.
1477 * If you use this function to create a text_and_pointer combo_box,
1478 * you should only manipulate its data source with the
1479 * following convenience functions:
1480 * ws_combo_box_append_text_and_pointer()
1481 * ws_combo_box_append_text_and_pointer_full()
1483 * @param cell_p pointer to return the 'GtkCellRenderer *' for the combo box (or NULL).
1484 * @return A pointer to a new text_and_pointer combo_box.
1488 * GtkComboBox style property: "appears-as-list":
1489 * Default: 0: ie: displays as menus
1490 * Wireshark Windows gtkrc: 1: ie: displays as lists (treeview)
1493 ws_combo_box_new_text_and_pointer_full(GtkCellRenderer
**cell_p
) {
1494 GtkWidget
*combo_box
;
1495 GtkCellRenderer
*cell
;
1496 GtkTreeStore
*store
;
1498 /* The Tree store for the GtkComboBox has 3 columns:
1499 0: text string for display in GtkComboBox list;
1500 1: pointer (data) associated with the entry;
1501 2: True/False depending upon whether this entry is selectable ("sensitive" attribute).
1504 store
= gtk_tree_store_new(3, G_TYPE_STRING
, G_TYPE_POINTER
, G_TYPE_BOOLEAN
);
1505 combo_box
= gtk_combo_box_new_with_model(GTK_TREE_MODEL(store
));
1506 g_object_unref(store
);
1507 cell
= gtk_cell_renderer_text_new();
1508 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box
), cell
, TRUE
);
1509 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box
), cell
,
1510 "text", 0, "sensitive", 2,
1512 if (cell_p
!= NULL
) {
1519 * ws_combo_box_new_text_and_pointer:
1521 * Convenience function which constructs a new "text and pointer" combo box, which
1522 * is a #GtkComboBox just displaying strings and storing a pointer associated with
1523 * each combo_box entry; The pointer can be retrieved when an entry is selected.
1524 * If you use this function to create a text_and_pointer combo_box,
1525 * you should only manipulate its data source with the
1526 * following convenience functions:
1527 * ws_combo_box_append_text_and_pointer()
1528 * ws_combo_box_append_text_and_pointer_full()
1530 * @return A pointer to a new text_and_pointer combo_box.
1534 ws_combo_box_new_text_and_pointer(void) {
1535 return ws_combo_box_new_text_and_pointer_full(NULL
);
1540 * ws_combo_box_clear_text_and_pointer:
1541 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1543 * Clears all the text_and_pointer entries in the text_and_pointer combo_box.
1544 * Note: A "changed" signal will be emitted after the clear if there was
1545 * an active (selected) entry before the clear.
1546 * You should use this function only with combo boxes constructed with
1547 * ws_combo_box_new_text_and_pointer().
1550 ws_combo_box_clear_text_and_pointer(GtkComboBox
*combo_box
)
1552 gtk_tree_store_clear(GTK_TREE_STORE(gtk_combo_box_get_model(combo_box
)));
1556 * ws_combo_box_append_text_and_pointer_full:
1557 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1558 * @param parent_iter Parent row for apending; NULL if appending to tree top-level;
1559 * @param text A string to be displayed as an entry in the dropdown list of the combo_box
1560 * @param ptr A pointer to be associated with this entry of the combo_box
1561 * @param sensitive TRUE/FALSE to set sensitivity of the entry
1562 * @return A GtkTreeIter pointing to the appended GtkVomboBox entry.
1564 * Appends text and ptr to the list of strings and pointers stored in combo_box.
1565 * The text and ptr can be appended to any existing level of the tree_store.
1566 * The sensitivity of the row will be set as requested.
1567 * Note that you can only use this function with combo boxes constructed with
1568 * ws_combo_box_new_text_and_pointer().
1571 ws_combo_box_append_text_and_pointer_full(GtkComboBox
*combo_box
,
1572 GtkTreeIter
*parent_iter
,
1575 const gboolean sensitive
)
1578 GtkTreeStore
*store
;
1580 store
= GTK_TREE_STORE(gtk_combo_box_get_model(combo_box
));
1582 gtk_tree_store_append(store
, &iter
, parent_iter
);
1583 gtk_tree_store_set(store
, &iter
, 0, text
, 1, ptr
, 2, sensitive
, -1);
1589 * ws_combo_box_append_text_and_pointer:
1590 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1591 * @param text A string to be displayed as an entry in the dropdown list of the combo_box
1592 * @param ptr A pointer to be associated with this entry of the combo_box
1593 * @return A GtkTreeIter pointing to the appended GtkComboBox entry.
1595 * Appends text and ptr to the list of strings and pointers stored in combo_box. Note that
1596 * you can only use this function with combo boxes constructed with
1597 * ws_combo_box_new_text_and_pointer().
1600 ws_combo_box_append_text_and_pointer(GtkComboBox
*combo_box
,
1604 return ws_combo_box_append_text_and_pointer_full(combo_box
, NULL
, text
, ptr
, TRUE
);
1609 * ws_combo_box_get_active_pointer:
1610 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1611 * @param ptr A pointer to a location in which to store the pointer associated with the active entry
1612 * @return TRUE if an entry is selected (i.e: an active entry exists); FALSE otherwise
1614 * You can only use this function with combo boxes constructed with
1615 * ws_combo_box_new_text_and_pointer().
1618 ws_combo_box_get_active_pointer(GtkComboBox
*combo_box
,
1621 GtkTreeStore
*store
;
1626 if (gtk_combo_box_get_active_iter(combo_box
, &iter
)) {
1627 store
= GTK_TREE_STORE(gtk_combo_box_get_model(combo_box
));
1628 gtk_tree_model_get(GTK_TREE_MODEL(store
), &iter
,
1636 * ws_combo_box_get_active:
1637 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1638 * @return Index of the active entry; -1 if no entry is selected;
1639 * Note: If the active item is not an immediate child of root of the tree then
1640 * the index returned is that of the top-level for the acftive entry.
1643 ws_combo_box_get_active(GtkComboBox
*combo_box
)
1645 return gtk_combo_box_get_active(combo_box
);
1649 * ws_combo_box_set_active:
1650 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1651 * @param idx of the entry which is to be set as active (ie: selected).
1652 * Index refers to the immediate children of the tree.
1655 ws_combo_box_set_active(GtkComboBox
*combo_box
,
1658 gtk_combo_box_set_active(combo_box
, idx
);
1662 * ws_combo_box_set_active_iter:
1663 * @param combo_box A #GtkComboBox constructed using ws_combo_box_new_text_and_pointer()
1664 * @param iter of the entry which is to be set as active (ie: selected).
1667 ws_combo_box_set_active_iter(GtkComboBox
*combo_box
, GtkTreeIter
*iter
)
1669 gtk_combo_box_set_active_iter(combo_box
, iter
);
1673 /* 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 */
1674 #if GTK_CHECK_VERSION(2,22,0)
1675 #if !GTK_CHECK_VERSION(3,0,0)
1676 static cairo_format_t
1677 gdk_cairo_format_for_content(cairo_content_t content
)
1681 case CAIRO_CONTENT_COLOR
:
1682 return CAIRO_FORMAT_RGB24
;
1683 case CAIRO_CONTENT_ALPHA
:
1684 return CAIRO_FORMAT_A8
;
1685 case CAIRO_CONTENT_COLOR_ALPHA
:
1687 return CAIRO_FORMAT_ARGB32
;
1691 static cairo_surface_t
*
1692 gdk_cairo_surface_coerce_to_image(cairo_surface_t
*surface
,
1693 cairo_content_t content
,
1699 cairo_surface_t
*copy
;
1702 copy
= cairo_image_surface_create(gdk_cairo_format_for_content(content
),
1706 cr
= cairo_create(copy
);
1707 cairo_set_operator(cr
, CAIRO_OPERATOR_SOURCE
);
1708 cairo_set_source_surface(cr
, surface
, -src_x
, -src_y
);
1716 convert_alpha(guchar
*dest_data
,
1727 src_data
+= src_stride
* src_y
+ src_x
* 4;
1729 for (y
= 0; y
< height
; y
++) {
1730 guint32
*src
= (guint32
*)src_data
;
1732 for (x
= 0; x
< width
; x
++) {
1733 guint alpha
= src
[x
] >> 24;
1737 dest_data
[x
* 4 + 0] = 0;
1738 dest_data
[x
* 4 + 1] = 0;
1739 dest_data
[x
* 4 + 2] = 0;
1743 dest_data
[x
* 4 + 0] = (((src
[x
] & 0xff0000) >> 16) * 255 + alpha
/ 2) / alpha
;
1744 dest_data
[x
* 4 + 1] = (((src
[x
] & 0x00ff00) >> 8) * 255 + alpha
/ 2) / alpha
;
1745 dest_data
[x
* 4 + 2] = (((src
[x
] & 0x0000ff) >> 0) * 255 + alpha
/ 2) / alpha
;
1747 dest_data
[x
* 4 + 3] = alpha
;
1750 src_data
+= src_stride
;
1751 dest_data
+= dest_stride
;
1756 convert_no_alpha(guchar
*dest_data
,
1767 src_data
+= src_stride
* src_y
+ src_x
* 4;
1769 for (y
= 0; y
< height
; y
++) {
1770 guint32
*src
= (guint32
*)src_data
;
1772 for (x
= 0; x
< width
; x
++) {
1773 dest_data
[x
* 3 + 0] = src
[x
] >> 16;
1774 dest_data
[x
* 3 + 1] = src
[x
] >> 8;
1775 dest_data
[x
* 3 + 2] = src
[x
];
1778 src_data
+= src_stride
;
1779 dest_data
+= dest_stride
;
1784 * gdk_pixbuf_get_from_surface:
1785 * @surface: surface to copy from
1786 * @src_x: Source X coordinate within @surface
1787 * @src_y: Source Y coordinate within @surface
1788 * @width: Width in pixels of region to get
1789 * @height: Height in pixels of region to get
1791 * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
1792 * representation inside a #GdkPixbuf. This allows you to efficiently read
1793 * individual pixels from cairo surfaces. For #GdkWindows, use
1794 * gdk_pixbuf_get_from_window() instead.
1796 * This function will create an RGB pixbuf with 8 bits per channel.
1797 * The pixbuf will contain an alpha channel if the @surface contains one.
1799 * Return value: (transfer full): A newly-created pixbuf with a reference
1800 * count of 1, or %NULL on error
1803 gdk_pixbuf_get_from_surface(cairo_surface_t
*surface
,
1809 cairo_content_t content
;
1812 /* General sanity checks */
1813 g_return_val_if_fail(surface
!= NULL
, NULL
);
1814 g_return_val_if_fail(width
> 0 && height
> 0, NULL
);
1816 content
= (cairo_content_t
)(cairo_surface_get_content(surface
) | CAIRO_CONTENT_COLOR
);
1817 dest
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
,
1818 !!(content
& CAIRO_CONTENT_ALPHA
),
1822 surface
= gdk_cairo_surface_coerce_to_image(surface
, content
,
1825 cairo_surface_flush(surface
);
1826 if (cairo_surface_status(surface
) || dest
== NULL
)
1828 cairo_surface_destroy(surface
);
1832 if (gdk_pixbuf_get_has_alpha(dest
))
1833 convert_alpha(gdk_pixbuf_get_pixels(dest
),
1834 gdk_pixbuf_get_rowstride(dest
),
1835 cairo_image_surface_get_data(surface
),
1836 cairo_image_surface_get_stride(surface
),
1840 convert_no_alpha(gdk_pixbuf_get_pixels(dest
),
1841 gdk_pixbuf_get_rowstride(dest
),
1842 cairo_image_surface_get_data(surface
),
1843 cairo_image_surface_get_stride(surface
),
1847 cairo_surface_destroy(surface
);
1850 #endif /* !GTK_CHECK_VERSION(3,0,0) */
1851 #endif /* GTK_CHECK_VERSION(2,22,0) */
1855 ws_gtk_box_new(GtkOrientation orientation
,
1857 gboolean homogeneous
)
1859 #if !GTK_CHECK_VERSION(3,0,0)
1860 if (orientation
== GTK_ORIENTATION_HORIZONTAL
)
1861 return gtk_hbox_new(homogeneous
, spacing
);
1863 return gtk_vbox_new(homogeneous
, spacing
);
1867 widget
= gtk_box_new(orientation
, spacing
);
1868 gtk_box_set_homogeneous(GTK_BOX(widget
), homogeneous
);
1871 #endif /* GTK_CHECK_VERSION(3,0,0) */
1874 #if !GTK_CHECK_VERSION(3,0,0)
1876 gtk_button_box_new(GtkOrientation orientation
)
1878 if (orientation
== GTK_ORIENTATION_HORIZONTAL
) {
1879 return gtk_hbutton_box_new();
1881 return gtk_vbutton_box_new();
1886 gtk_scrollbar_new(GtkOrientation orientation
,
1887 GtkAdjustment
*adjustment
)
1889 if (orientation
== GTK_ORIENTATION_HORIZONTAL
) {
1890 return gtk_hscrollbar_new(adjustment
);
1892 return gtk_vscrollbar_new(adjustment
);
1897 gtk_paned_new(GtkOrientation orientation
)
1899 if(orientation
== GTK_ORIENTATION_HORIZONTAL
) {
1900 return gtk_hpaned_new();
1902 return gtk_vpaned_new();
1907 gtk_separator_new(GtkOrientation orientation
)
1909 if (orientation
== GTK_ORIENTATION_HORIZONTAL
) {
1910 return gtk_hseparator_new();
1912 return gtk_vseparator_new();
1915 #endif /* GTK_CHECK_VERSION(3,0,0) */
1918 frame_new(const gchar
*title
) {
1919 GtkWidget
*frame
, *frame_lb
;
1920 GString
*mu_title
= g_string_new("");
1922 frame
= gtk_frame_new(NULL
);
1923 gtk_frame_set_shadow_type(GTK_FRAME(frame
), GTK_SHADOW_NONE
);
1925 #if defined(_WIN32) || defined(__APPLE__)
1926 g_string_printf(mu_title
, "%s", title
);
1928 g_string_printf(mu_title
, "<b>%s</b>", title
);
1930 frame_lb
= gtk_label_new(NULL
);
1931 gtk_label_set_markup(GTK_LABEL(frame_lb
), mu_title
->str
);
1932 gtk_frame_set_label_widget(GTK_FRAME(frame
), frame_lb
);
1934 g_string_free(mu_title
, TRUE
);
1940 /* ---------------------------------
1941 * ws_gtk_grid...() wrappers
1945 #if !GTK_CHECK_VERSION(3,0,0)
1949 ws_gtk_grid_attach_defaults(GtkGrid
*grid
, GtkWidget
*child
, gint left
, gint top
, gint width
, gint height
)
1951 /* Use defaults for [x|y]options and [x|y]padding which match those for gtk_table_attach_defaults() */
1952 ws_gtk_grid_attach_extended(grid
, child
, left
, top
, width
, height
,
1953 (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), 0, 0);
1957 ws_gtk_grid_attach_extended(GtkGrid
*grid
, GtkWidget
*child
,
1958 gint left
, gint top
, gint width
, gint height
,
1959 GtkAttachOptions xoptions
, GtkAttachOptions yoptions
,
1960 guint xpadding
, guint ypadding
)
1962 gtk_grid_attach(grid
, child
, left
, top
, width
, height
);
1964 /* XXX: On Gtk3, there's Some trickyness about EXPAND which I probably don't
1965 * really understand.
1967 * Default for EXPAND is "not set".
1968 * In this case "computed expand" based on any child(ren) of this widget will
1969 * affect this widget.
1970 * If EXPAND is set (either TRUE or FALSE) then the value overrides any effect
1974 /* Note: widget defaults are FALSE */
1975 if (xoptions
& GTK_EXPAND
)
1976 gtk_widget_set_hexpand(child
, TRUE
);
1977 if (yoptions
& GTK_EXPAND
)
1978 gtk_widget_set_vexpand(child
, TRUE
);
1980 /* Note: widget default is GTK_FILL */
1981 /* XXX: Is an 'align' ignored if the corresponding 'fill; is FALSE ? */
1982 /* XXX: don't set FILL(since is dedault) but just clear if not set ?? */
1983 /* ToDo: review effect of explicit set/clear vs explict clear only */
1984 gtk_widget_set_halign(child
, (xoptions
& GTK_FILL
) ? GTK_ALIGN_FILL
: GTK_ALIGN_CENTER
);
1985 gtk_widget_set_valign(child
, (yoptions
& GTK_FILL
) ? GTK_ALIGN_FILL
: GTK_ALIGN_CENTER
);
1987 if (xpadding
!= 0) {
1988 gtk_widget_set_margin_left(child
, xpadding
);
1989 gtk_widget_set_margin_right(child
, xpadding
);
1991 if (ypadding
!= 0) {
1992 gtk_widget_set_margin_top(child
, ypadding
);
1993 gtk_widget_set_margin_bottom(child
, ypadding
);
1998 ws_gtk_grid_set_homogeneous(GtkGrid
*grid
, gboolean homogeneous
)
2000 gtk_grid_set_row_homogeneous(grid
, homogeneous
);
2001 gtk_grid_set_column_homogeneous(grid
, homogeneous
);
2003 #endif /* !GTK_CHECK_VERSION(3,0,0) */
2006 * Wrap gdk_cairo_set_source_color() with the GTK 3 equivalent
2007 * to be used in GTK2
2009 #if !GTK_CHECK_VERSION(3,0,0)
2011 gdk_cairo_set_source_rgba(cairo_t
*cr
, const GdkRGBA
*rgba
)
2015 gdkRGBAcolor_to_GdkColor(&color
, rgba
);
2017 gdk_cairo_set_source_color(cr
, &color
);
2020 #endif /* GTK_CHECK_VERSION(3,0,0) */