Statistics
| Revision:

root / src / gtkutils.c @ 1577

History | View | Annotate | Download (24.4 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2007 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/gtkbox.h>
30
#include <gtk/gtkhbbox.h>
31
#include <gtk/gtkbutton.h>
32
#include <gtk/gtkarrow.h>
33
#include <gtk/gtkctree.h>
34
#include <gtk/gtkcombo.h>
35
#include <gtk/gtkbindings.h>
36
#include <gtk/gtkitemfactory.h>
37
#include <gtk/gtktreemodel.h>
38
#include <gtk/gtktreesortable.h>
39
#include <gtk/gtktreeview.h>
40
#include <gtk/gtktreestore.h>
41
#include <gtk/gtkversion.h>
42
#include <stdlib.h>
43
#include <stdarg.h>
44
45
#include "gtkutils.h"
46
#include "utils.h"
47
#include "codeconv.h"
48
#include "menu.h"
49
50
gboolean gtkut_get_str_size(GtkWidget *widget, const gchar *str,
51
                            gint *width, gint *height)
52
{
53
        PangoLayout *layout;
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
        g_object_unref(layout);
61
62
        return TRUE;
63
}
64
65
gboolean gtkut_get_font_size(GtkWidget *widget, gint *width, gint *height)
66
{
67
        const gchar *str = "Abcdef";
68
        gboolean ret;
69
70
        ret = gtkut_get_str_size(widget, str, width, height);
71
        if (ret && width)
72
                *width = *width / g_utf8_strlen(str, -1);
73
74
        return ret;
75
}
76
77
PangoFontDescription *gtkut_get_default_font_desc(void)
78
{
79
        static PangoFontDescription *font_desc = NULL;
80
81
        if (!font_desc) {
82
                GtkWidget *window;
83
84
                window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
85
                gtk_widget_ensure_style(window);
86
                font_desc = pango_font_description_copy
87
                        (window->style->font_desc);
88
                gtk_object_sink(GTK_OBJECT(window));
89
        }
90
91
        return pango_font_description_copy(font_desc);
92
}
93
94
void gtkut_widget_set_small_font_size(GtkWidget *widget)
95
{
96
        PangoFontDescription *font_desc;
97
        gint size;
98
99
        g_return_if_fail(widget != NULL);
100
        g_return_if_fail(widget->style != NULL);
101
102
        font_desc = gtkut_get_default_font_desc();
103
        size = pango_font_description_get_size(font_desc);
104
        pango_font_description_set_size(font_desc, size * PANGO_SCALE_SMALL);
105
        gtk_widget_modify_font(widget, font_desc);
106
        pango_font_description_free(font_desc);
107
}
108
109
void gtkut_convert_int_to_gdk_color(gint rgbvalue, GdkColor *color)
110
{
111
        g_return_if_fail(color != NULL);
112
113
        color->pixel = 0L;
114
        color->red   = (int) (((gdouble)((rgbvalue & 0xff0000) >> 16) / 255.0) * 65535.0);
115
        color->green = (int) (((gdouble)((rgbvalue & 0x00ff00) >>  8) / 255.0) * 65535.0);
116
        color->blue  = (int) (((gdouble) (rgbvalue & 0x0000ff)        / 255.0) * 65535.0);
117
}
118
119
static gboolean reverse_order = FALSE;
120
121
void gtkut_stock_button_set_set_reverse(gboolean reverse)
122
{
123
        reverse_order = reverse;
124
}
125
126
void gtkut_stock_button_set_create(GtkWidget **bbox,
127
                                   GtkWidget **button1, const gchar *label1,
128
                                   GtkWidget **button2, const gchar *label2,
129
                                   GtkWidget **button3, const gchar *label3)
130
{
131
        g_return_if_fail(bbox != NULL);
132
        g_return_if_fail(button1 != NULL);
133
134
        *bbox = gtk_hbutton_box_new();
135
        gtk_button_box_set_layout(GTK_BUTTON_BOX(*bbox), GTK_BUTTONBOX_END);
136
        gtk_box_set_spacing(GTK_BOX(*bbox), 6);
137
138
        if (button3) {
139
                *button3 = gtk_button_new_from_stock(label3);
140
                GTK_WIDGET_SET_FLAGS(*button3, GTK_CAN_DEFAULT);
141
                gtk_box_pack_start(GTK_BOX(*bbox), *button3, FALSE, FALSE, 0);
142
                gtk_widget_show(*button3);
143
        }
144
145
        if (button2) {
146
                *button2 = gtk_button_new_from_stock(label2);
147
                GTK_WIDGET_SET_FLAGS(*button2, GTK_CAN_DEFAULT);
148
                gtk_box_pack_start(GTK_BOX(*bbox), *button2, FALSE, FALSE, 0);
149
                gtk_widget_show(*button2);
150
        }
151
152
        *button1 = gtk_button_new_from_stock(label1);
153
        GTK_WIDGET_SET_FLAGS(*button1, GTK_CAN_DEFAULT);
154
        gtk_box_pack_start(GTK_BOX(*bbox), *button1, FALSE, FALSE, 0);
155
        gtk_widget_show(*button1);
156
157
        if (reverse_order)
158
                gtkut_box_set_reverse_order(GTK_BOX(*bbox), TRUE);
159
}
160
161
void gtkut_box_set_reverse_order(GtkBox *box, gboolean reverse)
162
{
163
        GList *cur;
164
        GList *new_order = NULL;
165
        gint pos = 0;
166
        gboolean is_reversed;
167
168
        g_return_if_fail(box != NULL);
169
170
        is_reversed = GPOINTER_TO_INT
171
                (g_object_get_data(G_OBJECT(box), "reverse-order"));
172
        if (is_reversed == reverse)
173
                return;
174
        g_object_set_data(G_OBJECT(box), "reverse-order",
175
                          GINT_TO_POINTER(reverse));
176
177
        for (cur = box->children; cur != NULL; cur = cur->next) {
178
                GtkBoxChild *cinfo = cur->data;
179
                new_order = g_list_prepend(new_order, cinfo->widget);
180
        }
181
182
        for (cur = new_order; cur != NULL; cur = cur->next) {
183
                GtkWidget *child = cur->data;
184
                gtk_box_reorder_child(box, child, pos++);
185
        }
186
187
        g_list_free(new_order);
188
}
189
190
static void combo_button_size_request(GtkWidget *widget,
191
                                      GtkRequisition *requisition,
192
                                      gpointer data)
193
{
194
        ComboButton *combo = (ComboButton *)data;
195
196
        if (combo->arrow->allocation.height != requisition->height)
197
                gtk_widget_set_size_request(combo->arrow,
198
                                            -1, requisition->height);
199
}
200
201
static void combo_button_enter(GtkWidget *widget, gpointer data)
202
{
203
        ComboButton *combo = (ComboButton *)data;
204
205
        if (GTK_WIDGET_STATE(combo->arrow) != GTK_STATE_PRELIGHT) {
206
                gtk_widget_set_state(combo->arrow, GTK_STATE_PRELIGHT);
207
                gtk_widget_queue_draw(combo->arrow);
208
        }
209
        if (GTK_WIDGET_STATE(combo->button) != GTK_STATE_PRELIGHT) {
210
                gtk_widget_set_state(combo->button, GTK_STATE_PRELIGHT);
211
                gtk_widget_queue_draw(combo->button);
212
        }
213
}
214
215
static void combo_button_leave(GtkWidget *widget, gpointer data)
216
{
217
        ComboButton *combo = (ComboButton *)data;
218
219
        if (GTK_WIDGET_STATE(combo->arrow) != GTK_STATE_NORMAL) {
220
                gtk_widget_set_state(combo->arrow, GTK_STATE_NORMAL);
221
                gtk_widget_queue_draw(combo->arrow);
222
        }
223
        if (GTK_WIDGET_STATE(combo->button) != GTK_STATE_NORMAL) {
224
                gtk_widget_set_state(combo->button, GTK_STATE_NORMAL);
225
                gtk_widget_queue_draw(combo->button);
226
        }
227
}
228
229
static gint combo_button_arrow_pressed(GtkWidget *widget, GdkEventButton *event,
230
                                       gpointer data)
231
{
232
        ComboButton *combo = (ComboButton *)data;
233
234
        if (!event) return FALSE;
235
236
        gtk_menu_popup(GTK_MENU(combo->menu), NULL, NULL,
237
                       menu_button_position, combo->button,
238
                       event->button, event->time);
239
240
        return TRUE;
241
}
242
243
static void combo_button_destroy(GtkWidget *widget, gpointer data)
244
{
245
        ComboButton *combo = (ComboButton *)data;
246
247
        gtk_object_destroy(GTK_OBJECT(combo->factory));
248
        g_free(combo);
249
}
250
251
ComboButton *gtkut_combo_button_create(GtkWidget *button,
252
                                       GtkItemFactoryEntry *entries,
253
                                       gint n_entries, const gchar *path,
254
                                       gpointer data)
255
{
256
        ComboButton *combo;
257
        GtkWidget *arrow;
258
259
        combo = g_new0(ComboButton, 1);
260
261
        combo->arrow = gtk_button_new();
262
        arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
263
        gtk_widget_set_size_request(arrow, 7, -1);
264
        gtk_container_add(GTK_CONTAINER(combo->arrow), arrow);
265
        GTK_WIDGET_UNSET_FLAGS(combo->arrow, GTK_CAN_FOCUS);
266
        gtk_widget_show_all(combo->arrow);
267
268
        combo->button = button;
269
        combo->menu = menu_create_items(entries, n_entries, path,
270
                                        &combo->factory, data);
271
        combo->data = data;
272
273
        g_signal_connect(G_OBJECT(combo->button), "size_request",
274
                         G_CALLBACK(combo_button_size_request), combo);
275
#if 0
276
        g_signal_connect(G_OBJECT(combo->button), "enter",
277
                         G_CALLBACK(combo_button_enter), combo);
278
        g_signal_connect(G_OBJECT(combo->button), "leave",
279
                         G_CALLBACK(combo_button_leave), combo);
280
#endif
281
        g_signal_connect(G_OBJECT(combo->arrow), "enter",
282
                         G_CALLBACK(combo_button_enter), combo);
283
        g_signal_connect(G_OBJECT(combo->arrow), "leave",
284
                         G_CALLBACK(combo_button_leave), combo);
285
        g_signal_connect(G_OBJECT(combo->arrow), "button_press_event",
286
                         G_CALLBACK(combo_button_arrow_pressed), combo);
287
        g_signal_connect(G_OBJECT(combo->arrow), "destroy",
288
                         G_CALLBACK(combo_button_destroy), combo);
289
290
        return combo;
291
}
292
293
gint gtkut_ctree_get_nth_from_node(GtkCTree *ctree, GtkCTreeNode *node)
294
{
295
        g_return_val_if_fail(ctree != NULL, -1);
296
        g_return_val_if_fail(node != NULL, -1);
297
298
        return g_list_position(GTK_CLIST(ctree)->row_list, (GList *)node);
299
}
300
301
void gtkut_ctree_set_focus_row(GtkCTree *ctree, GtkCTreeNode *node)
302
{
303
        gtkut_clist_set_focus_row(GTK_CLIST(ctree),
304
                                  gtkut_ctree_get_nth_from_node(ctree, node));
305
}
306
307
void gtkut_clist_set_focus_row(GtkCList *clist, gint row)
308
{
309
        clist->focus_row = row;
310
        GTKUT_CTREE_REFRESH(clist);
311
}
312
313
#ifdef G_OS_WIN32
314
static void vadjustment_changed(GtkAdjustment *adj, gpointer data)
315
{
316
        GtkWidget *widget = GTK_WIDGET(data);
317
318
        gtk_widget_queue_draw(widget);
319
}
320
#endif
321
322
void gtkut_clist_set_redraw(GtkCList *clist)
323
{
324
#ifdef G_OS_WIN32
325
        if (clist->vadjustment) {
326
                g_signal_connect(G_OBJECT(clist->vadjustment), "changed",
327
                                 G_CALLBACK(vadjustment_changed), clist);
328
        }
329
#endif
330
}
331
332
gboolean gtkut_tree_model_next(GtkTreeModel *model, GtkTreeIter *iter)
333
{
334
        GtkTreeIter iter_, parent;
335
        gboolean valid;
336
337
        if (gtk_tree_model_iter_children(model, &iter_, iter)) {
338
                *iter = iter_;
339
                return TRUE;
340
        }
341
342
        iter_ = *iter;
343
        if (gtk_tree_model_iter_next(model, &iter_)) {
344
                *iter = iter_;
345
                return TRUE;
346
        }
347
348
        iter_ = *iter;
349
        valid = gtk_tree_model_iter_parent(model, &parent, &iter_);
350
        while (valid) {
351
                iter_ = parent;
352
                if (gtk_tree_model_iter_next(model, &iter_)) {
353
                        *iter = iter_;
354
                        return TRUE;
355
                }
356
357
                iter_ = parent;
358
                valid = gtk_tree_model_iter_parent(model, &parent, &iter_);
359
        }
360
361
        return FALSE;
362
}
363
364
gboolean gtkut_tree_model_prev(GtkTreeModel *model, GtkTreeIter *iter)
365
{
366
        GtkTreeIter iter_, child, next, parent;
367
        GtkTreePath *path;
368
        gboolean found = FALSE;
369
370
        iter_ = *iter;
371
372
        path = gtk_tree_model_get_path(model, &iter_);
373
374
        if (gtk_tree_path_prev(path)) {
375
                gtk_tree_model_get_iter(model, &child, path);
376
377
                while (gtk_tree_model_iter_has_child(model, &child)) {
378
                        iter_ = child;
379
                        gtk_tree_model_iter_children(model, &child, &iter_);
380
                        next = child;
381
                        while (gtk_tree_model_iter_next(model, &next))
382
                                child = next;
383
                }
384
385
                *iter = child;
386
                found = TRUE;
387
        } else if (gtk_tree_model_iter_parent(model, &parent, &iter_)) {
388
                *iter = parent;
389
                found = TRUE;
390
        }
391
392
        gtk_tree_path_free(path);
393
394
        return found;
395
}
396
397
gboolean gtkut_tree_model_get_iter_last(GtkTreeModel *model, GtkTreeIter *iter)
398
{
399
        GtkTreeIter iter_, child, next;
400
401
        if (!gtk_tree_model_get_iter_first(model, &iter_))
402
                return FALSE;
403
404
        for (;;) {
405
                next = iter_;
406
                while (gtk_tree_model_iter_next(model, &next))
407
                        iter_ = next;
408
                if (gtk_tree_model_iter_children(model, &child, &iter_))
409
                        iter_ = child;
410
                else
411
                        break;
412
        }
413
414
        *iter = iter_;
415
        return TRUE;
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
                gtk_tree_model_get(model, start, col, &store_data, -1);
429
                if (store_data == data) {
430
                        *iter = *start;
431
                        return TRUE;
432
                }
433
                valid = gtk_tree_model_iter_children(model, &iter_, start);
434
        } else
435
                valid = gtk_tree_model_get_iter_first(model, &iter_);
436
437
        while (valid) {
438
                if (gtkut_tree_model_find_by_column_data
439
                        (model, iter, &iter_, col, data)) {
440
                        return TRUE;
441
                }
442
443
                valid = gtk_tree_model_iter_next(model, &iter_);
444
        }
445
446
        return FALSE;
447
}
448
449
void gtkut_tree_model_foreach(GtkTreeModel *model, GtkTreeIter *start,
450
                              GtkTreeModelForeachFunc func, gpointer user_data)
