~ctf/unity-settings-daemon/bug1389099_mic_volume_icons

« back to all changes in this revision

Viewing changes to plugins/wacom/gsd-wacom-osd-window.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-02-07 11:44:36 UTC
  • Revision ID: package-import@ubuntu.com-20140207114436-7t5u3yvwc4ul7w3e
Tags: upstream-14.04.0
ImportĀ upstreamĀ versionĀ 14.04.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2012 Red Hat, Inc.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
17
 *
 
18
 * Author: Olivier Fourdan <ofourdan@redhat.com>
 
19
 *
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <stdlib.h>
 
25
#include <stdio.h>
 
26
#include <glib/gi18n.h>
 
27
#include <gtk/gtk.h>
 
28
#include <cairo.h>
 
29
#include <librsvg/rsvg.h>
 
30
 
 
31
#include "gsd-wacom-osd-window.h"
 
32
#include "gsd-wacom-device.h"
 
33
#include "gsd-enums.h"
 
34
 
 
35
#define ROTATION_KEY                "rotation"
 
36
#define ACTION_TYPE_KEY             "action-type"
 
37
#define CUSTOM_ACTION_KEY           "custom-action"
 
38
#define CUSTOM_ELEVATOR_ACTION_KEY  "custom-elevator-action"
 
39
#define RES_PATH                    "/org/gnome/settings-daemon/plugins/wacom/"
 
40
 
 
41
#define BACK_OPACITY            0.8
 
42
#define INACTIVE_COLOR          "#ededed"
 
43
#define ACTIVE_COLOR            "#729fcf"
 
44
#define STROKE_COLOR            "#000000"
 
45
#define DARK_COLOR              "#535353"
 
46
#define BACK_COLOR              "#000000"
 
47
 
 
48
#define ELEVATOR_TIMEOUT        250 /* ms */
 
49
 
 
50
static struct {
 
51
        const gchar     *color_name;
 
52
        const gchar     *color_value;
 
53
} css_color_table[] = {
 
54
        { "inactive_color", INACTIVE_COLOR },
 
55
        { "active_color",   ACTIVE_COLOR   },
 
56
        { "stroke_color",   STROKE_COLOR   },
 
57
        { "dark_color",     DARK_COLOR     },
 
58
        { "back_color",     BACK_COLOR     }
 
59
};
 
60
 
 
61
static gchar *
 
62
replace_string (gchar **string, const gchar *search, const char *replacement)
 
63
{
 
64
        GRegex *regex;
 
65
        gchar *res;
 
66
 
 
67
        g_return_val_if_fail (*string != NULL, NULL);
 
68
        g_return_val_if_fail (string != NULL, NULL);
 
69
        g_return_val_if_fail (search != NULL, *string);
 
70
        g_return_val_if_fail (replacement != NULL, *string);
 
71
 
 
72
        regex = g_regex_new (search, 0, 0, NULL);
 
73
        res = g_regex_replace_literal (regex, *string, -1, 0, replacement, 0, NULL);
 
74
        g_regex_unref (regex);
 
75
        /* The given string is freed and replaced by the resulting replacement */
 
76
        g_free (*string);
 
77
        *string = res;
 
78
 
 
79
        return res;
 
80
}
 
81
 
 
82
static gchar
 
83
get_last_char (gchar *string)
 
84
{
 
85
        size_t pos;
 
86
 
 
87
        g_return_val_if_fail (string != NULL, '\0');
 
88
        pos = strlen (string);
 
89
        g_return_val_if_fail (pos > 0, '\0');
 
90
 
 
91
        return string[pos - 1];
 
92
}
 
93
 
 
94
static double
 
95
get_rotation_in_radian (GsdWacomRotation rotation)
 
96
{
 
97
        switch (rotation) {
 
98
        case GSD_WACOM_ROTATION_NONE:
 
99
                return 0.0;
 
100
                break;
 
101
        case GSD_WACOM_ROTATION_HALF:
 
102
                return G_PI;
 
103
                break;
 
104
        /* We only support left-handed/right-handed */
 
105
        case GSD_WACOM_ROTATION_CCW:
 
106
        case GSD_WACOM_ROTATION_CW:
 
107
        default:
 
108
                break;
 
109
        }
 
110
 
 
111
        /* Fallback */
 
112
        return 0.0;
 
113
}
 
114
 
 
115
static gboolean
 
116
get_sub_location (RsvgHandle *handle,
 
117
                  const char *sub,
 
118
                  cairo_t    *cr,
 
119
                  double     *x,
 
120
                  double     *y)
 
121
{
 
122
        RsvgPositionData  position;
 
123
        double tx, ty;
 
124
 
 
125
        if (!rsvg_handle_get_position_sub (handle, &position, sub)) {
 
126
                g_warning ("Failed to retrieve '%s' position", sub);
 
127
                return FALSE;
 
128
        }
 
129
 
 
130
        tx = (double) position.x;
 
131
        ty = (double) position.y;
 
132
        cairo_user_to_device (cr, &tx, &ty);
 
133
 
 
134
        if (x)
 
135
                *x = tx;
 
136
        if (y)
 
137
                *y = ty;
 
138
 
 
139
        return TRUE;
 
140
}
 
141
 
 
142
static gboolean
 
143
get_image_size (const char *filename, int *width, int *height)
 
144
{
 
145
        RsvgHandle       *handle;
 
146
        RsvgDimensionData dimensions;
 
147
        GError* error = NULL;
 
148
 
 
149
        if (filename == NULL)
 
150
                return FALSE;
 
151
 
 
152
        handle = rsvg_handle_new_from_file (filename, &error);
 
153
        if (error != NULL) {
 
154
                g_printerr ("%s\n", error->message);
 
155
                g_error_free (error);
 
156
        }
 
157
        if (handle == NULL)
 
158
                return FALSE;
 
159
 
 
160
        /* Compute image size */
 
161
        rsvg_handle_get_dimensions (handle, &dimensions);
 
162
        g_object_unref (handle);
 
163
 
 
164
        if (dimensions.width == 0 || dimensions.height == 0)
 
165
                return FALSE;
 
166
 
 
167
        if (width)
 
168
                *width = dimensions.width;
 
169
 
 
170
        if (height)
 
171
                *height = dimensions.height;
 
172
 
 
173
        return TRUE;
 
174
}
 
175
 
 
176
static int
 
177
get_pango_vertical_offset (PangoLayout *layout)
 
178
{
 
179
        const PangoFontDescription *desc;
 
180
        PangoContext               *context;
 
181
        PangoLanguage              *language;
 
182
        PangoFontMetrics           *metrics;
 
183
        int                         baseline;
 
184
        int                         strikethrough;
 
185
        int                         thickness;
 
186
 
 
187
        context = pango_layout_get_context (layout);
 
188
        language = pango_language_get_default ();
 
189
        desc = pango_layout_get_font_description (layout);
 
190
        metrics = pango_context_get_metrics (context, desc, language);
 
191
 
 
192
        baseline = pango_layout_get_baseline (layout);
 
193
        strikethrough =  pango_font_metrics_get_strikethrough_position (metrics);
 
194
        thickness =  pango_font_metrics_get_underline_thickness (metrics);
 
195
 
 
196
        return PANGO_PIXELS (baseline - strikethrough - thickness / 2);
 
197
}
 
198
 
 
199
#define GSD_TYPE_WACOM_OSD_BUTTON         (gsd_wacom_osd_button_get_type ())
 
200
#define GSD_WACOM_OSD_BUTTON(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_WACOM_OSD_BUTTON, GsdWacomOSDButton))
 
201
#define GSD_WACOM_OSD_BUTTON_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_WACOM_OSD_BUTTON, GsdWacomOSDButtonClass))
 
202
#define GSD_IS_WACOM_OSD_BUTTON(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_WACOM_OSD_BUTTON))
 
203
#define GSD_IS_WACOM_OSD_BUTTON_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_WACOM_OSD_BUTTON))
 
204
#define GSD_WACOM_OSD_BUTTON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_WACOM_OSD_BUTTON, GsdWacomOSDButtonClass))
 
205
 
 
206
typedef struct GsdWacomOSDButtonPrivate GsdWacomOSDButtonPrivate;
 
207
 
 
208
typedef struct {
 
209
        GObject                   parent;
 
210
        GsdWacomOSDButtonPrivate *priv;
 
211
} GsdWacomOSDButton;
 
212
 
 
213
typedef struct {
 
214
        GObjectClass              parent_class;
 
215
} GsdWacomOSDButtonClass;
 
216
 
 
217
GType                     gsd_wacom_osd_button_get_type        (void) G_GNUC_CONST;
 
218
 
 
219
enum {
 
220
        PROP_OSD_BUTTON_0,
 
221
        PROP_OSD_BUTTON_ID,
 
222
        PROP_OSD_BUTTON_CLASS,
 
223
        PROP_OSD_BUTTON_LABEL,
 
224
        PROP_OSD_BUTTON_ACTIVE,
 
225
        PROP_OSD_BUTTON_VISIBLE,
 
226
        PROP_OSD_BUTTON_AUTO_OFF
 
227
};
 
