Statistics
| Revision:

root / src / gtkutils.c @ 202

History | View | Annotate | Download (20 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2005 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 <glib/gi18n.h>
26
#include <gdk/gdkkeysyms.h>
27
#include <gdk/gdk.h>
28
#include <gtk/gtkwidget.h>
29
#include <gtk/gtkhbbox.h>
30
#include <gtk/gtkbutton.h>
31
#include <gtk/gtkctree.h>
32
#include <gtk/gtkcombo.h>
33
#include <gtk/gtkbindings.h>
34
#include <gtk/gtkitemfactory.h>
35
#include <stdlib.h>
36
#include <stdarg.h>
37
38
#if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
39
#  include <wchar.h>
40
#  include <wctype.h>
41
#endif
42
43
#include "gtkutils.h"
44
#include "utils.h"
45
#include "gtksctree.h"
46
#include "codeconv.h"
47
#include "menu.h"
48
49
#warning FIXME_GTK2
50
gboolean gtkut_get_font_size(GtkWidget *widget, gint *width, gint *height)
51
{
52
        PangoLayout *layout;
53
        const gchar *str = "Abcdef";
54
55
        g_return_val_if_fail(GTK_IS_WIDGET(widget), FALSE);
56
57
        layout = gtk_widget_create_pango_layout(widget, str);
58
        g_return_val_if_fail(layout, FALSE);
59
        pango_layout_get_pixel_size(layout, width, height);
60
        if (width)
61
                *width = *width / g_utf8_strlen(str, -1);
62
        g_object_unref(layout);
63
64
        return TRUE;
65
}
66
67
PangoFontDescription *gtkut_get_default_font_desc(void)
68
{
69
        static PangoFontDescription *font_desc = NULL;
70
71
        if (!font_desc) {
72
                GtkWidget *window;
73
74
                window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
75
                gtk_widget_ensure_style(window);
76
                font_desc = pango_font_description_copy
77
                        (window->style->font_desc);
78
                gtk_object_sink(GTK_OBJECT(window));
79
        }
80
81
        return pango_font_description_copy(font_desc);
82
}
83
84
void gtkut_widget_set_small_font_size(GtkWidget *widget)
85
{
86
        PangoFontDescription *font_desc;
87
        gint size;
88
89
        g_return_if_fail(widget != NULL);
90
        g_return_if_fail(widget->style != NULL);
91
92
        font_desc = gtkut_get_default_font_desc();
93
        size = pango_font_description_get_size(font_desc);
94
        pango_font_description_set_size(font_desc, size * PANGO_SCALE_SMALL);
95
        gtk_widget_modify_font(widget, font_desc);
96
        pango_font_description_free(font_desc);
97
}
98
99
void gtkut_convert_int_to_gdk_color(gint rgbvalue, GdkColor *color)
100
{
101
        g_return_if_fail(color != NULL);
102
103
        color->pixel = 0L;
104
        color->red   = (int) (((gdouble)((rgbvalue & 0xff0000) >> 16) / 255.0) * 65535.0);
105
        color->green = (int) (((gdouble)((rgbvalue & 0x00ff00) >>  8) / 255.0) * 65535.0);
106
        color->blue  = (int) (((gdouble) (rgbvalue & 0x0000ff)        / 255.0) * 65535.0);
107
}
108
109
void gtkut_stock_button_set_create(GtkWidget **bbox,
110
                                   GtkWidget **button1, const gchar *label1,
111
                                   GtkWidget **button2, const gchar *label2,
112
                                   GtkWidget **button3, const gchar *label3)
113
{
114
        g_return_if_fail(bbox != NULL);
115
        g_return_if_fail(button1 != NULL);
116
117
        *bbox = gtk_hbutton_box_new();
118
        gtk_button_box_set_layout(GTK_BUTTON_BOX(*bbox), GTK_BUTTONBOX_END);
119
        gtk_box_set_spacing(GTK_BOX(*bbox), 5);
120
121
        *button1 = gtk_button_new_from_stock(label1);
122
        GTK_WIDGET_SET_FLAGS(*button1, GTK_CAN_DEFAULT);
123
        gtk_box_pack_start(GTK_BOX(*bbox), *button1, TRUE, TRUE, 0);
124
        gtk_widget_show(*button1);
125
126
        if (button2) {
127
                *button2 = gtk_button_new_from_stock(label2);
128
                GTK_WIDGET_SET_FLAGS(*button2, GTK_CAN_DEFAULT);
129
                gtk_box_pack_start(GTK_BOX(*bbox), *button2, TRUE, TRUE, 0);
130
                gtk_widget_show(*button2);
131
        }
132
133
        if (button3) {
134
                *button3 = gtk_button_new_from_stock(label3);
135
                GTK_WIDGET_SET_FLAGS(*button3, GTK_CAN_DEFAULT);
136
                gtk_box_pack_start(GTK_BOX(*bbox), *button3, TRUE, TRUE, 0);
137
                gtk_widget_show(*button3);
138
        }
139
}
140
141
static void combo_button_size_request(GtkWidget *widget,
142
                                      GtkRequisition *requisition,
143
                                      gpointer data)
144
{
145
        ComboButton *combo = (ComboButton *)data;
146
147
        if (combo->arrow->allocation.height != requisition->height)
148
                gtk_widget_set_size_request(combo->arrow,
149
                                            -1, requisition->height);
150
}
151
152
static void combo_button_enter(GtkWidget *widget, gpointer data)
153
{
154
        ComboButton *combo = (ComboButton *)data;
155
156
        if (GTK_WIDGET_STATE(combo->arrow) != GTK_STATE_PRELIGHT) {
157
                gtk_widget_set_state(combo->arrow, GTK_STATE_PRELIGHT);
158
                gtk_widget_queue_draw(combo->arrow);
159
        }
160
        if (GTK_WIDGET_STATE(combo->button) != GTK_STATE_PRELIGHT) {
161
                gtk_widget_set_state(combo->button, GTK_STATE_PRELIGHT);
162
                gtk_widget_queue_draw(combo->button);
163
        }
164
}
165
166
static void combo_button_leave(GtkWidget *widget, gpointer data)
167
{
168
        ComboButton *combo = (ComboButton *)data;
169
170
        if (GTK_WIDGET_STATE(combo->arrow) != GTK_STATE_NORMAL) {
171
                gtk_widget_set_state(combo->arrow, GTK_STATE_NORMAL);
172
                gtk_widget_queue_draw(combo->arrow);
173
        }
174
        if (GTK_WIDGET_STATE(combo->button) != GTK_STATE_NORMAL) {
175
                gtk_widget_set_state(combo->button, GTK_STATE_NORMAL);
176
                gtk_widget_queue_draw(combo->button);
177
        }
178
}
179
180
static gint combo_button_arrow_pressed(GtkWidget *widget, GdkEventButton *event,
181
                                       gpointer data)
182
{
183
        ComboButton *combo = (ComboButton *)data;
184
185
        if (!event) return FALSE;
186
187
        gtk_menu_popup(GTK_MENU(combo->menu), NULL, NULL,
188
                       menu_button_position, combo->button,
189
                       event->button, event->time);
190
191
        return TRUE;
192
}
193
194
static void combo_button_destroy(GtkWidget *widget, gpointer data)
195
{
196
        ComboButton *combo = (ComboButton *)data;
197
198
        gtk_object_destroy(GTK_OBJECT(combo->factory));
199
        g_free(combo);
200
}
201
202
ComboButton *gtkut_combo_button_create(GtkWidget *button,
203
                                       GtkItemFactoryEntry *entries,
204
                                       gint n_entries, const gchar *path,
205
                                       gpointer data)
206
{
207
        ComboButton *combo;
208
        GtkWidget *arrow;
209
210
        combo = g_new0(ComboButton, 1);
211
212
        combo->arrow = gtk_button_new();
213
        arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
214
        gtk_widget_set_size_request(arrow, 7, -1);
215
        gtk_container_add(GTK_CONTAINER(combo->arrow), arrow);
216
        GTK_WIDGET_UNSET_FLAGS(combo->arrow, GTK_CAN_FOCUS);
217
        gtk_widget_show_all(combo->arrow);
218
219
        combo->button = button;
220
        combo->menu = menu_create_items(entries, n_entries, path,
221
                                        &combo->factory, data);
222
        combo->data = data;
223
224
        g_signal_connect(G_OBJECT(combo->button), "size_request",
225
                         G_CALLBACK(combo_button_size_request), combo);
226
        g_signal_connect(G_OBJECT(combo->button), "enter",
227
                         G_CALLBACK(combo_button_enter), combo);
228
        g_signal_connect(G_OBJECT(combo->button), "leave",
229
                         G_CALLBACK(combo_button_leave), combo);
230
        g_signal_connect(G_OBJECT(combo->arrow), "enter",
231
                         G_CALLBACK(combo_button_enter), combo);
232
        g_signal_connect(G_OBJECT(combo->arrow), "leave",
233
                         G_CALLBACK(combo_button_leave), combo);
234
        g_signal_connect(G_OBJECT(combo->arrow), "button_press_event",
235
                         G_CALLBACK(combo_button_arrow_pressed), combo);
236
        g_signal_connect(G_OBJECT(combo->arrow), "destroy",
237
                         G_CALLBACK(combo_button_destroy), combo);
238
239
        return combo;
240
}
241
242
#define CELL_SPACING 1
243
#define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
244
                                    (((row) + 1) * CELL_SPACING) + \
245
                                    (clist)->voffset)