451
{
452
        gboolean valid = TRUE;
453
        GtkTreeIter iter;
454
        GtkTreePath *path;
455
456
        g_return_if_fail(func != NULL);
457
458
        if (!start) {
459
                gtk_tree_model_foreach(model, func, user_data);
460
                return;
461
        }
462
463
        path = gtk_tree_model_get_path(model, start);
464
        func(model, path, start, user_data);
465
        gtk_tree_path_free(path);
466
467
        valid = gtk_tree_model_iter_children(model, &iter, start);
468
        while (valid) {
469
                gtkut_tree_model_foreach(model, &iter, func, user_data);
470
                valid = gtk_tree_model_iter_next(model, &iter);
471
        }
472
}
473
474
gboolean gtkut_tree_row_reference_get_iter(GtkTreeModel *model,
475
                                           GtkTreeRowReference *ref,
476
                                           GtkTreeIter *iter)
477
{
478
        GtkTreePath *path;
479
        gboolean valid = FALSE;
480
481
        if (ref) {
482
                path = gtk_tree_row_reference_get_path(ref);
483
                if (path) {
484
                        valid = gtk_tree_model_get_iter(model, iter, path);
485
                        gtk_tree_path_free(path);
486
                }
487
        }
488
489
        return valid;
490
}
491
492
gboolean gtkut_tree_row_reference_equal(GtkTreeRowReference *ref1,
493
                                        GtkTreeRowReference *ref2)