228
 
 
229
#define GSD_WACOM_OSD_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
 
230
                                             GSD_TYPE_WACOM_OSD_BUTTON, \
 
231
                                             GsdWacomOSDButtonPrivate))
 
232
#define MATCH_ID(b,s) (g_strcmp0 (b->priv->id, s) == 0)
 
233
 
 
234
struct GsdWacomOSDButtonPrivate {
 
235
        GtkWidget                *widget;
 
236
        char                     *id;
 
237
        char                     *class;
 
238
        char                     *label;
 
239
        double                    label_x;
 
240
        double                    label_y;
 
241
        GsdWacomTabletButtonType  type;
 
242
        GsdWacomTabletButtonPos   position;
 
243
        gboolean                  active;
 
244
        gboolean                  visible;
 
245
        guint                     auto_off;
 
246
        guint                     timeout;
 
247
};
 
248
 
 
249
static void     gsd_wacom_osd_button_class_init  (GsdWacomOSDButtonClass *klass);
 
250
static void     gsd_wacom_osd_button_init        (GsdWacomOSDButton      *osd_button);
 
251
static void     gsd_wacom_osd_button_finalize    (GObject                *object);
 
252
 
 
253
G_DEFINE_TYPE (GsdWacomOSDButton, gsd_wacom_osd_button, G_TYPE_OBJECT)
 
254
 
 
255
static void
 
256
gsd_wacom_osd_button_set_id (GsdWacomOSDButton *osd_button,
 
257
                             const gchar       *id)
 
258
{
 
259
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
 
260
 
 
261
        osd_button->priv->id = g_strdup (id);
 
262
}
 
263
 
 
264
static void
 
265
gsd_wacom_osd_button_set_class (GsdWacomOSDButton *osd_button,
 
266
                                const gchar       *class)
 
267
{
 
268
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
 
269
 
 
270
        osd_button->priv->class = g_strdup (class);
 
271
}
 
272
 
 
273
static gchar*
 
274
gsd_wacom_osd_button_get_label_class (GsdWacomOSDButton *osd_button)
 
275
{
 
276
        gchar *label_class;
 
277
 
 
278
        label_class = g_strconcat ("#Label", osd_button->priv->class, NULL);
 
279
 
 
280
        return (label_class);
 
281
}
 
282
 
 
283
static void
 
284
gsd_wacom_osd_button_set_label (GsdWacomOSDButton *osd_button,
 
285
                                const gchar       *str)
 
286
{
 
287
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
 
288
 
 
289
        g_free (osd_button->priv->label);
 
290
        osd_button->priv->label = g_strdup (str ? str : "");
 
291
}
 
292
 
 
293
static void
 
294
gsd_wacom_osd_button_set_button_type (GsdWacomOSDButton        *osd_button,
 
295
                                      GsdWacomTabletButtonType  type)
 
296
{
 
297
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
 
298
 
 
299
        osd_button->priv->type = type;
 
300
}
 
301
 
 
302
static void
 
303
gsd_wacom_osd_button_set_position (GsdWacomOSDButton        *osd_button,
 
304
                                   GsdWacomTabletButtonPos   position)
 
305
{
 
306
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
 
307
 
 
308
        osd_button->priv->position = position;
 
309
}
 
310
 
 
311
static void
 
312
gsd_wacom_osd_button_set_location (GsdWacomOSDButton        *osd_button,
 
313
                                   double                    x,
 
314
                                   double                    y)
 
315
{
 
316
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
 
317
 
 
318
        osd_button->priv->label_x = x;
 
319
        osd_button->priv->label_y = y;
 
320
}
 
321
 
 
322
static void
 
323
gsd_wacom_osd_button_set_auto_off (GsdWacomOSDButton        *osd_button,
 
324
                                   guint                     timeout)
 
325
{
 
326
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
 
327
 
 
328
        osd_button->priv->auto_off = timeout;
 
329
}
 
330
 
 
331
static void
 
332
gsd_wacom_osd_button_redraw (GsdWacomOSDButton *osd_button)
 
333
{
 
334
        GdkWindow *window;
 
335
 
 
336
        g_return_if_fail (GTK_IS_WIDGET (osd_button->priv->widget));
 
337
 
 
338
        window = gtk_widget_get_window (GTK_WIDGET (osd_button->priv->widget));
 
339
        gdk_window_invalidate_rect (window, NULL, FALSE);
 
340
}
 
341
 
 
342
static gboolean
 
343
gsd_wacom_osd_button_timer (GsdWacomOSDButton *osd_button)
 
344
{
 
345
        /* Auto de-activate the button */
 
346
        osd_button->priv->active = FALSE;
 
347
        gsd_wacom_osd_button_redraw (osd_button);
 
348
 
 
349
        return FALSE;
 
350
}
 
351
 
 
352
static void
 
353
gsd_wacom_osd_button_set_active (GsdWacomOSDButton *osd_button,
 
354
                                 gboolean           active)
 
355
{
 
356
        gboolean previous_state;
 
357
 
 
358
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
 
359
 
 
360
        previous_state = osd_button->priv->active;
 
361
        if (osd_button->priv->auto_off > 0) {
 
362
                /* For auto-off buttons, apply only if active, de-activation is done in the timeout */
 
363
                if (active == TRUE)
 
364
                        osd_button->priv->active = active;
 
365
 
 
366
                if (osd_button->priv->timeout)
 
367
                        g_source_remove (osd_button->priv->timeout);
 
368
                osd_button->priv->timeout = g_timeout_add (osd_button->priv->auto_off,
 
369
                                                           (GSourceFunc) gsd_wacom_osd_button_timer,
 
370
                                                           osd_button);
 
371
        } else {
 
372
                /* Whereas for other buttons, apply the change straight away */
 
373
                osd_button->priv->active = active;
 
374
        }
 
375
 
 
376
        if (previous_state != osd_button->priv->active)
 
377
                gsd_wacom_osd_button_redraw (osd_button);
 
378
}
 
379
 
 
380
static void
 
381
gsd_wacom_osd_button_set_visible (GsdWacomOSDButton *osd_button,
 
382
                                  gboolean           visible)
 
383
{
 
384
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
 
385
 
 
386
        osd_button->priv->visible = visible;
 
387
}
 
388
 
 
389
static GsdWacomOSDButton *
 
390
gsd_wacom_osd_button_new (GtkWidget *widget,
 
391
                          gchar *id)
 
392
{
 
393
        GsdWacomOSDButton *osd_button;
 
394
 
 
395
        osd_button = GSD_WACOM_OSD_BUTTON (g_object_new (GSD_TYPE_WACOM_OSD_BUTTON,
 
396
                                                         "id", id,
 
397
                                                         NULL));
 
398
        osd_button->priv->widget = widget;
 
399
 
 
400
        return osd_button;
 
401
}
 
402
 
 
403
static void
 
404
gsd_wacom_osd_button_set_property (GObject        *object,
 
405
                                   guint           prop_id,
 
406
                                   const GValue   *value,
 
407
                                   GParamSpec     *pspec)
 
408
{
 
409
        GsdWacomOSDButton *osd_button;
 
410
 
 
411
        osd_button = GSD_WACOM_OSD_BUTTON (object);
 
412
 
 
413
        switch (prop_id) {
 
414
        case PROP_OSD_BUTTON_ID:
 
415
                gsd_wacom_osd_button_set_id (osd_button, g_value_get_string (value));
 
416
                break;
 
417
        case PROP_OSD_BUTTON_CLASS:
 
418
                gsd_wacom_osd_button_set_class (osd_button, g_value_get_string (value));
 
419
                break;
 
420
        case PROP_OSD_BUTTON_LABEL:
 
421
                gsd_wacom_osd_button_set_label (osd_button, g_value_get_string (value));
 
422
                break;
 
423
        case PROP_OSD_BUTTON_ACTIVE:
 
424
                gsd_wacom_osd_button_set_active (osd_button, g_value_get_boolean (value));
 
425
                break;
 
426
        case PROP_OSD_BUTTON_VISIBLE:
 
427
                gsd_wacom_osd_button_set_visible (osd_button, g_value_get_boolean (value));
 
428
                break;
 
429
        case PROP_OSD_BUTTON_AUTO_OFF:
 
430
                gsd_wacom_osd_button_set_auto_off (osd_button, g_value_get_uint (value));
 
431
                break;
 
432
        default:
 
433
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
434
                break;
 
435
        }
 
436
}
 
437
 
 
438
static void
 
439
gsd_wacom_osd_button_get_property (GObject        *object,
 
440
                                   guint           prop_id,
 
441
                                   GValue         *value,
 
442
                                   GParamSpec     *pspec)
 
