~ubuntu-branches/ubuntu/quantal/sunpinyin/quantal

« back to all changes in this revision

Viewing changes to wrapper/xim/skin.c

  • Committer: Package Import Robot
  • Author(s): YunQiang Su
  • Date: 2012-04-11 03:06:40 UTC
  • mfrom: (1.1.4) (1.2.8 sid)
  • Revision ID: package-import@ubuntu.com-20120411030640-8mxepz5e6wffy87c
Tags: 2.0.3+git20120404-1
* Medium urgency for fixing RC bug.
* New upstream commit: fix FTBFS with gcc-4.7 (Closes: #667385).
* Add Multi-Arch: same to libsunpinyin3, -dev and -dbg.
* Add YunQiang Su to uploaders.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
3
 
 *
4
 
 * The contents of this file are subject to the terms of either the GNU Lesser
5
 
 * General Public License Version 2.1 only ("LGPL") or the Common Development and
6
 
 * Distribution License ("CDDL")(collectively, the "License"). You may not use this
7
 
 * file except in compliance with the License. You can obtain a copy of the CDDL at
8
 
 * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
9
 
 * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
10
 
 * specific language governing permissions and limitations under the License. When
11
 
 * distributing the software, include this License Header Notice in each file and
12
 
 * include the full text of the License in the License file as well as the
13
 
 * following notice:
14
 
 *
15
 
 * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
16
 
 * (CDDL)
17
 
 * For Covered Software in this distribution, this License shall be governed by the
18
 
 * laws of the State of California (excluding conflict-of-law provisions).
19
 
 * Any litigation relating to this License shall be subject to the jurisdiction of
20
 
 * the Federal Courts of the Northern District of California and the state courts
21
 
 * of the State of California, with venue lying in Santa Clara County, California.
22
 
 *
23
 
 * Contributor(s):
24
 
 *
25
 
 * If you wish your version of this file to be governed by only the CDDL or only
26
 
 * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
27
 
 * include this software in this distribution under the [CDDL or LGPL Version 2.1]
28
 
 * license." If you don't indicate a single choice of license, a recipient has the
29
 
 * option to distribute your version of this file under either the CDDL or the LGPL
30
 
 * Version 2.1, or to extend the choice of license to its licensees as provided
31
 
 * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
32
 
 * Version 2 license, then the option applies only if the new code is made subject
33
 
 * to such option by the copyright holder.
34
 
 */
35
 
 
36
 
#include <stdlib.h>
37
 
#include <string.h>
38
 
#include "skin.h"
39
 
 
40
 
struct _skin_window_priv_t
41
 
{
42
 
    skin_label_t* labels;
43
 
    skin_button_t* btns;
44
 
 
45
 
    /* current expose environment */
46
 
    skin_button_t* highlight_btn;
47
 
    skin_button_t* pressdown_btn;
48
 
 
49
 
    GCallback      press_cb;
50
 
    GCallback      release_cb;
51
 
    GCallback      motion_cb;
52
 
 
53
 
    void*          press_cb_data;
54
 
    void*          release_cb_data;
55
 
    void*          motion_cb_data;
56
 
 
57
 
    /* drag to move positions */
58
 
    gboolean       enable_drag_to_move;
59
 
    int            drag_init_x;
60
 
    int            drag_init_y;
61
 
    gboolean       drag_begin;
62
 
};
63
 
 
64
 
struct _skin_button_priv_t
65
 
{
66
 
    skin_button_t* next;
67
 
    skin_window_t* parent;
68
 
 
69
 
    GCallback press_cb;
70
 
    GCallback release_cb;
71
 
 
72
 
    void*     press_cb_data;
73
 
    void*     release_cb_data;
74
 
};
75
 
 
76
 
struct _skin_label_priv_t
77
 
{
78
 
    skin_label_t*  next;
79
 
    skin_window_t* wind;
80
 
};
81
 
 
82
 
static void
83
 
zoom_and_composite(GdkPixbuf* src,
84
 
                   GdkPixbuf* dst,
85
 
                   int        x,
86
 
                   int        y,
87
 
                   int        width,
88
 
                   int        height,
89
 
                   int        dst_x,
90
 
                   int        dst_y,
91
 
                   int        dst_width,
92
 
                   int        dst_height)
93
 
{
94
 
    if (width <= 0 || height <= 0 || dst_width <= 0 || dst_height <= 0)
95
 
        return;
96
 
    GdkPixbuf* sub = gdk_pixbuf_new_subpixbuf(src, x, y, width, height);
97
 
    double x_scale = 1.0 * dst_width / width;
98
 
    double y_scale = 1.0 * dst_height / height;
99
 
 
100
 
    gdk_pixbuf_scale(sub, dst, dst_x, dst_y, dst_width, dst_height,
101
 
                     dst_x, dst_y, x_scale, y_scale, GDK_INTERP_BILINEAR);
102
 
    g_object_unref(sub);
103
 
}
104
 
 
105
 
static void
106
 
cairo_paint_pixbuf(cairo_t*   cr,
107
 
                   GdkPixbuf* buf,
108
 
                   int        off_x,
109
 
                   int        off_y)
110
 
{
111
 
    gdk_cairo_set_source_pixbuf(cr, buf, off_x, off_y);
112
 
    cairo_paint(cr);
113
 
}
114
 
 
115
 
static void
116
 
paint_background_with_mask(GtkWidget*      wid,
117
 
                           skin_window_t*  wind)
118
 
{
119
 
    GdkPixbuf* bg = wind->background_image;
120
 
    int width, height;
121
 
    int bg_width, bg_height;
122
 
    int top, left, bottom, right;
123
 
 
124
 
    width = wid->allocation.width;
125
 
    height = wid->allocation.height;
126
 
    bg_width = gdk_pixbuf_get_width(bg);
127
 
    bg_height = gdk_pixbuf_get_height(bg);
128
 
 
129
 
    top = wind->margin_top;
130
 
    left = wind->margin_left;
131
 
    right = wind->margin_right;
132
 
    bottom = wind->margin_bottom;
133
 
 
134
 
    GdkPixbuf* newbg = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
135
 
                                       width, height);
136
 
 
137
 
    // 4 corners
138
 
    gdk_pixbuf_copy_area(bg, 0, 0, left, top, newbg, 0, 0);
139
 
    gdk_pixbuf_copy_area(bg, bg_width - right, 0, right, top,
140
 
                         newbg, width - right, 0);
141
 
    gdk_pixbuf_copy_area(bg, 0, bg_height - bottom, left, bottom,
142
 
                         newbg, 0, height - bottom);
143
 
    gdk_pixbuf_copy_area(bg, bg_width - right, bg_height - bottom,
144
 
                         right, bottom,
145
 
                         newbg, width - right, height - bottom);
146
 
 
147
 
    // 4 margins and the center area
148
 
    int content_width = bg_width - left - right;
149
 
    int content_height = bg_height - top - bottom;
150
 
    int new_content_width = width - left - right;
151
 
    int new_content_height = height - top - bottom;
152
 
 
153
 
    // top
154
 
    zoom_and_composite(bg, newbg, left, 0, content_width, top,
155
 
                       left, 0, new_content_width, top);
156
 
    // bottom
157
 
    zoom_and_composite(bg, newbg,
158
 
                       left, bg_height - bottom, content_width, bottom,
159
 
                       left, height - bottom, new_content_width, bottom);
160
 
    // left
161
 
    zoom_and_composite(bg, newbg,
162
 
                       0, top, left, content_height,
163
 
                       0, top, left, new_content_height);
164
 
    // right
165
 
    zoom_and_composite(bg, newbg,
166
 
                       bg_width - right, top, right, content_height,
167
 
                       width - right, top, right, new_content_height);
168
 
    // center
169
 
    zoom_and_composite(bg, newbg,
170
 
                       left, top, content_width, content_height,
171
 
                       left, top, new_content_width, new_content_height);
172
 
 
173
 
    gdk_window_clear(wid->window);
174
 
    // paint it
175
 
    cairo_t* cr = gdk_cairo_create(wid->window);
176
 
    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
177
 
    cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
178
 
    cairo_paint(cr);
179
 
    cairo_paint_pixbuf(cr, newbg, 0, 0);
180
 
    cairo_destroy(cr);
181
 
    // set the mask
182
 
    GdkBitmap* mask;
183
 
    gdk_pixbuf_render_pixmap_and_mask(newbg, NULL, &mask,
184
 
                                      wind->alpha_mask_threshold);
185
 
    gdk_window_shape_combine_mask(wid->window, mask, 0, 0);
186
 
 
187
 
    g_object_unref(newbg);
188
 
}
189
 
 
190
 