494
{
495
        GtkTreePath *path1, *path2;
496
        gint result;
497
498
        if (ref1 == NULL || ref2 == NULL)
499
                return FALSE;
500
501
        path1 = gtk_tree_row_reference_get_path(ref1);
502
        if (!path1)
503
                return FALSE;
504
        path2 = gtk_tree_row_reference_get_path(ref2);
505
        if (!path2) {
506
                gtk_tree_path_free(path1);
507
                return FALSE;
508
        }
509
510
        result = gtk_tree_path_compare(path1, path2);
511
512
        gtk_tree_path_free(path2);
513
        gtk_tree_path_free(path1);
514
515
        return (result == 0);
516
}
517
518
void gtkut_tree_sortable_unset_sort_column_id(GtkTreeSortable *sortable)
519
{
520
#if GTK_CHECK_VERSION(2, 6, 0)
521
        gtk_tree_sortable_set_sort_column_id
522
                (sortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
523
                 GTK_SORT_ASCENDING);
524
#else
525
        GtkTreeStore *store = GTK_TREE_STORE(sortable);
526
527
        g_return_if_fail(GTK_IS_TREE_STORE(sortable));
528
529
        if (store->sort_column_id == -2 && store->order == GTK_SORT_ASCENDING)
530
                return;
531
532
        store->sort_column_id = -2;
533
        store->order = GTK_SORT_ASCENDING;
534
535
        gtk_tree_sortable_sort_column_changed(sortable);
536
#endif
537
}
538
539
gboolean gtkut_tree_view_find_collapsed_parent(GtkTreeView *treeview,
540
                                               GtkTreeIter *parent,
541
                                               GtkTreeIter *iter)