443
{
 
444
        GsdWacomOSDButton *osd_button;
 
445
 
 
446
        osd_button = GSD_WACOM_OSD_BUTTON (object);
 
447
 
 
448
        switch (prop_id) {
 
449
        case PROP_OSD_BUTTON_ID:
 
450
                g_value_set_string (value, osd_button->priv->id);
 
451
                break;
 
452
        case PROP_OSD_BUTTON_CLASS:
 
453
                g_value_set_string (value, osd_button->priv->class);
 
454
                break;
 
455
        case PROP_OSD_BUTTON_LABEL:
 
456
                g_value_set_string (value, osd_button->priv->label);
 
457
                break;
 
458
        case PROP_OSD_BUTTON_ACTIVE:
 
459
                g_value_set_boolean (value, osd_button->priv->active);
 
460
                break;
 
461
        case PROP_OSD_BUTTON_VISIBLE:
 
462
                g_value_set_boolean (value, osd_button->priv->visible);
 
463
                break;
 
464
        case PROP_OSD_BUTTON_AUTO_OFF:
 
465
                g_value_set_uint (value, osd_button->priv->auto_off);
 
466
                break;
 
467
        default:
 
468
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
469
                break;
 
470
        }
 
471
}
 
472
 
 
473
static void
 
474
gsd_wacom_osd_button_class_init (GsdWacomOSDButtonClass *klass)
 
475
{
 
476
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
477
 
 
478
        object_class->set_property = gsd_wacom_osd_button_set_property;
 
479
        object_class->get_property = gsd_wacom_osd_button_get_property;
 
480
        object_class->finalize = gsd_wacom_osd_button_finalize;
 
481
 
 
482
        g_object_class_install_property (object_class,
 
483
                                         PROP_OSD_BUTTON_ID,
 
484
                                         g_param_spec_string ("id",
 
485
                                                              "Button Id",
 
486
                                                              "The Wacom Button ID",
 
487
                                                              "",
 
488
                                                              G_PARAM_READWRITE));
 
489
        g_object_class_install_property (object_class,
 
490
                                         PROP_OSD_BUTTON_CLASS,
 
491
                                         g_param_spec_string ("class",
 
492
                                                              "Button Class",
 
493
                                                              "The Wacom Button Class",
 
494
                                                              "",
 
495
                                                              G_PARAM_READWRITE));
 
496
        g_object_class_install_property (object_class,
 
497
                                         PROP_OSD_BUTTON_LABEL,
 
498
                                         g_param_spec_string ("label",
 
499
                                                              "Label",
 
500
                                                              "The button label",
 
501
                                                              "",
 
502
                                                              G_PARAM_READWRITE));
 
503
        g_object_class_install_property (object_class,
 
504
                                         PROP_OSD_BUTTON_ACTIVE,
 
505
                                         g_param_spec_boolean ("active",
 
506
                                                               "Active",
 
507
                                                               "Whether the button is active",
 
508
                                                               FALSE,
 
509
                                                               G_PARAM_READWRITE));
 
510
        g_object_class_install_property (object_class,
 
511
                                         PROP_OSD_BUTTON_VISIBLE,
 
512
                                         g_param_spec_boolean ("visible",
 
513
                                                               "Visible",
 
514
                                                               "Whether the button is visible",
 
515
                                                               TRUE,
 
516
                                                               G_PARAM_READWRITE));
 
517
        g_object_class_install_property (object_class,
 
518
                                         PROP_OSD_BUTTON_AUTO_OFF,
 
519
                                         g_param_spec_uint    ("auto-off",
 
520
                                                               "Auto Off",
 
521
                                                               "Timeout before button disables itself automatically",
 
522
                                                               0,
 
523
                                                               G_MAXUINT,
 
524
                                                               0, /* disabled by default */
 
525
                                                               G_PARAM_READWRITE));
 
526
 
 
527
        g_type_class_add_private (klass, sizeof (GsdWacomOSDButtonPrivate));
 
528
}
 
529
 
 
530
static void
 
531
gsd_wacom_osd_button_init (GsdWacomOSDButton *osd_button)
 
532
{
 
533
        osd_button->priv = GSD_WACOM_OSD_BUTTON_GET_PRIVATE (osd_button);
 
534
}
 
535
 
 
536
static void
 
537
gsd_wacom_osd_button_finalize (GObject *object)
 
538
{
 
539
        GsdWacomOSDButton *osd_button;
 
540
        GsdWacomOSDButtonPrivate *priv;
 
541
 
 
542
        g_return_if_fail (object != NULL);
 
543
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (object));
 
544
 
 
545
        osd_button = GSD_WACOM_OSD_BUTTON (object);
 
546
 
 
547
        g_return_if_fail (osd_button->priv != NULL);
 
548
 
 
549
        priv = osd_button->priv;
 
550
 
 
551
        if (priv->timeout > 0)
 
552
                g_source_remove (priv->timeout);
 
553
        g_clear_pointer (&priv->id, g_free);
 
554
        g_clear_pointer (&priv->class, g_free);
 
555
        g_clear_pointer (&priv->label, g_free);
 
556
 
 
557
        G_OBJECT_CLASS (gsd_wacom_osd_button_parent_class)->finalize (object);
 
558
}
 
559
 
 
560
/* Compute the new actual position once rotation is applied */
 
561
static GsdWacomTabletButtonPos
 
562
get_actual_position (GsdWacomTabletButtonPos position,
 
563
                     GsdWacomRotation        rotation)
 
564
{
 
565
        switch (rotation) {
 
566
        case GSD_WACOM_ROTATION_NONE:
 
567
                return position;
 
568
                break;
 
569
        case GSD_WACOM_ROTATION_HALF:
 
570
                if (position == WACOM_TABLET_BUTTON_POS_LEFT)
 
571
                        return WACOM_TABLET_BUTTON_POS_RIGHT;
 
572
                if (position == WACOM_TABLET_BUTTON_POS_RIGHT)
 
573
                        return WACOM_TABLET_BUTTON_POS_LEFT;
 
574
                if (position == WACOM_TABLET_BUTTON_POS_TOP)
 
575
                        return WACOM_TABLET_BUTTON_POS_BOTTOM;
 
576
                if (position == WACOM_TABLET_BUTTON_POS_BOTTOM)
 
577
                        return WACOM_TABLET_BUTTON_POS_TOP;
 
578
                break;
 
579
        /* We only support left-handed/right-handed */
 
580
        case GSD_WACOM_ROTATION_CCW:
 
581
        case GSD_WACOM_ROTATION_CW:
 
582
        default:
 
583
                break;
 
584
        }
 
585
        /* fallback */
 
586
        return position;
 
587
}
 
588
 
 
589
static void
 
590
gsd_wacom_osd_button_draw_label (GsdWacomOSDButton *osd_button,
 
591
                                 GtkStyleContext   *style_context,
 
592
                                 PangoContext      *pango_context,
 
593
                                 cairo_t           *cr,
 
594
                                 GsdWacomRotation   rotation)
 
595
{
 
596
        GsdWacomOSDButtonPrivate *priv;
 
597
        PangoLayout              *layout;
 
598
        PangoRectangle            logical_rect;
 
599
        GsdWacomTabletButtonPos   actual_position;
 
600
        double                    lx, ly;
 
601
        gchar                    *markup;
 
602
 
 
603
        g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
 
604
 
 
605
        priv = osd_button->priv;
 
606
        if (priv->visible == FALSE)
 
607
                return;
 
608
 
 
609
        actual_position = get_actual_position (priv->position, rotation);
 
610
        layout = pango_layout_new (pango_context);
 
611
        if (priv->active)
 
612
                markup = g_strdup_printf ("<span foreground=\"" ACTIVE_COLOR "\" weight=\"normal\">%s</span>", priv->label);
 
613
        else
 
614
                markup = g_strdup_printf ("<span foreground=\"" INACTIVE_COLOR "\" weight=\"normal\">%s</span>", priv->label);
 
615
        pango_layout_set_markup (layout, markup, -1);
 
616
        g_free (markup);
 
617
 
 
618
        pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
 
619
        switch (actual_position) {
 
620
        case WACOM_TABLET_BUTTON_POS_LEFT:
 
621
                pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT);
 
622
                lx = priv->label_x + logical_rect.x;
 
623
                ly = priv->label_y + logical_rect.y - get_pango_vertical_offset (layout);
 
624
                break;
 
625
        case WACOM_TABLET_BUTTON_POS_RIGHT:
 
626
                pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
 
627
                lx = priv->label_x + logical_rect.x - logical_rect.width;
 
628
                ly = priv->label_y + logical_rect.y - get_pango_vertical_offset (layout);
 
629
                break;
 
630
        case WACOM_TABLET_BUTTON_POS_TOP:
 
631
                pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
 
632
                lx = priv->label_x + logical_rect.x - logical_rect.width / 2;
 
633
                ly = priv->label_y + logical_rect.y;
 
634
                break;
 
635
        case WACOM_TABLET_BUTTON_POS_BOTTOM:
 
636
                pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
 
637
                lx = priv->label_x + logical_rect.x - logical_rect.width / 2;
 
638
                ly = priv->label_y + logical_rect.y - logical_rect.height;
 
639
                break;
 
640
        default:
 
641
                g_warning ("Unhandled button position");
 
642
                pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
 
643
                lx = priv->label_x + logical_rect.x - logical_rect.width / 2;
 
644
                ly = priv->label_y + logical_rect.y - logical_rect.height / 2;
 
645
                break;
 
646
        }
 
