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.
39 #include <gdk/gdkkeysyms.h>
41 #include "file_util.h"
42 #include "gtkglobals.h"
43 #include "gui_utils.h"
44 #include <epan/prefs.h>
45 #include "epan/epan.h"
46 #include "../ui_util.h"
47 #include "compat_macros.h"
51 #include "image/wsicon16.xpm"
53 /* XXX - remove this later again, when dlg_xx function cleanup done */
54 #include "dlg_utils.h"
57 #define WINDOW_GEOM_KEY "window_geom"
60 /* load the geometry values for a window from previously saved values */
61 static gboolean window_geom_load(const gchar *name, window_geometry_t *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, gpointer data _U_)
112 static GdkPixmap *icon_pmap = NULL;
113 static GdkBitmap *icon_mask = NULL;
116 style = gtk_widget_get_style (win);
118 if (icon_pmap == NULL) {
119 icon_pmap = gdk_pixmap_create_from_xpm_d (win->window,
120 &icon_mask, &style->bg[GTK_STATE_NORMAL],
121 (gchar **) wsicon16_xpm);
124 gdk_window_set_icon (win->window, NULL, icon_pmap, icon_mask);
129 /* Create a new window, of the specified type, with the specified title
130 (if any) and the Wireshark icon. */
132 window_new(GtkWindowType type, const gchar *title)
136 win = gtk_window_new(type);
138 gtk_window_set_title(GTK_WINDOW(win), title);
139 SIGNAL_CONNECT(win, "realize", window_icon_realize_cb, NULL);
141 /* XXX - which one is the correct default policy? or use a preference for this? */
142 /* GTK_WIN_POS_NONE, GTK_WIN_POS_CENTER or GTK_WIN_POS_MOUSE */
143 /* a lot of people dislike GTK_WIN_POS_MOUSE */
145 /* set the initial position (must be done, before show is called!) */
146 #if GTK_MAJOR_VERSION >= 2
147 /* gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER_ON_PARENT);*/
149 /* gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);*/
151 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_NONE);
153 #if GTK_MAJOR_VERSION < 2
154 /* allow window to be shrinked by user, as gtk_widget_set_usize() will set minimum size and */
155 /* the user never could shrink the window again */
156 gtk_window_set_policy(GTK_WINDOW(win), TRUE, TRUE, FALSE);
163 /* Same as window_new(), but will keep it's geometry values (size, position, ...).
164 * Be sure to use window_present() and window_destroy() appropriately! */
166 window_new_with_geom(GtkWindowType type, const gchar *title, const gchar *geom_name)
168 window_geometry_t geom;
169 GtkWidget *win = window_new(type, title);
171 OBJECT_SET_DATA(win, WINDOW_GEOM_KEY, (gpointer)g_strdup(geom_name));
173 /* do we have a previously saved size and position of this window? */
175 /* It's a good idea to set the position and size of the window already here,
176 * as it's still invisible and won't "flicker the screen" while initially resizing. */
177 if(window_geom_load(geom_name, &geom)) {
178 /* XXX - use prefs to select which values to set? */
180 geom.set_size = TRUE;
181 geom.set_maximized = FALSE; /* don't maximize until window is shown */
182 window_set_geometry(win, &geom);
190 #if GTK_MAJOR_VERSION < 2
191 /* We can't set the decorations until the window is realized. */
193 window_notitle_realize_cb (GtkWidget *win, gpointer data _U_)
195 gdk_window_set_decorations(win->window, 0);
200 /* Create a new window for a splash screen; it's a main window, with no title,
201 positioned in the center of the screen. */
203 splash_window_new(void)
207 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
208 #if GTK_MAJOR_VERSION >= 2
209 gtk_window_set_decorated(GTK_WINDOW(win), FALSE);
211 SIGNAL_CONNECT(win, "realize", window_notitle_realize_cb, NULL);
214 /* set the initial position (must be done, before show is called!) */
215 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
221 /* Present the created window on the screen. */
223 window_present(GtkWidget *win)
225 window_geometry_t geom;
228 #if GTK_MAJOR_VERSION >= 2
229 /* present this window */
230 gtk_window_present(GTK_WINDOW(win));
233 /* do we have a previously saved size and position of this window? */
234 name = OBJECT_GET_DATA(win, WINDOW_GEOM_KEY);
236 if(window_geom_load(name, &geom)) {
237 /* XXX - use prefs to select which values to set? */
239 geom.set_size = TRUE;
240 geom.set_maximized = TRUE;
241 window_set_geometry(win, &geom);
248 window_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer cancel_button)
250 g_return_val_if_fail (widget != NULL, FALSE);
251 g_return_val_if_fail (event != NULL, FALSE);
253 if (event->keyval == GDK_Escape) {
254 gtk_widget_activate(GTK_WIDGET(cancel_button));
262 /* Set the "key_press_event" signal for a top-level dialog window to
263 call a routine to activate the "Cancel" button for a dialog box if
264 the key being pressed is the <Esc> key.
266 XXX - there should be a GTK+ widget that'll do that for you, and
267 let you specify a "Cancel" button. It should also not impose
268 a requirement that there be a separator in the dialog box, as
269 the GtkDialog widget does; the visual convention that there's
270 such a separator between the rest of the dialog boxes and buttons
271 such as "OK" and "Cancel" is, for better or worse, not universal
272 (not even in GTK+ - look at the GtkFileSelection dialog!). */
274 window_set_cancel(GtkWidget *widget, GtkWidget *cancel_button)
276 SIGNAL_CONNECT(widget, "key_press_event", window_key_press_cb, cancel_button);
280 /* set the actions needed for the cancel "Close"/"Ok"/"Cancel" button that closes the window */
281 void window_set_cancel_button(GtkWidget *win, GtkWidget *bt, window_cancel_button_fct cb)
284 SIGNAL_CONNECT(bt, "clicked", cb, win);
286 gtk_widget_grab_default(bt);
288 window_set_cancel(win, bt);
292 /* default callback handler for cancel button "clicked" signal */
293 void window_cancel_button_cb(GtkWidget *w _U_, gpointer data)
295 window_destroy(GTK_WIDGET(data));
299 /* default callback handler: the window managers X of the window was clicked (delete_event) */
301 window_delete_event_cb(GtkWidget *win, GdkEvent *event _U_, gpointer user_data _U_)
305 /* event handled, don't do anything else */
310 /* get the geometry of a window from window_new() */
312 window_get_geometry(GtkWidget *widget, window_geometry_t *geom)
315 #if GTK_MAJOR_VERSION >= 2
316 GdkWindowState state;
319 /* Try to grab our geometry.
321 GTK+ provides two routines to get a window's position relative
322 to the X root window. If I understand the documentation correctly,
323 gdk_window_get_deskrelative_origin applies mainly to Enlightenment
324 and gdk_window_get_root_origin applies for all other WMs.
326 The code below tries both routines, and picks the one that returns
327 the upper-left-most coordinates.
331 http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
332 http://www.gtk.org/faq/#AEN606
335 gdk_window_get_root_origin(widget->window,
338 if (gdk_window_get_deskrelative_origin(widget->window,
340 if (desk_x <= geom->x &&
348 /* XXX - Is this the "approved" method? */
349 gdk_window_get_size(widget->window,
353 #if GTK_MAJOR_VERSION >= 2
354 state = gdk_window_get_state(widget->window);
355 geom->maximized = (state == GDK_WINDOW_STATE_MAXIMIZED);
360 /* set the geometry of a window from window_new() */
362 window_set_geometry(GtkWidget *widget, window_geometry_t *geom)
364 /* as we now have the geometry from the recent file, set it */
365 /* if the window was minimized, x and y are -32000 (at least on Win32) */
366 if (geom->set_pos && geom->x != -32000 && geom->y != -32000) {
367 #if GTK_MAJOR_VERSION >= 2
368 gtk_window_move(GTK_WINDOW(widget),
372 gtk_widget_set_uposition(widget,
378 if (geom->set_size) {
379 #if GTK_MAJOR_VERSION >= 2
380 gtk_window_resize(GTK_WINDOW(widget),
382 gtk_window_set_default_size(GTK_WINDOW(widget),
385 gtk_widget_set_usize(widget,
387 /*WIDGET_SET_SIZE(widget,*/
392 #if GTK_MAJOR_VERSION >= 2
393 if(geom->set_maximized) {
394 if (geom->maximized) {
395 gdk_window_maximize(widget->window);
397 gdk_window_unmaximize(widget->window);
404 /* the geometry hashtable for all known window classes,
405 * the window name is the key, and the geometry struct is the value */
406 GHashTable *window_geom_hash = NULL;
409 /* save the window and it's current geometry into the geometry hashtable */
411 window_geom_save(const gchar *name, window_geometry_t *geom)
414 window_geometry_t *work;
416 /* init hashtable, if not already done */
417 if(!window_geom_hash) {
418 window_geom_hash = g_hash_table_new (g_str_hash, g_str_equal);
420 /* if we have an old one, remove and free it first */
421 work = g_hash_table_lookup(window_geom_hash, name);
423 g_hash_table_remove(window_geom_hash, name);
428 /* g_malloc and insert the new one */
429 work = g_malloc(sizeof(*geom));
431 key = g_strdup(name);
433 g_hash_table_insert(window_geom_hash, key, work);
437 /* load the desired geometry for this window from the geometry hashtable */
439 window_geom_load(const gchar *name, window_geometry_t *geom)
441 window_geometry_t *p;
443 /* init hashtable, if not already done */
444 if(!window_geom_hash) {
445 window_geom_hash = g_hash_table_new (g_str_hash, g_str_equal);
448 p = g_hash_table_lookup(window_geom_hash, name);
458 /* read in a single key value pair from the recent file into the geometry hashtable */
460 window_geom_recent_read_pair(const char *name, const char *key, const char *value)
462 window_geometry_t geom;
465 /* find window geometry maybe already in hashtable */
466 if(!window_geom_load(name, &geom)) {
467 /* not in table, init geom with "basic" values */
468 geom.key = g_strdup(name);
469 geom.set_pos = FALSE;
472 geom.set_size = FALSE;
476 geom.set_maximized = FALSE;/* this is valid in GTK2 only */
477 geom.maximized = FALSE; /* this is valid in GTK2 only */
480 if (strcmp(key, "x") == 0) {
481 geom.x = strtol(value, NULL, 10);
483 } else if (strcmp(key, "y") == 0) {
484 geom.y = strtol(value, NULL, 10);
486 } else if (strcmp(key, "width") == 0) {
487 geom.width = strtol(value, NULL, 10);
488 geom.set_size = TRUE;
489 } else if (strcmp(key, "height") == 0) {
490 geom.height = strtol(value, NULL, 10);
491 geom.set_size = TRUE;
492 } else if (strcmp(key, "maximized") == 0) {
493 if (strcasecmp(value, "true") == 0) {
494 geom.maximized = TRUE;
497 geom.maximized = FALSE;
499 geom.set_maximized = TRUE;
501 g_assert_not_reached();
504 /* save / replace geometry in hashtable */
505 window_geom_save(name, &geom);
509 /* write all geometry values of all windows from the hashtable to the recent file */
511 window_geom_recent_write_all(gpointer rf)
513 /* init hashtable, if not already done */
514 if(!window_geom_hash) {
515 window_geom_hash = g_hash_table_new (g_str_hash, g_str_equal);
518 g_hash_table_foreach(window_geom_hash, write_recent_geom, rf);
523 window_destroy(GtkWidget *win)
525 window_geometry_t geom;
528 /* get_geometry must be done *before* destroy is running, as the window geometry
529 * cannot be retrieved at destroy time (so don't use event "destroy" for this) */
530 /* ...and don't do this at all, if we currently have no GdkWindow (e.g. if the
531 * GtkWidget is hidden) */
532 if(!GTK_WIDGET_NO_WINDOW(win) && GTK_WIDGET_VISIBLE(win)) {
533 window_get_geometry(win, &geom);
535 name = OBJECT_GET_DATA(win, WINDOW_GEOM_KEY);
537 window_geom_save(name, &geom);
538 g_free((gpointer)name);
542 gtk_widget_destroy(win);
546 /* convert an xpm to a GtkWidget, using the window settings from it's parent */
547 /* (be sure that the parent window is already being displayed) */
548 GtkWidget *xpm_to_widget_from_parent(GtkWidget *parent, const char ** xpm) {
549 #if GTK_MAJOR_VERSION < 2
554 icon = gdk_pixmap_create_from_xpm_d(parent->window, &mask, &parent->style->white, (char **) xpm);
555 return gtk_pixmap_new(icon, mask);
562 pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
563 gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf, gtk_widget_get_colormap(parent), &pixmap, &bitmap, 128);
565 return gtk_image_new_from_pixmap (pixmap, bitmap);
570 /* convert an xpm to a GtkWidget, using the top_level window settings */
571 /* (be sure that the top_level window is already being displayed) */
572 GtkWidget *xpm_to_widget(const char ** xpm) {
573 return xpm_to_widget_from_parent(top_level, xpm);
576 /* Create a new hbox with an image packed into it
577 * and return the box. */
578 GtkWidget *xpm_box( gchar **xpm )
583 /* Create box for image */
584 box = gtk_hbox_new (FALSE, 0);
585 gtk_container_set_border_width (GTK_CONTAINER (box), 3);
587 /* Now on to the image stuff */
588 image = xpm_to_widget (xpm);
590 /* Pack the image into the box */
591 gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 3);
597 /* Set the name of the top-level window and its icon to the specified
600 set_main_window_name(gchar *window_name)
604 /* use user-defined window title if preference is set */
605 title = create_user_window_title(window_name);
606 gtk_window_set_title(GTK_WINDOW(top_level), title);
607 gdk_window_set_icon_name(top_level->window, title);
612 /* update the main window */
613 void main_window_update(void)
615 while (gtk_events_pending()) gtk_main_iteration();
620 /* exit the main window */
621 void main_window_exit(void)
626 /* quit a nested main window */
627 void main_window_nested_quit(void)
629 if (gtk_main_level() > 0)
633 /* quit the main window */
634 void main_window_quit(void)
641 typedef struct pipe_input_tag {
645 pipe_input_cb_t input_cb;
651 /* The timer has expired, see if there's stuff to read from the pipe,
652 if so, do the callback */
654 pipe_timer_cb(gpointer data)
658 gboolean result, result1;
660 pipe_input_t *pipe_input = data;
664 /* try to read data from the pipe only 5 times, to avoid blocking */
665 while(iterations < 5) {
666 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/
668 /* Oddly enough although Named pipes don't work on win9x,
669 PeekNamedPipe does !!! */
670 handle = (HANDLE) _get_osfhandle (pipe_input->source);
671 result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
673 /* Get the child process exit status */
674 result1 = GetExitCodeProcess((HANDLE)*(pipe_input->child_process),
677 /* If the Peek returned an error, or there are bytes to be read
678 or the childwatcher thread has terminated then call the normal
680 if (!result || avail > 0 || childstatus != STILL_ACTIVE) {
682 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/
684 if(pipe_input->pipe_input_id != 0) {
685 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: stop timer");*/
686 /* avoid reentrancy problems and stack overflow */
687 gtk_timeout_remove(pipe_input->pipe_input_id);
688 pipe_input->pipe_input_id = 0;
691 /* And call the real handler */
692 if (!pipe_input->input_cb(pipe_input->source, pipe_input->user_data)) {
693 g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations);
694 /* pipe closed, return false so that the old timer is not run again */
699 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/
700 /* No data, stop now */
707 if(pipe_input->pipe_input_id == 0) {
708 /* restore pipe handler */
709 pipe_input->pipe_input_id = gtk_timeout_add(200, pipe_timer_cb, data);
710 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, new timer", iterations);*/
712 /* Return false so that the old timer is not run again */
715 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, old timer", iterations);*/
717 /* we didn't stopped the old timer, so let it run */
724 /* There's stuff to read from the sync pipe, meaning the child has sent
725 us a message, or the sync pipe has closed, meaning the child has
726 closed it (perhaps because it exited). */
728 pipe_input_cb(gpointer data, gint source _U_,
729 GdkInputCondition condition _U_)
731 pipe_input_t *pipe_input = data;
734 /* avoid reentrancy problems and stack overflow */
735 gtk_input_remove(pipe_input->pipe_input_id);
737 if (pipe_input->input_cb(source, pipe_input->user_data)) {
738 /* restore pipe handler */
739 pipe_input->pipe_input_id = gtk_input_add_full (source,
740 GDK_INPUT_READ|GDK_INPUT_EXCEPTION,
749 void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb)
751 static pipe_input_t pipe_input;
753 pipe_input.source = source;
754 pipe_input.child_process = child_process;
755 pipe_input.user_data = user_data;
756 pipe_input.input_cb = input_cb;
759 /* Tricky to use pipes in win9x, as no concept of wait. NT can
760 do this but that doesn't cover all win32 platforms. GTK can do
761 this but doesn't seem to work over processes. Attempt to do
762 something similar here, start a timer and check for data on every
764 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/
765 pipe_input.pipe_input_id = gtk_timeout_add(200, pipe_timer_cb, &pipe_input);
767 pipe_input.pipe_input_id = gtk_input_add_full(source,
768 GDK_INPUT_READ|GDK_INPUT_EXCEPTION,
777 #endif /* HAVE_LIBPCAP */
779 /* Given a pointer to a GtkWidget for a top-level window, raise it and
780 de-iconify it. This routine is used if the user has done something to
781 ask that a window of a certain type be popped up when there can be only
782 one such window and such a window has already been popped up - we
783 pop up the existing one rather than creating a new one.
785 XXX - we should request that it be given the input focus, too. Alas,
786 GDK has nothing to do that, e.g. by calling "XSetInputFocus()" in a
787 window in X. Besides, using "XSetInputFocus()" doesn't work anyway,
788 apparently due to the way GTK+/GDK manages the input focus.
790 The X Desktop Group's Window Manager Standard specifies, in the section
791 on Root Window Properties, an _NET_ACTIVE_WINDOW client message that
792 can be sent to the root window, containing the window ID of the
793 window to activate; I infer that this might be the way to give the
794 window the input focus - I assume that means it's also de-iconified,
795 but I wouldn't assume it'd raise it.
797 XXX - will this do the right thing on window systems other than X? */
799 reactivate_window(GtkWidget *win)
801 gdk_window_show(win->window);
802 gdk_window_raise(win->window);
805 /* List of all GtkScrolledWindows, so we can globally set the scrollbar
806 placement of all of them. */
807 static GList *scrolled_windows;
809 static void setup_scrolled_window(GtkWidget *scrollw);
810 static void forget_scrolled_window(GtkWidget *scrollw, gpointer data);
811 static void set_scrollbar_placement_scrollw(GtkWidget *scrollw);
813 /* Create a GtkScrolledWindow, set its scrollbar placement appropriately,
816 scrolled_window_new(GtkAdjustment *hadjustment, GtkAdjustment *vadjustment)
820 scrollw = gtk_scrolled_window_new(hadjustment, vadjustment);
821 setup_scrolled_window(scrollw);
825 /* Set a GtkScrolledWindow's scrollbar placement and add it to the list
826 of GtkScrolledWindows. */
828 setup_scrolled_window(GtkWidget *scrollw)
830 set_scrollbar_placement_scrollw(scrollw);
832 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw),
833 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
835 scrolled_windows = g_list_append(scrolled_windows, scrollw);
837 /* Catch the "destroy" event on the widget, so that we remove it from
838 the list when it's destroyed. */
839 SIGNAL_CONNECT(scrollw, "destroy", forget_scrolled_window, NULL);
842 /* Remove a GtkScrolledWindow from the list of GtkScrolledWindows. */
844 forget_scrolled_window(GtkWidget *scrollw, gpointer data _U_)
846 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
849 /* Set the scrollbar placement of a GtkScrolledWindow based upon user
852 set_scrollbar_placement_scrollw(GtkWidget *scrollw)
854 if (prefs.gui_scrollbar_on_right) {
855 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
856 GTK_CORNER_TOP_LEFT);
858 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
859 GTK_CORNER_TOP_RIGHT);
864 set_scrollbar_placement_cb(gpointer data, gpointer user_data _U_)
866 set_scrollbar_placement_scrollw((GtkWidget *)data);
869 /* Set the scrollbar placement of all GtkScrolledWindows based on
872 set_scrollbar_placement_all(void)
874 g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, NULL);
877 /* List of all CTrees/TreeViews, so we can globally set the line and
878 * expander style of all of them. */
881 static void setup_tree(GtkWidget *tree);
882 static void forget_tree(GtkWidget *tree, gpointer data);
883 static void set_tree_styles(GtkWidget *tree);
885 /* Create a Tree, give it the right styles, and remember it. */
886 #if GTK_MAJOR_VERSION < 2
888 ctree_new(gint columns, gint tree_column)
891 tree_view_new(GtkTreeModel *model)
896 #if GTK_MAJOR_VERSION < 2
897 tree = gtk_ctree_new(columns, tree_column);
899 tree = gtk_tree_view_new_with_model(model);
905 #if GTK_MAJOR_VERSION < 2
907 ctree_new_with_titles(gint columns, gint tree_column, const gchar *titles[])
911 tree = gtk_ctree_new_with_titles(columns, tree_column, (gchar **) titles);
917 /* Set a Tree's styles and add it to the list of Trees. */
919 setup_tree(GtkWidget *tree)
921 set_tree_styles(tree);
923 trees = g_list_append(trees, tree);
925 /* Catch the "destroy" event on the widget, so that we remove it from
926 the list when it's destroyed. */
927 SIGNAL_CONNECT(tree, "destroy", forget_tree, NULL);
930 /* Remove a Tree from the list of Trees. */
932 forget_tree(GtkWidget *tree, gpointer data _U_)
934 trees = g_list_remove(trees, tree);
937 /* Set the styles of a Tree based upon user preferences. */
939 set_tree_styles(GtkWidget *tree)
941 #if GTK_MAJOR_VERSION < 2
942 g_assert(prefs.gui_ptree_line_style >= GTK_CTREE_LINES_NONE &&
943 prefs.gui_ptree_line_style <= GTK_CTREE_LINES_TABBED);
944 gtk_ctree_set_line_style(GTK_CTREE(tree), prefs.gui_ptree_line_style);
945 g_assert(prefs.gui_ptree_expander_style >= GTK_CTREE_EXPANDER_NONE &&
946 prefs.gui_ptree_expander_style <= GTK_CTREE_EXPANDER_CIRCULAR);
947 gtk_ctree_set_expander_style(GTK_CTREE(tree),
948 prefs.gui_ptree_expander_style);
950 g_assert(prefs.gui_altern_colors >= 0 && prefs.gui_altern_colors <= 1);
951 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree),
952 prefs.gui_altern_colors);
957 set_tree_styles_cb(gpointer data, gpointer user_data _U_)
959 set_tree_styles((GtkWidget *)data);
962 /* Set the styles of all Trees based upon style values. */
964 set_tree_styles_all(void)
966 g_list_foreach(trees, set_tree_styles_cb, NULL);
972 #if GTK_MAJOR_VERSION < 2
973 /* convert variable argument list of values to array of strings (GTK2 -> GTK1) */
975 simple_list_convert(gchar **ent, va_list ap)
980 while( (i = va_arg(ap, int)) != -1 ) {
981 s = va_arg(ap, char *);
988 /* append a row to the simple list */
989 /* use it like: simple_list_append(list, 0, "first", 1, "second", -1) */
991 simple_list_append(GtkWidget *list, ...)
995 #if GTK_MAJOR_VERSION < 2
996 gchar *ent[10]; /* new entry added in clist */
1003 #if GTK_MAJOR_VERSION < 2
1004 simple_list_convert(ent, ap);
1005 gtk_clist_append(GTK_CLIST(list), ent);
1007 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
1008 gtk_list_store_append(store, &iter);
1009 gtk_list_store_set_valist(store, &iter, ap);
1014 /* create a simple list widget */
1016 simple_list_new(gint cols, const gchar **titles) {
1017 GtkWidget *plugins_list;
1018 #if GTK_MAJOR_VERSION >= 2
1020 GtkListStore *store;
1021 GtkCellRenderer *renderer;
1022 GtkTreeViewColumn *column;
1026 #if GTK_MAJOR_VERSION < 2
1027 plugins_list = gtk_clist_new_with_titles(cols, (gchar **) titles);
1028 gtk_clist_set_selection_mode(GTK_CLIST(plugins_list), GTK_SELECTION_SINGLE);
1029 gtk_clist_column_titles_passive(GTK_CLIST(plugins_list));
1031 gtk_clist_column_titles_show(GTK_CLIST(plugins_list));
1033 gtk_clist_column_titles_hide(GTK_CLIST(plugins_list));
1035 gtk_clist_set_column_auto_resize(GTK_CLIST(plugins_list), 0, TRUE);
1036 gtk_clist_set_column_auto_resize(GTK_CLIST(plugins_list), 1, TRUE);
1038 g_assert(cols <= 10);
1039 store = gtk_list_store_new(cols,
1040 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
1041 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
1042 plugins_list = tree_view_new(GTK_TREE_MODEL(store));
1043 g_object_unref(G_OBJECT(store));
1044 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(plugins_list), (titles != NULL));
1045 for(i=0; i<cols; i++) {
1046 renderer = gtk_cell_renderer_text_new();
1047 column = gtk_tree_view_column_new_with_attributes(titles ? titles[i] : "", renderer,
1049 gtk_tree_view_column_set_sort_column_id(column, i);
1050 gtk_tree_view_append_column(GTK_TREE_VIEW(plugins_list), column);
1054 return plugins_list;
1058 copy_to_clipboard(GString *str)
1060 #if (GTK_MAJOR_VERSION >= 2)
1063 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
1064 gtk_clipboard_set_text(cb, str->str, -1); /* Copy the byte data into the clipboard */
1069 window = window_new (GTK_WINDOW_TOPLEVEL,"");
1070 text = gtk_text_new (NULL, NULL); /* Create the GtkText widget */
1071 gtk_container_add (GTK_CONTAINER (window), text); /* Avoid a GTK assertion */
1072 gtk_widget_realize (text); /* Realizing a widget creates a window for it, ready for us to insert some text */
1073 gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str->str, -1);
1074 gtk_editable_select_region((GtkEditable *)text, 0, -1); /* Select ALL text */
1075 gtk_editable_copy_clipboard((GtkEditable *)text); /* Copy the byte data into the clipboard */
1080 * Create a new window title string with user-defined title preference.
1081 * (Or ignore it if unspecified).
1084 create_user_window_title(const gchar *caption)
1087 if (caption == NULL)
1088 return g_strdup("");
1090 /* no user-defined title specified */
1091 if ((prefs.gui_window_title == NULL) || (*prefs.gui_window_title == '\0'))
1092 return g_strdup(caption);
1094 return g_strdup_printf("%s %s", prefs.gui_window_title, caption);