542
{
543
        GtkTreeModel *model;
544
        GtkTreeIter iter_, parent_;
545
        GtkTreePath *path;
546
        gboolean valid;
547
548
        if (!iter) return FALSE;
549
550
        model = gtk_tree_view_get_model(treeview);
551
        valid = gtk_tree_model_iter_parent(model, &parent_, iter);
552
553
        while (valid) {
554
                path = gtk_tree_model_get_path(model, &parent_);
555
                if (!gtk_tree_view_row_expanded(treeview, path)) {
556
                        *parent = parent_;
557
                        gtk_tree_path_free(path);
558
                        return TRUE;
559
                }
560
                gtk_tree_path_free(path);
561
                iter_ = parent_;
562
                valid = gtk_tree_model_iter_parent(model, &parent_, &iter_);
563
        }
564
565
        return FALSE;
566
}
567
568
void gtkut_tree_view_expand_parent_all(GtkTreeView *treeview, GtkTreeIter *iter)
569
{
570
        GtkTreeModel *model;
571
        GtkTreeIter parent;
572
        GtkTreePath *path;
573
574
        model = gtk_tree_view_get_model(treeview);
575
576
        if (gtk_tree_model_iter_parent(model, &parent, iter)) {
577
                path = gtk_tree_model_get_path(model, &parent);
578
                gtk_tree_view_expand_to_path(treeview, path);
579
                gtk_tree_path_free(path);
580
        }
581
}
582
583
#define SCROLL_EDGE_SIZE 15
584
585
/* borrowed from gtktreeview.c */
586
void gtkut_tree_view_vertical_autoscroll(GtkTreeView *treeview)
587
{
588
        GdkRectangle visible_rect;
589
        gint y, wy;
590
        gint offset;
591
        GtkAdjustment *vadj;
592
        gfloat value;
593
594
        gdk_window_get_pointer(gtk_tree_view_get_bin_window(treeview),
595
                               NULL, &wy, NULL);
596
        gtk_tree_view_widget_to_tree_coords(treeview, 0, wy, NULL, &y);
597
598
        gtk_tree_view_get_visible_rect(treeview, &visible_rect);
599
600
        /* see if we are near the edge. */
601
        offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
602
        if (offset > 0) {
603
                offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
604
                if (offset < 0)
605
                        return;
606
        }
607
608
        vadj = gtk_tree_view_get_vadjustment(treeview);
609
        value = CLAMP(vadj->value + offset, 0.0, vadj->upper - vadj->page_size);
610
        gtk_adjustment_set_value(vadj, value);
611
}
612
613
/* modified version of gtk_tree_view_scroll_to_cell */
614
void gtkut_tree_view_scroll_to_cell(GtkTreeView *treeview, GtkTreePath *path,
615
                                    gboolean align_center)