246
#define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
247
                                   ((clist)->row_height + CELL_SPACING))
248
249
void gtkut_ctree_node_move_if_on_the_edge(GtkCTree *ctree, GtkCTreeNode *node)
250
{
251
        GtkCList *clist = GTK_CLIST(ctree);
252
        gint row;
253
        GtkVisibility row_visibility, prev_row_visibility, next_row_visibility;
254
255
        g_return_if_fail(ctree != NULL);
256
        g_return_if_fail(node != NULL);
257
258
        row = g_list_position(clist->row_list, (GList *)node);
259
        if (row < 0 || row >= clist->rows || clist->row_height == 0) return;
260
        row_visibility = gtk_clist_row_is_visible(clist, row);
261
        prev_row_visibility = gtk_clist_row_is_visible(clist, row - 1);
262
        next_row_visibility = gtk_clist_row_is_visible(clist, row + 1);
263
264
        if (row_visibility == GTK_VISIBILITY_NONE) {
265
                gtk_clist_moveto(clist, row, -1, 0.5, 0);
266
                return;
267
        }
268
        if (row_visibility == GTK_VISIBILITY_FULL &&
269
            prev_row_visibility == GTK_VISIBILITY_FULL &&
270
            next_row_visibility == GTK_VISIBILITY_FULL)
271
                return;
272
        if (prev_row_visibility != GTK_VISIBILITY_FULL &&
273
            next_row_visibility != GTK_VISIBILITY_FULL)
274
                return;
275
276
        if (prev_row_visibility != GTK_VISIBILITY_FULL) {
277
                gtk_clist_moveto(clist, row, -1, 0.2, 0);
278
                return;
279
        }
280
        if (next_row_visibility != GTK_VISIBILITY_FULL) {
281
                gtk_clist_moveto(clist, row, -1, 0.8, 0);
282
                return;
283
        }
284
}
285
286
#undef CELL_SPACING
287
#undef ROW_TOP_YPIXEL
288
#undef ROW_FROM_YPIXEL
289
290
gint gtkut_ctree_get_nth_from_node(GtkCTree *ctree, GtkCTreeNode *node)
291
{
292
        g_return_val_if_fail(ctree != NULL, -1);
293
        g_return_val_if_fail(node != NULL, -1);
294
295
        return g_list_position(GTK_CLIST(ctree)->row_list, (GList *)node);
296
}
297
298
/* get the next node, including the invisible one */
299
GtkCTreeNode *gtkut_ctree_node_next(GtkCTree *ctree, GtkCTreeNode *node)
300
{
301
        GtkCTreeNode *parent;
302
303
        if (!node) return NULL;
304
305
        if (GTK_CTREE_ROW(node)->children)
306
                return GTK_CTREE_ROW(node)->children;
307
308
        if (GTK_CTREE_ROW(node)->sibling)
309
                return GTK_CTREE_ROW(node)->sibling;
310
311
        for (parent = GTK_CTREE_ROW(node)->parent; parent != NULL;
312
             parent = GTK_CTREE_ROW(parent)->parent) {
313
                if (GTK_CTREE_ROW(parent)->sibling)
314
                        return GTK_CTREE_ROW(parent)->sibling;
315
        }
316
317
        return NULL;
318
}
319
320
/* get the previous node, including the invisible one */
321
GtkCTreeNode *gtkut_ctree_node_prev(GtkCTree *ctree, GtkCTreeNode *node)
322
{
323
        GtkCTreeNode *prev;
324
        GtkCTreeNode *child;
325
326
        if (!node) return NULL;
327
328
        prev = GTK_CTREE_NODE_PREV(node);
329
        if (prev == GTK_CTREE_ROW(node)->parent)
330
                return prev;
331
332
        child = prev;
333
        while (GTK_CTREE_ROW(child)->children != NULL) {
334
                child = GTK_CTREE_ROW(child)->children;
335
                while (GTK_CTREE_ROW(child)->sibling != NULL)
336
                        child = GTK_CTREE_ROW(child)->sibling;
337
        }
338
339
        return child;
340
}
341
342
gboolean gtkut_ctree_node_is_selected(GtkCTree *ctree, GtkCTreeNode *node)
343
{
344
        GtkCList *clist = GTK_CLIST(ctree);
345
        GList *cur;
346
347
        for (cur = clist->selection; cur != NULL; cur = cur->next) {
348
                if (node == GTK_CTREE_NODE(cur->data))
349
                        return TRUE;
350
        }
351
352
        return FALSE;
353
}
354
355
GtkCTreeNode *gtkut_ctree_find_collapsed_parent(GtkCTree *ctree,
356
                                                GtkCTreeNode *node)
