2
* Copyright (C) 2012 Red Hat, Inc.
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.
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.
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.
18
* Author: Olivier Fourdan <ofourdan@redhat.com>
26
#include <glib/gi18n.h>
29
#include <librsvg/rsvg.h>
31
#include "gsd-wacom-osd-window.h"
32
#include "gsd-wacom-device.h"
33
#include "gsd-enums.h"
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/"
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"
48
#define ELEVATOR_TIMEOUT 250 /* ms */
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 }
62
replace_string (gchar **string, const gchar *search, const char *replacement)
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);
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 */
83
get_last_char (gchar *string)
87
g_return_val_if_fail (string != NULL, '\0');
88
pos = strlen (string);
89
g_return_val_if_fail (pos > 0, '\0');
91
return string[pos - 1];
95
get_rotation_in_radian (GsdWacomRotation rotation)
98
case GSD_WACOM_ROTATION_NONE:
101
case GSD_WACOM_ROTATION_HALF:
104
/* We only support left-handed/right-handed */
105
case GSD_WACOM_ROTATION_CCW:
106
case GSD_WACOM_ROTATION_CW:
116
get_sub_location (RsvgHandle *handle,
122
RsvgPositionData position;
125
if (!rsvg_handle_get_position_sub (handle, &position, sub)) {
126
g_warning ("Failed to retrieve '%s' position", sub);
130
tx = (double) position.x;
131
ty = (double) position.y;
132
cairo_user_to_device (cr, &tx, &ty);
143
get_image_size (const char *filename, int *width, int *height)
146
RsvgDimensionData dimensions;
147
GError* error = NULL;
149
if (filename == NULL)
152
handle = rsvg_handle_new_from_file (filename, &error);
154
g_printerr ("%s\n", error->message);
155
g_error_free (error);
160
/* Compute image size */
161
rsvg_handle_get_dimensions (handle, &dimensions);
162
g_object_unref (handle);
164
if (dimensions.width == 0 || dimensions.height == 0)
168
*width = dimensions.width;
171
*height = dimensions.height;
177
get_pango_vertical_offset (PangoLayout *layout)
179
const PangoFontDescription *desc;
180
PangoContext *context;
181
PangoLanguage *language;
182
PangoFontMetrics *metrics;
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);
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);
196
return PANGO_PIXELS (baseline - strikethrough - thickness / 2);
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))
206
typedef struct GsdWacomOSDButtonPrivate GsdWacomOSDButtonPrivate;
210
GsdWacomOSDButtonPrivate *priv;
214
GObjectClass parent_class;
215
} GsdWacomOSDButtonClass;
217
GType gsd_wacom_osd_button_get_type (void) G_GNUC_CONST;
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
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)
234
struct GsdWacomOSDButtonPrivate {
241
GsdWacomTabletButtonType type;
242
GsdWacomTabletButtonPos position;
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);
253
G_DEFINE_TYPE (GsdWacomOSDButton, gsd_wacom_osd_button, G_TYPE_OBJECT)
256
gsd_wacom_osd_button_set_id (GsdWacomOSDButton *osd_button,
259
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
261
osd_button->priv->id = g_strdup (id);
265
gsd_wacom_osd_button_set_class (GsdWacomOSDButton *osd_button,
268
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
270
osd_button->priv->class = g_strdup (class);
274
gsd_wacom_osd_button_get_label_class (GsdWacomOSDButton *osd_button)
278
label_class = g_strconcat ("#Label", osd_button->priv->class, NULL);
280
return (label_class);
284
gsd_wacom_osd_button_set_label (GsdWacomOSDButton *osd_button,
287
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
289
g_free (osd_button->priv->label);
290
osd_button->priv->label = g_strdup (str ? str : "");
294
gsd_wacom_osd_button_set_button_type (GsdWacomOSDButton *osd_button,
295
GsdWacomTabletButtonType type)
297
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
299
osd_button->priv->type = type;
303
gsd_wacom_osd_button_set_position (GsdWacomOSDButton *osd_button,
304
GsdWacomTabletButtonPos position)
306
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
308
osd_button->priv->position = position;
312
gsd_wacom_osd_button_set_location (GsdWacomOSDButton *osd_button,
316
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
318
osd_button->priv->label_x = x;
319
osd_button->priv->label_y = y;
323
gsd_wacom_osd_button_set_auto_off (GsdWacomOSDButton *osd_button,
326
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
328
osd_button->priv->auto_off = timeout;
332
gsd_wacom_osd_button_redraw (GsdWacomOSDButton *osd_button)
336
g_return_if_fail (GTK_IS_WIDGET (osd_button->priv->widget));
338
window = gtk_widget_get_window (GTK_WIDGET (osd_button->priv->widget));
339
gdk_window_invalidate_rect (window, NULL, FALSE);
343
gsd_wacom_osd_button_timer (GsdWacomOSDButton *osd_button)
345
/* Auto de-activate the button */
346
osd_button->priv->active = FALSE;
347
gsd_wacom_osd_button_redraw (osd_button);
353
gsd_wacom_osd_button_set_active (GsdWacomOSDButton *osd_button,
356
gboolean previous_state;
358
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
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 */
364
osd_button->priv->active = active;
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,
372
/* Whereas for other buttons, apply the change straight away */
373
osd_button->priv->active = active;
376
if (previous_state != osd_button->priv->active)
377
gsd_wacom_osd_button_redraw (osd_button);
381
gsd_wacom_osd_button_set_visible (GsdWacomOSDButton *osd_button,
384
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
386
osd_button->priv->visible = visible;
389
static GsdWacomOSDButton *
390
gsd_wacom_osd_button_new (GtkWidget *widget,
393
GsdWacomOSDButton *osd_button;
395
osd_button = GSD_WACOM_OSD_BUTTON (g_object_new (GSD_TYPE_WACOM_OSD_BUTTON,
398
osd_button->priv->widget = widget;
404
gsd_wacom_osd_button_set_property (GObject *object,
409
GsdWacomOSDButton *osd_button;
411
osd_button = GSD_WACOM_OSD_BUTTON (object);
414
case PROP_OSD_BUTTON_ID:
415
gsd_wacom_osd_button_set_id (osd_button, g_value_get_string (value));
417
case PROP_OSD_BUTTON_CLASS:
418
gsd_wacom_osd_button_set_class (osd_button, g_value_get_string (value));
420
case PROP_OSD_BUTTON_LABEL:
421
gsd_wacom_osd_button_set_label (osd_button, g_value_get_string (value));
423
case PROP_OSD_BUTTON_ACTIVE:
424
gsd_wacom_osd_button_set_active (osd_button, g_value_get_boolean (value));
426
case PROP_OSD_BUTTON_VISIBLE:
427
gsd_wacom_osd_button_set_visible (osd_button, g_value_get_boolean (value));
429
case PROP_OSD_BUTTON_AUTO_OFF:
430
gsd_wacom_osd_button_set_auto_off (osd_button, g_value_get_uint (value));
433
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
439
gsd_wacom_osd_button_get_property (GObject *object,
444
GsdWacomOSDButton *osd_button;
446
osd_button = GSD_WACOM_OSD_BUTTON (object);
449
case PROP_OSD_BUTTON_ID:
450
g_value_set_string (value, osd_button->priv->id);
452
case PROP_OSD_BUTTON_CLASS:
453
g_value_set_string (value, osd_button->priv->class);
455
case PROP_OSD_BUTTON_LABEL:
456
g_value_set_string (value, osd_button->priv->label);
458
case PROP_OSD_BUTTON_ACTIVE:
459
g_value_set_boolean (value, osd_button->priv->active);
461
case PROP_OSD_BUTTON_VISIBLE:
462
g_value_set_boolean (value, osd_button->priv->visible);
464
case PROP_OSD_BUTTON_AUTO_OFF:
465
g_value_set_uint (value, osd_button->priv->auto_off);
468
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
474
gsd_wacom_osd_button_class_init (GsdWacomOSDButtonClass *klass)
476
GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
482
g_object_class_install_property (object_class,
484
g_param_spec_string ("id",
486
"The Wacom Button ID",
489
g_object_class_install_property (object_class,
490
PROP_OSD_BUTTON_CLASS,
491
g_param_spec_string ("class",
493
"The Wacom Button Class",
496
g_object_class_install_property (object_class,
497
PROP_OSD_BUTTON_LABEL,
498
g_param_spec_string ("label",
503
g_object_class_install_property (object_class,
504
PROP_OSD_BUTTON_ACTIVE,
505
g_param_spec_boolean ("active",
507
"Whether the button is active",
510
g_object_class_install_property (object_class,
511
PROP_OSD_BUTTON_VISIBLE,
512
g_param_spec_boolean ("visible",
514
"Whether the button is visible",
517
g_object_class_install_property (object_class,
518
PROP_OSD_BUTTON_AUTO_OFF,
519
g_param_spec_uint ("auto-off",
521
"Timeout before button disables itself automatically",
524
0, /* disabled by default */
527
g_type_class_add_private (klass, sizeof (GsdWacomOSDButtonPrivate));
531
gsd_wacom_osd_button_init (GsdWacomOSDButton *osd_button)
533
osd_button->priv = GSD_WACOM_OSD_BUTTON_GET_PRIVATE (osd_button);
537
gsd_wacom_osd_button_finalize (GObject *object)
539
GsdWacomOSDButton *osd_button;
540
GsdWacomOSDButtonPrivate *priv;
542
g_return_if_fail (object != NULL);
543
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (object));
545
osd_button = GSD_WACOM_OSD_BUTTON (object);
547
g_return_if_fail (osd_button->priv != NULL);
549
priv = osd_button->priv;
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);
557
G_OBJECT_CLASS (gsd_wacom_osd_button_parent_class)->finalize (object);
560
/* Compute the new actual position once rotation is applied */
561
static GsdWacomTabletButtonPos
562
get_actual_position (GsdWacomTabletButtonPos position,
563
GsdWacomRotation rotation)
566
case GSD_WACOM_ROTATION_NONE:
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;
579
/* We only support left-handed/right-handed */
580
case GSD_WACOM_ROTATION_CCW:
581
case GSD_WACOM_ROTATION_CW:
590
gsd_wacom_osd_button_draw_label (GsdWacomOSDButton *osd_button,
591
GtkStyleContext *style_context,
592
PangoContext *pango_context,
594
GsdWacomRotation rotation)
596
GsdWacomOSDButtonPrivate *priv;
598
PangoRectangle logical_rect;
599
GsdWacomTabletButtonPos actual_position;
603
g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button));
605
priv = osd_button->priv;
606
if (priv->visible == FALSE)
609
actual_position = get_actual_position (priv->position, rotation);
610
layout = pango_layout_new (pango_context);
612
markup = g_strdup_printf ("<span foreground=\"" ACTIVE_COLOR "\" weight=\"normal\">%s</span>", priv->label);
614
markup = g_strdup_printf ("<span foreground=\"" INACTIVE_COLOR "\" weight=\"normal\">%s</span>", priv->label);
615
pango_layout_set_markup (layout, markup, -1);
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);
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);
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;
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;
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;
647
gtk_render_layout (style_context, cr, lx, ly, layout);
648
g_object_unref (layout);
653
PROP_OSD_WINDOW_MESSAGE,
654
PROP_OSD_WINDOW_GSD_WACOM_DEVICE
657
#define GSD_WACOM_OSD_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
658
GSD_TYPE_WACOM_OSD_WINDOW, \
659
GsdWacomOSDWindowPrivate))
661
struct GsdWacomOSDWindowPrivate
665
GsdWacomRotation rotation;
666
GdkRectangle screen_area;
667
GdkRectangle monitor_area;
668
GdkRectangle tablet_area;
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);
677
G_DEFINE_TYPE (GsdWacomOSDWindow, gsd_wacom_osd_window, GTK_TYPE_WINDOW)
680
load_rsvg_with_base (const char *css_string,
681
const char *original_layout_path,
687
handle = rsvg_handle_new ();
689
dirname = g_path_get_dirname (original_layout_path);
690
rsvg_handle_set_base_uri (handle, dirname);
693
if (!rsvg_handle_write (handle,
694
(guint8 *) css_string,
697
g_object_unref (handle);
700
if (!rsvg_handle_close (handle, error)) {
701
g_object_unref (handle);
709
gsd_wacom_osd_window_update (GsdWacomOSDWindow *osd_window)
711
GError *error = NULL;
712
gchar *width, *height;
713
gchar *buttons_section;
715
const gchar *layout_file;
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));
723
css_data = g_resources_lookup_data (RES_PATH "tablet-layout.css", 0, &error);
725
g_printerr ("GResource error: %s\n", error->message);
726
g_clear_pointer (&error, g_error_free);
728
if (css_data == NULL)
730
css_string = g_strdup ((gchar *) g_bytes_get_data (css_data, NULL));
731
g_bytes_unref(css_data);
733
width = g_strdup_printf ("%d", osd_window->priv->tablet_area.width);
734
replace_string (&css_string, "layout_width", width);
737
height = g_strdup_printf ("%d", osd_window->priv->tablet_area.height);
738
replace_string (&css_string, "layout_height", height);
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;
746
if (osd_button->priv->visible == FALSE)
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"
758
replace_string (&css_string, "buttons_section", buttons_section);
759
g_free (buttons_section);
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);
766
layout_file = gsd_wacom_device_get_layout_path (osd_window->priv->pad);
767
replace_string (&css_string, "layout_file", layout_file);
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);
781
gsd_wacom_osd_window_draw_message (GsdWacomOSDWindow *osd_window,
782
GtkStyleContext *style_context,
783
PangoContext *pango_context,
786
GdkRectangle *monitor_area = &osd_window->priv->monitor_area;
787
PangoRectangle logical_rect;
793
if (osd_window->priv->message == NULL)
796
layout = pango_layout_new (pango_context);
797
pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
799
markup = g_strdup_printf ("<span foreground=\"white\">%s</span>", osd_window->priv->message);
800
pango_layout_set_markup (layout, markup, -1);
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;
807
gtk_render_layout (style_context, cr, x, y, layout);
808
g_object_unref (layout);
812
gsd_wacom_osd_window_draw_labels (GsdWacomOSDWindow *osd_window,
813
GtkStyleContext *style_context,
814
PangoContext *pango_context,
819
for (l = osd_window->priv->buttons; l != NULL; l = l->next) {
820
GsdWacomOSDButton *osd_button = l->data;
822
if (osd_button->priv->visible == FALSE)
825
gsd_wacom_osd_button_draw_label (osd_button,
829
osd_window->priv->rotation);
834
gsd_wacom_osd_window_place_buttons (GsdWacomOSDWindow *osd_window,
839
g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
841
for (l = osd_window->priv->buttons; l != NULL; l = l->next) {
842
GsdWacomOSDButton *osd_button = l->data;
843
double label_x, label_y;
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);
853
gsd_wacom_osd_button_set_location (osd_button, label_x, label_y);
857
/* Note: this function does modify the given cairo context */
859
gsd_wacom_osd_window_adjust_cairo (GsdWacomOSDWindow *osd_window,
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;
868
cairo_rotate (cr, get_rotation_in_radian (osd_window->priv->rotation));
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);
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);
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);
884
twidth = twidth + (double) (monitor_area->x - screen_area->x);
885
theight = theight + (double) (monitor_area->y - screen_area->y);
887
cairo_translate (cr, twidth, theight);
891
gsd_wacom_osd_window_draw (GtkWidget *widget,
894
GsdWacomOSDWindow *osd_window = GSD_WACOM_OSD_WINDOW (widget);
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);
899
if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget))) {
900
GtkStyleContext *style_context;
901
PangoContext *pango_context;
903
style_context = gtk_widget_get_style_context (widget);
904
pango_context = gtk_widget_get_pango_context (widget);
906
cairo_set_source_rgba (cr, 0, 0, 0, BACK_OPACITY);
907
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
909
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
911
/* Save original matrix */
914
/* Apply new cairo transformation matrix */
915
gsd_wacom_osd_window_adjust_cairo (osd_window, cr);
917
/* And render the tablet layout */
918
gsd_wacom_osd_window_update (osd_window);
919
rsvg_handle_render_cairo (osd_window->priv->handle, cr);
921
gsd_wacom_osd_window_place_buttons (osd_window, cr);
923
/* Reset to original matrix */
926
/* Draw button labels and message */
927
gsd_wacom_osd_window_draw_labels (osd_window,
931
gsd_wacom_osd_window_draw_message (osd_window,
941
get_escaped_accel_shortcut (const gchar *accel)
944
GdkModifierType mask;
947
if (accel == NULL || accel[0] == '\0')
948
return g_strdup (C_("Action type", "None"));
950
gtk_accelerator_parse (accel, &keyval, &mask);
952
str = gtk_accelerator_get_label (keyval, mask);
953
label = g_markup_printf_escaped (C_("Action type", "Send Keystroke %s"), str);
960
get_tablet_button_label_normal (GsdWacomDevice *device,
961
GsdWacomTabletButton *button)
963
GsdWacomActionType type;
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"));
970
if (type == GSD_WACOM_ACTION_TYPE_HELP)
971
return g_strdup (C_("Action type", "Show On-Screen Help"));
973
if (type == GSD_WACOM_ACTION_TYPE_SWITCH_MONITOR)
974
return g_strdup (C_("Action type", "Switch Monitor"));
976
str = g_settings_get_string (button->settings, CUSTOM_ACTION_KEY);
977
if (str == NULL || *str == '\0') {
979
return g_strdup (C_("Action type", "None"));
982
name = get_escaped_accel_shortcut (str);
989
get_tablet_button_label_touch (GsdWacomDevice *device,
990
GsdWacomTabletButton *button,
991
GtkDirectionType dir)
993
char **strv, *name, *str;
995
strv = g_settings_get_strv (button->settings, CUSTOM_ELEVATOR_ACTION_KEY);
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]);
1006
str = get_escaped_accel_shortcut (name);
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);
1020
get_tablet_button_label (GsdWacomDevice *device,
1021
GsdWacomTabletButton *button,
1022
GtkDirectionType dir)
1024
g_return_val_if_fail (button, NULL);
1026
if (!button->settings)
1029
switch (button->type) {
1030
case WACOM_TABLET_BUTTON_TYPE_NORMAL:
1031
return get_tablet_button_label_normal (device, button);
1033
case WACOM_TABLET_BUTTON_TYPE_RING:
1034
case WACOM_TABLET_BUTTON_TYPE_STRIP:
1035
return get_tablet_button_label_touch (device, button, dir);
1037
case WACOM_TABLET_BUTTON_TYPE_HARDCODED:
1042
return g_strdup (button->name);
1046
get_tablet_button_class_name (GsdWacomTabletButton *tablet_button,
1047
GtkDirectionType dir)
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);
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);
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));
1076
g_warning ("Unknown button type '%s'", id);
1084
get_tablet_button_id_name (GsdWacomTabletButton *tablet_button,
1085
GtkDirectionType dir)
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);
1095
case WACOM_TABLET_BUTTON_TYPE_STRIP:
1096
return g_strconcat (id, (dir == GTK_DIR_UP ? "-up" : "-down"), NULL);
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));
1104
g_warning ("Unknown button type '%s'", id);
1112
get_elevator_current_mode (GsdWacomOSDWindow *osd_window,
1113
GsdWacomTabletButton *elevator_button)
1119
/* Search in the list of buttons the corresponding
1120
* mode-switch button and get the current mode
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;
1126
if (tablet_button->type != WACOM_TABLET_BUTTON_TYPE_HARDCODED)
1128
if (elevator_button->group_id != tablet_button->group_id)
1130
mode = gsd_wacom_device_get_current_mode (osd_window->priv->pad,
1131
tablet_button->group_id);
1139
static GsdWacomOSDButton *
1140
gsd_wacom_osd_window_add_button_with_dir (GsdWacomOSDWindow *osd_window,
1141
GsdWacomTabletButton *tablet_button,
1143
GtkDirectionType dir)
1145
GsdWacomOSDButton *osd_button;
1148
str = get_tablet_button_id_name (tablet_button, dir);
1149
osd_button = gsd_wacom_osd_button_new (GTK_WIDGET (osd_window), str);
1152
str = get_tablet_button_class_name (tablet_button, dir);
1153
gsd_wacom_osd_button_set_class (osd_button, str);
1156
str = get_tablet_button_label (osd_window->priv->pad, tablet_button, dir);
1157
gsd_wacom_osd_button_set_label (osd_button, str);
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);
1169
gsd_wacom_osd_window_add_tablet_button (GsdWacomOSDWindow *osd_window,
1170
GsdWacomTabletButton *tablet_button)
1172
GsdWacomOSDButton *osd_button;
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,
1182
gsd_wacom_osd_button_set_visible (osd_button, TRUE);
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;
1188
/* Add 2 buttons per elevator, one "Up"... */
1189
osd_button = gsd_wacom_osd_window_add_button_with_dir (osd_window,
1193
gsd_wacom_osd_button_set_visible (osd_button, tablet_button->idx == mode);
1195
/* ... and one "Down" */
1196
osd_button = gsd_wacom_osd_window_add_button_with_dir (osd_window,
1200
gsd_wacom_osd_button_set_visible (osd_button, tablet_button->idx == mode);
1204
g_warning ("Unknown button type");
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)
1214
static GsdWacomRotation
1215
display_relative_rotation (GsdWacomRotation device_rotation,
1216
GsdWacomRotation output_rotation)
1218
GsdWacomRotation rotations[] = { GSD_WACOM_ROTATION_HALF,
1219
GSD_WACOM_ROTATION_CW,
1220
GSD_WACOM_ROTATION_NONE,
1221
GSD_WACOM_ROTATION_CCW };
1224
if (device_rotation == output_rotation)
1225
return GSD_WACOM_ROTATION_NONE;
1227
if (output_rotation == GSD_WACOM_ROTATION_NONE)
1228
return device_rotation;
1230
for (i = 0; i < G_N_ELEMENTS (rotations); i++) {
1231
if (device_rotation == rotations[i])
1235
if (output_rotation == GSD_WACOM_ROTATION_HALF)
1236
return rotations[(i + G_N_ELEMENTS (rotations) - 2) % G_N_ELEMENTS (rotations)];
1238
if (output_rotation == GSD_WACOM_ROTATION_CW)
1239
return rotations[(i + 1) % G_N_ELEMENTS (rotations)];
1241
if (output_rotation == GSD_WACOM_ROTATION_CCW)
1242
return rotations[(i + G_N_ELEMENTS (rotations) - 1) % G_N_ELEMENTS (rotations)];
1245
return GSD_WACOM_ROTATION_NONE;
1249
gsd_wacom_osd_window_mapped (GtkWidget *widget,
1252
GsdWacomOSDWindow *osd_window = GSD_WACOM_OSD_WINDOW (widget);
1254
g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
1256
/* Position the window at its expected postion before moving
1257
* to fullscreen, so the window will be on the right monitor.
1259
gtk_window_move (GTK_WINDOW (osd_window),
1260
osd_window->priv->screen_area.x,
1261
osd_window->priv->screen_area.y);
1263
gtk_window_fullscreen (GTK_WINDOW (osd_window));
1264
gtk_window_set_keep_above (GTK_WINDOW (osd_window), TRUE);
1268
gsd_wacom_osd_window_realized (GtkWidget *widget,
1271
GsdWacomOSDWindow *osd_window = GSD_WACOM_OSD_WINDOW (widget);
1272
GdkWindow *gdk_window;
1273
GdkRGBA transparent;
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));
1282
if (!gtk_widget_get_realized (widget))
1285
screen = gtk_widget_get_screen (widget);
1286
gdk_window = gtk_widget_get_window (widget);
1288
transparent.red = transparent.green = transparent.blue = 0.0;
1289
transparent.alpha = BACK_OPACITY;
1290
gdk_window_set_background_rgba (gdk_window, &transparent);
1292
cursor = gdk_cursor_new (GDK_BLANK_CURSOR);
1293
gdk_window_set_cursor (gdk_window, cursor);
1294
g_object_unref (cursor);
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);
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);
1312
gtk_window_set_default_size (GTK_WINDOW (osd_window),
1313
osd_window->priv->screen_area.width,
1314
osd_window->priv->screen_area.height);
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;
1324
gsd_wacom_osd_window_set_device (GsdWacomOSDWindow *osd_window,
1325
GsdWacomDevice *device)
1327
GsdWacomRotation device_rotation;
1328
GsdWacomRotation output_rotation;
1329
GSettings *settings;
1332
g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
1333
g_return_if_fail (GSD_IS_WACOM_DEVICE (device));
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;
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,
1345
osd_window->priv->pad = device;
1346
g_object_weak_ref (G_OBJECT(osd_window->priv->pad),
1347
(GWeakNotify) gtk_widget_destroy,
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);
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;
1361
gsd_wacom_osd_window_add_tablet_button (osd_window, tablet_button);
1367
gsd_wacom_osd_window_get_device (GsdWacomOSDWindow *osd_window)
1369
g_return_val_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window), NULL);
1371
return osd_window->priv->pad;
1375
gsd_wacom_osd_window_set_message (GsdWacomOSDWindow *osd_window,
1378
g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
1380
g_free (osd_window->priv->message);
1381
osd_window->priv->message = g_strdup (str);
1385
gsd_wacom_osd_window_get_message (GsdWacomOSDWindow *osd_window)
1387
g_return_val_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window), NULL);
1389
return osd_window->priv->message;
1393
gsd_wacom_osd_window_set_property (GObject *object,
1395
const GValue *value,
1398
GsdWacomOSDWindow *osd_window;
1400
osd_window = GSD_WACOM_OSD_WINDOW (object);
1403
case PROP_OSD_WINDOW_MESSAGE:
1404
gsd_wacom_osd_window_set_message (osd_window, g_value_get_string (value));
1406
case PROP_OSD_WINDOW_GSD_WACOM_DEVICE:
1407
gsd_wacom_osd_window_set_device (osd_window, g_value_get_object (value));
1410
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1416
gsd_wacom_osd_window_get_property (GObject *object,
1421
GsdWacomOSDWindow *osd_window;
1423
osd_window = GSD_WACOM_OSD_WINDOW (object);
1426
case PROP_OSD_WINDOW_MESSAGE:
1427
g_value_set_string (value, osd_window->priv->message);
1429
case PROP_OSD_WINDOW_GSD_WACOM_DEVICE:
1430
g_value_set_object (value, (GObject*) osd_window->priv->pad);
1433
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1439
gsd_wacom_osd_window_set_active (GsdWacomOSDWindow *osd_window,
1440
GsdWacomTabletButton *button,
1441
GtkDirectionType dir,
1447
g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window));
1448
g_return_if_fail (button != NULL);
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);
1460
gsd_wacom_osd_window_set_mode (GsdWacomOSDWindow *osd_window,
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;
1470
gchar *id_up, *id_down;
1472
if (tablet_button->type != WACOM_TABLET_BUTTON_TYPE_STRIP &&
1473
tablet_button->type != WACOM_TABLET_BUTTON_TYPE_RING)
1475
if (tablet_button->group_id != group_id)
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);
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);
1485
if (MATCH_ID (osd_button, id_up) || MATCH_ID (osd_button, id_down))
1486
gsd_wacom_osd_button_set_visible (osd_button, visible);
1497
gsd_wacom_osd_window_new (GsdWacomDevice *pad,
1498
const gchar *message)
1500
GsdWacomOSDWindow *osd_window;
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,
1511
"accept-focus", TRUE,
1512
"wacom-device", pad,
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);
1521
visual = gdk_screen_get_system_visual (screen);
1522
gtk_widget_set_visual (GTK_WIDGET (osd_window), visual);
1524
g_signal_connect (GTK_WIDGET (osd_window), "realize",
1525
G_CALLBACK (gsd_wacom_osd_window_realized),
1527
g_signal_connect (GTK_WIDGET (osd_window), "map",
1528
G_CALLBACK (gsd_wacom_osd_window_mapped),
1531
return GTK_WIDGET (osd_window);
1535
gsd_wacom_osd_window_class_init (GsdWacomOSDWindowClass *klass)
1537
GObjectClass *gobject_class;
1538
GtkWidgetClass *widget_class;
1540
gobject_class = G_OBJECT_CLASS (klass);
1541
widget_class = GTK_WIDGET_CLASS (klass);
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;
1548
g_object_class_install_property (gobject_class,
1549
PROP_OSD_WINDOW_MESSAGE,
1550
g_param_spec_string ("message",
1552
"The message shown in the OSD window",
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",
1559
"The Wacom device represented by the OSD window",
1560
GSD_TYPE_WACOM_DEVICE,
1561
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
1563
g_type_class_add_private (klass, sizeof (GsdWacomOSDWindowPrivate));
1567
gsd_wacom_osd_window_init (GsdWacomOSDWindow *osd_window)
1569
osd_window->priv = GSD_WACOM_OSD_WINDOW_GET_PRIVATE (osd_window);
1573
gsd_wacom_osd_window_finalize (GObject *object)
1575
GsdWacomOSDWindow *osd_window;
1576
GsdWacomOSDWindowPrivate *priv;
1578
g_return_if_fail (object != NULL);
1579
g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (object));
1581
osd_window = GSD_WACOM_OSD_WINDOW (object);
1582
g_return_if_fail (osd_window->priv != NULL);
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;
1592
G_OBJECT_CLASS (gsd_wacom_osd_window_parent_class)->finalize (object);