616
{
617
        GdkRectangle cell_rect;
618
        GdkRectangle vis_rect;
619
        gint dest_x, dest_y;
620
        gint margin = 0;
621
622
        if (!path)
623
                return;
624
625
        gtk_tree_view_get_cell_area(treeview, path, NULL, &cell_rect);
626
        gtk_tree_view_widget_to_tree_coords(treeview, cell_rect.x, cell_rect.y,
627
                                            NULL, &(cell_rect.y));
628
        gtk_tree_view_get_visible_rect(treeview, &vis_rect);
629
630
        dest_x = vis_rect.x;
631
        dest_y = vis_rect.y;
632
633
        /* add margin */
634
        if (cell_rect.height * 2 < vis_rect.height)
635
                margin = cell_rect.height + (align_center ? 0 : 2);
636
637
        if (cell_rect.y < vis_rect.y + margin) {
638
                if (align_center)
639
                        dest_y = cell_rect.y -
640
                                (vis_rect.height - cell_rect.height) / 2;
641
                else
642
                        dest_y = cell_rect.y - margin;
643
        }
644
        if (cell_rect.y + cell_rect.height >
645
                vis_rect.y + vis_rect.height - margin) {
646
                if (align_center)
647
                        dest_y = cell_rect.y -
648
                                (vis_rect.height - cell_rect.height) / 2;
649
                else
650
                        dest_y = cell_rect.y + cell_rect.height -
651
                                vis_rect.height + margin;
652
        }
653
654
        gtk_tree_view_scroll_to_point(treeview, dest_x, dest_y);
655
}
656
657
void gtkut_tree_view_fast_clear(GtkTreeView *treeview, GtkTreeStore *store)
658
{
659
#if GTK_CHECK_VERSION(2, 8, 0) && !GTK_CHECK_VERSION(2, 10, 0)
660
        gtk_tree_store_clear(store);
661
#else
662
        /* this is faster than above, but it seems to trigger crashes in
663
           GTK+ 2.8.x */
664
        gtk_tree_view_set_model(treeview, NULL);
665
        gtk_tree_store_clear(store);
666
        gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
667
#endif
668
}
669
670
void gtkut_combo_set_items(GtkCombo *combo, const gchar *str1, ...)
671
{
672
        va_list args;
673
        gchar *s;
674
        GList *combo_items = NULL;
675
676
        g_return_if_fail(str1 != NULL);
677
678
        combo_items = g_list_append(combo_items, (gpointer)str1);
679
        va_start(args, str1);
680
        s = va_arg(args, gchar*);
681
        while (s) {
682
                combo_items = g_list_append(combo_items, (gpointer)s);
683
                s = va_arg(args, gchar*);
684
        }
685
        va_end(args);
686
687
        gtk_combo_set_popdown_strings(combo, combo_items);
688
689
        g_list_free(combo_items);
690
}
691
692
gchar *gtkut_editable_get_selection(GtkEditable *editable)
693
{
694
        gint start_pos, end_pos;
695
        gboolean found;
696
697
        g_return_val_if_fail(GTK_IS_EDITABLE(editable), NULL);
698
699
        found = gtk_editable_get_selection_bounds(editable,
700
                                                  &start_pos, &end_pos);
701
        if (found)
702
                return gtk_editable_get_chars(editable, start_pos, end_pos);
703
        else
704
                return NULL;
705
}
706
707
void gtkut_editable_disable_im(GtkEditable *editable)
708
{
709
        g_return_if_fail(editable != NULL);
710
711
#if USE_XIM
712
        if (editable->ic) {
713
                gdk_ic_destroy(editable->ic);
714
                editable->ic = NULL;
715
        }
716
        if (editable->ic_attr) {
717
                gdk_ic_attr_destroy(editable->ic_attr);
718
                editable->ic_attr = NULL;
719
        }
720
#endif
721
}
722
723
void gtkut_container_remove(GtkContainer *container, GtkWidget *widget)
724
{
725
        gtk_container_remove(container, widget);
726
}
727
728
void gtkut_scrolled_window_reset_position(GtkScrolledWindow *window)
729
{
730
        GtkAdjustment *adj;
731
732
        adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(window));