357
{
358
        if (!node) return NULL;
359
360
        while ((node = GTK_CTREE_ROW(node)->parent) != NULL) {
361
                if (!GTK_CTREE_ROW(node)->expanded)
362
                        return node;
363
        }
364
365
        return NULL;
366
}
367
368
void gtkut_ctree_expand_parent_all(GtkCTree *ctree, GtkCTreeNode *node)
369
{
370
        while ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
371
                gtk_ctree_expand(ctree, node);
372
}
373
374
void gtkut_ctree_set_focus_row(GtkCTree *ctree, GtkCTreeNode *node)
375
{
376
        gtkut_clist_set_focus_row(GTK_CLIST(ctree),
377
                                  gtkut_ctree_get_nth_from_node(ctree, node));
378
}
379
380
void gtkut_clist_set_focus_row(GtkCList *clist, gint row)
381
{
382
        clist->focus_row = row;
383
        GTKUT_CTREE_REFRESH(clist);
384
}
385
386
gboolean gtkut_tree_model_next(GtkTreeModel *model, GtkTreeIter *iter)
387
{
388
        GtkTreeIter iter_, parent;
389
        gboolean valid;
390
391
        if (gtk_tree_model_iter_children(model, &iter_, iter)) {
392
                *iter = iter_;
393
                return TRUE;
394
        }
395
396
        iter_ = *iter;
397
        if (gtk_tree_model_iter_next(model, &iter_)) {
398
                *iter = iter_;
399
                return TRUE;
400
        }
401
402
        iter_ = *iter;
403
        valid = gtk_tree_model_iter_parent(model, &parent, &iter_);
404
        while (valid) {
405
                iter_ = parent;
406
                if (gtk_tree_model_iter_next(model, &iter_)) {
407
                        *iter = iter_;
408
                        return TRUE;
409
                }
410
411
                iter_ = parent;
412
                valid = gtk_tree_model_iter_parent(model, &parent, &iter_);
413
        }
414
415
        return FALSE;
416
}
417
418
gboolean gtkut_tree_model_find_by_column_data(GtkTreeModel *model,
419
                                              GtkTreeIter *iter,
420
                                              GtkTreeIter *start,
421
                                              gint col, gpointer data)