static void
191
 
paint_buttons(GtkWidget*     wid,
192
 
              skin_window_t* wind)
193
 
{
194
 
    cairo_t* cr = gdk_cairo_create(wid->window);
195
 
    skin_button_t* btn = wind->priv->btns;
196
 
    for (; btn != NULL; btn = btn->priv->next) {
197
 
        if (btn == wind->priv->pressdown_btn) {
198
 
            cairo_paint_pixbuf(cr, btn->pressdown_image, btn->x, btn->y);
199
 
        } else if (btn == wind->priv->highlight_btn) {
200
 
            cairo_paint_pixbuf(cr, btn->highlight_image, btn->x, btn->y);
201
 
        } else {
202
 
            cairo_paint_pixbuf(cr, btn->normal_image, btn->x, btn->y);
203
 
        }
204
 
    }
205
 
    cairo_destroy(cr);
206
 
}
207
 
 
208
 
static void
209
 
paint_labels(GtkWidget*     wid,
210
 
             skin_window_t* wind)
211
 
{
212
 
    cairo_t* cr = gdk_cairo_create(wid->window);
213
 
    skin_label_t* label = wind->priv->labels;
214
 
    for (; label != NULL; label = label->priv->next) {
215
 
        cairo_set_source_rgba(cr, label->color_r, label->color_g,
216
 
                              label->color_b, label->color_a);
217
 
        if (label->layout == NULL) {
218
 
            label->layout = pango_cairo_create_layout(cr);
219
 
            pango_layout_set_font_description(
220
 
                label->layout, pango_font_description_from_string(label->font));
221
 
        }
222
 
        pango_layout_set_text(label->layout, label->text, -1);
223
 
        cairo_move_to(cr, label->x, label->y);
224
 
        pango_cairo_layout_path(cr, label->layout);
225
 
        cairo_fill(cr);
226
 
    }
227
 
    cairo_destroy(cr);
228
 
}
229
 
 
230
 