647
        gtk_render_layout (style_context, cr, lx, ly, layout);
 
648
        g_object_unref (layout);
 
649
}
 
650
 
 
651
enum {
 
652
  PROP_OSD_WINDOW_0,
 
653
  PROP_OSD_WINDOW_MESSAGE,
 
654
  PROP_OSD_WINDOW_GSD_WACOM_DEVICE
 
655
};
 
656
 
 
657
#define GSD_WACOM_OSD_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
 
658
                                             GSD_TYPE_WACOM_OSD_WINDOW, \
 
659
                                             GsdWacomOSDWindowPrivate))
 
660
 
 
661
struct GsdWacomOSDWindowPrivate
 
662
{
 
663
        RsvgHandle               *handle;
 
664
        GsdWacomDevice           *pad;
 
665
        GsdWacomRotation          rotation;
 
666
        GdkRectangle              screen_area;
 
667
        GdkRectangle              monitor_area;
 
668
        GdkRectangle              tablet_area;
 
669
        char                     *message;
 
670
        GList                    *buttons;
 
671
};
 
672
 
 
673
static void     gsd_wacom_osd_window_class_init  (GsdWacomOSDWindowClass *klass);
 
674
static void     gsd_wacom_osd_window_init        (GsdWacomOSDWindow      *osd_window);
 
675
static void     gsd_wacom_osd_window_finalize    (GObject                *object);
 
676
 
 
677
G_DEFINE_TYPE (GsdWacomOSDWindow, gsd_wacom_osd_window, GTK_TYPE_WINDOW)
 
678
 
 
679
static RsvgHandle *
 
680
load_rsvg_with_base (const char  *css_string,
 
681
                     const char  *original_layout_path,
 
682
                     GError     **error)
 
683
{
 
684
        RsvgHandle *handle;
 
685
        char *dirname;
 
686
 
 
687
        handle = rsvg_handle_new ();
 
688
 
 
689
        dirname = g_path_get_dirname (original_layout_path);
 
690
        rsvg_handle_set_base_uri (handle, dirname);
 
691
        g_free (dirname);
 
692
 
 
693
        if (!rsvg_handle_write (handle,
 
694
                                (guint8 *) css_string,
 
695
                                strlen (css_string),
 
696
                                error)) {
 
697
                g_object_unref (handle);
 
698
                return NULL;
 
699
        }
 
700
        if (!rsvg_handle_close (handle, error)) {
 
701
                g_object_unref (handle);
 
702
                return NULL;
 
703
        }
 
704
 
 
705
        return handle;
 
706
}
 
707
 
 
708
static void
 
709
gsd_wacom_osd_window_update (GsdWacomOSDWindow *osd_window)
 
710
{
 
711
        GError      *error = NULL;
 
712
        gchar       *width, *height;
 
713
        gchar       *buttons_section;
 
714
        gchar       *css_string;
 
715
        const gchar *layout_file;
 
716
        GBytes      *css_data;
 
717
        guint i;
 
718
        GList *l;
 
719
 
 
720
        g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
 
721
        g_return_if_fail (GSD_IS_WACOM_DEVICE (osd_window->priv->pad));
 
722
 
 
723
        css_data = g_resources_lookup_data (RES_PATH "tablet-layout.css", 0, &error);
 
724
        if (error != NULL) {
 
725
                g_printerr ("GResource error: %s\n", error->message);
 
726
                g_clear_pointer (&error, g_error_free);
 
727
        }
 
728
        if (css_data == NULL)
 
729
                return;
 
730
        css_string = g_strdup ((gchar *) g_bytes_get_data (css_data, NULL));
 
731
        g_bytes_unref(css_data);
 
732
 
 
733
        width = g_strdup_printf ("%d", osd_window->priv->tablet_area.width);
 
734
        replace_string (&css_string, "layout_width", width);
 
735
        g_free (width);
 
736
 
 
737
        height = g_strdup_printf ("%d", osd_window->priv->tablet_area.height);
 
738
        replace_string (&css_string, "layout_height", height);
 
739
        g_free (height);
 
740
 
 
741
        /* Build the buttons section */
 
742
        buttons_section = g_strdup ("");
 
743
        for (l = osd_window->priv->buttons; l != NULL; l = l->next) {
 
744
                GsdWacomOSDButton *osd_button = l->data;
 
745
 
 
746
                if (osd_button->priv->visible == FALSE)
 
747
                        continue;
 
748
 
 
749
                if (osd_button->priv->active) {
 
750
                        buttons_section = g_strconcat (buttons_section,
 
751
                                                       ".", osd_button->priv->class, " {\n"
 
752
                                                       "      stroke:   active_color !important;\n"
 
753
                                                       "      fill:     active_color !important;\n"
 
754
                                                       "    }\n",
 
755
                                                       NULL);
 
756
                }
 
757
        }
 
758
        replace_string (&css_string, "buttons_section", buttons_section);
 
759
        g_free (buttons_section);
 
760
 
 
761
        for (i = 0; i < G_N_ELEMENTS (css_color_table); i++)
 
762
                replace_string (&css_string,
 
763
                                css_color_table[i].color_name,
 
764
                                css_color_table[i].color_value);
 
765
 
 
766
        layout_file = gsd_wacom_device_get_layout_path (osd_window->priv->pad);
 
767
        replace_string (&css_string, "layout_file", layout_file);
 
768
 
 
769
        /* Render the SVG with the CSS applied */
 
770
        g_clear_object (&osd_window->priv->handle);
 
771
        osd_window->priv->handle = load_rsvg_with_base (css_string, layout_file, &error);
 
772
        if (osd_window->priv->handle == NULL) {
 
773
                g_debug ("CSS applied:\n%s\n", css_string);
 
774
                g_printerr ("RSVG error: %s\n", error->message);
 
775
                g_clear_error (&error);
 
776
        }
 
777
        g_free (css_string);
 
778
}
 
779
 
 
780
static void
 
781
gsd_wacom_osd_window_draw_message (GsdWacomOSDWindow   *osd_window,
 
782
                                   GtkStyleContext     *style_context,
 
783
                                   PangoContext        *pango_context,
 
784
                                   cairo_t             *cr)
 
785
{
 
786
        GdkRectangle  *monitor_area = &osd_window->priv->monitor_area;
 
787
        PangoRectangle logical_rect;
 
788
        PangoLayout *layout;
 
789
        char *markup;
 
790
        double x;
 
791
        double y;
 
792
 
 
793
        if (osd_window->priv->message == NULL)
 
794
                return;
 
795
 
 
796
        layout = pango_layout_new (pango_context);
 
797
        pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
 
798
 
 
799
        markup = g_strdup_printf ("<span foreground=\"white\">%s</span>", osd_window->priv->message);
 
800
        pango_layout_set_markup (layout, markup, -1);
 
801
        g_free (markup);
 
802
 
 
803
        pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
 
804
        x = (monitor_area->width - logical_rect.width) / 2 + logical_rect.x;
 
805
        y = (monitor_area->height - logical_rect.height) / 2 + logical_rect.y;
 
806
 
 
807
        gtk_render_layout (style_context, cr, x, y, layout);
 
808
        g_object_unref (layout);
 
809
}
 
810
 
 
811
static void
 
812
gsd_wacom_osd_window_draw_labels (GsdWacomOSDWindow   *osd_window,
 
813
                                  GtkStyleContext     *style_context,
 
814
                                  PangoContext        *pango_context,
 
815
                                  cairo_t             *cr)
 
816
{
 
817
        GList *l;
 
818
 
 
819
        for (l = osd_window->priv->buttons; l != NULL; l = l->next) {
 
820
                GsdWacomOSDButton *osd_button = l->data;
 
821
 
 
822
                if (osd_button->priv->visible == FALSE)
 
823
                        continue;
 
824
 
 
825
                gsd_wacom_osd_button_draw_label (osd_button,
 
826
                                                 style_context,
 
827
                                                 pango_context,
 
828
                                                 cr,
 
829
                                                 osd_window->priv->rotation);
 
830
        }
 
831
}
 
832
 
 
833
static void
 
834
gsd_wacom_osd_window_place_buttons (GsdWacomOSDWindow *osd_window,
 
835
                                    cairo_t           *cr)
 
836
{
 
837
        GList            *l;
 
838
 
 
839
        g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
 
840
 
 
841
        for (l = osd_window->priv->buttons; l != NULL; l = l->next) {
 
842
                GsdWacomOSDButton *osd_button = l->data;
 
843
                double             label_x, label_y;
 
844
                gchar             *sub;
 
845
 
 
846
                sub = gsd_wacom_osd_button_get_label_class (osd_button);
 
847
                if (!get_sub_location (osd_window->priv->handle, sub, cr, &label_x, &label_y)) {
 
848
                        g_warning ("Failed to retrieve %s position", sub);
 
849
                        g_free (sub);
 
850
                        continue;
 
851
                }
 
852
                g_free (sub);
 
853
                gsd_wacom_osd_button_set_location (osd_button, label_x, label_y);
 
854
        }
 
855
}
 
