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/eicon3d16.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 Ethereal's windows has a resource name of "ethereal" and a class
103 name of "Ethereal". 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 Ethereal.
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], eicon3d16_xpm);
123 gdk_window_set_icon (win->window, NULL, icon_pmap, icon_mask);
128 /* Create a new window, of the specified type, with the specified title
129 (if any) and the Ethereal icon. */
131 window_new(GtkWindowType type, const gchar *title)
135 win = gtk_window_new(type);
137 gtk_window_set_title(GTK_WINDOW(win), title);
138 SIGNAL_CONNECT(win, "realize", window_icon_realize_cb, NULL);
140 /* XXX - which one is the correct default policy? or use a preference for this? */
141 /* GTK_WIN_POS_NONE, GTK_WIN_POS_CENTER or GTK_WIN_POS_MOUSE */
142 /* a lot of people dislike GTK_WIN_POS_MOUSE */
144 /* set the initial position (must be done, before show is called!) */
145 #if GTK_MAJOR_VERSION >= 2
146 /* gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER_ON_PARENT);*/
148 /* gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);*/
150 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_NONE);
152 #if GTK_MAJOR_VERSION < 2
153 /* allow window to be shrinked by user, as gtk_widget_set_usize() will set minimum size and */
154 /* the user never could shrink the window again */
155 gtk_window_set_policy(GTK_WINDOW(win), TRUE, TRUE, FALSE);
162 /* Same as window_new(), but will keep it's geometry values (size, position, ...).
163 * Be sure to use window_present() and window_destroy() appropriately! */
165 window_new_with_geom(GtkWindowType type, const gchar *title, const gchar *geom_name)
167 window_geometry_t geom;
168 GtkWidget *win = window_new(type, title);
170 OBJECT_SET_DATA(win, WINDOW_GEOM_KEY, (gpointer)g_strdup(geom_name));
172 /* do we have a previously saved size and position of this window? */
174 /* It's a good idea to set the position and size of the window already here,
175 * as it's still invisible and won't "flicker the screen" while initially resizing. */
176 if(window_geom_load(geom_name, &geom)) {
177 /* XXX - use prefs to select which values to set? */
179 geom.set_size = TRUE;
180 geom.set_maximized = FALSE; /* don't maximize until window is shown */
181 window_set_geometry(win, &geom);
189 #if GTK_MAJOR_VERSION < 2
190 /* We can't set the decorations until the window is realized. */
192 window_notitle_realize_cb (GtkWidget *win, gpointer data _U_)
194 gdk_window_set_decorations(win->window, 0);
199 /* Create a new window for a splash screen; it's a main window, with no title,
200 positioned in the center of the screen. */
202 splash_window_new(void)
206 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
207 #if GTK_MAJOR_VERSION >= 2
208 gtk_window_set_decorated(GTK_WINDOW(win), FALSE);
210 SIGNAL_CONNECT(win, "realize", window_notitle_realize_cb, NULL);
213 /* set the initial position (must be done, before show is called!) */
214 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
220 /* Present the created window on the screen. */
222 window_present(GtkWidget *win)
224 window_geometry_t geom;
227 #if GTK_MAJOR_VERSION >= 2
228 /* present this window */
229 gtk_window_present(GTK_WINDOW(win));
232 /* do we have a previously saved size and position of this window? */
233 name = OBJECT_GET_DATA(win, WINDOW_GEOM_KEY);
235 if(window_geom_load(name, &geom)) {
236 /* XXX - use prefs to select which values to set? */
238 geom.set_size = TRUE;
239 geom.set_maximized = TRUE;
240 window_set_geometry(win, &geom);
247 window_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer cancel_button)
249 g_return_val_if_fail (widget != NULL, FALSE);
250 g_return_val_if_fail (event != NULL, FALSE);
252 if (event->keyval == GDK_Escape) {
253 gtk_widget_activate(GTK_WIDGET(cancel_button));
261 /* Set the "key_press_event" signal for a top-level dialog window to
262 call a routine to activate the "Cancel" button for a dialog box if
263 the key being pressed is the <Esc> key.
265 XXX - there should be a GTK+ widget that'll do that for you, and
266 let you specify a "Cancel" button. It should also not impose
267 a requirement that there be a separator in the dialog box, as
268 the GtkDialog widget does; the visual convention that there's
269 such a separator between the rest of the dialog boxes and buttons
270 such as "OK" and "Cancel" is, for better or worse, not universal
271 (not even in GTK+ - look at the GtkFileSelection dialog!). */
273 window_set_cancel(GtkWidget *widget, GtkWidget *cancel_button)
275 SIGNAL_CONNECT(widget, "key_press_event", window_key_press_cb, cancel_button);
279 /* set the actions needed for the cancel "Close"/"Ok"/"Cancel" button that closes the window */
280 void window_set_cancel_button(GtkWidget *win, GtkWidget *bt, window_cancel_button_fct cb)
283 SIGNAL_CONNECT(bt, "clicked", cb, win);
285 gtk_widget_grab_default(bt);
287 window_set_cancel(win, bt);
291 /* default callback handler for cancel button "clicked" signal */
292 void window_cancel_button_cb(GtkWidget *w _U_, gpointer data)
294 window_destroy(GTK_WIDGET(data));
298 /* default callback handler: the window managers X of the window was clicked (delete_event) */
300 window_delete_event_cb(GtkWidget *win, GdkEvent *event _U_, gpointer user_data _U_)
304 /* event handled, don't do anything else */
309 /* get the geometry of a window from window_new() */
311 window_get_geometry(GtkWidget *widget, window_geometry_t *geom)
314 #if GTK_MAJOR_VERSION >= 2
315 GdkWindowState state;
318 /* Try to grab our geometry.
320 GTK+ provides two routines to get a window's position relative
321 to the X root window. If I understand the documentation correctly,
322 gdk_window_get_deskrelative_origin applies mainly to Enlightenment
323 and gdk_window_get_root_origin applies for all other WMs.
325 The code below tries both routines, and picks the one that returns
326 the upper-left-most coordinates.
330 http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
331 http://www.gtk.org/faq/#AEN606
334 gdk_window_get_root_origin(widget->window,
337 if (gdk_window_get_deskrelative_origin(widget->window,
339 if (desk_x <= geom->x &&
347 /* XXX - Is this the "approved" method? */
348 gdk_window_get_size(widget->window,
352 #if GTK_MAJOR_VERSION >= 2
353 state = gdk_window_get_state(widget->window);
354 geom->maximized = (state == GDK_WINDOW_STATE_MAXIMIZED);
359 /* set the geometry of a window from window_new() */
361 window_set_geometry(GtkWidget *widget, window_geometry_t *geom)
363 /* as we now have the geometry from the recent file, set it */
365 #if GTK_MAJOR_VERSION >= 2
366 gtk_window_move(GTK_WINDOW(widget),
370 gtk_widget_set_uposition(widget,
376 if (geom->set_size) {
377 #if GTK_MAJOR_VERSION >= 2
378 gtk_window_resize(GTK_WINDOW(widget),
380 gtk_window_set_default_size(GTK_WINDOW(widget),
383 gtk_widget_set_usize(widget,
385 /*WIDGET_SET_SIZE(widget,*/
390 #if GTK_MAJOR_VERSION >= 2
391 if(geom->set_maximized) {
392 if (geom->maximized) {
393 gdk_window_maximize(widget->window);
395 gdk_window_unmaximize(widget->window);
402 /* the geometry hashtable for all known window classes,
403 * the window name is the key, and the geometry struct is the value */
404 GHashTable *window_geom_hash = NULL;
407 /* save the window and it's current geometry into the geometry hashtable */
409 window_geom_save(const gchar *name, window_geometry_t *geom)
412 window_geometry_t *work;
414 /* init hashtable, if not already done */
415 if(!window_geom_hash) {
416 window_geom_hash = g_hash_table_new (g_str_hash, g_str_equal);
418 /* if we have an old one, remove and free it first */
419 work = g_hash_table_lookup(window_geom_hash, name);
421 g_hash_table_remove(window_geom_hash, name);
426 /* g_malloc and insert the new one */
427 work = g_malloc(sizeof(*geom));
429 key = g_strdup(name);
431 g_hash_table_insert(window_geom_hash, key, work);
435 /* load the desired geometry for this window from the geometry hashtable */
437 window_geom_load(const gchar *name, window_geometry_t *geom)
439 window_geometry_t *p;
441 /* init hashtable, if not already done */
442 if(!window_geom_hash) {
443 window_geom_hash = g_hash_table_new (g_str_hash, g_str_equal);
446 p = g_hash_table_lookup(window_geom_hash, name);
456 /* read in a single key value pair from the recent file into the geometry hashtable */
458 window_geom_recent_read_pair(const char *name, const char *key, const char *value)
460 window_geometry_t geom;
463 /* find window geometry maybe already in hashtable */
464 if(!window_geom_load(name, &geom)) {
465 /* not in table, init geom with "basic" values */
466 geom.key = g_strdup(name);
467 geom.set_pos = FALSE;
470 geom.set_size = FALSE;
474 geom.set_maximized = FALSE;/* this is valid in GTK2 only */
475 geom.maximized = FALSE; /* this is valid in GTK2 only */
478 if (strcmp(key, "x") == 0) {
479 geom.x = strtol(value, NULL, 10);
481 } else if (strcmp(key, "y") == 0) {
482 geom.y = strtol(value, NULL, 10);
484 } else if (strcmp(key, "width") == 0) {
485 geom.width = strtol(value, NULL, 10);
486 geom.set_size = TRUE;
487 } else if (strcmp(key, "height") == 0) {
488 geom.height = strtol(value, NULL, 10);
489 geom.set_size = TRUE;
490 } else if (strcmp(key, "maximized") == 0) {
491 if (strcasecmp(value, "true") == 0) {
492 geom.maximized = TRUE;
495 geom.maximized = FALSE;
497 geom.set_maximized = TRUE;
499 g_assert_not_reached();
502 /* save / replace geometry in hashtable */
503 window_geom_save(name, &geom);
507 /* write all geometry values of all windows from the hashtable to the recent file */
509 window_geom_recent_write_all(gpointer rf)
511 /* init hashtable, if not already done */
512 if(!window_geom_hash) {
513 window_geom_hash = g_hash_table_new (g_str_hash, g_str_equal);
516 g_hash_table_foreach(window_geom_hash, write_recent_geom, rf);
521 window_destroy(GtkWidget *win)
523 window_geometry_t geom;
526 /* get_geometry must be done *before* destroy is running, as the window geometry
527 * cannot be retrieved at destroy time (so don't use event "destroy" for this) */
528 /* ...and don't do this at all, if we currently have no GdkWindow (e.g. if the
529 * GtkWidget is hidden) */
530 if(!GTK_WIDGET_NO_WINDOW(win) && GTK_WIDGET_VISIBLE(win)) {
531 window_get_geometry(win, &geom);
533 name = OBJECT_GET_DATA(win, WINDOW_GEOM_KEY);
535 window_geom_save(name, &geom);
536 g_free((gpointer)name);
540 gtk_widget_destroy(win);
544 /* convert an xpm to a GtkWidget, using the window settings from it's parent */
545 /* (be sure that the parent window is already being displayed) */
546 GtkWidget *xpm_to_widget_from_parent(GtkWidget *parent, const char ** xpm) {
547 #if GTK_MAJOR_VERSION < 2
552 icon = gdk_pixmap_create_from_xpm_d(parent->window, &mask, &parent->style->white, (char **) xpm);
553 return gtk_pixmap_new(icon, mask);
560 pixbuf = gdk_pixbuf_new_from_xpm_data(xpm);
561 gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf, gtk_widget_get_colormap(parent), &pixmap, &bitmap, 128);
563 return gtk_image_new_from_pixmap (pixmap, bitmap);
568 /* convert an xpm to a GtkWidget, using the top_level window settings */
569 /* (be sure that the top_level window is already being displayed) */
570 GtkWidget *xpm_to_widget(const char ** xpm) {
571 return xpm_to_widget_from_parent(top_level, xpm);
575 /* Set the name of the top-level window and its icon to the specified
578 set_main_window_name(gchar *window_name)
582 /* use user-defined window title if preference is set */
583 title = create_user_window_title(window_name);
584 gtk_window_set_title(GTK_WINDOW(top_level), title);
585 gdk_window_set_icon_name(top_level->window, title);
590 /* update the main window */
591 void main_window_update(void)
593 while (gtk_events_pending()) gtk_main_iteration();
598 /* exit the main window */
599 void main_window_exit(void)
604 /* quit a nested main window */
605 void main_window_nested_quit(void)
607 if (gtk_main_level() > 0)
611 /* quit the main window */
612 void main_window_quit(void)
619 typedef struct pipe_input_tag {
623 pipe_input_cb_t input_cb;
629 /* The timer has expired, see if there's stuff to read from the pipe,
630 if so, do the callback */
632 pipe_timer_cb(gpointer data)
636 gboolean result, result1;
638 pipe_input_t *pipe_input = data;
642 /* try to read data from the pipe only 5 times, to avoid blocking */
643 while(iterations < 5) {
644 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/
646 /* Oddly enough although Named pipes don't work on win9x,
647 PeekNamedPipe does !!! */
648 handle = (HANDLE) _get_osfhandle (pipe_input->source);
649 result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
651 /* Get the child process exit status */
652 result1 = GetExitCodeProcess((HANDLE)*(pipe_input->child_process),
655 /* If the Peek returned an error, or there are bytes to be read
656 or the childwatcher thread has terminated then call the normal
658 if (!result || avail > 0 || childstatus != STILL_ACTIVE) {
660 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/
662 if(pipe_input->pipe_input_id != 0) {
663 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: stop timer");*/
664 /* avoid reentrancy problems and stack overflow */
665 gtk_timeout_remove(pipe_input->pipe_input_id);
666 pipe_input->pipe_input_id = 0;
669 /* And call the real handler */
670 if (!pipe_input->input_cb(pipe_input->source, pipe_input->user_data)) {
671 g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations);
672 /* pipe closed, return false so that the old timer is not run again */
677 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/
678 /* No data, stop now */
685 if(pipe_input->pipe_input_id == 0) {
686 /* restore pipe handler */
687 pipe_input->pipe_input_id = gtk_timeout_add(200, pipe_timer_cb, data);
688 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, new timer", iterations);*/
690 /* Return false so that the old timer is not run again */
693 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, old timer", iterations);*/
695 /* we didn't stopped the old timer, so let it run */
702 /* There's stuff to read from the sync pipe, meaning the child has sent
703 us a message, or the sync pipe has closed, meaning the child has
704 closed it (perhaps because it exited). */
706 pipe_input_cb(gpointer data, gint source _U_,
707 GdkInputCondition condition _U_)
709 pipe_input_t *pipe_input = data;
712 /* avoid reentrancy problems and stack overflow */
713 gtk_input_remove(pipe_input->pipe_input_id);
715 if (pipe_input->input_cb(source, pipe_input->user_data)) {
716 /* restore pipe handler */
717 pipe_input->pipe_input_id = gtk_input_add_full (source,
718 GDK_INPUT_READ|GDK_INPUT_EXCEPTION,
727 void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb)
729 static pipe_input_t pipe_input;
731 pipe_input.source = source;
732 pipe_input.child_process = child_process;
733 pipe_input.user_data = user_data;
734 pipe_input.input_cb = input_cb;
737 /* Tricky to use pipes in win9x, as no concept of wait. NT can
738 do this but that doesn't cover all win32 platforms. GTK can do
739 this but doesn't seem to work over processes. Attempt to do
740 something similar here, start a timer and check for data on every
742 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/
743 pipe_input.pipe_input_id = gtk_timeout_add(200, pipe_timer_cb, &pipe_input);
745 pipe_input.pipe_input_id = gtk_input_add_full(source,
746 GDK_INPUT_READ|GDK_INPUT_EXCEPTION,
755 #endif /* HAVE_LIBPCAP */
757 /* Given a pointer to a GtkWidget for a top-level window, raise it and
758 de-iconify it. This routine is used if the user has done something to
759 ask that a window of a certain type be popped up when there can be only
760 one such window and such a window has already been popped up - we
761 pop up the existing one rather than creating a new one.
763 XXX - we should request that it be given the input focus, too. Alas,
764 GDK has nothing to do that, e.g. by calling "XSetInputFocus()" in a
765 window in X. Besides, using "XSetInputFocus()" doesn't work anyway,
766 apparently due to the way GTK+/GDK manages the input focus.
768 The X Desktop Group's Window Manager Standard specifies, in the section
769 on Root Window Properties, an _NET_ACTIVE_WINDOW client message that
770 can be sent to the root window, containing the window ID of the
771 window to activate; I infer that this might be the way to give the
772 window the input focus - I assume that means it's also de-iconified,
773 but I wouldn't assume it'd raise it.
775 XXX - will this do the right thing on window systems other than X? */
777 reactivate_window(GtkWidget *win)
779 gdk_window_show(win->window);
780 gdk_window_raise(win->window);
783 /* List of all GtkScrolledWindows, so we can globally set the scrollbar
784 placement of all of them. */
785 static GList *scrolled_windows;
787 static void setup_scrolled_window(GtkWidget *scrollw);
788 static void forget_scrolled_window(GtkWidget *scrollw, gpointer data);
789 static void set_scrollbar_placement_scrollw(GtkWidget *scrollw);
791 /* Create a GtkScrolledWindow, set its scrollbar placement appropriately,
794 scrolled_window_new(GtkAdjustment *hadjustment, GtkAdjustment *vadjustment)
798 scrollw = gtk_scrolled_window_new(hadjustment, vadjustment);
799 setup_scrolled_window(scrollw);
803 /* Set a GtkScrolledWindow's scrollbar placement and add it to the list
804 of GtkScrolledWindows. */
806 setup_scrolled_window(GtkWidget *scrollw)
808 set_scrollbar_placement_scrollw(scrollw);
810 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw),
811 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
813 scrolled_windows = g_list_append(scrolled_windows, scrollw);
815 /* Catch the "destroy" event on the widget, so that we remove it from
816 the list when it's destroyed. */
817 SIGNAL_CONNECT(scrollw, "destroy", forget_scrolled_window, NULL);
820 /* Remove a GtkScrolledWindow from the list of GtkScrolledWindows. */
822 forget_scrolled_window(GtkWidget *scrollw, gpointer data _U_)
824 scrolled_windows = g_list_remove(scrolled_windows, scrollw);
827 /* Set the scrollbar placement of a GtkScrolledWindow based upon user
830 set_scrollbar_placement_scrollw(GtkWidget *scrollw)
832 if (prefs.gui_scrollbar_on_right) {
833 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
834 GTK_CORNER_TOP_LEFT);
836 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
837 GTK_CORNER_TOP_RIGHT);
842 set_scrollbar_placement_cb(gpointer data, gpointer user_data _U_)
844 set_scrollbar_placement_scrollw((GtkWidget *)data);
847 /* Set the scrollbar placement of all GtkScrolledWindows based on
850 set_scrollbar_placement_all(void)
852 g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, NULL);
855 /* List of all CTrees/TreeViews, so we can globally set the line and
856 * expander style of all of them. */
859 static void setup_tree(GtkWidget *tree);
860 static void forget_tree(GtkWidget *tree, gpointer data);
861 static void set_tree_styles(GtkWidget *tree);
863 /* Create a Tree, give it the right styles, and remember it. */
864 #if GTK_MAJOR_VERSION < 2
866 ctree_new(gint columns, gint tree_column)
869 tree_view_new(GtkTreeModel *model)
874 #if GTK_MAJOR_VERSION < 2
875 tree = gtk_ctree_new(columns, tree_column);
877 tree = gtk_tree_view_new_with_model(model);
883 #if GTK_MAJOR_VERSION < 2
885 ctree_new_with_titles(gint columns, gint tree_column, const gchar *titles[])
889 tree = gtk_ctree_new_with_titles(columns, tree_column, (gchar **) titles);
895 /* Set a Tree's styles and add it to the list of Trees. */
897 setup_tree(GtkWidget *tree)
899 set_tree_styles(tree);
901 trees = g_list_append(trees, tree);
903 /* Catch the "destroy" event on the widget, so that we remove it from
904 the list when it's destroyed. */
905 SIGNAL_CONNECT(tree, "destroy", forget_tree, NULL);
908 /* Remove a Tree from the list of Trees. */
910 forget_tree(GtkWidget *tree, gpointer data _U_)
912 trees = g_list_remove(trees, tree);
915 /* Set the styles of a Tree based upon user preferences. */
917 set_tree_styles(GtkWidget *tree)
919 #if GTK_MAJOR_VERSION < 2
920 g_assert(prefs.gui_ptree_line_style >= GTK_CTREE_LINES_NONE &&
921 prefs.gui_ptree_line_style <= GTK_CTREE_LINES_TABBED);
922 gtk_ctree_set_line_style(GTK_CTREE(tree), prefs.gui_ptree_line_style);
923 g_assert(prefs.gui_ptree_expander_style >= GTK_CTREE_EXPANDER_NONE &&
924 prefs.gui_ptree_expander_style <= GTK_CTREE_EXPANDER_CIRCULAR);
925 gtk_ctree_set_expander_style(GTK_CTREE(tree),
926 prefs.gui_ptree_expander_style);
928 g_assert(prefs.gui_altern_colors >= 0 && prefs.gui_altern_colors <= 1);
929 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree),
930 prefs.gui_altern_colors);
935 set_tree_styles_cb(gpointer data, gpointer user_data _U_)
937 set_tree_styles((GtkWidget *)data);
940 /* Set the styles of all Trees based upon style values. */
942 set_tree_styles_all(void)
944 g_list_foreach(trees, set_tree_styles_cb, NULL);
950 #if GTK_MAJOR_VERSION < 2
951 /* convert variable argument list of values to array of strings (GTK2 -> GTK1) */
953 simple_list_convert(gchar **ent, va_list ap)
958 while( (i = va_arg(ap, int)) != -1 ) {
959 s = va_arg(ap, char *);
966 /* append a row to the simple list */
967 /* use it like: simple_list_append(list, 0, "first", 1, "second", -1) */
969 simple_list_append(GtkWidget *list, ...)
973 #if GTK_MAJOR_VERSION < 2
974 gchar *ent[10]; /* new entry added in clist */
981 #if GTK_MAJOR_VERSION < 2
982 simple_list_convert(ent, ap);
983 gtk_clist_append(GTK_CLIST(list), ent);
985 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
986 gtk_list_store_append(store, &iter);
987 gtk_list_store_set_valist(store, &iter, ap);
992 /* create a simple list widget */
994 simple_list_new(gint cols, const gchar **titles) {
995 GtkWidget *plugins_list;
996 #if GTK_MAJOR_VERSION >= 2
999 GtkCellRenderer *renderer;
1000 GtkTreeViewColumn *column;
1004 #if GTK_MAJOR_VERSION < 2
1005 plugins_list = gtk_clist_new_with_titles(cols, (gchar **) titles);
1006 gtk_clist_set_selection_mode(GTK_CLIST(plugins_list), GTK_SELECTION_SINGLE);
1007 gtk_clist_column_titles_passive(GTK_CLIST(plugins_list));
1009 gtk_clist_column_titles_show(GTK_CLIST(plugins_list));
1011 gtk_clist_column_titles_hide(GTK_CLIST(plugins_list));
1013 gtk_clist_set_column_auto_resize(GTK_CLIST(plugins_list), 0, TRUE);
1014 gtk_clist_set_column_auto_resize(GTK_CLIST(plugins_list), 1, TRUE);
1016 g_assert(cols <= 10);
1017 store = gtk_list_store_new(cols,
1018 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
1019 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
1020 plugins_list = tree_view_new(GTK_TREE_MODEL(store));
1021 g_object_unref(G_OBJECT(store));
1022 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(plugins_list), (titles != NULL));
1023 for(i=0; i<cols; i++) {
1024 renderer = gtk_cell_renderer_text_new();
1025 column = gtk_tree_view_column_new_with_attributes(titles ? titles[i] : "", renderer,
1027 gtk_tree_view_column_set_sort_column_id(column, i);
1028 gtk_tree_view_append_column(GTK_TREE_VIEW(plugins_list), column);
1032 return plugins_list;
1036 copy_to_clipboard(GString *str)
1038 #if (GTK_MAJOR_VERSION >= 2)
1041 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
1042 gtk_clipboard_set_text(cb, str->str, -1); /* Copy the byte data into the clipboard */
1047 window = window_new (GTK_WINDOW_TOPLEVEL,"");
1048 text = gtk_text_new (NULL, NULL); /* Create the GtkText widget */
1049 gtk_container_add (GTK_CONTAINER (window), text); /* Avoid a GTK assertion */
1050 gtk_widget_realize (text); /* Realizing a widget creates a window for it, ready for us to insert some text */
1051 gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str->str, -1);
1052 gtk_editable_select_region((GtkEditable *)text, 0, -1); /* Select ALL text */
1053 gtk_editable_copy_clipboard((GtkEditable *)text); /* Copy the byte data into the clipboard */
1058 * Create a new window title string with user-defined title preference.
1059 * (Or ignore it if unspecified).
1062 create_user_window_title(const gchar *caption)
1065 if (caption == NULL)
1066 return g_strdup("");
1068 /* no user-defined title specified */
1069 if ((prefs.gui_window_title == NULL) || (*prefs.gui_window_title == '\0'))
1070 return g_strdup(caption);
1072 return g_strdup_printf("%s %s", prefs.gui_window_title, caption);