static gboolean
231
 
window_on_expose(GtkWidget*      wid,
232
 
                 GdkEventExpose* evt,
233
 
                 skin_window_t*  wind)
234
 
{
235
 
    paint_background_with_mask(wid, wind);
236
 
    paint_labels(wid, wind);
237
 
    paint_buttons(wid, wind);
238
 
    return TRUE;
239
 
}
240
 
 
241
 
static gboolean
242
 
window_on_configure(GtkWidget*         wid,
243
 
                    GdkEventConfigure* evt,
244
 
                    skin_window_t*     wind)
245
 
{
246
 
    gtk_widget_queue_draw(wid);
247
 
    return FALSE;
248
 
}
249
 
 
250
 
static skin_button_t*
251
 
find_button(skin_window_t* wind, int pos_x, int pos_y)
252
 
{
253
 
    skin_button_t* btn = wind->priv->btns;
254
 
    for (; btn != NULL; btn = btn->priv->next) {
255
 
        int x = btn->x, y = btn->y, width = btn->width, height = btn->height;
256
 
        if (pos_x > x && pos_y > y && pos_x < x + width && pos_y < y + height) {
257
 
            return btn;
258
 
        }
259
 
    }
260
 
    return NULL;
261
 
}
262
 
 
263
 
static gboolean
264
 
set_expose_env(skin_window_t* wind,
265
 
               skin_button_t* highlight,
266
 
               skin_button_t* down)
267
 
{
268
 
    gboolean ret = FALSE;
269
 
    if (wind->priv->highlight_btn != highlight) {
270
 
        ret |= TRUE;
271
 
        wind->priv->highlight_btn = highlight;
272
 
    }
273
 
    if (wind->priv->pressdown_btn != down) {
274
 
        ret |= TRUE;
275
 
        wind->priv->pressdown_btn = down;
276
 
    }
277
 
    return ret;
278
 
}
279
 
 
280
 
typedef gboolean (*motion_cb_t) (GtkWidget*, GdkEventMotion*, void*);
281
 
typedef gboolean (*mouse_cb_t) (GtkWidget*, GdkEventButton*, void*);
282
 
 
283
 
static gboolean
284
 