856
 
 
857
/* Note: this function does modify the given cairo context */
 
858
static void
 
859
gsd_wacom_osd_window_adjust_cairo (GsdWacomOSDWindow *osd_window,
 
860
                                   cairo_t           *cr)
 
861
{
 
862
        double         scale, twidth, theight;
 
863
        GdkRectangle  *tablet_area  = &osd_window->priv->tablet_area;
 
864
        GdkRectangle  *screen_area  = &osd_window->priv->screen_area;
 
865
        GdkRectangle  *monitor_area = &osd_window->priv->monitor_area;
 
866
 
 
867
        /* Rotate */
 
868
        cairo_rotate (cr, get_rotation_in_radian (osd_window->priv->rotation));
 
869
 
 
870
        /* Scale to fit in window */
 
871
        scale = MIN ((double) monitor_area->width / tablet_area->width,
 
872
                     (double) monitor_area->height / tablet_area->height);
 
873
        cairo_scale (cr, scale, scale);
 
874
 
 
875
        /* Center the result in window */
 
876
        twidth = (double) tablet_area->width;
 
877
        theight = (double) tablet_area->height;
 
878
        cairo_user_to_device_distance (cr, &twidth, &theight);
 
879
 
 
880
        twidth = ((double) monitor_area->width - twidth) / 2.0;
 
881
        theight = ((double) monitor_area->height - theight) / 2.0;
 
882
        cairo_device_to_user_distance (cr, &twidth, &theight);
 
883
 
 
884
        twidth = twidth + (double) (monitor_area->x - screen_area->x);
 
885
        theight = theight + (double) (monitor_area->y - screen_area->y);
 
886
 
 
887
        cairo_translate (cr, twidth, theight);
 
888
}
 
889
 
 
890
static gboolean
 
891
gsd_wacom_osd_window_draw (GtkWidget *widget,
 
892
                           cairo_t   *cr)
 
893
{
 
894
        GsdWacomOSDWindow *osd_window = GSD_WACOM_OSD_WINDOW (widget);
 
895
 
 
896
        g_return_val_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window), FALSE);
 
897
        g_return_val_if_fail (GSD_IS_WACOM_DEVICE (osd_window->priv->pad), FALSE);
 
898
 
 
899
        if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget))) {
 
900
                GtkStyleContext     *style_context;
 
901
                PangoContext        *pango_context;
 
902
 
 
903
                style_context = gtk_widget_get_style_context (widget);
 
904
                pango_context = gtk_widget_get_pango_context (widget);
 
905
 
 
906
                cairo_set_source_rgba (cr, 0, 0, 0, BACK_OPACITY);
 
907
                cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
908
                cairo_paint (cr);
 
909
                cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
910
 
 
911
                /* Save original matrix */
 
912
                cairo_save (cr);
 
913
 
 
914
                /* Apply new cairo transformation matrix */
 
915
                gsd_wacom_osd_window_adjust_cairo (osd_window, cr);
 
916
 
 
917
                /* And render the tablet layout */
 
918
                gsd_wacom_osd_window_update (osd_window);
 
919
                rsvg_handle_render_cairo (osd_window->priv->handle, cr);
 
920
 
 
921
                gsd_wacom_osd_window_place_buttons (osd_window, cr);
 
922
 
 
923
                /* Reset to original matrix */
 
924
                cairo_restore (cr);
 
925
 
 
926
                /* Draw button labels and message */
 
927
                gsd_wacom_osd_window_draw_labels (osd_window,
 
928
                                                  style_context,
 
929
                                                  pango_context,
 
930
                                                  cr);
 
931
                gsd_wacom_osd_window_draw_message (osd_window,
 
932
                                                   style_context,
 
933
                                                   pango_context,
 
934
                                                   cr);
 
935
        }
 
936
 
 
937
        return FALSE;
 
938
}
 
939
 
 
940
static gchar *
 
941
get_escaped_accel_shortcut (const gchar *accel)
 
942
{
 
943
        guint keyval;
 
944
        GdkModifierType mask;
 
945
        gchar *str, *label;
 
946
 
 
947
        if (accel == NULL || accel[0] == '\0')
 
948
                return g_strdup (C_("Action type", "None"));
 
949
 
 
950
        gtk_accelerator_parse (accel, &keyval, &mask);
 
951
 
 
952
        str = gtk_accelerator_get_label (keyval, mask);
 
953
        label = g_markup_printf_escaped (C_("Action type", "Send Keystroke %s"), str);
 
954
        g_free (str);
 
955
 
 
956
        return label;
 
957
}
 
958
 
 
959
static gchar *
 
960
get_tablet_button_label_normal (GsdWacomDevice       *device,
 
961
                                GsdWacomTabletButton *button)
 
962
{
 
963
        GsdWacomActionType type;
 
964
        gchar *name, *str;
 
965
 
 
966
        type = g_settings_get_enum (button->settings, ACTION_TYPE_KEY);
 
967
        if (type == GSD_WACOM_ACTION_TYPE_NONE)
 
968
                return g_strdup (C_("Action type", "None"));
 
969
 
 
970
        if (type == GSD_WACOM_ACTION_TYPE_HELP)
 
971
                return g_strdup (C_("Action type", "Show On-Screen Help"));
 
972
 
 
973
        if (type == GSD_WACOM_ACTION_TYPE_SWITCH_MONITOR)
 
974
                return g_strdup (C_("Action type", "Switch Monitor"));
 
975
 
 
976
        str = g_settings_get_string (button->settings, CUSTOM_ACTION_KEY);
 
977
        if (str == NULL || *str == '\0') {
 
978
                g_free (str);
 
979
                return g_strdup (C_("Action type", "None"));
 
980
        }
 
981
 
 
982
        name = get_escaped_accel_shortcut (str);
 
983
        g_free (str);
 
984
 
 
985
        return name;
 
986
}
 
987
 
 
988
static gchar *
 
989
get_tablet_button_label_touch  (GsdWacomDevice       *device,
 
990
                                GsdWacomTabletButton *button,
 
991
                                GtkDirectionType      dir)
 
992
{
 
993
        char **strv, *name, *str;
 
994
 
 
995
        strv = g_settings_get_strv (button->settings, CUSTOM_ELEVATOR_ACTION_KEY);
 
996
        name = NULL;
 
997
 
 
998
        if (strv) {
 
999
                if (g_strv_length (strv) >= 1 && dir == GTK_DIR_UP)
 
1000
                        name = g_strdup (strv[0]);
 
1001
                else if (g_strv_length (strv) >= 2 && dir == GTK_DIR_DOWN)
 
1002
                        name = g_strdup (strv[1]);
 
1003
                g_strfreev (strv);
 
1004
        }
 
1005
 
 
1006
        str = get_escaped_accel_shortcut (name);
 
1007
        g_free (name);
 
1008
        name = str;
 
1009
 
 
1010
        /* With multiple modes, also show the current mode for that action */
 
1011
        if (gsd_wacom_device_get_num_modes (device, button->group_id) > 1) {
 
1012
                name = g_strdup_printf (_("Mode %d: %s"), button->idx + 1, str);
 
1013
                g_free (str);
 
1014
        }
 
1015
 
 
1016
        return name;
 
1017
}
 
1018
 
 
1019
static gchar *
 
1020
get_tablet_button_label (GsdWacomDevice       *device,
 
1021
                         GsdWacomTabletButton *button,
 
1022
                         GtkDirectionType      dir)
 
1023
{
 
1024
        g_return_val_if_fail (button, NULL);
 
1025
 
 
1026
        if (!button->settings)
 
1027
                goto out;
 
1028
 
 
1029
        switch (button->type) {
 
1030
        case WACOM_TABLET_BUTTON_TYPE_NORMAL:
 
1031
                return get_tablet_button_label_normal (device, button);
 
1032
                break;
 
1033
        case WACOM_TABLET_BUTTON_TYPE_RING:
 
1034
        case WACOM_TABLET_BUTTON_TYPE_STRIP:
 
1035
                return get_tablet_button_label_touch (device, button, dir);
 
1036
                break;
 
1037
        case WACOM_TABLET_BUTTON_TYPE_HARDCODED:
 
1038
        default:
 
1039
                break;
 
1040
        }
 
1041
out:
 
1042
        return g_strdup (button->name);
 
1043
}
 
1044
 
 
1045
static gchar*
 
1046
get_tablet_button_class_name (GsdWacomTabletButton *tablet_button,
 
1047
                              GtkDirectionType      dir)
 