422
{
423
        gboolean valid;
424
        GtkTreeIter iter_;
425
        gpointer store_data;
426
427
        if (start)
428
                valid = gtk_tree_model_iter_children(model, &iter_, start);
429
        else
430
                valid = gtk_tree_model_get_iter_first(model, &iter_);
431
432
        while (valid) {
433
                gtk_tree_model_get(model, &iter_, col, &store_data, -1);
434
                if (store_data == data) {
435
                        *iter = iter_;
436
                        return TRUE;
437
                }
438
439
                if (gtk_tree_model_iter_has_child(model, &iter_)) {
440
                        if (gtkut_tree_model_find_by_column_data
441
                                (model, iter, &iter_, col, data)) {
442
                                return TRUE;
443
                        }
444
                }
445
446
                valid = gtk_tree_model_iter_next(model, &iter_);
447
        }
448
449
        return FALSE;
450
}
451
452
gboolean gtkut_tree_view_find_collapsed_parent(GtkTreeView *treeview,
453
                                               GtkTreeIter *parent,
454
                                               GtkTreeIter *iter)
455
{
456
        GtkTreeModel *model;
457
        GtkTreeIter iter_, parent_;
458
        GtkTreePath *path;
459
        gboolean valid;
460
461
        if (!iter) return FALSE;
462
463
        model = gtk_tree_view_get_model(treeview);
464
        valid = gtk_tree_model_iter_parent(model, &parent_, iter);
465
466
        while (valid) {
467
                path = gtk_tree_model_get_path(model, &parent_);
468
                if (!gtk_tree_view_row_expanded(treeview, path)) {
469
                        *parent = parent_;
470
                        gtk_tree_path_free(path);
471
                        return TRUE;
472
                }
473
                gtk_tree_path_free(path);
474
                iter_ = parent_;
475
                valid = gtk_tree_model_iter_parent(model, &parent_, &iter_);
476
        }
477
478
        return FALSE;
479
}
480
481
void gtkut_combo_set_items(GtkCombo *combo, const gchar *str1, ...)
482
{
483
        va_list args;
484
        gchar *s;
485
        GList *combo_items = NULL;
486
487
        g_return_if_fail(str1 != NULL);
488
489
        combo_items = g_list_append(combo_items, (gpointer)str1);
490
        va_start(args, str1);
491
        s = va_arg(args, gchar*);
492
        while (s) {
493
                combo_items = g_list_append(combo_items, (gpointer)s);
494
                s = va_arg(args, gchar*);
495
        }
496
        va_end(args);
497
498
        gtk_combo_set_popdown_strings(combo, combo_items);
499
500
        g_list_free(combo_items);
501
}
502
503
gchar *gtkut_editable_get_selection(GtkEditable *editable)
504
{
505
        guint start_pos, end_pos;
506
        gboolean found;
507
508
        g_return_val_if_fail(GTK_IS_EDITABLE(editable), NULL);
509
510
        found = gtk_editable_get_selection_bounds(editable,
511
                                                  &start_pos, &end_pos);
512
        if (found)
513
                return gtk_editable_get_chars(editable, start_pos, end_pos);
514
        else
515
                return NULL;
516
}
517
518
void gtkut_editable_disable_im(GtkEditable *editable)
519
{
520
        g_return_if_fail(editable != NULL);
521
522
#if USE_XIM
523
        if (editable->ic) {
524
                gdk_ic_destroy(editable->ic);
525
                editable->ic = NULL;
526
        }
527
        if (editable->ic_attr) {
528
                gdk_ic_attr_destroy(editable->ic_attr);
529
                editable->ic_attr = NULL;
530
        }
531
#endif
532
}
533
534
void gtkut_container_remove(GtkContainer *container, GtkWidget *widget)
535
{
536
        gtk_container_remove(container, widget);
537
}
538
539
void gtkut_scrolled_window_reset_position(GtkScrolledWindow *window)
540
{
541
        GtkAdjustment *adj;
542
543
        adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(window));
