ac9fe554dff9c4c4a53fb6af5ea4a928aa908302
[claws.git] / src / gtk / gtkutils.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2004 Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <glib.h>
25 #include <gdk/gdkkeysyms.h>
26 #include <gdk/gdk.h>
27 #include <gtk/gtkwidget.h>
28 #include <gtk/gtkhbbox.h>
29 #include <gtk/gtkbutton.h>
30 #include <gtk/gtkctree.h>
31 #include <gtk/gtkcombo.h>
32 #warning FIXME_GTK2
33 /* #include <gtk/gtkthemes.h> */
34 #include <gtk/gtkbindings.h>
35 #include <gtk/gtkitemfactory.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <sys/stat.h>
39
40 #if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
41 #  include <wchar.h>
42 #  include <wctype.h>
43 #endif
44
45 #include "intl.h"
46 #include "gtkutils.h"
47 #include "utils.h"
48 #include "gtksctree.h"
49 #include "codeconv.h"
50 #include "stock_pixmap.h"
51 #include "menu.h"
52 #include "prefs_account.h"
53
54 #warning FIXME_GTK2
55 gboolean gtkut_get_font_size(GtkWidget *widget,
56                              gint *width, gint *height)
57 {
58         PangoLayout *layout;
59         const gchar *str = "Abcdef";
60
61         g_return_val_if_fail(GTK_IS_WIDGET(widget), FALSE);
62
63         layout = gtk_widget_create_pango_layout(widget, str);
64         g_return_val_if_fail(layout, FALSE);
65         pango_layout_get_pixel_size(layout, width, height);
66         if (width)
67                 *width = *width / g_utf8_strlen(str, -1);
68         g_object_unref(layout);
69
70         return TRUE;
71 }
72
73 void gtkut_convert_int_to_gdk_color(gint rgbvalue, GdkColor *color)
74 {
75         g_return_if_fail(color != NULL);
76
77         color->pixel = 0L;
78         color->red   = (int) (((gdouble)((rgbvalue & 0xff0000) >> 16) / 255.0) * 65535.0);
79         color->green = (int) (((gdouble)((rgbvalue & 0x00ff00) >>  8) / 255.0) * 65535.0);
80         color->blue  = (int) (((gdouble) (rgbvalue & 0x0000ff)        / 255.0) * 65535.0);
81 }
82
83 void gtkut_button_set_create(GtkWidget **bbox,
84                              GtkWidget **button1, const gchar *label1,
85                              GtkWidget **button2, const gchar *label2,
86                              GtkWidget **button3, const gchar *label3)
87 {
88         g_return_if_fail(bbox != NULL);
89         g_return_if_fail(button1 != NULL);
90
91         *bbox = gtk_hbutton_box_new();
92         gtk_button_box_set_layout(GTK_BUTTON_BOX(*bbox), GTK_BUTTONBOX_END);
93         gtk_box_set_spacing(GTK_BOX(*bbox), 5);
94
95         *button1 = gtk_button_new_with_label(label1);
96         GTK_WIDGET_SET_FLAGS(*button1, GTK_CAN_DEFAULT);
97         gtk_box_pack_start(GTK_BOX(*bbox), *button1, TRUE, TRUE, 0);
98         gtk_widget_show(*button1);
99
100         if (button2) {
101                 *button2 = gtk_button_new_with_label(label2);
102                 GTK_WIDGET_SET_FLAGS(*button2, GTK_CAN_DEFAULT);
103                 gtk_box_pack_start(GTK_BOX(*bbox), *button2, TRUE, TRUE, 0);
104                 gtk_widget_show(*button2);
105         }
106
107         if (button3) {
108                 *button3 = gtk_button_new_with_label(label3);
109                 GTK_WIDGET_SET_FLAGS(*button3, GTK_CAN_DEFAULT);
110                 gtk_box_pack_start(GTK_BOX(*bbox), *button3, TRUE, TRUE, 0);
111                 gtk_widget_show(*button3);
112         }
113 }
114
115 static void combo_button_size_request(GtkWidget *widget,
116                                       GtkRequisition *requisition,
117                                       gpointer data)
118 {
119         ComboButton *combo = (ComboButton *)data;
120
121         if (combo->arrow->allocation.height != requisition->height)
122                 gtk_widget_set_usize(combo->arrow, -1, requisition->height);
123 }
124
125 static void combo_button_enter(GtkWidget *widget, gpointer data)
126 {
127         ComboButton *combo = (ComboButton *)data;
128
129         if (GTK_WIDGET_STATE(combo->arrow) != GTK_STATE_PRELIGHT) {
130                 gtk_widget_set_state(combo->arrow, GTK_STATE_PRELIGHT);
131                 gtk_widget_queue_draw(combo->arrow);
132         }
133         if (GTK_WIDGET_STATE(combo->button) != GTK_STATE_PRELIGHT) {
134                 gtk_widget_set_state(combo->button, GTK_STATE_PRELIGHT);
135                 gtk_widget_queue_draw(combo->button);
136         }
137 }
138
139 static void combo_button_leave(GtkWidget *widget, gpointer data)
140 {
141         ComboButton *combo = (ComboButton *)data;
142
143         if (GTK_WIDGET_STATE(combo->arrow) != GTK_STATE_NORMAL) {
144                 gtk_widget_set_state(combo->arrow, GTK_STATE_NORMAL);
145                 gtk_widget_queue_draw(combo->arrow);
146         }
147         if (GTK_WIDGET_STATE(combo->button) != GTK_STATE_NORMAL) {
148                 gtk_widget_set_state(combo->button, GTK_STATE_NORMAL);
149                 gtk_widget_queue_draw(combo->button);
150         }
151 }
152
153 static gint combo_button_arrow_pressed(GtkWidget *widget, GdkEventButton *event,
154                                        gpointer data)
155 {
156         ComboButton *combo = (ComboButton *)data;
157
158         if (!event) return FALSE;
159
160         gtk_menu_popup(GTK_MENU(combo->menu), NULL, NULL,
161                        menu_button_position, combo->button,
162                        event->button, event->time);
163
164         return FALSE;
165 }
166
167 static void combo_button_destroy(GtkWidget *widget, gpointer data)
168 {
169         ComboButton *combo = (ComboButton *)data;
170
171         gtk_object_destroy(GTK_OBJECT(combo->factory));
172         g_free(combo);
173 }
174
175 ComboButton *gtkut_combo_button_create(GtkWidget *button,
176                                        GtkItemFactoryEntry *entries,
177                                        gint n_entries, const gchar *path,
178                                        gpointer data)
179 {
180         ComboButton *combo;
181         GtkWidget *arrow;
182
183         combo = g_new0(ComboButton, 1);
184
185         combo->arrow = gtk_button_new();
186         arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
187         gtk_container_add(GTK_CONTAINER(combo->arrow), arrow);
188         GTK_WIDGET_UNSET_FLAGS(combo->arrow, GTK_CAN_FOCUS);
189         gtk_widget_show_all(combo->arrow);
190
191         combo->button = button;
192         combo->menu = menu_create_items(entries, n_entries, path,
193                                         &combo->factory, data);
194         combo->data = data;
195
196         gtk_signal_connect(GTK_OBJECT(combo->button), "size_request",
197                            GTK_SIGNAL_FUNC(combo_button_size_request), combo);
198         gtk_signal_connect(GTK_OBJECT(combo->button), "enter",
199                            GTK_SIGNAL_FUNC(combo_button_enter), combo);
200         gtk_signal_connect(GTK_OBJECT(combo->button), "leave",
201                            GTK_SIGNAL_FUNC(combo_button_leave), combo);
202         gtk_signal_connect(GTK_OBJECT(combo->arrow), "enter",
203                            GTK_SIGNAL_FUNC(combo_button_enter), combo);
204         gtk_signal_connect(GTK_OBJECT(combo->arrow), "leave",
205                            GTK_SIGNAL_FUNC(combo_button_leave), combo);
206         gtk_signal_connect(GTK_OBJECT(combo->arrow), "button_press_event",
207                            GTK_SIGNAL_FUNC(combo_button_arrow_pressed), combo);
208         gtk_signal_connect(GTK_OBJECT(combo->arrow), "destroy",
209                            GTK_SIGNAL_FUNC(combo_button_destroy), combo);
210
211         return combo;
212 }
213
214 #define CELL_SPACING 1
215 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
216                                     (((row) + 1) * CELL_SPACING) + \
217                                     (clist)->voffset)
218 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
219                                    ((clist)->row_height + CELL_SPACING))
220
221 void gtkut_ctree_node_move_if_on_the_edge(GtkCTree *ctree, GtkCTreeNode *node)
222 {
223         GtkCList *clist = GTK_CLIST(ctree);
224         gint row;
225         GtkVisibility row_visibility, prev_row_visibility, next_row_visibility;
226
227         g_return_if_fail(ctree != NULL);
228         g_return_if_fail(node != NULL);
229
230         row = g_list_position(clist->row_list, (GList *)node);
231         if (row < 0 || row >= clist->rows || clist->row_height == 0) return;
232         row_visibility = gtk_clist_row_is_visible(clist, row);
233         prev_row_visibility = gtk_clist_row_is_visible(clist, row - 1);
234         next_row_visibility = gtk_clist_row_is_visible(clist, row + 1);
235
236         if (row_visibility == GTK_VISIBILITY_NONE) {
237                 gtk_clist_moveto(clist, row, -1, 0.5, 0);
238                 return;
239         }
240         if (row_visibility == GTK_VISIBILITY_FULL &&
241             prev_row_visibility == GTK_VISIBILITY_FULL &&
242             next_row_visibility == GTK_VISIBILITY_FULL)
243                 return;
244         if (prev_row_visibility != GTK_VISIBILITY_FULL &&
245             next_row_visibility != GTK_VISIBILITY_FULL)
246                 return;
247
248         if (prev_row_visibility != GTK_VISIBILITY_FULL) {
249                 gtk_clist_moveto(clist, row, -1, 0.2, 0);
250                 return;
251         }
252         if (next_row_visibility != GTK_VISIBILITY_FULL) {
253                 gtk_clist_moveto(clist, row, -1, 0.8, 0);
254                 return;
255         }
256 }
257
258 #undef CELL_SPACING
259 #undef ROW_TOP_YPIXEL
260 #undef ROW_FROM_YPIXEL
261
262 gint gtkut_ctree_get_nth_from_node(GtkCTree *ctree, GtkCTreeNode *node)
263 {
264         g_return_val_if_fail(ctree != NULL, -1);
265         g_return_val_if_fail(node != NULL, -1);
266
267         return g_list_position(GTK_CLIST(ctree)->row_list, (GList *)node);
268 }
269
270 /* get the next node, including the invisible one */
271 GtkCTreeNode *gtkut_ctree_node_next(GtkCTree *ctree, GtkCTreeNode *node)
272 {
273         GtkCTreeNode *parent;
274
275         if (!node) return NULL;
276
277         if (GTK_CTREE_ROW(node)->children)
278                 return GTK_CTREE_ROW(node)->children;
279
280         if (GTK_CTREE_ROW(node)->sibling)
281                 return GTK_CTREE_ROW(node)->sibling;
282
283         for (parent = GTK_CTREE_ROW(node)->parent; parent != NULL;
284              parent = GTK_CTREE_ROW(parent)->parent) {
285                 if (GTK_CTREE_ROW(parent)->sibling)
286                         return GTK_CTREE_ROW(parent)->sibling;
287         }
288
289         return NULL;
290 }
291
292 /* get the previous node, including the invisible one */
293 GtkCTreeNode *gtkut_ctree_node_prev(GtkCTree *ctree, GtkCTreeNode *node)
294 {
295         GtkCTreeNode *prev;
296         GtkCTreeNode *child;
297
298         if (!node) return NULL;
299
300         prev = GTK_CTREE_NODE_PREV(node);
301         if (prev == GTK_CTREE_ROW(node)->parent)
302                 return prev;
303
304         child = prev;
305         while (GTK_CTREE_ROW(child)->children != NULL) {
306                 child = GTK_CTREE_ROW(child)->children;
307                 while (GTK_CTREE_ROW(child)->sibling != NULL)
308                         child = GTK_CTREE_ROW(child)->sibling;
309         }
310
311         return child;
312 }
313
314 gboolean gtkut_ctree_node_is_selected(GtkCTree *ctree, GtkCTreeNode *node)
315 {
316         GtkCList *clist = GTK_CLIST(ctree);
317         GList *cur;
318
319         for (cur = clist->selection; cur != NULL; cur = cur->next) {
320                 if (node == GTK_CTREE_NODE(cur->data))
321                         return TRUE;
322         }
323
324         return FALSE;
325 }
326
327 GtkCTreeNode *gtkut_ctree_find_collapsed_parent(GtkCTree *ctree,
328                                                 GtkCTreeNode *node)
329 {
330         if (!node) return NULL;
331
332         while ((node = GTK_CTREE_ROW(node)->parent) != NULL) {
333                 if (!GTK_CTREE_ROW(node)->expanded)
334                         return node;
335         }
336
337         return NULL;
338 }
339
340 void gtkut_ctree_expand_parent_all(GtkCTree *ctree, GtkCTreeNode *node)
341 {
342         while ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
343                 gtk_ctree_expand(ctree, node);
344 }
345
346 gboolean gtkut_ctree_node_is_parent(GtkCTreeNode *parent, GtkCTreeNode *node)
347 {
348         GtkCTreeNode *tmp;
349         g_return_val_if_fail(node != NULL, FALSE);
350         g_return_val_if_fail(parent != NULL, FALSE);
351         tmp = node;
352         
353         while (tmp) {
354                 if(GTK_CTREE_ROW(tmp)->parent && GTK_CTREE_ROW(tmp)->parent == parent)
355                         return TRUE;
356                 tmp = GTK_CTREE_ROW(tmp)->parent;
357         }
358         
359         return FALSE;
360 }
361
362 void gtkut_ctree_set_focus_row(GtkCTree *ctree, GtkCTreeNode *node)
363 {
364         gtkut_clist_set_focus_row(GTK_CLIST(ctree),
365                                   gtkut_ctree_get_nth_from_node(ctree, node));
366 }
367
368 void gtkut_clist_set_focus_row(GtkCList *clist, gint row)
369 {
370         clist->focus_row = row;
371         GTKUT_CTREE_REFRESH(clist);
372 }
373
374 void gtkut_combo_set_items(GtkCombo *combo, const gchar *str1, ...)
375 {
376         va_list args;
377         gchar *s;
378         GList *combo_items = NULL;
379
380         g_return_if_fail(str1 != NULL);
381
382         combo_items = g_list_append(combo_items, (gpointer)str1);
383         va_start(args, str1);
384         s = va_arg(args, gchar*);
385         while (s) {
386                 combo_items = g_list_append(combo_items, (gpointer)s);
387                 s = va_arg(args, gchar*);
388         }
389         va_end(args);
390
391         gtk_combo_set_popdown_strings(combo, combo_items);
392
393         g_list_free(combo_items);
394 }
395
396 gchar *gtkut_editable_get_selection(GtkEditable *editable)
397 {
398         guint start_pos, end_pos;
399         gboolean found;
400
401         g_return_val_if_fail(GTK_IS_EDITABLE(editable), NULL);
402
403         found = gtk_editable_get_selection_bounds(editable,
404                                                   &start_pos, &end_pos);
405         if (found)
406                 return gtk_editable_get_chars(editable, start_pos, end_pos);
407         else
408                 return NULL;
409 }
410
411 /*
412  * Walk through the widget tree and disclaim the selection from all currently
413  * realized GtkEditable widgets.
414  */
415 static void gtkut_check_before_remove(GtkWidget *widget, gpointer unused)
416 {
417         g_return_if_fail(widget != NULL);
418
419         if (!GTK_WIDGET_REALIZED(widget))
420                 return; /* all nested widgets must be unrealized too */
421         if (GTK_IS_CONTAINER(widget))
422                 gtk_container_forall(GTK_CONTAINER(widget),
423                                      gtkut_check_before_remove, NULL);
424 #warning FIXME_GTK2
425 #if 0
426         if (GTK_IS_EDITABLE(widget))
427                 gtk_editable_claim_selection(GTK_EDITABLE(widget),
428                                              FALSE, GDK_CURRENT_TIME);
429 #endif
430 }
431
432 /*
433  * Wrapper around gtk_container_remove to work around a bug in GtkText and
434  * GtkEntry (in all GTK+ versions up to and including at least 1.2.10).
435  *
436  * The problem is that unrealizing a GtkText or GtkEntry widget which has the
437  * active selection completely messes up selection handling, leading to
438  * non-working selections and crashes.  Removing a widget from its container
439  * implies unrealizing it and all its child widgets; this triggers the bug if
440  * the removed widget or any of its children is GtkText or GtkEntry.  As a
441  * workaround, this function walks through the widget subtree before removing
442  * and disclaims the selection from all GtkEditable widgets found.
443  *
444  * A similar workaround may be needed for gtk_widget_reparent(); currently it
445  * is not necessary because Sylpheed does not use gtk_widget_reparent() for
446  * GtkEditable widgets or containers holding such widgets.
447  */
448 void gtkut_container_remove(GtkContainer *container, GtkWidget *widget)
449 {
450         gtkut_check_before_remove(widget, NULL);
451         gtk_container_remove(container, widget);
452 }
453
454 void gtkut_window_popup(GtkWidget *window)
455 {
456         gint x, y, sx, sy, new_x, new_y;
457
458         g_return_if_fail(window != NULL);
459         g_return_if_fail(window->window != NULL);
460
461         sx = gdk_screen_width();
462         sy = gdk_screen_height();
463
464         gdk_window_get_origin(window->window, &x, &y);
465         new_x = x % sx; if (new_x < 0) new_x = 0;
466         new_y = y % sy; if (new_y < 0) new_y = 0;
467         if (new_x != x || new_y != y)
468                 gdk_window_move(window->window, new_x, new_y);
469
470         gdk_window_raise(window->window);
471         gdk_window_show(window->window);
472 }
473
474 void gtkut_widget_get_uposition(GtkWidget *widget, gint *px, gint *py)
475 {
476         gint x, y;
477         gint sx, sy;
478
479         g_return_if_fail(widget != NULL);
480         g_return_if_fail(widget->window != NULL);
481
482         sx = gdk_screen_width();
483         sy = gdk_screen_height();
484
485         /* gdk_window_get_root_origin ever return *rootwindow*'s position */
486         gdk_window_get_root_origin(widget->window, &x, &y);
487
488         x %= sx; if (x < 0) x = 0;
489         y %= sy; if (y < 0) y = 0;
490         *px = x;
491         *py = y;
492 }
493
494 void gtkut_widget_disable_theme_engine(GtkWidget *widget)
495 {
496 #warning FIXME_GTK2
497 #if 0
498         GtkStyle *style, *new_style;
499
500         style = gtk_widget_get_style(widget);
501
502         if (style->engine) {
503                 GtkThemeEngine *engine;
504
505                 engine = style->engine;
506                 style->engine = NULL;
507                 new_style = gtk_style_copy(style);
508                 style->engine = engine;
509                 gtk_widget_set_style(widget, new_style);
510         }
511 #endif
512 }
513
514 void gtkut_widget_wait_for_draw(GtkWidget *widget)
515 {
516         if (!GTK_WIDGET_DRAWABLE(widget)) return;
517
518         while (gtk_events_pending())
519                 gtk_main_iteration();
520 }
521
522 static void gtkut_clist_bindings_add(GtkWidget *clist)
523 {
524         GtkBindingSet *binding_set;
525
526         binding_set = gtk_binding_set_by_class
527                 (GTK_CLIST_GET_CLASS(clist));
528
529         gtk_binding_entry_add_signal(binding_set, GDK_n, GDK_CONTROL_MASK,
530                                      "scroll_vertical", 2,
531                                      G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
532                                      G_TYPE_FLOAT, 0.0);
533         gtk_binding_entry_add_signal(binding_set, GDK_p, GDK_CONTROL_MASK,
534                                      "scroll_vertical", 2,
535                                      G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
536                                      G_TYPE_FLOAT, 0.0);
537 }
538
539 void gtkut_widget_init(void)
540 {
541         GtkWidget *clist;
542
543         clist = gtk_clist_new(1);
544         g_object_ref(G_OBJECT(clist));
545         gtk_object_sink(GTK_OBJECT(clist));
546         gtkut_clist_bindings_add(clist);
547         g_object_unref(G_OBJECT(clist));
548
549         clist = gtk_ctree_new(1, 0);
550         g_object_ref(G_OBJECT(clist));
551         gtk_object_sink(GTK_OBJECT(clist));
552         gtkut_clist_bindings_add(clist);
553         g_object_unref(G_OBJECT(clist));
554
555         clist = gtk_sctree_new_with_titles(1, 0, NULL);
556         g_object_ref(G_OBJECT(clist));
557         gtk_object_sink(GTK_OBJECT(clist));
558         gtkut_clist_bindings_add(clist);
559         g_object_unref(G_OBJECT(clist));
560 }
561
562 void gtkut_widget_set_app_icon(GtkWidget *widget)
563 {
564 #include "pixmaps/sylpheed.xpm" 
565         static GdkPixmap *sylpheedxpm;
566         static GdkBitmap *sylpheedxpmmask;
567         
568         g_return_if_fail(widget != NULL);
569         g_return_if_fail(widget->window != NULL);
570         if (!sylpheedxpm) {
571                 PIXMAP_CREATE(widget, sylpheedxpm, sylpheedxpmmask, sylpheed_xpm);
572         }               
573         gdk_window_set_icon(widget->window, NULL, sylpheedxpm, sylpheedxpmmask);
574 }
575
576 void gtkut_widget_set_composer_icon(GtkWidget *widget)
577 {
578         static GdkPixmap *xpm;
579         static GdkBitmap *bmp;
580
581         g_return_if_fail(widget != NULL);
582         g_return_if_fail(widget->window != NULL);
583         if (!xpm) {
584                 stock_pixmap_gdk(widget, STOCK_PIXMAP_MAIL_COMPOSE, &xpm, &bmp);
585         }
586         gdk_window_set_icon(widget->window, NULL, xpm, bmp);    
587 }
588
589 GtkWidget *gtkut_account_menu_new(GList                 *ac_list,
590                                   GtkSignalFunc          callback,
591                                   gpointer               data)
592 {
593         GList *cur_ac;
594         GtkWidget *menu;
595         
596         g_return_val_if_fail(ac_list != NULL, NULL);
597
598         menu = gtk_menu_new();
599
600         for (cur_ac = ac_list; cur_ac != NULL; cur_ac = cur_ac->next) {
601                 gchar *name;
602                 GtkWidget *menuitem;
603                 PrefsAccount *account;
604                 
605                 account = (PrefsAccount *) cur_ac->data;
606                 if (account->name)
607                         name = g_strdup_printf("%s: %s <%s>",
608                                                account->account_name,
609                                                account->name,
610                                                account->address);
611                 else
612                         name = g_strdup_printf("%s: %s",
613                                                account->account_name,
614                                                account->address);
615                 MENUITEM_ADD(menu, menuitem, name, account->account_id);
616                 g_free(name);
617                 if (callback != NULL)
618                         gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
619                                            callback,
620                                            data);
621         }
622         return menu;
623 }
624
625 void gtkut_set_widget_bgcolor_rgb(GtkWidget *widget, guint rgbvalue)
626 {
627         GtkStyle *newstyle;
628         GdkColor gdk_color;
629
630         gtkut_convert_int_to_gdk_color(rgbvalue, &gdk_color);
631         newstyle = gtk_style_copy(gtk_widget_get_default_style());
632         newstyle->bg[GTK_STATE_NORMAL]   = gdk_color;
633         newstyle->bg[GTK_STATE_PRELIGHT] = gdk_color;
634         newstyle->bg[GTK_STATE_ACTIVE]   = gdk_color;
635         gtk_widget_set_style(widget, newstyle);
636 }
637   
638 #warning FIXME_GTK2
639 #if 1 /* FIXME_GTK2 */
640 gboolean gtkut_text_buffer_match_string(GtkTextBuffer *textbuf, gint pos, gunichar *wcs,
641                                         gint len, gboolean case_sens)
642 {
643         GtkTextIter start_iter, end_iter;
644         gchar *utf8str;
645         gint match_count = 0;
646
647         gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter, pos);
648         gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter, pos + len);
649
650         utf8str = gtk_text_buffer_get_text(textbuf, &start_iter, &end_iter, FALSE);
651         if (!utf8str) return FALSE;
652
653         if ((gint) g_utf8_strlen(utf8str, -1) != len) {
654                 g_free(utf8str);
655                 return FALSE;
656         }
657
658         for (; match_count < len; pos++, match_count++) {
659                 gchar *ptr = g_utf8_offset_to_pointer(utf8str, match_count);
660                 gunichar ch;
661
662                 if (!ptr) break;
663                 ch = g_utf8_get_char(ptr);
664
665                 if (case_sens) {
666                         if (ch != wcs[match_count])
667                                 break;
668                 } else {
669                         if (g_unichar_tolower(ch) !=
670                             g_unichar_tolower(wcs[match_count]))
671                                 break;
672                 }
673         }
674
675         g_free(utf8str);
676
677         if (match_count == len)
678                 return TRUE;
679         else
680                 return FALSE;
681 }
682
683 guint gtkut_text_buffer_str_compare_n(GtkTextBuffer *textbuf,
684                                       guint pos1, guint pos2,
685                                       guint len, guint text_len)
686 {
687         guint i;
688
689         for (i = 0; i < len && pos1 + i < text_len && pos2 + i < text_len; i++) {
690                 GtkTextIter start_iter, end_iter;
691                 gchar *utf8str1, *utf8str2;
692
693                 gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter,
694                                                    pos1 + i);
695                 gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter,
696                                                    pos1 + i + 1);
697                 utf8str1 = gtk_text_buffer_get_text(textbuf,
698                                                     &start_iter,
699                                                     &end_iter,
700                                                     FALSE);
701
702                 gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter,
703                                                    pos2 + i);
704                 gtk_text_buffer_get_iter_at_offset(textbuf, &end_iter,
705                                                    pos2 + i + 1);
706                 utf8str2 = gtk_text_buffer_get_text(textbuf,
707                                                     &start_iter,
708                                                     &end_iter,
709                                                     FALSE);
710
711                 if (!utf8str1 || !utf8str2 || strcmp(utf8str1, utf8str2)) {
712                         g_free(utf8str1);
713                         g_free(utf8str2);
714                         break;
715                 }
716
717                 g_free(utf8str1);
718                 g_free(utf8str2);
719         }
720
721         return i;
722 }
723
724 guint gtkut_text_buffer_str_compare(GtkTextBuffer *textbuf,
725                                     guint start_pos, guint text_len,
726                                     const gchar *str)
727 {
728         gunichar *wcs;
729         guint len = 0;
730         glong items_read = 0, items_written = 0;
731         gboolean result;
732         GError *error = NULL;
733
734         if (!str) return 0;
735
736         wcs = g_utf8_to_ucs4(str, -1, &items_read, &items_written, &error);
737         if (error != NULL) {
738                 g_warning("An error occured while converting a string from UTF-8 to UCS-4: %s\n",
739                           error->message);
740                 g_error_free(error);
741         }
742         if (!wcs || items_written <= 0) return 0;
743         len = (guint) items_written;
744
745         if (len > text_len - start_pos)
746                 result = FALSE;
747         else
748                 result = gtkut_text_buffer_match_string(textbuf, start_pos,
749                                                         wcs, len,
750                                                         TRUE);
751
752         g_free(wcs);
753
754         return result ? len : 0;
755 }
756
757 gboolean gtkut_text_buffer_is_uri_string(GtkTextBuffer *textbuf,
758                                          guint start_pos, guint text_len)
759 {
760         if (gtkut_text_buffer_str_compare(textbuf, start_pos, text_len, "http://")  ||
761             gtkut_text_buffer_str_compare(textbuf, start_pos, text_len, "ftp://")   ||
762             gtkut_text_buffer_str_compare(textbuf, start_pos, text_len, "https://") ||
763             gtkut_text_buffer_str_compare(textbuf, start_pos, text_len, "www."))
764                 return TRUE;
765
766         return FALSE;
767 }
768   
769 gchar *gtkut_text_view_get_selection(GtkTextView *textview)
770 {
771         GtkTextBuffer *buffer;
772         GtkTextIter start_iter, end_iter;
773         gboolean found;
774
775         g_return_val_if_fail(GTK_IS_TEXT_VIEW(textview), NULL);
776
777         buffer = gtk_text_view_get_buffer(textview);
778         found = gtk_text_buffer_get_selection_bounds(buffer,
779                                                      &start_iter,
780                                                      &end_iter);
781         if (found)
782                 return gtk_text_buffer_get_text(buffer, &start_iter, &end_iter,
783                                                 FALSE);
784         else
785                 return NULL;
786 }
787 #endif /* FIXME_GTK2 */