aboutsummaryrefslogtreecommitdiff
path: root/src/gtkutils.c
diff options
context:
space:
mode:
authorhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2005-01-12 11:22:08 +0000
committerhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2005-01-12 11:22:08 +0000
commitb9ca7b1ef5cd1f96ae6e28ae78d12c1e3258c23f (patch)
tree1203adec5f70af1ddd49868528d8d3a5b9004329 /src/gtkutils.c
Initial import of Sylpheed (GTK2 version).
git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@1 ee746299-78ed-0310-b773-934348b2243d
Diffstat (limited to 'src/gtkutils.c')
-rw-r--r--src/gtkutils.c686
1 files changed, 686 insertions, 0 deletions
diff --git a/src/gtkutils.c b/src/gtkutils.c
new file mode 100644
index 00000000..196b46ee
--- /dev/null
+++ b/src/gtkutils.c
@@ -0,0 +1,686 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2004 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdk.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkhbbox.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkctree.h>
+#include <gtk/gtkcombo.h>
+#include <gtk/gtkbindings.h>
+#include <gtk/gtkitemfactory.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
+# include <wchar.h>
+# include <wctype.h>
+#endif
+
+#include "intl.h"
+#include "gtkutils.h"
+#include "utils.h"
+#include "gtksctree.h"
+#include "codeconv.h"
+#include "menu.h"
+
+#warning FIXME_GTK2
+gboolean gtkut_get_font_size(GtkWidget *widget, gint *width, gint *height)
+{
+ PangoLayout *layout;
+ const gchar *str = "Abcdef";
+
+ g_return_val_if_fail(GTK_IS_WIDGET(widget), FALSE);
+
+ layout = gtk_widget_create_pango_layout(widget, str);
+ g_return_val_if_fail(layout, FALSE);
+ pango_layout_get_pixel_size(layout, width, height);
+ if (width)
+ *width = *width / g_utf8_strlen(str, -1);
+ g_object_unref(layout);
+
+ return TRUE;
+}
+
+void gtkut_convert_int_to_gdk_color(gint rgbvalue, GdkColor *color)
+{
+ g_return_if_fail(color != NULL);
+
+ color->pixel = 0L;
+ color->red = (int) (((gdouble)((rgbvalue & 0xff0000) >> 16) / 255.0) * 65535.0);
+ color->green = (int) (((gdouble)((rgbvalue & 0x00ff00) >> 8) / 255.0) * 65535.0);
+ color->blue = (int) (((gdouble) (rgbvalue & 0x0000ff) / 255.0) * 65535.0);
+}
+
+void gtkut_button_set_create(GtkWidget **bbox,
+ GtkWidget **button1, const gchar *label1,
+ GtkWidget **button2, const gchar *label2,
+ GtkWidget **button3, const gchar *label3)
+{
+ g_return_if_fail(bbox != NULL);
+ g_return_if_fail(button1 != NULL);
+
+ *bbox = gtk_hbutton_box_new();
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(*bbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing(GTK_BOX(*bbox), 5);
+
+ *button1 = gtk_button_new_with_label(label1);
+ GTK_WIDGET_SET_FLAGS(*button1, GTK_CAN_DEFAULT);
+ gtk_box_pack_start(GTK_BOX(*bbox), *button1, TRUE, TRUE, 0);
+ gtk_widget_show(*button1);
+
+ if (button2) {
+ *button2 = gtk_button_new_with_label(label2);
+ GTK_WIDGET_SET_FLAGS(*button2, GTK_CAN_DEFAULT);
+ gtk_box_pack_start(GTK_BOX(*bbox), *button2, TRUE, TRUE, 0);
+ gtk_widget_show(*button2);
+ }
+
+ if (button3) {
+ *button3 = gtk_button_new_with_label(label3);
+ GTK_WIDGET_SET_FLAGS(*button3, GTK_CAN_DEFAULT);
+ gtk_box_pack_start(GTK_BOX(*bbox), *button3, TRUE, TRUE, 0);
+ gtk_widget_show(*button3);
+ }
+}
+
+static void combo_button_size_request(GtkWidget *widget,
+ GtkRequisition *requisition,
+ gpointer data)
+{
+ ComboButton *combo = (ComboButton *)data;
+
+ if (combo->arrow->allocation.height != requisition->height)
+ gtk_widget_set_size_request(combo->arrow,
+ -1, requisition->height);
+}
+
+static void combo_button_enter(GtkWidget *widget, gpointer data)
+{
+ ComboButton *combo = (ComboButton *)data;
+
+ if (GTK_WIDGET_STATE(combo->arrow) != GTK_STATE_PRELIGHT) {
+ gtk_widget_set_state(combo->arrow, GTK_STATE_PRELIGHT);
+ gtk_widget_queue_draw(combo->arrow);
+ }
+ if (GTK_WIDGET_STATE(combo->button) != GTK_STATE_PRELIGHT) {
+ gtk_widget_set_state(combo->button, GTK_STATE_PRELIGHT);
+ gtk_widget_queue_draw(combo->button);
+ }
+}
+
+static void combo_button_leave(GtkWidget *widget, gpointer data)
+{
+ ComboButton *combo = (ComboButton *)data;
+
+ if (GTK_WIDGET_STATE(combo->arrow) != GTK_STATE_NORMAL) {
+ gtk_widget_set_state(combo->arrow, GTK_STATE_NORMAL);
+ gtk_widget_queue_draw(combo->arrow);
+ }
+ if (GTK_WIDGET_STATE(combo->button) != GTK_STATE_NORMAL) {
+ gtk_widget_set_state(combo->button, GTK_STATE_NORMAL);
+ gtk_widget_queue_draw(combo->button);
+ }
+}
+
+static gint combo_button_arrow_pressed(GtkWidget *widget, GdkEventButton *event,
+ gpointer data)
+{
+ ComboButton *combo = (ComboButton *)data;
+
+ if (!event) return FALSE;
+
+ gtk_menu_popup(GTK_MENU(combo->menu), NULL, NULL,
+ menu_button_position, combo->button,
+ event->button, event->time);
+
+ return TRUE;
+}
+
+static void combo_button_destroy(GtkWidget *widget, gpointer data)
+{
+ ComboButton *combo = (ComboButton *)data;
+
+ gtk_object_destroy(GTK_OBJECT(combo->factory));
+ g_free(combo);
+}
+
+ComboButton *gtkut_combo_button_create(GtkWidget *button,
+ GtkItemFactoryEntry *entries,
+ gint n_entries, const gchar *path,
+ gpointer data)
+{
+ ComboButton *combo;
+ GtkWidget *arrow;
+
+ combo = g_new0(ComboButton, 1);
+
+ combo->arrow = gtk_button_new();
+ arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
+ gtk_container_add(GTK_CONTAINER(combo->arrow), arrow);
+ GTK_WIDGET_UNSET_FLAGS(combo->arrow, GTK_CAN_FOCUS);
+ gtk_widget_show_all(combo->arrow);
+
+ combo->button = button;
+ combo->menu = menu_create_items(entries, n_entries, path,
+ &combo->factory, data);
+ combo->data = data;
+
+ g_signal_connect(G_OBJECT(combo->button), "size_request",
+ G_CALLBACK(combo_button_size_request), combo);
+ g_signal_connect(G_OBJECT(combo->button), "enter",
+ G_CALLBACK(combo_button_enter), combo);
+ g_signal_connect(G_OBJECT(combo->button), "leave",
+ G_CALLBACK(combo_button_leave), combo);
+ g_signal_connect(G_OBJECT(combo->arrow), "enter",
+ G_CALLBACK(combo_button_enter), combo);
+ g_signal_connect(G_OBJECT(combo->arrow), "leave",
+ G_CALLBACK(combo_button_leave), combo);
+ g_signal_connect(G_OBJECT(combo->arrow), "button_press_event",
+ G_CALLBACK(combo_button_arrow_pressed), combo);
+ g_signal_connect(G_OBJECT(combo->arrow), "destroy",
+ G_CALLBACK(combo_button_destroy), combo);
+
+ return combo;
+}
+
+#define CELL_SPACING 1
+#define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
+ (((row) + 1) * CELL_SPACING) + \
+ (clist)->voffset)
+#define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
+ ((clist)->row_height + CELL_SPACING))
+
+void gtkut_ctree_node_move_if_on_the_edge(GtkCTree *ctree, GtkCTreeNode *node)
+{
+ GtkCList *clist = GTK_CLIST(ctree);
+ gint row;
+ GtkVisibility row_visibility, prev_row_visibility, next_row_visibility;
+
+ g_return_if_fail(ctree != NULL);
+ g_return_if_fail(node != NULL);
+
+ row = g_list_position(clist->row_list, (GList *)node);
+ if (row < 0 || row >= clist->rows || clist->row_height == 0) return;
+ row_visibility = gtk_clist_row_is_visible(clist, row);
+ prev_row_visibility = gtk_clist_row_is_visible(clist, row - 1);
+ next_row_visibility = gtk_clist_row_is_visible(clist, row + 1);
+
+ if (row_visibility == GTK_VISIBILITY_NONE) {
+ gtk_clist_moveto(clist, row, -1, 0.5, 0);
+ return;
+ }
+ if (row_visibility == GTK_VISIBILITY_FULL &&
+ prev_row_visibility == GTK_VISIBILITY_FULL &&
+ next_row_visibility == GTK_VISIBILITY_FULL)
+ return;
+ if (prev_row_visibility != GTK_VISIBILITY_FULL &&
+ next_row_visibility != GTK_VISIBILITY_FULL)
+ return;
+
+ if (prev_row_visibility != GTK_VISIBILITY_FULL) {
+ gtk_clist_moveto(clist, row, -1, 0.2, 0);
+ return;
+ }
+ if (next_row_visibility != GTK_VISIBILITY_FULL) {
+ gtk_clist_moveto(clist, row, -1, 0.8, 0);
+ return;
+ }
+}
+
+#undef CELL_SPACING
+#undef ROW_TOP_YPIXEL
+#undef ROW_FROM_YPIXEL
+
+gint gtkut_ctree_get_nth_from_node(GtkCTree *ctree, GtkCTreeNode *node)
+{
+ g_return_val_if_fail(ctree != NULL, -1);
+ g_return_val_if_fail(node != NULL, -1);
+
+ return g_list_position(GTK_CLIST(ctree)->row_list, (GList *)node);
+}
+
+/* get the next node, including the invisible one */
+GtkCTreeNode *gtkut_ctree_node_next(GtkCTree *ctree, GtkCTreeNode *node)
+{
+ GtkCTreeNode *parent;
+
+ if (!node) return NULL;
+
+ if (GTK_CTREE_ROW(node)->children)
+ return GTK_CTREE_ROW(node)->children;
+
+ if (GTK_CTREE_ROW(node)->sibling)
+ return GTK_CTREE_ROW(node)->sibling;
+
+ for (parent = GTK_CTREE_ROW(node)->parent; parent != NULL;
+ parent = GTK_CTREE_ROW(parent)->parent) {
+ if (GTK_CTREE_ROW(parent)->sibling)
+ return GTK_CTREE_ROW(parent)->sibling;
+ }
+
+ return NULL;
+}
+
+/* get the previous node, including the invisible one */
+GtkCTreeNode *gtkut_ctree_node_prev(GtkCTree *ctree, GtkCTreeNode *node)
+{
+ GtkCTreeNode *prev;
+ GtkCTreeNode *child;
+
+ if (!node) return NULL;
+
+ prev = GTK_CTREE_NODE_PREV(node);
+ if (prev == GTK_CTREE_ROW(node)->parent)
+ return prev;
+
+ child = prev;
+ while (GTK_CTREE_ROW(child)->children != NULL) {
+ child = GTK_CTREE_ROW(child)->children;
+ while (GTK_CTREE_ROW(child)->sibling != NULL)
+ child = GTK_CTREE_ROW(child)->sibling;
+ }
+
+ return child;
+}
+
+gboolean gtkut_ctree_node_is_selected(GtkCTree *ctree, GtkCTreeNode *node)
+{
+ GtkCList *clist = GTK_CLIST(ctree);
+ GList *cur;
+
+ for (cur = clist->selection; cur != NULL; cur = cur->next) {
+ if (node == GTK_CTREE_NODE(cur->data))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+GtkCTreeNode *gtkut_ctree_find_collapsed_parent(GtkCTree *ctree,
+ GtkCTreeNode *node)
+{
+ if (!node) return NULL;
+
+ while ((node = GTK_CTREE_ROW(node)->parent) != NULL) {
+ if (!GTK_CTREE_ROW(node)->expanded)
+ return node;
+ }
+
+ return NULL;
+}
+
+void gtkut_ctree_expand_parent_all(GtkCTree *ctree, GtkCTreeNode *node)
+{
+ while ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
+ gtk_ctree_expand(ctree, node);
+}
+
+void gtkut_ctree_set_focus_row(GtkCTree *ctree, GtkCTreeNode *node)
+{
+ gtkut_clist_set_focus_row(GTK_CLIST(ctree),
+ gtkut_ctree_get_nth_from_node(ctree, node));
+}
+
+void gtkut_clist_set_focus_row(GtkCList *clist, gint row)
+{
+ clist->focus_row = row;
+ GTKUT_CTREE_REFRESH(clist);
+}
+
+void gtkut_combo_set_items(GtkCombo *combo, const gchar *str1, ...)
+{
+ va_list args;
+ gchar *s;
+ GList *combo_items = NULL;
+
+ g_return_if_fail(str1 != NULL);
+
+ combo_items = g_list_append(combo_items, (gpointer)str1);
+ va_start(args, str1);
+ s = va_arg(args, gchar*);
+ while (s) {
+ combo_items = g_list_append(combo_items, (gpointer)s);
+ s = va_arg(args, gchar*);
+ }
+ va_end(args);
+
+ gtk_combo_set_popdown_strings(combo, combo_items);
+
+ g_list_free(combo_items);
+}
+
+gchar *gtkut_editable_get_selection(GtkEditable *editable)
+{
+ guint start_pos, end_pos;
+ gboolean found;
+
+ g_return_val_if_fail(GTK_IS_EDITABLE(editable), NULL);
+
+ found = gtk_editable_get_selection_bounds(editable,
+ &start_pos, &end_pos);
+ if (found)
+ return gtk_editable_get_chars(editable, start_pos, end_pos);
+ else
+ return NULL;
+}
+
+void gtkut_editable_disable_im(GtkEditable *editable)
+{
+ g_return_if_fail(editable != NULL);
+
+#if USE_XIM
+ if (editable->ic) {
+ gdk_ic_destroy(editable->ic);
+ editable->ic = NULL;
+ }
+ if (editable->ic_attr) {
+ gdk_ic_attr_destroy(editable->ic_attr);
+ editable->ic_attr = NULL;
+ }
+#endif
+}
+
+/*
+ * Walk through the widget tree and disclaim the selection from all currently
+ * realized GtkEditable widgets.
+ */
+static void gtkut_check_before_remove(GtkWidget *widget, gpointer unused)
+{
+ g_return_if_fail(widget != NULL);
+
+ if (!GTK_WIDGET_REALIZED(widget))
+ return; /* all nested widgets must be unrealized too */
+ if (GTK_IS_CONTAINER(widget))
+ gtk_container_forall(GTK_CONTAINER(widget),
+ gtkut_check_before_remove, NULL);
+#if 0
+ if (GTK_IS_EDITABLE(widget))
+ gtk_editable_claim_selection(GTK_EDITABLE(widget),
+ FALSE, GDK_CURRENT_TIME);
+#endif
+}
+
+/*
+ * Wrapper around gtk_container_remove to work around a bug in GtkText and
+ * GtkEntry (in all GTK+ versions up to and including at least 1.2.10).
+ *
+ * The problem is that unrealizing a GtkText or GtkEntry widget which has the
+ * active selection completely messes up selection handling, leading to
+ * non-working selections and crashes. Removing a widget from its container
+ * implies unrealizing it and all its child widgets; this triggers the bug if
+ * the removed widget or any of its children is GtkText or GtkEntry. As a
+ * workaround, this function walks through the widget subtree before removing
+ * and disclaims the selection from all GtkEditable widgets found.
+ *
+ * A similar workaround may be needed for gtk_widget_reparent(); currently it
+ * is not necessary because Sylpheed does not use gtk_widget_reparent() for
+ * GtkEditable widgets or containers holding such widgets.
+ */
+void gtkut_container_remove(GtkContainer *container, GtkWidget *widget)
+{
+ gtkut_check_before_remove(widget, NULL);
+ gtk_container_remove(container, widget);
+}
+
+#warning FIXME_GTK2
+gboolean gtkut_text_buffer_match_string(GtkTextBuffer *textbuf, gint pos,
+ gunichar *wcs, gint len,
+ gboolean case_sens)
+{
+ GtkTextIter start_iter, end_iter;
+ gchar *utf8str;
+ gint match_count = 0;
+
+ gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter, pos);
+ gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter, pos + len);
+
+ utf8str = gtk_text_buffer_get_text(textbuf, &start_iter, &end_iter, FALSE);
+ if (!utf8str) return FALSE;
+
+ if ((gint)g_utf8_strlen(utf8str, -1) != len) {
+ g_free(utf8str);
+ return FALSE;
+ }
+
+ for (; match_count < len; pos++, match_count++) {
+ gchar *ptr;
+ gunichar ch;
+
+ ptr = g_utf8_offset_to_pointer(utf8str, match_count);
+ if (!ptr) break;
+ ch = g_utf8_get_char(ptr);
+
+ if (case_sens) {
+ if (ch != wcs[match_count])
+ break;
+ } else {
+ if (g_unichar_tolower(ch) !=
+ g_unichar_tolower(wcs[match_count]))
+ break;
+ }
+ }
+
+ g_free(utf8str);
+
+ if (match_count == len)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+guint gtkut_text_buffer_str_compare_n(GtkTextBuffer *textbuf,
+ guint pos1, guint pos2,
+ guint len, guint text_len)
+{
+ guint i;
+
+ for (i = 0; i < len && pos1 + i < text_len && pos2 + i < text_len; i++) {
+ GtkTextIter start_iter, end_iter;
+ gchar *utf8str1, *utf8str2;
+
+ gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter,
+ pos1 + i);
+ gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter,
+ pos1 + i + 1);
+ utf8str1 = gtk_text_buffer_get_text(textbuf,
+ &start_iter,
+ &end_iter,
+ FALSE);
+
+ gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter,
+ pos2 + i);
+ gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter,
+ pos2 + i + 1);
+ utf8str2 = gtk_text_buffer_get_text(textbuf,
+ &start_iter,
+ &end_iter,
+ FALSE);
+
+ if (!utf8str1 || !utf8str2 || strcmp(utf8str1, utf8str2) != 0) {
+ g_free(utf8str1);
+ g_free(utf8str2);
+ break;
+ }
+
+ g_free(utf8str1);
+ g_free(utf8str2);
+ }
+
+ return i;
+}
+
+guint gtkut_text_buffer_str_compare(GtkTextBuffer *textbuf,
+ guint start_pos, guint text_len,
+ const gchar *str)
+{
+ gunichar *wcs;
+ guint len = 0;
+ glong items_read = 0, items_written = 0;
+ gboolean result;
+ GError *error = NULL;
+
+ if (!str) return 0;
+
+ wcs = g_utf8_to_ucs4(str, -1, &items_read, &items_written, &error);
+ if (error != NULL) {
+ g_warning("An error occured while converting a string from UTF-8 to UCS-4: %s\n", error->message);
+ g_error_free(error);
+ }
+ if (!wcs || items_written <= 0) return 0;
+ len = (guint)items_written;
+
+ if (len > text_len - start_pos)
+ result = FALSE;
+ else
+ result = gtkut_text_buffer_match_string(textbuf, start_pos,
+ wcs, len, TRUE);
+
+ g_free(wcs);
+
+ return result ? len : 0;
+}
+
+gboolean gtkut_text_buffer_is_uri_string(GtkTextBuffer *textbuf,
+ guint start_pos, guint text_len)
+{
+ if (gtkut_text_buffer_str_compare
+ (textbuf, start_pos, text_len, "http://") ||
+ gtkut_text_buffer_str_compare
+ (textbuf, start_pos, text_len, "ftp://") ||
+ gtkut_text_buffer_str_compare
+ (textbuf, start_pos, text_len, "https://") ||
+ gtkut_text_buffer_str_compare
+ (textbuf, start_pos, text_len, "www."))
+ return TRUE;
+
+ return FALSE;
+}
+
+gchar *gtkut_text_view_get_selection(GtkTextView *textview)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start_iter, end_iter;
+ gboolean found;
+
+ g_return_val_if_fail(GTK_IS_TEXT_VIEW(textview), NULL);
+
+ buffer = gtk_text_view_get_buffer(textview);
+ found = gtk_text_buffer_get_selection_bounds(buffer,
+ &start_iter, &end_iter);
+ if (found)
+ return gtk_text_buffer_get_text(buffer, &start_iter, &end_iter,
+ FALSE);
+ else
+ return NULL;
+}
+
+void gtkut_window_popup(GtkWidget *window)
+{
+ gint x, y, sx, sy, new_x, new_y;
+
+ g_return_if_fail(window != NULL);
+ g_return_if_fail(window->window != NULL);
+
+ sx = gdk_screen_width();
+ sy = gdk_screen_height();
+
+ gdk_window_get_origin(window->window, &x, &y);
+ new_x = x % sx; if (new_x < 0) new_x = 0;
+ new_y = y % sy; if (new_y < 0) new_y = 0;
+ if (new_x != x || new_y != y)
+ gdk_window_move(window->window, new_x, new_y);
+
+ gdk_window_raise(window->window);
+ gdk_window_show(window->window);
+}
+
+void gtkut_widget_get_uposition(GtkWidget *widget, gint *px, gint *py)
+{
+ gint x, y;
+ gint sx, sy;
+
+ g_return_if_fail(widget != NULL);
+ g_return_if_fail(widget->window != NULL);
+
+ sx = gdk_screen_width();
+ sy = gdk_screen_height();
+
+ /* gdk_window_get_root_origin ever return *rootwindow*'s position */
+ gdk_window_get_root_origin(widget->window, &x, &y);
+
+ x %= sx; if (x < 0) x = 0;
+ y %= sy; if (y < 0) y = 0;
+ *px = x;
+ *py = y;
+}
+
+#warning FIXME_GTK2
+void gtkut_widget_wait_for_draw(GtkWidget *widget)
+{
+ if (!GTK_WIDGET_VISIBLE(widget) || !GTK_WIDGET_MAPPED(widget)) return;
+
+ while (gtk_events_pending())
+ gtk_main_iteration();
+}
+
+static void gtkut_clist_bindings_add(GtkWidget *clist)
+{
+ GtkBindingSet *binding_set;
+
+ binding_set = gtk_binding_set_by_class(GTK_CLIST_GET_CLASS(clist));
+
+ gtk_binding_entry_add_signal(binding_set, GDK_n, GDK_CONTROL_MASK,
+ "scroll_vertical", 2,
+ G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
+ G_TYPE_FLOAT, 0.0);
+ gtk_binding_entry_add_signal(binding_set, GDK_p, GDK_CONTROL_MASK,
+ "scroll_vertical", 2,
+ G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
+ G_TYPE_FLOAT, 0.0);
+}
+
+void gtkut_widget_init(void)
+{
+ GtkWidget *clist;
+
+ clist = gtk_clist_new(1);
+ g_object_ref(G_OBJECT(clist));
+ gtk_object_sink(GTK_OBJECT(clist));
+ gtkut_clist_bindings_add(clist);
+ g_object_unref(G_OBJECT(clist));
+
+ clist = gtk_ctree_new(1, 0);
+ g_object_ref(G_OBJECT(clist));
+ gtk_object_sink(GTK_OBJECT(clist));
+ gtkut_clist_bindings_add(clist);
+ g_object_unref(G_OBJECT(clist));
+
+ clist = gtk_sctree_new_with_titles(1, 0, NULL);
+ g_object_ref(G_OBJECT(clist));
+ gtk_object_sink(GTK_OBJECT(clist));
+ gtkut_clist_bindings_add(clist);
+ g_object_unref(G_OBJECT(clist));
+}