733
        gtk_adjustment_set_value(adj, adj->lower);
734
        adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(window));
735
        gtk_adjustment_set_value(adj, adj->lower);
736
}
737
738
gboolean gtkut_text_buffer_match_string(GtkTextBuffer *textbuf,
739
                                        const GtkTextIter *iter,
740
                                        gunichar *wcs, gint len,
741
                                        gboolean case_sens)
742
{
743
        GtkTextIter start_iter, end_iter;
744
        gchar *utf8str, *p;
745
        gint match_count;
746
747
        start_iter = end_iter = *iter;
748
        gtk_text_iter_forward_chars(&end_iter, len);
749
750
        utf8str = gtk_text_buffer_get_text(textbuf, &start_iter, &end_iter,
751
                                           FALSE);
752
        if (!utf8str) return FALSE;
753
754
        if ((gint)g_utf8_strlen(utf8str, -1) != len) {
755
                g_free(utf8str);
756
                return FALSE;
757
        }
758
759
        for (p = utf8str, match_count = 0;
760
             *p != '\0' && match_count < len;
761
             p = g_utf8_next_char(p), match_count++) {
762
                gunichar wc;
763
764
                wc = g_utf8_get_char(p);
765
766
                if (case_sens) {
767
                        if (wc != wcs[match_count])
768
                                break;
769
                } else {
770
                        if (g_unichar_tolower(wc) !=
771
                            g_unichar_tolower(wcs[match_count]))
772
                                break;
773
                }
774
        }
775
776
        g_free(utf8str);
777
778
        if (match_count == len)
779
                return TRUE;
780
        else
781
                return FALSE;
782
}
783
784
gboolean gtkut_text_buffer_find(GtkTextBuffer *buffer, const GtkTextIter *iter,
785
                                const gchar *str, gboolean case_sens,
786
                                GtkTextIter *match_pos)
