From 0b3cbf57875fd692e4ba0b336fefa4bee1ed00dc Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Mon, 26 Feb 2018 11:23:00 +0100 Subject: Initial commit for sylpheed 3.7.0 --- src/gtkutils.c | 1119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1119 insertions(+) create mode 100644 src/gtkutils.c (limited to 'src/gtkutils.c') diff --git a/src/gtkutils.c b/src/gtkutils.c new file mode 100644 index 0000000..b1a488a --- /dev/null +++ b/src/gtkutils.c @@ -0,0 +1,1119 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2014 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 +#include +#include +#include +#include +#include +#include +#include + +#ifdef G_OS_WIN32 +# include +#endif + +#include "gtkutils.h" +#include "utils.h" +#include "codeconv.h" +#include "menu.h" + +gboolean gtkut_get_str_size(GtkWidget *widget, const gchar *str, + gint *width, gint *height) +{ + PangoLayout *layout; + + 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); + g_object_unref(layout); + + return TRUE; +} + +gboolean gtkut_get_font_size(GtkWidget *widget, gint *width, gint *height) +{ + const gchar *str = "Abcdef"; + gboolean ret; + + ret = gtkut_get_str_size(widget, str, width, height); + if (ret && width) + *width = *width / g_utf8_strlen(str, -1); + + return ret; +} + +PangoFontDescription *gtkut_get_default_font_desc(void) +{ + static PangoFontDescription *font_desc = NULL; + + if (!font_desc) { + GtkWidget *window; + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_ensure_style(window); + font_desc = pango_font_description_copy + (window->style->font_desc); + gtk_object_sink(GTK_OBJECT(window)); + } + + return pango_font_description_copy(font_desc); +} + +void gtkut_widget_set_small_font_size(GtkWidget *widget) +{ + PangoFontDescription *font_desc; + gint size; + + g_return_if_fail(widget != NULL); + g_return_if_fail(widget->style != NULL); + + font_desc = gtkut_get_default_font_desc(); + size = pango_font_description_get_size(font_desc); + pango_font_description_set_size(font_desc, size * PANGO_SCALE_SMALL); + gtk_widget_modify_font(widget, font_desc); + pango_font_description_free(font_desc); +} + +gboolean gtkut_font_can_load(const gchar *str) +{ +#ifdef G_OS_WIN32 + PangoFontDescription *desc; + PangoContext *context; + PangoFont *font; + gboolean can_load = FALSE; + + desc = pango_font_description_from_string(str); + if (desc) { + context = pango_win32_get_context(); + font = pango_context_load_font(context, desc); + if (font) { + can_load = TRUE; + g_object_unref(font); + } + g_object_unref(context); + pango_font_description_free(desc); + } + + return can_load; +#elif defined(__APPLE__) + PangoFontDescription *desc; + PangoContext *context; + PangoFont *font; + gboolean can_load = FALSE; + + desc = pango_font_description_from_string(str); + if (desc) { + context = gdk_pango_context_get_for_screen + (gdk_screen_get_default()); + font = pango_context_load_font(context, desc); + if (font) { + can_load = TRUE; + g_object_unref(font); + } + g_object_unref(context); + pango_font_description_free(desc); + } + + return can_load; +#else + return FALSE; +#endif +} + +static gdouble system_dpi = 0.0; + +gdouble gtkut_get_dpi(void) +{ + gdouble dp, di; + + if (system_dpi > 0.0) + return system_dpi; + + //dpi = gdk_screen_get_resolution(gdk_screen_get_default()); + + dp = gdk_screen_get_height(gdk_screen_get_default()); + di = gdk_screen_get_height_mm(gdk_screen_get_default()) / 25.4; + system_dpi = dp / di; + + debug_print("gtkut_get_dpi: dpi: %f\n", system_dpi); + return system_dpi; +} + +gdouble gtkut_get_dpi_multiplier(void) +{ + gdouble dpi; + gdouble mul; + + dpi = gtkut_get_dpi(); + + /* 96 / 120 / 144 dpi */ + if (dpi > 142) + mul = 1.5; + else if (dpi > 118) + mul = 1.25; + else + mul = 1.0; + + return mul; +} + +void gtkut_set_dpi(gdouble dpi) +{ + system_dpi = dpi; +} + +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); +} + +static gboolean reverse_order = FALSE; + +void gtkut_stock_button_set_set_reverse(gboolean reverse) +{ + reverse_order = reverse; +} + +void gtkut_stock_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), 6 * gtkut_get_dpi_multiplier()); + + if (button3) { + *button3 = gtk_button_new_from_stock(label3); + GTK_WIDGET_SET_FLAGS(*button3, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(*bbox), *button3, FALSE, FALSE, 0); + gtk_widget_show(*button3); + } + + if (button2) { + *button2 = gtk_button_new_from_stock(label2); + GTK_WIDGET_SET_FLAGS(*button2, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(*bbox), *button2, FALSE, FALSE, 0); + gtk_widget_show(*button2); + } + + *button1 = gtk_button_new_from_stock(label1); + GTK_WIDGET_SET_FLAGS(*button1, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(*bbox), *button1, FALSE, FALSE, 0); + gtk_widget_show(*button1); + + if (reverse_order) + gtkut_box_set_reverse_order(GTK_BOX(*bbox), TRUE); +} + +void gtkut_box_set_reverse_order(GtkBox *box, gboolean reverse) +{ + GList *cur; + GList *new_order = NULL; + gint pos = 0; + gboolean is_reversed; + + g_return_if_fail(box != NULL); + + is_reversed = GPOINTER_TO_INT + (g_object_get_data(G_OBJECT(box), "reverse-order")); + if (is_reversed == reverse) + return; + g_object_set_data(G_OBJECT(box), "reverse-order", + GINT_TO_POINTER(reverse)); + + for (cur = box->children; cur != NULL; cur = cur->next) { + GtkBoxChild *cinfo = cur->data; + new_order = g_list_prepend(new_order, cinfo->widget); + } + + for (cur = new_order; cur != NULL; cur = cur->next) { + GtkWidget *child = cur->data; + gtk_box_reorder_child(box, child, pos++); + } + + g_list_free(new_order); +} + +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_widget_set_size_request(arrow, 7, -1); + 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); +#if 0 + 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); +#endif + 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; +} + +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); +} + +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); +} + +#ifdef G_OS_WIN32 +static void vadjustment_changed(GtkAdjustment *adj, gpointer data) +{ + GtkWidget *widget = GTK_WIDGET(data); + + gtk_widget_queue_draw(widget); +} +#elif defined(__APPLE__) +static void clist_select_row(GtkCList *clist, gint row, gint column, GdkEventButton *event, gpointer data) +{ + gtk_widget_queue_draw(GTK_WIDGET(clist)); +} +#endif + +void gtkut_clist_set_redraw(GtkCList *clist) +{ +#ifdef G_OS_WIN32 + if (clist->vadjustment) { + g_signal_connect(G_OBJECT(clist->vadjustment), "changed", + G_CALLBACK(vadjustment_changed), clist); + } +#elif defined(__APPLE__) + g_signal_connect(G_OBJECT(clist), "select-row", + G_CALLBACK(clist_select_row), NULL); +#endif +} + +gboolean gtkut_tree_model_next(GtkTreeModel *model, GtkTreeIter *iter) +{ + GtkTreeIter iter_, parent; + gboolean valid; + + if (gtk_tree_model_iter_children(model, &iter_, iter)) { + *iter = iter_; + return TRUE; + } + + iter_ = *iter; + if (gtk_tree_model_iter_next(model, &iter_)) { + *iter = iter_; + return TRUE; + } + + iter_ = *iter; + valid = gtk_tree_model_iter_parent(model, &parent, &iter_); + while (valid) { + iter_ = parent; + if (gtk_tree_model_iter_next(model, &iter_)) { + *iter = iter_; + return TRUE; + } + + iter_ = parent; + valid = gtk_tree_model_iter_parent(model, &parent, &iter_); + } + + return FALSE; +} + +gboolean gtkut_tree_model_prev(GtkTreeModel *model, GtkTreeIter *iter) +{ + GtkTreeIter iter_, child, next, parent; + GtkTreePath *path; + gboolean found = FALSE; + + iter_ = *iter; + + path = gtk_tree_model_get_path(model, &iter_); + + if (gtk_tree_path_prev(path)) { + gtk_tree_model_get_iter(model, &child, path); + + while (gtk_tree_model_iter_has_child(model, &child)) { + iter_ = child; + gtk_tree_model_iter_children(model, &child, &iter_); + next = child; + while (gtk_tree_model_iter_next(model, &next)) + child = next; + } + + *iter = child; + found = TRUE; + } else if (gtk_tree_model_iter_parent(model, &parent, &iter_)) { + *iter = parent; + found = TRUE; + } + + gtk_tree_path_free(path); + + return found; +} + +gboolean gtkut_tree_model_get_iter_last(GtkTreeModel *model, GtkTreeIter *iter) +{ + GtkTreeIter iter_, child, next; + + if (!gtk_tree_model_get_iter_first(model, &iter_)) + return FALSE; + + for (;;) { + next = iter_; + while (gtk_tree_model_iter_next(model, &next)) + iter_ = next; + if (gtk_tree_model_iter_children(model, &child, &iter_)) + iter_ = child; + else + break; + } + + *iter = iter_; + return TRUE; +} + +gboolean gtkut_tree_model_find_by_column_data(GtkTreeModel *model, + GtkTreeIter *iter, + GtkTreeIter *start, + gint col, gpointer data) +{ + gboolean valid; + GtkTreeIter iter_; + gpointer store_data; + + if (start) { + gtk_tree_model_get(model, start, col, &store_data, -1); + if (store_data == data) { + *iter = *start; + return TRUE; + } + valid = gtk_tree_model_iter_children(model, &iter_, start); + } else + valid = gtk_tree_model_get_iter_first(model, &iter_); + + while (valid) { + if (gtkut_tree_model_find_by_column_data + (model, iter, &iter_, col, data)) { + return TRUE; + } + + valid = gtk_tree_model_iter_next(model, &iter_); + } + + return FALSE; +} + +void gtkut_tree_model_foreach(GtkTreeModel *model, GtkTreeIter *start, + GtkTreeModelForeachFunc func, gpointer user_data) +{ + gboolean valid = TRUE; + GtkTreeIter iter; + GtkTreePath *path; + + g_return_if_fail(func != NULL); + + if (!start) { + gtk_tree_model_foreach(model, func, user_data); + return; + } + + path = gtk_tree_model_get_path(model, start); + func(model, path, start, user_data); + gtk_tree_path_free(path); + + valid = gtk_tree_model_iter_children(model, &iter, start); + while (valid) { + gtkut_tree_model_foreach(model, &iter, func, user_data); + valid = gtk_tree_model_iter_next(model, &iter); + } +} + +gboolean gtkut_tree_row_reference_get_iter(GtkTreeModel *model, + GtkTreeRowReference *ref, + GtkTreeIter *iter) +{ + GtkTreePath *path; + gboolean valid = FALSE; + + if (ref) { + path = gtk_tree_row_reference_get_path(ref); + if (path) { + valid = gtk_tree_model_get_iter(model, iter, path); + gtk_tree_path_free(path); + } + } + + return valid; +} + +gboolean gtkut_tree_row_reference_equal(GtkTreeRowReference *ref1, + GtkTreeRowReference *ref2) +{ + GtkTreePath *path1, *path2; + gint result; + + if (ref1 == NULL || ref2 == NULL) + return FALSE; + + path1 = gtk_tree_row_reference_get_path(ref1); + if (!path1) + return FALSE; + path2 = gtk_tree_row_reference_get_path(ref2); + if (!path2) { + gtk_tree_path_free(path1); + return FALSE; + } + + result = gtk_tree_path_compare(path1, path2); + + gtk_tree_path_free(path2); + gtk_tree_path_free(path1); + + return (result == 0); +} + +void gtkut_tree_sortable_unset_sort_column_id(GtkTreeSortable *sortable) +{ +#if GTK_CHECK_VERSION(2, 6, 0) + gtk_tree_sortable_set_sort_column_id + (sortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, + GTK_SORT_ASCENDING); +#else + GtkTreeStore *store = GTK_TREE_STORE(sortable); + + g_return_if_fail(GTK_IS_TREE_STORE(sortable)); + + if (store->sort_column_id == -2 && store->order == GTK_SORT_ASCENDING) + return; + + store->sort_column_id = -2; + store->order = GTK_SORT_ASCENDING; + + gtk_tree_sortable_sort_column_changed(sortable); +#endif +} + +gboolean gtkut_tree_view_find_collapsed_parent(GtkTreeView *treeview, + GtkTreeIter *parent, + GtkTreeIter *iter) +{ + GtkTreeModel *model; + GtkTreeIter iter_, parent_; + GtkTreePath *path; + gboolean valid; + + if (!iter) return FALSE; + + model = gtk_tree_view_get_model(treeview); + valid = gtk_tree_model_iter_parent(model, &parent_, iter); + + while (valid) { + path = gtk_tree_model_get_path(model, &parent_); + if (!gtk_tree_view_row_expanded(treeview, path)) { + *parent = parent_; + gtk_tree_path_free(path); + return TRUE; + } + gtk_tree_path_free(path); + iter_ = parent_; + valid = gtk_tree_model_iter_parent(model, &parent_, &iter_); + } + + return FALSE; +} + +void gtkut_tree_view_expand_parent_all(GtkTreeView *treeview, GtkTreeIter *iter) +{ + GtkTreeModel *model; + GtkTreeIter parent; + GtkTreePath *path; + + model = gtk_tree_view_get_model(treeview); + + if (gtk_tree_model_iter_parent(model, &parent, iter)) { + path = gtk_tree_model_get_path(model, &parent); + gtk_tree_view_expand_to_path(treeview, path); + gtk_tree_path_free(path); + } +} + +#define SCROLL_EDGE_SIZE 15 + +/* borrowed from gtktreeview.c */ +void gtkut_tree_view_vertical_autoscroll(GtkTreeView *treeview) +{ + GdkRectangle visible_rect; + gint y, wy; + gint offset; + GtkAdjustment *vadj; + gfloat value; + + gdk_window_get_pointer(gtk_tree_view_get_bin_window(treeview), + NULL, &wy, NULL); + gtk_tree_view_widget_to_tree_coords(treeview, 0, wy, NULL, &y); + + gtk_tree_view_get_visible_rect(treeview, &visible_rect); + + /* see if we are near the edge. */ + offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE); + if (offset > 0) { + offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE); + if (offset < 0) + return; + } + + vadj = gtk_tree_view_get_vadjustment(treeview); + value = CLAMP(vadj->value + offset, 0.0, vadj->upper - vadj->page_size); + gtk_adjustment_set_value(vadj, value); +} + +/* modified version of gtk_tree_view_scroll_to_cell */ +void gtkut_tree_view_scroll_to_cell(GtkTreeView *treeview, GtkTreePath *path, + gboolean align_center) +{ + GdkRectangle cell_rect; + GdkRectangle vis_rect; + gint dest_x, dest_y; + gint margin = 0; + + if (!path) + return; + + gtk_tree_view_get_cell_area(treeview, path, NULL, &cell_rect); + gtk_tree_view_widget_to_tree_coords(treeview, cell_rect.x, cell_rect.y, + NULL, &(cell_rect.y)); + gtk_tree_view_get_visible_rect(treeview, &vis_rect); + + dest_x = vis_rect.x; + dest_y = vis_rect.y; + + /* add margin */ + if (cell_rect.height * 2 < vis_rect.height) + margin = cell_rect.height + (align_center ? 0 : 2); + + if (cell_rect.y < vis_rect.y + margin) { + if (align_center) + dest_y = cell_rect.y - + (vis_rect.height - cell_rect.height) / 2; + else + dest_y = cell_rect.y - margin; + } + if (cell_rect.y + cell_rect.height > + vis_rect.y + vis_rect.height - margin) { + if (align_center) + dest_y = cell_rect.y - + (vis_rect.height - cell_rect.height) / 2; + else + dest_y = cell_rect.y + cell_rect.height - + vis_rect.height + margin; + } + + gtk_tree_view_scroll_to_point(treeview, dest_x, dest_y); +} + +void gtkut_tree_view_fast_clear(GtkTreeView *treeview, GtkTreeStore *store) +{ +#if GTK_CHECK_VERSION(2, 8, 0) && !GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_store_clear(store); +#else + /* this is faster than above, but it seems to trigger crashes in + GTK+ 2.8.x */ + gtk_tree_view_set_model(treeview, NULL); + gtk_tree_store_clear(store); + gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store)); +#endif +} + +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) +{ + gint 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 +} + +void gtkut_entry_strip_text(GtkEntry *entry) +{ + gchar *text; + gint len; + + text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1); + len = strlen(text); + g_strstrip(text); + if (len > strlen(text)) + gtk_entry_set_text(entry, text); + g_free(text); +} + +void gtkut_container_remove(GtkContainer *container, GtkWidget *widget) +{ + gtk_container_remove(container, widget); +} + +void gtkut_scrolled_window_reset_position(GtkScrolledWindow *window) +{ + GtkAdjustment *adj; + + adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(window)); + gtk_adjustment_set_value(adj, adj->lower); + adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(window)); + gtk_adjustment_set_value(adj, adj->lower); +} + +gboolean gtkut_text_buffer_match_string(GtkTextBuffer *textbuf, + const GtkTextIter *iter, + gunichar *wcs, gint len, + gboolean case_sens) +{ + GtkTextIter start_iter, end_iter; + gchar *utf8str, *p; + gint match_count; + + start_iter = end_iter = *iter; + gtk_text_iter_forward_chars(&end_iter, 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 (p = utf8str, match_count = 0; + *p != '\0' && match_count < len; + p = g_utf8_next_char(p), match_count++) { + gunichar wc; + + wc = g_utf8_get_char(p); + + if (case_sens) { + if (wc != wcs[match_count]) + break; + } else { + if (g_unichar_tolower(wc) != + g_unichar_tolower(wcs[match_count])) + break; + } + } + + g_free(utf8str); + + if (match_count == len) + return TRUE; + else + return FALSE; +} + +gboolean gtkut_text_buffer_find(GtkTextBuffer *buffer, const GtkTextIter *iter, + const gchar *str, gboolean case_sens, + GtkTextIter *match_pos) +{ + gunichar *wcs; + gint len; + glong items_read = 0, items_written = 0; + GError *error = NULL; + GtkTextIter iter_; + gboolean found = FALSE; + + wcs = g_utf8_to_ucs4(str, -1, &items_read, &items_written, &error); + if (error != NULL) { + g_warning("An error occurred while converting a string from UTF-8 to UCS-4: %s\n", error->message); + g_error_free(error); + } + if (!wcs || items_written <= 0) return FALSE; + len = (gint)items_written; + + iter_ = *iter; + do { + found = gtkut_text_buffer_match_string + (buffer, &iter_, wcs, len, case_sens); + if (found) { + *match_pos = iter_; + break; + } + } while (gtk_text_iter_forward_char(&iter_)); + + g_free(wcs); + + return found; +} + +gboolean gtkut_text_buffer_find_backward(GtkTextBuffer *buffer, + const GtkTextIter *iter, + const gchar *str, gboolean case_sens, + GtkTextIter *match_pos) +{ + gunichar *wcs; + gint len; + glong items_read = 0, items_written = 0; + GError *error = NULL; + GtkTextIter iter_; + gboolean found = FALSE; + + wcs = g_utf8_to_ucs4(str, -1, &items_read, &items_written, &error); + if (error != NULL) { + g_warning("An error occurred while converting a string from UTF-8 to UCS-4: %s\n", error->message); + g_error_free(error); + } + if (!wcs || items_written <= 0) return FALSE; + len = (gint)items_written; + + iter_ = *iter; + while (gtk_text_iter_backward_char(&iter_)) { + found = gtkut_text_buffer_match_string + (buffer, &iter_, wcs, len, case_sens); + if (found) { + *match_pos = iter_; + break; + } + } + + g_free(wcs); + + return found; +} + +#define MAX_TEXT_LINE_LEN 8190 + +void gtkut_text_buffer_insert_with_tag_by_name(GtkTextBuffer *buffer, + GtkTextIter *iter, + const gchar *text, + gint len, + const gchar *tag) +{ + if (len < 0) + len = strlen(text); + + gtk_text_buffer_insert_with_tags_by_name + (buffer, iter, text, len, tag, NULL); + + if (len > 0 && text[len - 1] != '\n') { + /* somehow returns invalid value first (bug?), + so call it twice */ + gtk_text_iter_get_chars_in_line(iter); + if (gtk_text_iter_get_chars_in_line(iter) > MAX_TEXT_LINE_LEN) { + gtk_text_buffer_insert_with_tags_by_name + (buffer, iter, "\n", 1, tag, NULL); + } + } +} + +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); + + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window), FALSE); + gtk_widget_show(window); + gtk_window_present(GTK_WINDOW(window)); +#ifdef G_OS_WIN32 + /* ensure that the window is displayed at the top */ + gdk_window_show(window->window); +#endif +} + +gboolean gtkut_window_modal_exist(void) +{ + GList *window_list, *cur; + gboolean exist = FALSE; + + window_list = gtk_window_list_toplevels(); + for (cur = window_list; cur != NULL; cur = cur->next) { + GtkWidget *window = GTK_WIDGET(cur->data); + + if (GTK_WIDGET_VISIBLE(window) && + gtk_window_get_modal(GTK_WINDOW(window))) { + exist = TRUE; + break; + } + } + g_list_free(window_list); + + return exist; +} + +/* ensure that the window is displayed on screen */ +void gtkut_window_move(GtkWindow *window, gint x, gint y) +{ + g_return_if_fail(window != NULL); + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + x %= gdk_screen_width(); + y %= gdk_screen_height(); + + gtk_window_move(window, x, y); +} + +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; +} + +void gtkut_widget_draw_now(GtkWidget *widget) +{ + if (GTK_WIDGET_VISIBLE(widget) && GTK_WIDGET_DRAWABLE(widget)) + gdk_window_process_updates(widget->window, FALSE); +} + +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)); +} + +void gtkut_events_flush(void) +{ + GTK_EVENTS_FLUSH(); +} -- cgit v1.3