1048
{
 
1049
        gchar *id;
 
1050
        gchar  c;
 
1051
 
 
1052
        id = tablet_button->id;
 
1053
        switch (tablet_button->type) {
 
1054
        case WACOM_TABLET_BUTTON_TYPE_RING:
 
1055
                if (id[0] == 'l') /* left-ring */
 
1056
                        return g_strdup_printf ("Ring%s", (dir == GTK_DIR_UP ? "CCW" : "CW"));
 
1057
                if (id[0] == 'r') /* right-ring */
 
1058
                        return g_strdup_printf ("Ring2%s", (dir == GTK_DIR_UP ? "CCW" : "CW"));
 
1059
                g_warning ("Unknown ring type '%s'", id);
 
1060
                return NULL;
 
1061
                break;
 
1062
        case WACOM_TABLET_BUTTON_TYPE_STRIP:
 
1063
                if (id[0] == 'l') /* left-strip */
 
1064
                        return g_strdup_printf ("Strip%s", (dir == GTK_DIR_UP ? "Up" : "Down"));
 
1065
                if (id[0] == 'r') /* right-strip */
 
1066
                        return g_strdup_printf ("Strip2%s", (dir == GTK_DIR_UP ? "Up" : "Down"));
 
1067
                g_warning ("Unknown strip type '%s'", id);
 
1068
                return NULL;
 
1069
                break;
 
1070
        case WACOM_TABLET_BUTTON_TYPE_NORMAL:
 
1071
        case WACOM_TABLET_BUTTON_TYPE_HARDCODED:
 
1072
                c = get_last_char (id);
 
1073
                return g_strdup_printf ("%c", g_ascii_toupper (c));
 
1074
                break;
 
1075
        default:
 
1076
                g_warning ("Unknown button type '%s'", id);
 
1077
                break;
 
1078
        }
 
1079
 
 
1080
        return NULL;
 
1081
}
 
1082
 
 
1083
static gchar*
 
1084
get_tablet_button_id_name (GsdWacomTabletButton *tablet_button,
 
1085
                           GtkDirectionType      dir)
 
1086
{
 
1087
        gchar *id;
 
1088
        gchar  c;
 
1089
 
 
1090
        id = tablet_button->id;
 
1091
        switch (tablet_button->type) {
 
1092
        case WACOM_TABLET_BUTTON_TYPE_RING:
 
1093
                return g_strconcat (id, (dir == GTK_DIR_UP ? "-ccw" : "-cw"), NULL);
 
1094
                break;
 
1095
        case WACOM_TABLET_BUTTON_TYPE_STRIP:
 
1096
                return g_strconcat (id, (dir == GTK_DIR_UP ? "-up" : "-down"), NULL);
 
1097
                break;
 
1098
        case WACOM_TABLET_BUTTON_TYPE_NORMAL:
 
1099
        case WACOM_TABLET_BUTTON_TYPE_HARDCODED:
 
1100
                c = get_last_char (id);
 
1101
                return g_strdup_printf ("%c", g_ascii_toupper (c));
 
1102
                break;
 
1103
        default:
 
1104
                g_warning ("Unknown button type '%s'", id);
 
1105
                break;
 
1106
        }
 
1107
 
 
1108
        return NULL;
 
1109
}
 
1110
 
 
1111
static gint
 
1112
get_elevator_current_mode (GsdWacomOSDWindow    *osd_window,
 
1113
                           GsdWacomTabletButton *elevator_button)
 
1114
{
 
1115
        GList *list, *l;
 
1116
        gint   mode;
 
1117
 
 
1118
        mode = 1;
 
1119
        /* Search in the list of buttons the corresponding
 
1120
         * mode-switch button and get the current mode
 
1121
         */
 
1122
        list = gsd_wacom_device_get_buttons (osd_window->priv->pad);
 
1123
        for (l = list; l != NULL; l = l->next) {
 
1124
                GsdWacomTabletButton *tablet_button = l->data;
 
1125
 
 
1126
                if (tablet_button->type != WACOM_TABLET_BUTTON_TYPE_HARDCODED)
 
1127
                        continue;
 
1128
                if (elevator_button->group_id != tablet_button->group_id)
 
1129
                        continue;
 
1130
                mode = gsd_wacom_device_get_current_mode (osd_window->priv->pad,
 
1131
                                                          tablet_button->group_id);
 
1132
                break;
 
1133
        }
 
1134
        g_list_free (list);
 
1135
 
 
1136
        return mode;
 
1137
}
 
1138
 
 
1139
static GsdWacomOSDButton *
 
1140
gsd_wacom_osd_window_add_button_with_dir (GsdWacomOSDWindow    *osd_window,
 
1141
                                          GsdWacomTabletButton *tablet_button,
 
1142
                                          guint                 timeout,
 
1143
                                          GtkDirectionType      dir)
 
1144
{
 
1145
        GsdWacomOSDButton    *osd_button;
 
1146
        gchar                *str;
 
1147
 
 
1148
        str = get_tablet_button_id_name (tablet_button, dir);
 
1149
        osd_button = gsd_wacom_osd_button_new (GTK_WIDGET (osd_window), str);
 
1150
        g_free (str);
 
1151
 
 
1152
        str = get_tablet_button_class_name (tablet_button, dir);
 
1153
        gsd_wacom_osd_button_set_class (osd_button, str);
 
1154
        g_free (str);
 
1155
 
 
1156
        str = get_tablet_button_label (osd_window->priv->pad, tablet_button, dir);
 
1157
        gsd_wacom_osd_button_set_label (osd_button, str);
 
1158
        g_free (str);
 
1159
 
 
1160
        gsd_wacom_osd_button_set_button_type (osd_button, tablet_button->type);
 
1161
        gsd_wacom_osd_button_set_position (osd_button, tablet_button->pos);
 
1162
        gsd_wacom_osd_button_set_auto_off (osd_button, timeout);
 
1163
        osd_window->priv->buttons = g_list_append (osd_window->priv->buttons, osd_button);
 
1164
 
 
1165
        return osd_button;
 
1166
}
 
1167
 
 
1168
static void
 
1169
gsd_wacom_osd_window_add_tablet_button (GsdWacomOSDWindow    *osd_window,
 
1170
                                        GsdWacomTabletButton *tablet_button)
 
1171
{
 
1172
        GsdWacomOSDButton    *osd_button;
 
1173
        gint                  mode;
 
1174
 
 
1175
        switch (tablet_button->type) {
 
1176
        case WACOM_TABLET_BUTTON_TYPE_NORMAL:
 
1177
        case WACOM_TABLET_BUTTON_TYPE_HARDCODED:
 
1178
                osd_button = gsd_wacom_osd_window_add_button_with_dir (osd_window,
 
1179
                                                                       tablet_button,
 
1180
                                                                       0,
 
1181
                                                                       0);
 
1182
                gsd_wacom_osd_button_set_visible (osd_button, TRUE);
 
1183
                break;
 
1184
        case WACOM_TABLET_BUTTON_TYPE_RING:
 
1185
        case WACOM_TABLET_BUTTON_TYPE_STRIP:
 
1186
                mode = get_elevator_current_mode (osd_window, tablet_button) - 1;
 
1187
 
 
1188
                /* Add 2 buttons per elevator, one "Up"... */
 
1189
                osd_button = gsd_wacom_osd_window_add_button_with_dir (osd_window,
 
1190
                                                                       tablet_button,
 
1191
                                                                       ELEVATOR_TIMEOUT,
 
1192
                                                                       GTK_DIR_UP);
 
1193
                gsd_wacom_osd_button_set_visible (osd_button, tablet_button->idx == mode);
 
1194
 
 
1195
                /* ... and one "Down" */
 
1196
                osd_button = gsd_wacom_osd_window_add_button_with_dir (osd_window,
 
1197
                                                                       tablet_button,
 
1198
                                                                       ELEVATOR_TIMEOUT,
 
1199
                                                                       GTK_DIR_DOWN);
 
1200
                gsd_wacom_osd_button_set_visible (osd_button, tablet_button->idx == mode);
 
1201
 
 
1202
                break;
 
1203
        default:
 
1204
                g_warning ("Unknown button type");
 
1205
                break;
 
1206
        }
 
1207
}
 
1208
 
 
1209
/*
 
1210
 * Returns the rotation to apply a device to get a representation relative to
 
1211
 * the current rotation of the output.
 
1212
 * (This function is _not_ the same as in gsd-wacom-manager.c)
 
1213
 */
 
1214
static GsdWacomRotation
 
1215
display_relative_rotation (GsdWacomRotation device_rotation,
 
1216
                           GsdWacomRotation output_rotation)
 