787
{
788
        gunichar *wcs;
789
        gint len;
790
        glong items_read = 0, items_written = 0;
791
        GError *error = NULL;
792
        GtkTextIter iter_;
793
        gboolean found = FALSE;
794
795
        wcs = g_utf8_to_ucs4(str, -1, &items_read, &items_written, &error);
796
        if (error != NULL) {
797
                g_warning("An error occured while converting a string from UTF-8 to UCS-4: %s\n", error->message);
798
                g_error_free(error);
799
        }
800
        if (!wcs || items_written <= 0) return FALSE;
801
        len = (gint)items_written;
802
803
        iter_ = *iter;
804
        do {
805
                found = gtkut_text_buffer_match_string
806
                        (buffer, &iter_, wcs, len, case_sens);
807
                if (found) {
808
                        *match_pos = iter_;
809
                        break;
810
                }
811
        } while (gtk_text_iter_forward_char(&iter_));
812
813
        g_free(wcs);
814
815
        return found;
816
}
817
818
gboolean gtkut_text_buffer_find_backward(GtkTextBuffer *buffer,
819
                                         const GtkTextIter *iter,
820
                                         const gchar *str, gboolean case_sens,
821
                                         GtkTextIter *match_pos)
822
{
823
        gunichar *wcs;
824
        gint len;
825
        glong items_read = 0, items_written = 0;
826
        GError *error = NULL;
827
        GtkTextIter iter_;
828
        gboolean found = FALSE;
829
830
        wcs = g_utf8_to_ucs4(str, -1, &items_read, &items_written, &error);
831
        if (error != NULL) {
832
                g_warning("An error occured while converting a string from UTF-8 to UCS-4: %s\n", error->message);
833
                g_error_free(error);
834
        }
835
        if (!wcs || items_written <= 0) return FALSE;
836
        len = (gint)items_written;
837
838
        iter_ = *iter;
839
        while (gtk_text_iter_backward_char(&iter_)) {
840
                found = gtkut_text_buffer_match_string
841
                        (buffer, &iter_, wcs, len, case_sens);
842
                if (found) {
843
                        *match_pos = iter_;
844
                        break;
845
                }
846
        }
847
848
        g_free(wcs);
849
850
        return found;
851
}
852
853
#define MAX_TEXT_LINE_LEN        8190
854
855
void gtkut_text_buffer_insert_with_tag_by_name(GtkTextBuffer *buffer,
856
                                               GtkTextIter *iter,
857
                                               const gchar *text,
858
                                               gint len,
859
                                               const gchar *tag)
860
{
861
        if (len < 0)
862
                len = strlen(text);
863
864
        gtk_text_buffer_insert_with_tags_by_name
865
                (buffer, iter, text, len, tag, NULL);
866
867
        if (text[len - 1] != '\n') {
868
                /* somehow returns invalid value first (bug?),
869
                   so call it twice */
870
                gtk_text_iter_get_chars_in_line(iter);
871
                if (gtk_text_iter_get_chars_in_line(iter) > MAX_TEXT_LINE_LEN) {
872
                        gtk_text_buffer_insert_with_tags_by_name
873
                                (buffer, iter, "\n", 1, tag, NULL);
874
                }
875
        }
876
}
877
878
gchar *gtkut_text_view_get_selection(GtkTextView *textview)
879
{
880
        GtkTextBuffer *buffer;
881
        GtkTextIter start_iter, end_iter;
882
        gboolean found;
883
884
        g_return_val_if_fail(GTK_IS_TEXT_VIEW(textview), NULL);
885
886
        buffer = gtk_text_view_get_buffer(textview);
887
        found = gtk_text_buffer_get_selection_bounds(buffer,
888
                                                     &start_iter, &end_iter);
889
        if (found)
890
                return gtk_text_buffer_get_text(buffer, &start_iter, &end_iter,
891
                                                FALSE);
892
        else
893
                return NULL;
894
}
895
896
void gtkut_window_popup(GtkWidget *window)
897
{
898
        gint x, y, sx, sy, new_x, new_y;
899
900
        g_return_if_fail(window != NULL);
901
        g_return_if_fail(window->window != NULL);
902
903
        sx = gdk_screen_width();
904
        sy = gdk_screen_height();
905
906
        gdk_window_get_origin(window->window, &x, &y);
907
        new_x = x % sx; if (new_x < 0) new_x = 0;
908
        new_y = y % sy; if (new_y < 0) new_y = 0;
909
        if (new_x != x || new_y != y)
910
                gdk_window_move(window->window, new_x, new_y);
911
912
        gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window), FALSE);