window_on_motion(GtkWidget*      wid,
285
 
                 GdkEventMotion* evt,
286
 
                 skin_window_t*  wind)
287
 
{
288
 
    skin_button_t* btn = find_button(wind, evt->x, evt->y);
289
 
    gboolean need_redraw = FALSE;
290
 
    if (btn) {
291
 
        if ((evt->state & GDK_BUTTON1_MASK) != 0
292
 
            || (evt->state & GDK_BUTTON2_MASK) != 0
293
 
            || (evt->state & GDK_BUTTON3_MASK) != 0) {
294
 
            need_redraw = set_expose_env(wind, NULL, btn);
295
 
        } else {
296
 
            need_redraw = set_expose_env(wind, btn, NULL);
297
 
        }
298
 
    } else {
299
 
        /* move it if drag */
300
 
        if (wind->priv->enable_drag_to_move && wind->priv->drag_begin) {
301
 
            gtk_window_move(GTK_WINDOW(wind->widget),
302
 
                            evt->x_root - wind->priv->drag_init_x,
303
 
                            evt->y_root - wind->priv->drag_init_y);
304
 
        }
305
 
        need_redraw = set_expose_env(wind, NULL, NULL);
306
 
        motion_cb_t cb = (motion_cb_t) wind->priv->motion_cb;
307
 
        if (cb) {
308
 
            cb(wid, evt, wind->priv->motion_cb_data);
309
 
        }
310
 
    }
311
 
    if (need_redraw) {
312
 
        gtk_widget_queue_draw(wid);
313
 
    }
314
 
    return TRUE;
315
 
}
316
 
 
317
 
static gboolean
318
 
window_on_press_or_release(GtkWidget*      wid,
319
 
                           GdkEventButton* evt,
320
 
                           skin_window_t*  wind,
321
 
                           gboolean        press)
322
 
{
323
 
    skin_button_t* btn = find_button(wind, evt->x, evt->y);
324
 
    gboolean need_redraw = FALSE;
325
 
    skin_button_t* highlight_btn = NULL;
326
 
    skin_button_t* pressdown_btn = NULL;
327
 
    mouse_cb_t btncb = NULL;
328
 
    mouse_cb_t wincb = NULL;
329
 
 
330
 
    if (press) {
331
 
        wincb = (mouse_cb_t) wind->priv->press_cb;
332
 
        pressdown_btn = btn;
333
 
        if (!btn) {
334
 
            /* update drag init positions */
335
 
            wind->priv->drag_init_x = evt->x;
336
 
            wind->priv->drag_init_y = evt->y;
337
 
            wind->priv->drag_begin = wind->priv->enable_drag_to_move;
338
 
        } else {
339
 
            btncb = (mouse_cb_t) btn->priv->press_cb;
340
 
        }
341
 
    } else {
342
 
        wincb = (mouse_cb_t) wind->priv->release_cb;
343
 
        highlight_btn = btn;
344
 
        if (!btn) {
345
 
            wind->priv->drag_begin = FALSE;
346
 
        } else {
347
 
            btncb = (mouse_cb_t) btn->priv->release_cb;
348
 
        }
349
 
    }
350
 
 
351
 
    if (btn) {
352
 
        need_redraw = set_expose_env(wind, highlight_btn, pressdown_btn);
353
 
        if (btncb) {
354
 
            btncb(wid, evt, btn->priv->press_cb_data);
355
 
        }
356
 
    } else {
357
 
        if (wincb) {
358
 
            wincb(wid, evt, wind->priv->press_cb_data);
359
 
        }
360
 
    }
361
 
    if (need_redraw) {
362
 
        gtk_widget_queue_draw(wid);
363
 
    }
364
 
    return TRUE;
365
 
}
366
 
 
367
 
static gboolean
368
 
window_on_press(GtkWidget*      wid,
369
 
                GdkEventButton* evt,
370
 
                skin_window_t*  wind)
371
 
{
372
 
    return window_on_press_or_release(wid, evt, wind, TRUE);
373
 
}
374
 
 
375
 
static gboolean
376
 
window_on_release(GtkWidget* wid,
377
 
                  GdkEventButton* evt,
378
 
                  skin_window_t* wind)
379
 
{
380
 
    return window_on_press_or_release(wid, evt, wind, FALSE);
381
 
}
382
 
 
383
 
skin_window_t*
384
 