1217
{
 
1218
        GsdWacomRotation rotations[] = { GSD_WACOM_ROTATION_HALF,
 
1219
                                         GSD_WACOM_ROTATION_CW,
 
1220
                                         GSD_WACOM_ROTATION_NONE,
 
1221
                                         GSD_WACOM_ROTATION_CCW };
 
1222
        guint i;
 
1223
 
 
1224
        if (device_rotation == output_rotation)
 
1225
                return GSD_WACOM_ROTATION_NONE;
 
1226
 
 
1227
        if (output_rotation == GSD_WACOM_ROTATION_NONE)
 
1228
                return device_rotation;
 
1229
 
 
1230
        for (i = 0; i < G_N_ELEMENTS (rotations); i++) {
 
1231
                if (device_rotation == rotations[i])
 
1232
                        break;
 
1233
        }
 
1234
 
 
1235
        if (output_rotation == GSD_WACOM_ROTATION_HALF)
 
1236
                return rotations[(i + G_N_ELEMENTS (rotations) - 2) % G_N_ELEMENTS (rotations)];
 
1237
 
 
1238
        if (output_rotation == GSD_WACOM_ROTATION_CW)
 
1239
                return rotations[(i + 1) % G_N_ELEMENTS (rotations)];
 
1240
 
 
1241
        if (output_rotation == GSD_WACOM_ROTATION_CCW)
 
1242
                return rotations[(i + G_N_ELEMENTS (rotations) - 1) % G_N_ELEMENTS (rotations)];
 
1243
 
 
1244
        /* fallback */
 
1245
        return GSD_WACOM_ROTATION_NONE;
 
1246
}
 
1247
 
 
1248
static void
 
1249
gsd_wacom_osd_window_mapped (GtkWidget *widget,
 
1250
                             gpointer   data)
 
1251
{
 
1252
        GsdWacomOSDWindow *osd_window = GSD_WACOM_OSD_WINDOW (widget);
 
1253
 
 
1254
        g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
 
1255
 
 
1256
        /* Position the window at its expected postion before moving
 
1257
         * to fullscreen, so the window will be on the right monitor.
 
1258
         */
 
1259
        gtk_window_move (GTK_WINDOW (osd_window),
 
1260
                         osd_window->priv->screen_area.x,
 
1261
                         osd_window->priv->screen_area.y);
 
1262
 
 
1263
        gtk_window_fullscreen (GTK_WINDOW (osd_window));
 
1264
        gtk_window_set_keep_above (GTK_WINDOW (osd_window), TRUE);
 
1265
}
 
1266
 
 
1267
static void
 
1268
gsd_wacom_osd_window_realized (GtkWidget *widget,
 
1269
                               gpointer   data)
 
1270
{
 
1271
        GsdWacomOSDWindow *osd_window = GSD_WACOM_OSD_WINDOW (widget);
 
1272
        GdkWindow         *gdk_window;
 
1273
        GdkRGBA            transparent;
 
1274
        GdkScreen         *screen;
 
1275
        GdkCursor         *cursor;
 
1276
        gint               monitor;
 
1277
        gboolean           status;
 
1278
 
 
1279
        g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
 
1280
        g_return_if_fail (GSD_IS_WACOM_DEVICE (osd_window->priv->pad));
 
1281
 
 
1282
        if (!gtk_widget_get_realized (widget))
 
1283
                return;
 
1284
 
 
1285
        screen = gtk_widget_get_screen (widget);
 
1286
        gdk_window = gtk_widget_get_window (widget);
 
1287
 
 
1288
        transparent.red = transparent.green = transparent.blue = 0.0;
 
1289
        transparent.alpha = BACK_OPACITY;
 
1290
        gdk_window_set_background_rgba (gdk_window, &transparent);
 
1291
 
 
1292
        cursor = gdk_cursor_new (GDK_BLANK_CURSOR);
 
1293
        gdk_window_set_cursor (gdk_window, cursor);
 
1294
        g_object_unref (cursor);
 
1295
 
 
1296
        /* Determine the monitor for that device and set appropriate fullscreen mode*/
 
1297
        monitor = gsd_wacom_device_get_display_monitor (osd_window->priv->pad);
 
1298
        if (monitor == GSD_WACOM_SET_ALL_MONITORS) {
 
1299
                /* Covers the entire screen */
 
1300
                osd_window->priv->screen_area.x = 0;
 
1301
                osd_window->priv->screen_area.y = 0;
 
1302
                osd_window->priv->screen_area.width = gdk_screen_get_width (screen);
 
1303
                osd_window->priv->screen_area.height = gdk_screen_get_height (screen);
 
1304
                gdk_screen_get_monitor_geometry (screen, 0, &osd_window->priv->monitor_area);
 
1305
                gdk_window_set_fullscreen_mode (gdk_window, GDK_FULLSCREEN_ON_ALL_MONITORS);
 
1306
        } else {
 
1307
                gdk_screen_get_monitor_geometry (screen, monitor, &osd_window->priv->screen_area);
 
1308
                osd_window->priv->monitor_area = osd_window->priv->screen_area;
 
1309
                gdk_window_set_fullscreen_mode (gdk_window, GDK_FULLSCREEN_ON_CURRENT_MONITOR);
 
1310
        }
 
1311
 
 
1312
        gtk_window_set_default_size (GTK_WINDOW (osd_window),
 
1313
                                     osd_window->priv->screen_area.width,
 
1314
                                     osd_window->priv->screen_area.height);
 
1315
 
 
1316
        status = get_image_size (gsd_wacom_device_get_layout_path (osd_window->priv->pad),
 
1317
                                 &osd_window->priv->tablet_area.width,
 
1318
                                 &osd_window->priv->tablet_area.height);
 
1319
        if (status == FALSE)
 
1320
                osd_window->priv->tablet_area = osd_window->priv->monitor_area;
 
1321
}
 
1322
 
 
1323
static void
 
1324
gsd_wacom_osd_window_set_device (GsdWacomOSDWindow *osd_window,
 
1325
                                 GsdWacomDevice    *device)
 
1326
{
 
1327
        GsdWacomRotation  device_rotation;
 
1328
        GsdWacomRotation  output_rotation;
 
1329
        GSettings        *settings;
 
1330
        GList            *list, *l;
 
1331
 
 
1332
        g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
 
1333
        g_return_if_fail (GSD_IS_WACOM_DEVICE (device));
 
1334
 
 
1335
        /* If we had a layout previously handled, get rid of it */
 
1336
        if (osd_window->priv->handle)
 
1337
                g_object_unref (osd_window->priv->handle);
 
1338
        osd_window->priv->handle = NULL;
 
1339
 
 
1340
        /* Bind the device with the OSD window */
 
1341
        if (osd_window->priv->pad)
 
1342
                g_object_weak_unref (G_OBJECT(osd_window->priv->pad),
 
1343
                                     (GWeakNotify) gtk_widget_destroy,
 
1344
                                     osd_window);
 
1345
        osd_window->priv->pad = device;
 
1346
        g_object_weak_ref (G_OBJECT(osd_window->priv->pad),
 
1347
                           (GWeakNotify) gtk_widget_destroy,
 
1348
                           osd_window);
 
1349
 
 
1350
        /* Capture current rotation, we do not update that later, OSD window is meant to be short lived */
 
1351
        settings = gsd_wacom_device_get_settings (osd_window->priv->pad);
 
1352
        device_rotation = g_settings_get_enum (settings, ROTATION_KEY);
 
1353
        output_rotation = gsd_wacom_device_get_display_rotation (osd_window->priv->pad);
 
1354
        osd_window->priv->rotation = display_relative_rotation (device_rotation, output_rotation);
 
1355
 
 
1356
        /* Create the buttons */
 
1357
        list = gsd_wacom_device_get_buttons (device);
 
1358
        for (l = list; l != NULL; l = l->next) {
 
1359
                GsdWacomTabletButton *tablet_button = l->data;
 
1360
 
 
1361
                gsd_wacom_osd_window_add_tablet_button (osd_window, tablet_button);
 
1362
        }
 
1363
        g_list_free (list);
 
1364
}
 
1365
 
 
1366
GsdWacomDevice *
 
1367
gsd_wacom_osd_window_get_device (GsdWacomOSDWindow *osd_window)
 
1368
{
 
1369
        g_return_val_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window), NULL);
 
1370
 
 
1371
        return osd_window->priv->pad;
 
1372
}
 
1373
 
 
1374
void
 
1375
gsd_wacom_osd_window_set_message (GsdWacomOSDWindow *osd_window,
 
1376
                                  const gchar       *str)
 
1377
{
 
1378
        g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
 
1379
 
 
1380
        g_free (osd_window->priv->message);
 
1381
        osd_window->priv->message = g_strdup (str);
 
1382
}
 
1383
 
 
1384
const char *
 
1385
gsd_wacom_osd_window_get_message (GsdWacomOSDWindow *osd_window)
 
1386
{
 
1387
        g_return_val_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window), NULL);
 
1388
 
 
1389
        return osd_window->priv->message;
 
1390
}
 
1391
 
 
1392
static void
 
1393
gsd_wacom_osd_window_set_property (GObject        *object,
 
1394
                                   guint           prop_id,
 
1395
                                   const GValue   *value,
 
1396
                                   GParamSpec     *pspec)
 
1397
{
 
1398
        GsdWacomOSDWindow *osd_window;
 
1399
 
 
1400
        osd_window = GSD_WACOM_OSD_WINDOW (object);
 
1401
 
 
1402
        switch (prop_id) {
 
1403
        case PROP_OSD_WINDOW_MESSAGE:
 
1404
                gsd_wacom_osd_window_set_message (osd_window, g_value_get_string (value));
 
1405
                break;
 
1406
        case PROP_OSD_WINDOW_GSD_WACOM_DEVICE:
 
1407
                gsd_wacom_osd_window_set_device (osd_window, g_value_get_object (value));
 
1408
                break;
 
1409
        default:
 
1410
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
1411
                break;
 
1412
        }
 
1413
}
 