544
        gtk_adjustment_set_value(adj, adj->lower);
545
        adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(window));
546
        gtk_adjustment_set_value(adj, adj->lower);
547
}
548
549
gboolean gtkut_text_buffer_match_string(GtkTextBuffer *textbuf,
550
                                        const GtkTextIter *iter,
551
                                        gunichar *wcs, gint len,
552
                                        gboolean case_sens)
553
{
554
        GtkTextIter start_iter, end_iter;
555
        gchar *utf8str, *p;
556
        gint match_count;
557
558
        start_iter = end_iter = *iter;
559
        gtk_text_iter_forward_chars(&end_iter, len);
560
561
        utf8str = gtk_text_buffer_get_text(textbuf, &start_iter, &end_iter,
562
                                           FALSE);
563
        if (!utf8str) return FALSE;
564
565
        if ((gint)g_utf8_strlen(utf8str, -1) != len) {
566
                g_free(utf8str);
567
                return FALSE;
568
        }
569
570
        for (p = utf8str, match_count = 0;
571
             *p != '\0' && match_count < len;
572
             p = g_utf8_next_char(p), match_count++) {
573
                gunichar wc;
574
575
                wc = g_utf8_get_char(p);
576
577
                if (case_sens) {
578
                        if (wc != wcs[match_count])
579
                                break;
580
                } else {
581
                        if (g_unichar_tolower(wc) !=
582
                            g_unichar_tolower(wcs[match_count]))
583
                                break;
584
                }
585
        }
586
587
        g_free(utf8str);
588
589
        if (match_count == len)
590
                return TRUE;
591
        else
592
                return FALSE;
593
}
594
595
gboolean gtkut_text_buffer_find(GtkTextBuffer *buffer, const GtkTextIter *iter,
596
                                const gchar *str, gboolean case_sens,
597
                                GtkTextIter *match_pos)