913
        gtk_window_present(GTK_WINDOW(window));
914
#ifdef G_OS_WIN32
915
        /* ensure that the window is displayed at the top */
916
        gdk_window_show(window->window);
917
#endif
918
}
919
920
gboolean gtkut_window_modal_exist(void)
921
{
922
        GList *window_list, *cur;
923
        gboolean exist = FALSE;
924
925
        window_list = gtk_window_list_toplevels();
926
        for (cur = window_list; cur != NULL; cur = cur->next) {
927
                GtkWidget *window = GTK_WIDGET(cur->data);
928
929
                if (GTK_WIDGET_VISIBLE(window) &&
930
                    gtk_window_get_modal(GTK_WINDOW(window))) {
931
                        exist = TRUE;
932
                        break;
933
                }
934
        }
935
        g_list_free(window_list);
936
937
        return exist;
938
}
939
940
void gtkut_widget_get_uposition(GtkWidget *widget, gint *px, gint *py)
941
{
942
        gint x, y;
943
        gint sx, sy;
944
945
        g_return_if_fail(widget != NULL);
946
        g_return_if_fail(widget->window != NULL);
947
948
        sx = gdk_screen_width();
949
        sy = gdk_screen_height();
950
951
        /* gdk_window_get_root_origin ever return *rootwindow*'s position */
952
        gdk_window_get_root_origin(widget->window, &x, &y);
953
954
        x %= sx; if (x < 0) x = 0;
955
        y %= sy; if (y < 0) y = 0;
956
        *px = x;
957
        *py = y;
958
}
959
960
void gtkut_widget_draw_now(GtkWidget *widget)
961
{
962
        if (GTK_WIDGET_VISIBLE(widget) && GTK_WIDGET_DRAWABLE(widget))
963
                gdk_window_process_updates(widget->window, FALSE);
964
}
965
966
static void gtkut_clist_bindings_add(GtkWidget *clist)
967
{
968
        GtkBindingSet *binding_set;
969
970
        binding_set = gtk_binding_set_by_class(GTK_CLIST_GET_CLASS(clist));
971
972
        gtk_binding_entry_add_signal(binding_set, GDK_n, GDK_CONTROL_MASK,
973
                                     "scroll_vertical", 2,
974
                                     G_TYPE_ENUM, GTK_SCROLL_STEP_FORWARD,
975
                                     G_TYPE_FLOAT, 0.0);
976
        gtk_binding_entry_add_signal(binding_set, GDK_p, GDK_CONTROL_MASK,
977
                                     "scroll_vertical", 2,
978
                                     G_TYPE_ENUM, GTK_SCROLL_STEP_BACKWARD,
979
                                     G_TYPE_FLOAT, 0.0);
980
}
981
982
void gtkut_widget_init(void)
983
{
984
        GtkWidget *clist;
985
986
        clist = gtk_clist_new(1);
987
        g_object_ref(G_OBJECT(clist));
988
        gtk_object_sink(GTK_OBJECT(clist));
989
        gtkut_clist_bindings_add(clist);
990
        g_object_unref(G_OBJECT(clist));
991
992
        clist = gtk_ctree_new(1, 0);
993
        g_object_ref(G_OBJECT(clist));
994
        gtk_object_sink(GTK_OBJECT(clist));
995
        gtkut_clist_bindings_add(clist);
996
        g_object_unref(G_OBJECT(clist));
997
}
998
999
void gtkut_events_flush(void)
1000
{
1001
        GTK_EVENTS_FLUSH();
1002
}