skin_window_new(GtkWindow* widget,
385
 
                GdkPixbuf* background_image,
386
 
                int        margin_top,
387
 
                int        margin_left,
388
 
                int        margin_bottom,
389
 
                int        margin_right,
390
 
                int        alpha_mask_threshold)
391
 
{
392
 
    skin_window_t* wind = malloc(sizeof(skin_window_t));
393
 
    wind->widget = GTK_WIDGET(widget);
394
 
    wind->background_image = background_image;
395
 
    wind->margin_top = margin_top;
396
 
    wind->margin_left = margin_left;
397
 
    wind->margin_bottom = margin_bottom;
398
 
    wind->margin_right = margin_right;
399
 
    wind->alpha_mask_threshold = alpha_mask_threshold;
400
 
    wind->priv = malloc(sizeof(skin_window_priv_t));
401
 
    memset(wind->priv, 0, sizeof(skin_window_priv_t));
402
 
    gtk_window_set_default_size(widget,
403
 
                                gdk_pixbuf_get_width(background_image),
404
 
                                gdk_pixbuf_get_height(background_image));
405
 
 
406
 
    /* set rgba */
407
 
    GdkScreen* screen = gdk_screen_get_default();
408
 
    GdkColormap* cmap = gdk_screen_get_rgba_colormap(screen);
409
 
    if (cmap) {
410
 
        gtk_widget_set_colormap(wind->widget, cmap);
411
 
    } else {
412
 
        fprintf(stderr, "Cannot set rgba colormap!\n");
413
 
    }
414
 
 
415
 
    /* signal expose */
416
 
    gtk_widget_set_events(wind->widget,
417
 
                          GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK
418
 
                          | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
419
 
    gtk_widget_realize(wind->widget);
420
 
 
421
 
    g_signal_connect(wind->widget, "expose-event",
422
 
                     G_CALLBACK(window_on_expose), wind);
423
 
    g_signal_connect(wind->widget, "configure-event",
424
 
                     G_CALLBACK(window_on_configure), wind);
425
 
    g_signal_connect(wind->widget, "motion-notify-event",
426
 
                     G_CALLBACK(window_on_motion), wind);
427
 
    g_signal_connect(wind->widget, "button-press-event",
428
 
                     G_CALLBACK(window_on_press), wind);
429
 
    g_signal_connect(wind->widget, "button-release-event",
430
 
                     G_CALLBACK(window_on_release), wind);
431
 
    return wind;
432
 
}
433
 
 
434
 
void
435
 
skin_window_destroy(skin_window_t* wind)
436
 
{
437
 
    gtk_widget_destroy(wind->widget);
438
 
    free(wind->priv);
439
 
    free(wind);
440
 
}
441
 
 
442
 
void
443
 
skin_window_add_button(skin_window_t* wind,
444
 
                       skin_button_t* btn,
445
 
                       int            x,
446
 
                       int            y)
447
 
{
448
 
    /* append to the buttons list */
449
 
    btn->priv->next = wind->priv->btns;
450
 
    wind->priv->btns = btn;
451
 
 
452
 
    btn->priv->parent = wind;
453
 
    btn->x = x;
454
 
    btn->y = y;
455
 
}
456
 
 
457
 
void
458
 
skin_window_set_drag_to_move(skin_window_t* wind,
459
 
                             gboolean       drag_to_move)
460
 
{
461
 
    wind->priv->enable_drag_to_move = drag_to_move;
462
 
}
463
 
 
464
 
skin_button_t*
465
 
skin_button_new(GdkPixbuf* normal_image,
466
 
                GdkPixbuf* highlight_image,
467
 
                GdkPixbuf* pressdown_image)
468
 
{
469
 
    skin_button_t* btn = malloc(sizeof(skin_button_t));
470
 
    btn->normal_image = normal_image;
471
 
    btn->highlight_image = highlight_image;
472
 
    btn->pressdown_image = pressdown_image;
473
 
    btn->width = gdk_pixbuf_get_width(normal_image);
474
 
    btn->height = gdk_pixbuf_get_height(normal_image);
475
 
    btn->priv = malloc(sizeof(skin_button_priv_t));
476
 
    memset(btn->priv, 0, sizeof(skin_button_priv_t));
477
 
    return btn;
478
 
}
479
 
 
480
 
void
481
 
skin_button_destroy(skin_button_t* btn)
482
 
{
483
 
    free(btn->priv);
484
 
    free(btn);
485
 
}
486
 
 
487
 
void
488
 
skin_button_set_image(skin_button_t* btn,
489
 
                      GdkPixbuf* normal_image,
490
 
                      GdkPixbuf* highlight_image,
491
 
                      GdkPixbuf* pressdown_image)
492
 
{
493
 
    /* since we're redraw it, we'd better check if we really changed
494
 
       the pixbuf. This can save a lot of time.
495
 
    */
496
 
    gboolean need_set = (btn->normal_image != normal_image) ||
497
 
        (btn->highlight_image != highlight_image) ||
498
 
        (btn->pressdown_image != pressdown_image);
499
 
 
500
 
    if (!need_set)
501
 
        return;
502
 
 
503
 
    btn->normal_image = normal_image;
504
 
    btn->highlight_image = highlight_image;
505
 
    btn->pressdown_image = pressdown_image;
506
 
    if (btn->priv->parent) {
507
 
        gtk_widget_queue_draw(btn->priv->parent->widget);
508
 
    }
509
 
}
510
 
 
511
 
skin_label_t*
512
 
skin_label_new(char*  font,
513
 
               char*  text,
514
 
               double color_r,
515
 
               double color_g,
516
 
               double color_b,
517
 
               double color_a)
518
 
{
519
 
    skin_label_t* label = malloc(sizeof(skin_label_t));
520
 
    label->color_r = color_r;
521
 
    label->color_g = color_g;
522
 
    label->color_b = color_b;
523
 
    label->color_a = color_a;
524
 
    label->font = strdup(font);
525
 
    if (text) {
526
 
        label->text = strdup(text);
527
 
    } else {
528
 
        label->text = NULL;
529
 
    }
530
 
    label->layout = NULL;
531
 
    label->priv = malloc(sizeof(skin_label_priv_t));
532
 
    memset(label->priv, 0, sizeof(skin_label_priv_t));
533
 
 
534
 
    return label;
535
 
}
536
 
 
537
 
void
538
 
skin_label_destroy(skin_label_t* label)
539
 
{
540
 
    free(label->text);
541
 
    free(label->font);
542
 
    free(label->priv);
543
 
    if (label->layout) {
544
 
        g_object_unref(label->layout);
545
 
    }
546
 
    free(label);
547
 
}
548
 
 
549
 
void
550
 
skin_window_add_label(skin_window_t* wind,
551
 
                      skin_label_t*  label,
552
 
                      int            x,
553
 
                      int            y)
554
 
{
555
 
    label->x = x;
556
 
    label->y = y;
557
 
    label->priv->wind = wind;
558
 
    label->priv->next = wind->priv->labels;
559
 
    wind->priv->labels = label;
560
 
 
561
 
    cairo_t* cr = gdk_cairo_create(wind->widget->window);
562
 
    label->layout = pango_cairo_create_layout(cr);
563
 
    pango_layout_set_font_description(
564
 
        label->layout, pango_font_description_from_string(label->font));
565
 
    cairo_destroy(cr);
566
 
}
567
 
 
568
 
void
569
 
skin_label_set_text(skin_label_t* label, const char* text)
570
 
{
571
 
    free(label->text);
572
 
    if (text) {
573
 
        label->text = strdup(text);
574
 
        pango_layout_set_text(label->layout, label->text, -1);
575
 
    } else {
576
 
        label->text = NULL;
577
 
    }
578
 
    if (label->layout && label->priv->wind) {
579
 
        gtk_widget_queue_draw(label->priv->wind->widget);
580
 
    }
581
 
}
582
 
 
583
 
#define SET_CB_IMPL(name, event)                                        \
584
 
    void skin_##name##_set_##event##_cb(skin_##name##_t* wid,           \
585
 
                                        GCallback        cb,            \
586
 
                                        void*            data)          \
587
 
    { wid->priv->event##_cb = cb; wid->priv->event##_cb_data = data; }  \
588
 
 
589
 
 
590
 
SET_CB_IMPL(window, press);
591
 
SET_CB_IMPL(window, release);
592
 
SET_CB_IMPL(window, motion);
593
 
SET_CB_IMPL(button, press);
594
 
SET_CB_IMPL(button, release);