598
{
599
        gunichar *wcs;
600
        gint len;
601
        glong items_read = 0, items_written = 0;
602
        GError *error = NULL;
603
        GtkTextIter iter_;
604
        gboolean found = FALSE;
605
606
        wcs = g_utf8_to_ucs4(str, -1, &items_read, &items_written, &error);
607
        if (error != NULL) {
608
                g_warning("An error occured while converting a string from UTF-8 to UCS-4: %s\n", error->message);
609
                g_error_free(error);
610
        }
611
        if (!wcs || items_written <= 0) return FALSE;
612
        len = (gint)items_written;
613
614
        iter_ = *iter;
615
        do {
616
                found = gtkut_text_buffer_match_string
617
                        (buffer, &iter_, wcs, len, case_sens);
618
                if (found) {
619
                        *match_pos = iter_;
620
                        break;
621
                }
622
        } while (gtk_text_iter_forward_char(&iter_));
623
624
        g_free(wcs);
625
626
        return found;
627
}
628
629
gboolean gtkut_text_buffer_find_backward(GtkTextBuffer *buffer,
630
                                         const GtkTextIter *iter,
631
                                         const gchar *str, gboolean case_sens,
632
                                         GtkTextIter *match_pos)
633
{
634
        gunichar *wcs;
635
        gint len;
636
        glong items_read = 0, items_written = 0;
637
        GError *error = NULL;
638
        GtkTextIter iter_;
639
        gboolean found = FALSE;
640
641
        wcs = g_utf8_to_ucs4(str, -1, &items_read, &items_written, &error);
642
        if (error != NULL) {
643
                g_warning("An error occured while converting a string from UTF-8 to UCS-4: %s\n", error->message);
644
                g_error_free(error);
645
        }
646
        if (!wcs || items_written <= 0) return FALSE;
647
        len = (gint)items_written;
648
649
        iter_ = *iter;
650
        while (gtk_text_iter_backward_char(&iter_)) {
651
                found = gtkut_text_buffer_match_string
652
                        (buffer, &iter_, wcs, len, case_sens);
653
                if (found) {
654
                        *match_pos = iter_;
655
                        break;
656
                }
657
        }
658
659
        g_free(wcs);
660
661
        return found;
662
}
663
664
#define MAX_TEXT_LINE_LEN        8190
665
666
void gtkut_text_buffer_insert_with_tag_by_name(GtkTextBuffer *buffer,
667
                                               GtkTextIter *iter,
668
                                               const gchar *text,
669
                                               gint len,
670
                                               const gchar *tag)