1414
 
 
1415
static void
 
1416
gsd_wacom_osd_window_get_property (GObject        *object,
 
1417
                                   guint           prop_id,
 
1418
                                   GValue         *value,
 
1419
                                   GParamSpec     *pspec)
 
1420
{
 
1421
        GsdWacomOSDWindow *osd_window;
 
1422
 
 
1423
        osd_window = GSD_WACOM_OSD_WINDOW (object);
 
1424
 
 
1425
        switch (prop_id) {
 
1426
        case PROP_OSD_WINDOW_MESSAGE:
 
1427
                g_value_set_string (value, osd_window->priv->message);
 
1428
                break;
 
1429
        case PROP_OSD_WINDOW_GSD_WACOM_DEVICE:
 
1430
                g_value_set_object (value, (GObject*) osd_window->priv->pad);
 
1431
                break;
 
1432
        default:
 
1433
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
1434
                break;
 
1435
        }
 
1436
}
 
1437
 
 
1438
void
 
1439
gsd_wacom_osd_window_set_active (GsdWacomOSDWindow    *osd_window,
 
1440
                                 GsdWacomTabletButton *button,
 
1441
                                 GtkDirectionType      dir,
 
1442
                                 gboolean              active)
 
1443
{
 
1444
        GList     *l;
 
1445
        gchar     *id;
 
1446
 
 
1447
        g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
 
1448
        g_return_if_fail (button != NULL);
 
1449
 
 
1450
        id = get_tablet_button_id_name (button, dir);
 
1451
        for (l = osd_window->priv->buttons; l != NULL; l = l->next) {
 
1452
                GsdWacomOSDButton *osd_button = l->data;
 
1453
                if (MATCH_ID (osd_button, id))
 
1454
                        gsd_wacom_osd_button_set_active (osd_button, active);
 
1455
        }
 
1456
        g_free (id);
 
1457
}
 
1458
 
 
1459
void
 
1460
gsd_wacom_osd_window_set_mode (GsdWacomOSDWindow    *osd_window,
 
1461
                               gint                  group_id,
 
1462
                               gint                  mode)
 
1463
{
 
1464
        GList                *list, *l;
 
1465
 
 
1466
        list = gsd_wacom_device_get_buttons (osd_window->priv->pad);
 
1467
        for (l = list; l != NULL; l = l->next) {
 
1468
                GsdWacomTabletButton *tablet_button = l->data;
 
1469
                GList                *l2;
 
1470
                gchar                *id_up, *id_down;
 
1471
 
 
1472
                if (tablet_button->type != WACOM_TABLET_BUTTON_TYPE_STRIP &&
 
1473
                    tablet_button->type != WACOM_TABLET_BUTTON_TYPE_RING)
 
1474
                        continue;
 
1475
                if (tablet_button->group_id != group_id)
 
1476
                        continue;
 
1477
 
 
1478
                id_up = get_tablet_button_id_name (tablet_button, GTK_DIR_UP);
 
1479
                id_down = get_tablet_button_id_name (tablet_button, GTK_DIR_DOWN);
 
1480
 
 
1481
                for (l2 = osd_window->priv->buttons; l2 != NULL; l2 = l2->next) {
 
1482
                        GsdWacomOSDButton *osd_button = l2->data;
 
1483
                        gboolean           visible = (tablet_button->idx == mode - 1);
 
1484
 
 
1485
                        if (MATCH_ID (osd_button, id_up) || MATCH_ID (osd_button, id_down))
 
1486
                                gsd_wacom_osd_button_set_visible (osd_button, visible);
 
1487
                }
 
1488
 
 
1489
                g_free (id_up);
 
1490
                g_free (id_down);
 
1491
 
 
1492
        }
 
1493
        g_list_free (list);
 
1494
}
 
1495
 
 
1496
GtkWidget *
 
1497
gsd_wacom_osd_window_new (GsdWacomDevice       *pad,
 
1498
                          const gchar          *message)
 
1499
{
 
1500
        GsdWacomOSDWindow *osd_window;
 
1501
        GdkScreen         *screen;
 
1502
        GdkVisual         *visual;
 
1503
 
 
1504
        osd_window = GSD_WACOM_OSD_WINDOW (g_object_new (GSD_TYPE_WACOM_OSD_WINDOW,
 
1505
                                                         "type",              GTK_WINDOW_TOPLEVEL,
 
1506
                                                         "skip-pager-hint",   TRUE,
 
1507
                                                         "skip-taskbar-hint", TRUE,
 
1508
                                                         "focus-on-map",      TRUE,
 
1509
                                                         "decorated",         FALSE,
 
1510
                                                         "deletable",         FALSE,
 
1511
                                                         "accept-focus",      TRUE,
 
1512
                                                         "wacom-device",      pad,
 
1513
                                                         "message",           message,
 
1514
                                                         NULL));
 
1515
 
 
1516
        /* Must set the visual before realizing the window */
 
1517
        gtk_widget_set_app_paintable (GTK_WIDGET (osd_window), TRUE);
 
1518
        screen = gdk_screen_get_default ();
 
1519
        visual = gdk_screen_get_rgba_visual (screen);
 
1520
        if (visual == NULL)
 
1521
                visual = gdk_screen_get_system_visual (screen);
 
1522
        gtk_widget_set_visual (GTK_WIDGET (osd_window), visual);
 
1523
 
 
1524
        g_signal_connect (GTK_WIDGET (osd_window), "realize",
 
1525
                          G_CALLBACK (gsd_wacom_osd_window_realized),
 
1526
                          NULL);
 
1527
        g_signal_connect (GTK_WIDGET (osd_window), "map",
 
1528
                          G_CALLBACK (gsd_wacom_osd_window_mapped),
 
1529
                          NULL);
 
1530
 
 
1531
        return GTK_WIDGET (osd_window);
 
1532
}
 
1533
 
 
1534
static void
 
1535
gsd_wacom_osd_window_class_init (GsdWacomOSDWindowClass *klass)
 
1536
{
 
1537
        GObjectClass *gobject_class;
 
1538
        GtkWidgetClass *widget_class;
 
1539
 
 
1540
        gobject_class = G_OBJECT_CLASS (klass);
 
1541
        widget_class  = GTK_WIDGET_CLASS (klass);
 
1542
 
 
1543
        gobject_class->set_property = gsd_wacom_osd_window_set_property;
 
1544
        gobject_class->get_property = gsd_wacom_osd_window_get_property;
 
1545
        gobject_class->finalize     = gsd_wacom_osd_window_finalize;
 
1546
        widget_class->draw          = gsd_wacom_osd_window_draw;
 
1547
 
 
1548
        g_object_class_install_property (gobject_class,
 
1549
                                         PROP_OSD_WINDOW_MESSAGE,
 
1550
                                         g_param_spec_string ("message",
 
1551
                                                              "Window message",
 
1552
                                                              "The message shown in the OSD window",
 
1553
                                                              "",
 
1554
                                                              G_PARAM_READWRITE));
 
1555
        g_object_class_install_property (gobject_class,
 
1556
                                         PROP_OSD_WINDOW_GSD_WACOM_DEVICE,
 
1557
                                         g_param_spec_object ("wacom-device",
 
1558
                                                              "Wacom device",
 
1559
                                                              "The Wacom device represented by the OSD window",
 
1560
                                                              GSD_TYPE_WACOM_DEVICE,
 
1561
                                                              G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
 
1562
 
 
1563
        g_type_class_add_private (klass, sizeof (GsdWacomOSDWindowPrivate));
 
1564
}
 
1565
 
 
1566
static void
 
1567
gsd_wacom_osd_window_init (GsdWacomOSDWindow *osd_window)
 
1568
{
 
1569
        osd_window->priv = GSD_WACOM_OSD_WINDOW_GET_PRIVATE (osd_window);
 
1570
}
 
1571
 
 
1572
static void
 
1573
gsd_wacom_osd_window_finalize (GObject *object)
 
1574
{
 
1575
        GsdWacomOSDWindow *osd_window;
 
1576
        GsdWacomOSDWindowPrivate *priv;
 
1577
 
 
1578
        g_return_if_fail (object != NULL);
 
1579
        g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (object));
 
1580
 
 
1581
        osd_window = GSD_WACOM_OSD_WINDOW (object);
 
1582
        g_return_if_fail (osd_window->priv != NULL);
 
1583
 
 
1584
        priv = osd_window->priv;
 
1585
        g_clear_object (&priv->handle);
 
1586
        g_clear_pointer (&priv->message, g_free);
 
1587
        if (priv->buttons) {
 
1588
                g_list_free_full (priv->buttons, g_object_unref);
 
1589
                priv->buttons = NULL;
 
1590
        }
 
1591
 
 
1592
        G_OBJECT_CLASS (gsd_wacom_osd_window_parent_class)->finalize (object);
 
1593
}