671
{
672
        if (len < 0)
673
                len = strlen(text);
674
675
        gtk_text_buffer_insert_with_tags_by_name
676
                (buffer, iter, text, len, tag, NULL);
677
678
        if (text[len - 1] != '\n') {
679
                /* somehow returns invalid value first (bug?),
680
                   so call it twice */
681
                gtk_text_iter_get_chars_in_line(iter);
682
                if (gtk_text_iter_get_chars_in_line(iter) > MAX_TEXT_LINE_LEN) {
683
                        gtk_text_buffer_insert_with_tags_by_name
684
                                (buffer, iter, "\n", 1, tag, NULL);
685
                }
686
        }
687
}
688
689
gchar *gtkut_text_view_get_selection(GtkTextView *textview)
690
{
691
        GtkTextBuffer *buffer;
692
        GtkTextIter start_iter, end_iter;
693
        gboolean found;
694
695
        g_return_val_if_fail(GTK_IS_TEXT_VIEW(textview), NULL);
696
697
        buffer = gtk_text_view_get_buffer(textview);
698
        found = gtk_text_buffer_get_selection_bounds(buffer,
699
                                                     &start_iter, &end_iter);
700
        if (found)
701
                return gtk_text_buffer_get_text(buffer, &start_iter, &end_iter,
702
                                                FALSE);
703
        else
704
                return NULL;
705
}
706
707
void gtkut_window_popup(GtkWidget *window)
708
{
709
        gint x, y, sx, sy, new_x, new_y;
710
711
        g_return_if_fail(window != NULL);
712
        g_return_if_fail(window->window != NULL);
713
714
        sx = gdk_screen_width();
715
        sy = gdk_screen_height();
716
717
        gdk_window_get_origin(window->window, &x, &y);
718
        new_x = x % sx; if (new_x < 0) new_x = 0;
719
        new_y = y % sy; if (new_y < 0) new_y = 0;
720
        if (new_x != x || new_y != y)
721
                gdk_window_move(window->window, new_x, new_y);
722
723
        gtk_window_present(GTK_WINDOW(window));
724
}
725
726
void gtkut_widget_get_uposition(GtkWidget *widget, gint *px, gint *py)
727
{
728
        gint x, y;
729
        gint sx, sy;
730
731
        g_return_if_fail(widget != NULL);
732
        g_return_if_fail(widget->window != NULL);
733
734
        sx = gdk_screen_width();
735
        sy = gdk_screen_height();
736
737
        /* gdk_window_get_root_origin ever return *rootwindow*'s position */
738
        gdk_window_get_root_origin(widget->window, &x, &y);
739
740
        x %= sx; if (x < 0) x = 0;
741
        y %= sy; if (y < 0) y = 0;
742
        *px = x;
743
        *py = y;
744
}
745
746
#warning FIXME_GTK2
747
void gtkut_widget_wait_for_draw(GtkWidget *widget)
748
{
749
        if (!GTK_WIDGET_VISIBLE(widget) || !GTK_WIDGET_MAPPED(widget)) return;
750
751
        while (gtk_events_pending())
752
                gtk_main_iteration();
753
}
754
755
static void gtkut_clist_bindings_add(GtkWidget *clist)
756
{
757
        GtkBindingSet *binding_set;
758
759
        binding_set = gtk_binding_set_by_class(GTK_CLIST_GET_CLASS(clist));
760
761
        gtk_binding_entry_add_signal(binding_set, GDK_n, GDK_CONTROL_MASK,
762
                                     "scroll_vertical", 2,
763
                                     G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
764
                                     G_TYPE_FLOAT, 0.0);
765
        gtk_binding_entry_add_signal(binding_set, GDK_p, GDK_CONTROL_MASK,
766
                                     "scroll_vertical", 2,
767
                                     G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
768
                                     G_TYPE_FLOAT, 0.0);
769
}
770
771
void gtkut_widget_init(void)
772
{
773
        GtkWidget *clist;
774
775
        clist = gtk_clist_new(1);
776
        g_object_ref(G_OBJECT(clist));
777
        gtk_object_sink(GTK_OBJECT(clist));
778
        gtkut_clist_bindings_add(clist);
779
        g_object_unref(G_OBJECT(clist));
780
781
        clist = gtk_ctree_new(1, 0);
782
        g_object_ref(G_OBJECT(clist));
783
        gtk_object_sink(GTK_OBJECT(clist));
784
        gtkut_clist_bindings_add(clist);
785
        g_object_unref(G_OBJECT(clist));
786
787
        clist = gtk_sctree_new_with_titles(1, 0, NULL);
788
        g_object_ref(G_OBJECT(clist));
789
        gtk_object_sink(GTK_OBJECT(clist));
790
        gtkut_clist_bindings_add(clist);
791
        g_object_unref(G_OBJECT(clist));
792
}