~ubuntu-branches/ubuntu/trusty/unity-control-center/trusty

« back to all changes in this revision

Viewing changes to panels/wacom/cc-wacom-page.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-01-08 16:29:18 UTC
  • Revision ID: package-import@ubuntu.com-20140108162918-g29dd08tr913y2qh
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 Ā© 2011 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
 * Authors: Peter Hutterer <peter.hutterer@redhat.com>
 
19
 *          Bastien Nocera <hadess@hadess.net>
 
20
 *
 
21
 */
 
22
 
 
23
#include <config.h>
 
24
 
 
25
#include <glib/gi18n-lib.h>
 
26
#include <gtk/gtk.h>
 
27
 
 
28
#include "cc-wacom-page.h"
 
29
#include "cc-wacom-nav-button.h"
 
30
#include "cc-wacom-mapping-panel.h"
 
31
#include "cc-wacom-stylus-page.h"
 
32
#include "gsd-enums.h"
 
33
#include "gui_gtk.h"
 
34
 
 
35
#include <string.h>
 
36
 
 
37
#define WID(x) (GtkWidget *) gtk_builder_get_object (priv->builder, x)
 
38
#define CWID(x) (GtkContainer *) gtk_builder_get_object (priv->builder, x)
 
39
#define MWID(x) (GtkWidget *) gtk_builder_get_object (priv->mapping_builder, x)
 
40
 
 
41
G_DEFINE_TYPE (CcWacomPage, cc_wacom_page, GTK_TYPE_BOX)
 
42
 
 
43
#define WACOM_PAGE_PRIVATE(o) \
 
44
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_WACOM_PAGE, CcWacomPagePrivate))
 
45
 
 
46
#define THRESHOLD_MISCLICK      15
 
47
#define THRESHOLD_DOUBLECLICK   7
 
48
 
 
49
#define ACTION_TYPE_KEY         "action-type"
 
50
#define CUSTOM_ACTION_KEY       "custom-action"
 
51
#define KEY_CUSTOM_ELEVATOR_ACTION "custom-elevator-action"
 
52
 
 
53
enum {
 
54
        MAPPING_DESCRIPTION_COLUMN,
 
55
        MAPPING_TYPE_COLUMN,
 
56
        MAPPING_BUTTON_COLUMN,
 
57
        MAPPING_BUTTON_DIRECTION,
 
58
        MAPPING_N_COLUMNS
 
59
};
 
60
 
 
61
enum {
 
62
        ACTION_NAME_COLUMN,
 
63
        ACTION_TYPE_COLUMN,
 
64
        ACTION_N_COLUMNS
 
65
};
 
66
 
 
67
struct _CcWacomPagePrivate
 
68
{
 
69
        CcWacomPanel   *panel;
 
70
        GsdWacomDevice *stylus, *eraser, *pad;
 
71
        GtkBuilder     *builder;
 
72
        GtkWidget      *nav;
 
73
        GtkWidget      *notebook;
 
74
        CalibArea      *area;
 
75
        GSettings      *wacom_settings;
 
76
 
 
77
        /* Button mapping */
 
78
        GtkBuilder     *mapping_builder;
 
79
        GtkWidget      *button_map;
 
80
        GtkListStore   *action_store;
 
81
 
 
82
        /* Display mapping */
 
83
        GtkWidget      *mapping;
 
84
        GtkWidget      *dialog;
 
85
};
 
86
 
 
87
/* Button combo box storage columns */
 
88
enum {
 
89
        BUTTONNUMBER_COLUMN,
 
90
        BUTTONNAME_COLUMN,
 
91
        N_BUTTONCOLUMNS
 
92
};
 
93
 
 
94
/* Tablet mode combo box storage columns */
 
95
enum {
 
96
        MODENUMBER_COLUMN,
 
97
        MODELABEL_COLUMN,
 
98
        N_MODECOLUMNS
 
99
};
 
100
 
 
101
/* Tablet mode options - keep in sync with .ui */
 
102
enum {
 
103
        MODE_ABSOLUTE, /* stylus + eraser absolute */
 
104
        MODE_RELATIVE, /* stylus + eraser relative */
 
105
};
 
106
 
 
107
/* Different types of layout for the tablet config */
 
108
enum {
 
109
        LAYOUT_NORMAL,        /* tracking mode, button mapping */
 
110
        LAYOUT_REVERSIBLE,    /* tracking mode, button mapping, left-hand orientation */
 
111
        LAYOUT_SCREEN        /* button mapping, calibration, display resolution */
 
112
};
 
113
 
 
114
static struct {
 
115
       GsdWacomActionType  action_type;
 
116
       const gchar        *action_name;
 
117
} action_table[] = {
 
118
       { GSD_WACOM_ACTION_TYPE_NONE,           NC_("Wacom action-type", "None")                },
 
119
       { GSD_WACOM_ACTION_TYPE_CUSTOM,         NC_("Wacom action-type", "Send Keystroke")      },
 
120
       { GSD_WACOM_ACTION_TYPE_SWITCH_MONITOR, NC_("Wacom action-type", "Switch Monitor")      }
 
121
};
 
122
 
 
123
#define WACOM_C(x) g_dpgettext2(NULL, "Wacom action-type", x)
 
124
 
 
125
static void
 
126
update_tablet_ui (CcWacomPage *page,
 
127
                  int          layout);
 
128
 
 
129
static int
 
130
get_layout_type (GsdWacomDevice *device)
 
131
{
 
132
        int layout;
 
133
 
 
134
        if (gsd_wacom_device_is_screen_tablet (device))
 
135
                layout = LAYOUT_SCREEN;
 
136
        else if (gsd_wacom_device_reversible (device))
 
137
                layout = LAYOUT_REVERSIBLE;
 
138
        else
 
139
                layout = LAYOUT_NORMAL;
 
140
 
 
141
        return layout;
 
142
}
 
143
 
 
144
static void
 
145
set_calibration (gint      *cal,
 
146
                 gsize      ncal,
 
147
                 GSettings *settings)
 
148
{
 
149
        GVariant    *current; /* current calibration */
 
150
        GVariant    *array;   /* new calibration */
 
151
        GVariant   **tmp;
 
152
        gsize        nvalues;
 
153
        int          i;
 
154
 
 
155
        current = g_settings_get_value (settings, "area");
 
156
        g_variant_get_fixed_array (current, &nvalues, sizeof (gint32));
 
157
        if ((ncal != 4) || (nvalues != 4)) {
 
158
                g_warning("Unable set set device calibration property. Got %"G_GSIZE_FORMAT" items to put in %"G_GSIZE_FORMAT" slots; expected %d items.\n", ncal, nvalues, 4);
 
159
                return;
 
160
        }
 
161
 
 
162
        tmp = g_malloc (nvalues * sizeof (GVariant*));
 
163
        for (i = 0; i < ncal; i++)
 
164
                tmp[i] = g_variant_new_int32 (cal[i]);
 
165
 
 
166
        array = g_variant_new_array (G_VARIANT_TYPE_INT32, tmp, nvalues);
 
167
        g_settings_set_value (settings, "area", array);
 
168
 
 
169
        g_free (tmp);
 
170
}
 
171
 
 
172
static void
 
173
finish_calibration (CalibArea *area,
 
174
                    gpointer   user_data)
 
175
{
 
176
        CcWacomPage *page = (CcWacomPage *) user_data;
 
177
        CcWacomPagePrivate *priv = page->priv;
 
178
        XYinfo axis;
 
179
        gboolean swap_xy;
 
180
        int cal[4];
 
181
 
 
182
        if (calib_area_finish (area, &axis, &swap_xy)) {
 
183
                cal[0] = axis.x_min;
 
184
                cal[1] = axis.y_min;
 
185
                cal[2] = axis.x_max;
 
186
                cal[3] = axis.y_max;
 
187
 
 
188
                set_calibration(cal, 4, page->priv->wacom_settings);
 
189
        }
 
190
 
 
191
        calib_area_free (area);
 
192
        page->priv->area = NULL;
 
193
        gtk_widget_set_sensitive (WID ("button-calibrate"), TRUE);
 
194
}
 
195
 
 
196
static gboolean
 
197
run_calibration (CcWacomPage *page,
 
198
                 gint        *cal,
 
199
                 gint         monitor)
 
200
{
 
201
        XYinfo              old_axis;
 
202
        GdkDevice          *gdk_device;
 
203
        CcWacomPagePrivate *priv;
 
204
        int                 device_id;
 
205
 
 
206
        g_assert (page->priv->area == NULL);
 
207
 
 
208
        old_axis.x_min = cal[0];
 
209
        old_axis.y_min = cal[1];
 
210
        old_axis.x_max = cal[2];
 
211
        old_axis.y_max = cal[3];
 
212
 
 
213
        priv = page->priv;
 
214
        g_object_get (priv->stylus, "gdk-device", &gdk_device, NULL);
 
215
 
 
216
        if (gdk_device != NULL)
 
217
                g_object_get (gdk_device, "device-id", &device_id, NULL);
 
218
        else
 
219
                device_id = -1;
 
220
 
 
221
        page->priv->area = calib_area_new (NULL,
 
222
                                           monitor,
 
223
                                           device_id,
 
224
                                           finish_calibration,
 
225
                                           page,
 
226
                                           &old_axis,
 
227
                                           THRESHOLD_MISCLICK,
 
228
                                           THRESHOLD_DOUBLECLICK);
 
229
 
 
230
        return FALSE;
 
231
}
 
232
 
 
233
static void
 
234
calibrate_button_clicked_cb (GtkButton   *button,
 
235
                             CcWacomPage *page)
 
236
{
 
237
        int i, calibration[4];
 
238
        GVariant *variant;
 
239
        int *current;
 
240
        gsize ncal;
 
241
        gint monitor;
 
242
 
 
243
        monitor = gsd_wacom_device_get_display_monitor (page->priv->stylus);
 
244
        if (monitor < 0) {
 
245
                /* The display the tablet should be mapped to could not be located.
 
246
                 * This shouldn't happen if the EDID data is good...
 
247
                 */
 
248
                g_critical("Output associated with the tablet is not connected. Unable to calibrate.");
 
249
                return;
 
250
        }
 
251
 
 
252
        variant = g_settings_get_value (page->priv->wacom_settings, "area");
 
253
        current = (int *) g_variant_get_fixed_array (variant, &ncal, sizeof (gint32));
 
254
 
 
255
        if (ncal != 4) {
 
256
                g_warning("Device calibration property has wrong length. Got %"G_GSIZE_FORMAT" items; expected %d.\n", ncal, 4);
 
257
                g_free (current);
 
258
                return;
 
259
        }
 
260
 
 
261
        for (i = 0; i < 4; i++)
 
262
                calibration[i] = current[i];
 
263
 
 
264
        if (calibration[0] == -1 &&
 
265
            calibration[1] == -1 &&
 
266
            calibration[2] == -1 &&
 
267
            calibration[3] == -1) {
 
268
                gint *device_cal;
 
269
                device_cal = gsd_wacom_device_get_area (page->priv->stylus);
 
270
                for (i = 0; i < 4; i++)
 
271
                        calibration[i] = device_cal[i];
 
272
                g_free (device_cal);
 
273
        }
 
274
 
 
275
        run_calibration (page, calibration, monitor);
 
276
        gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
 
277
}
 
278
 
 
279
static char *
 
280
get_elevator_shortcut_string (GSettings        *settings,
 
281
                              GtkDirectionType  dir)
 
282
{
 
283
        char **strv, *str;
 
284
 
 
285
        strv = g_settings_get_strv (settings, KEY_CUSTOM_ELEVATOR_ACTION);
 
286
        if (strv == NULL)
 
287
                return NULL;
 
288
 
 
289
        if (g_strv_length (strv) >= 1 && dir == GTK_DIR_UP)
 
290
                str = g_strdup (strv[0]);
 
291
        else if (g_strv_length (strv) >= 2 && dir == GTK_DIR_DOWN)
 
292
                str = g_strdup (strv[1]);
 
293
        else
 
294
                str = NULL;
 
295
 
 
296
        g_strfreev (strv);
 
297
 
 
298
        return str;
 
299
}
 
300
 
 
301
static void
 
302
accel_set_func (GtkTreeViewColumn *tree_column,
 
303
                GtkCellRenderer   *cell,
 
304
                GtkTreeModel      *model,
 
305
                GtkTreeIter       *iter,
 
306
                gpointer           data)
 
307
{
 
308
        GsdWacomTabletButton *button;
 
309
        GsdWacomActionType type;
 
310
        GtkDirectionType dir;
 
311
        char *str;
 
312
        guint keyval;
 
313
        guint mask;
 
314
 
 
315
        gtk_tree_model_get (model, iter,
 
316
                            MAPPING_BUTTON_COLUMN, &button,
 
317
                            MAPPING_BUTTON_DIRECTION, &dir,
 
318
                            -1);
 
319
 
 
320
        if (button == NULL) {
 
321
                g_object_set (cell,
 
322
                              "visible", FALSE,
 
323
                              NULL);
 
324
                return;
 
325
        }
 
326
 
 
327
        if (button->type == WACOM_TABLET_BUTTON_TYPE_HARDCODED) {
 
328
                /* FIXME this should list the name of the button,
 
329
                 * Switch Modes Touchring #1 for example */
 
330
                g_object_set (cell,
 
331
                              "visible", TRUE,
 
332
                              "editable", FALSE,
 
333
                              "accel-key", 0,
 
334
                              "accel-mods", 0,
 
335
                              "style", PANGO_STYLE_NORMAL,
 
336
                              "text", "",
 
337
                              NULL);
 
338
                return;
 
339
        }
 
340
 
 
341
        if (button->settings == NULL) {
 
342
                g_warning ("Button '%s' does not have an associated GSettings", button->id);
 
343
                return;
 
344
        }
 
345
 
 
346
        type = g_settings_get_enum (button->settings, ACTION_TYPE_KEY);
 
347
        if (type != GSD_WACOM_ACTION_TYPE_CUSTOM) {
 
348
                g_object_set (cell,
 
349
                              "visible", TRUE,
 
350
                              "editable", TRUE,
 
351
                              "accel-key", 0,
 
352
                              "accel-mods", 0,
 
353
                              "style", PANGO_STYLE_NORMAL,
 
354
                              "text", "",
 
355
                              NULL);
 
356
                return;
 
357
        }
 
358
 
 
359
        if (button->type == WACOM_TABLET_BUTTON_TYPE_ELEVATOR)
 
360
                str = get_elevator_shortcut_string (button->settings, dir);
 
361
        else
 
362
                str = g_settings_get_string (button->settings, CUSTOM_ACTION_KEY);
 
363
 
 
364
        if (str == NULL || *str == '\0') {
 
365
                g_object_set (cell,
 
366
                              "visible", TRUE,
 
367
                              "editable", TRUE,
 
368
                              "accel-key", 0,
 
369
                              "accel-mods", 0,
 
370
                              "style", PANGO_STYLE_NORMAL,
 
371
                              "text", C_("Wacom action-type", "None"),
 
372
                              NULL);
 
373
                g_free (str);
 
374
                return;
 
375
        }
 
376
        gtk_accelerator_parse (str, &keyval, &mask);
 
377
        g_free (str);
 
378
 
 
379
        g_object_set (cell,
 
380
                      "visible", TRUE,
 
381
                      "editable", TRUE,
 
382
                      "accel-key", keyval,
 
383
                      "accel-mods", mask,
 
384
                      "style", PANGO_STYLE_NORMAL,
 
385
                      NULL);
 
386
}
 
387
 
 
388
static gboolean
 
389
start_editing_cb (GtkTreeView    *tree_view,
 
390
                  GdkEventButton *event,
 
391
                  gpointer        user_data)
 
392
{
 
393
        GtkTreePath *path;
 
394
        GtkTreeViewColumn *column;
 
395
        gboolean handled;
 
396
 
 
397
        if (event->window != gtk_tree_view_get_bin_window (tree_view))
 
398
                return FALSE;
 
399
 
 
400
        handled = FALSE;
 
401
        if (gtk_tree_view_get_path_at_pos (tree_view,
 
402
                                           (gint) event->x,
 
403
                                           (gint) event->y,
 
404
                                           &path, &column,
 
405
                                           NULL, NULL))
 
406
        {
 
407
                GtkTreeModel *model;
 
408
                GtkTreeIter iter;
 
409
                GsdWacomTabletButton *button;
 
410
                GsdWacomActionType type;
 
411
 
 
412
                if (column == gtk_tree_view_get_column (tree_view, MAPPING_TYPE_COLUMN))
 
413
                        goto out;
 
414
 
 
415
                model = gtk_tree_view_get_model (tree_view);
 
416
                gtk_tree_model_get_iter (model, &iter, path);
 
417
                gtk_tree_model_get (model, &iter,
 
418
                                    MAPPING_BUTTON_COLUMN, &button,
 
419
                                    -1);
 
420
                if (button == NULL)
 
421
                        goto out;
 
422
 
 
423
                if (button->settings == NULL)
 
424
                        goto out;
 
425
 
 
426
                type = g_settings_get_enum (button->settings, ACTION_TYPE_KEY);
 
427
                if (type != GSD_WACOM_ACTION_TYPE_CUSTOM)
 
428
                        goto out;
 
429
 
 
430
                gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 
431
                gtk_tree_view_set_cursor (tree_view,
 
432
                                          path,
 
433
                                          gtk_tree_view_get_column (tree_view, MAPPING_BUTTON_COLUMN),
 
434
                                          TRUE);
 
435
                g_signal_stop_emission_by_name (tree_view, "button_press_event");
 
436
                handled = TRUE;
 
437
out:
 
438
                gtk_tree_path_free (path);
 
439
        }
 
440
        return handled;
 
441
}
 
442
 
 
443
static void
 
444
start_editing_kb_cb (GtkTreeView *treeview,
 
445
                          GtkTreePath *path,
 
446
                          GtkTreeViewColumn *column,
 
447
                          gpointer user_data)
 
448
{
 
449
  GtkTreeModel *model;
 
450
  GtkTreeIter iter;
 
451
  GsdWacomTabletButton *button;
 
452
 
 
453
  model = gtk_tree_view_get_model (treeview);
 
454
  gtk_tree_model_get_iter (model, &iter, path);
 
455
  gtk_tree_model_get (model, &iter,
 
456
                      MAPPING_BUTTON_COLUMN, &button,
 
457
                      -1);
 
458
 
 
459
  gtk_widget_grab_focus (GTK_WIDGET (treeview));
 
460
  gtk_tree_view_set_cursor (treeview,
 
461
                            path,
 
462
                            gtk_tree_view_get_column (treeview, MAPPING_BUTTON_COLUMN),
 
463
                            TRUE);
 
464
}
 
465
 
 
466
static void
 
467
accel_edited_callback (GtkCellRendererText   *cell,
 
468
                       const char            *path_string,
 
469
                       guint                  keyval,
 
470
                       GdkModifierType        mask,
 
471
                       guint                  keycode,
 
472
                       CcWacomPage           *page)
 
473
{
 
474
  GtkTreeModel *model;
 
475
  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
 
476
  GtkTreeView *view;
 
477
  GtkTreeIter iter;
 
478
  CcWacomPagePrivate *priv;
 
479
  GsdWacomTabletButton *button;
 
480
  GtkDirectionType dir;
 
481
  char *str;
 
482
 
 
483
  priv = page->priv;
 
484
  view = GTK_TREE_VIEW (MWID("shortcut_treeview"));
 
485
  model = gtk_tree_view_get_model (view);
 
486
  gtk_tree_model_get_iter (model, &iter, path);
 
487
  gtk_tree_path_free (path);
 
488
  gtk_tree_model_get (model, &iter,
 
489
                      MAPPING_BUTTON_COLUMN, &button,
 
490
                      MAPPING_BUTTON_DIRECTION, &dir,
 
491
                      -1);
 
492
 
 
493
  /* sanity check */
 
494
  if (button == NULL)
 
495
    return;
 
496
 
 
497
  /* CapsLock isn't supported as a keybinding modifier, so keep it from confusing us */
 
498
  mask &= ~GDK_LOCK_MASK;
 
499
 
 
500
  str = gtk_accelerator_name (keyval, mask);
 
501
 
 
502
  if (button->type == WACOM_TABLET_BUTTON_TYPE_ELEVATOR) {
 
503
    char *strs[3];
 
504
    char **strv;
 
505
 
 
506
    strs[2] = NULL;
 
507
    strs[0] = strs[1] = "";
 
508
    strv = g_settings_get_strv (button->settings, KEY_CUSTOM_ELEVATOR_ACTION);
 
509
    if (strv != NULL) {
 
510
            if (g_strv_length (strv) >= 1)
 
511
                    strs[0] = strv[0];
 
512
            if (g_strv_length (strv) >= 2)
 
513
                    strs[1] = strv[1];
 
514
    }
 
515
 
 
516
    if (dir == GTK_DIR_UP)
 
517
            strs[0] = str;
 
518
    else
 
519
            strs[1] = str;
 
520
 
 
521
    g_settings_set_strv (button->settings, KEY_CUSTOM_ELEVATOR_ACTION, (const gchar * const*) strs);
 
522
    if (strv != NULL)
 
523
            g_strfreev (strv);
 
524
  } else {
 
525
    g_settings_set_string (button->settings, CUSTOM_ACTION_KEY, str);
 
526
  }
 
527
  g_settings_set_enum (button->settings, ACTION_TYPE_KEY, GSD_WACOM_ACTION_TYPE_CUSTOM);
 
528
  g_free (str);
 
529
}
 
530
 
 
531
static void
 
532
accel_cleared_callback (GtkCellRendererText *cell,
 
533
                        const char          *path_string,
 
534
                        CcWacomPage         *page)
 
535
{
 
536
  GtkTreeView *view;
 
537
  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
 
538
  GtkTreeIter iter;
 
539
  GtkTreeModel *model;
 
540
  GsdWacomTabletButton *button;
 
541
  CcWacomPagePrivate *priv;
 
542
  GtkDirectionType dir;
 
543
 
 
544
  priv = page->priv;
 
545
  view = GTK_TREE_VIEW (MWID("shortcut_treeview"));
 
546
  model = gtk_tree_view_get_model (view);
 
547
  gtk_tree_model_get_iter (model, &iter, path);
 
548
  gtk_tree_path_free (path);
 
549
  gtk_tree_model_get (model, &iter,
 
550
                      MAPPING_BUTTON_COLUMN, &button,
 
551
                      MAPPING_BUTTON_DIRECTION, &dir,
 
552
                      -1);
 
553
 
 
554
  /* sanity check */
 
555
  if (button == NULL)
 
556
    return;
 
557
 
 
558
  /* Unset the key */
 
559
  if (button->type == WACOM_TABLET_BUTTON_TYPE_ELEVATOR) {
 
560
    char *strs[3];
 
561
    char **strv;
 
562
 
 
563
    strs[2] = NULL;
 
564
    strs[0] = strs[1] = "";
 
565
    strv = g_settings_get_strv (button->settings, KEY_CUSTOM_ELEVATOR_ACTION);
 
566
    if (strv != NULL) {
 
567
            if (g_strv_length (strv) >= 1)
 
568
                    strs[0] = strv[0];
 
569
            if (g_strv_length (strv) >= 2)
 
570
                    strs[1] = strv[1];
 
571
    }
 
572
 
 
573
    if (dir == GTK_DIR_UP)
 
574
            strs[0] = "";
 
575
    else
 
576
            strs[1] = "";
 
577
 
 
578
    if (*strs[0] == '\0' && *strs[1] == '\0')
 
579
            g_settings_set_enum (button->settings, ACTION_TYPE_KEY, GSD_WACOM_ACTION_TYPE_NONE);
 
580
    g_settings_set_strv (button->settings, KEY_CUSTOM_ELEVATOR_ACTION, (const gchar * const*) strs);
 
581
    if (strv != NULL)
 
582
            g_strfreev (strv);
 
583
  } else {
 
584
          g_settings_set_enum (button->settings, ACTION_TYPE_KEY, GSD_WACOM_ACTION_TYPE_NONE);
 
585
          g_settings_set_string (button->settings, CUSTOM_ACTION_KEY, "");
 
586
  }
 
587
}
 
588
 
 
589
static void
 
590
add_button_to_store (GtkListStore         *model,
 
591
                     GsdWacomTabletButton *button,
 
592
                     GtkDirectionType      dir,
 
593
                     GsdWacomActionType    type)
 
594
{
 
595
        GtkTreeIter new_row;
 
596
        char *dir_name;
 
597
 
 
598
        if (dir == GTK_DIR_UP || dir == GTK_DIR_DOWN) {
 
599
                dir_name = g_strdup_printf ("%s (%s)",
 
600
                                            button->name,
 
601
                                            dir == GTK_DIR_UP ? _("Up") : _("Down"));
 
602
        } else {
 
603
                dir_name = NULL;
 
604
        }
 
605
 
 
606
        /* Sanity check */
 
607
        if (type >= G_N_ELEMENTS(action_table))
 
608
                type = GSD_WACOM_ACTION_TYPE_NONE;
 
609
 
 
610
        gtk_list_store_append (model, &new_row);
 
611
        gtk_list_store_set (model, &new_row,
 
612
                            MAPPING_DESCRIPTION_COLUMN, dir_name ? dir_name : button->name,
 
613
                            MAPPING_TYPE_COLUMN, WACOM_C(action_table[type].action_name),
 
614
                            MAPPING_BUTTON_COLUMN, button,
 
615
                            MAPPING_BUTTON_DIRECTION, dir,
 
616
                            -1);
 
617
        g_free (dir_name);
 
618
}
 
619
 
 
620
static void
 
621
action_set_func (GtkTreeViewColumn *tree_column,
 
622
                 GtkCellRenderer   *cell,
 
623
                 GtkTreeModel      *model,
 
624
                 GtkTreeIter       *iter,
 
625
                 gpointer           data)
 
626
{
 
627
        GsdWacomTabletButton *button;
 
628
        GsdWacomActionType type;
 
629
 
 
630
        gtk_tree_model_get (model, iter, MAPPING_BUTTON_COLUMN, &button, -1);
 
631
 
 
632
        if (button == NULL) {
 
633
                g_object_set (cell, "visible", FALSE, NULL);
 
634
                return;
 
635
        }
 
636
 
 
637
        if (button->type == WACOM_TABLET_BUTTON_TYPE_HARDCODED) {
 
638
                g_object_set (cell,
 
639
                              "visible", TRUE,
 
640
                              "editable", FALSE,
 
641
                              "style", PANGO_STYLE_NORMAL,
 
642
                              "text", _("Switch Modes"),
 
643
                              NULL);
 
644
                return;
 
645
        }
 
646
 
 
647
        if (button->type == WACOM_TABLET_BUTTON_TYPE_ELEVATOR) {
 
648
                g_object_set (cell,
 
649
                              "visible", TRUE,
 
650
                              "editable", FALSE,
 
651
                              "style", PANGO_STYLE_NORMAL,
 
652
                              "text", WACOM_C(action_table[GSD_WACOM_ACTION_TYPE_CUSTOM].action_name),
 
653
                              NULL);
 
654
                return;
 
655
        }
 
656
 
 
657
        if (button->settings == NULL) {
 
658
                g_warning ("Button '%s' does not have an associated GSettings", button->id);
 
659
                return;
 
660
        }
 
661
 
 
662
        type = g_settings_get_enum (button->settings, ACTION_TYPE_KEY);
 
663
        /* Sanity check */
 
664
        if (type >= G_N_ELEMENTS(action_table))
 
665
                type = GSD_WACOM_ACTION_TYPE_NONE;
 
666
 
 
667
        g_object_set (cell,
 
668
                      "visible", TRUE,
 
669
                      "editable", TRUE,
 
670
                      "style", PANGO_STYLE_NORMAL,
 
671
                      "text",  WACOM_C(action_table[type].action_name),
 
672
                      NULL);
 
673
}
 
674
 
 
675
static void
 
676
combo_action_cell_changed (GtkCellRendererCombo *cell,
 
677
                           const gchar          *path_string,
 
678
                           GtkTreeIter          *new_iter,
 
679
                           CcWacomPage          *page)
 
680
{
 
681
        GtkTreeView          *tree_view;
 
682
        GtkTreePath          *path;
 
683
        GtkTreeModel         *model;
 
684
        CcWacomPagePrivate   *priv;
 
685
        GsdWacomActionType    type;
 
686
        GtkTreeIter           iter;
 
687
        GsdWacomTabletButton *button;
 
688
 
 
689
        priv = page->priv;
 
690
        tree_view = GTK_TREE_VIEW (MWID("shortcut_treeview"));
 
691
        model = gtk_tree_view_get_model (tree_view);
 
692
        path = gtk_tree_path_new_from_string (path_string);
 
693
 
 
694
        gtk_tree_model_get (GTK_TREE_MODEL (priv->action_store), new_iter, ACTION_TYPE_COLUMN, &type, -1);
 
695
        gtk_tree_model_get_iter (model, &iter, path);
 
696
        gtk_list_store_set (GTK_LIST_STORE (model), &iter, MAPPING_TYPE_COLUMN, WACOM_C(action_table[type].action_name), -1);
 
697
        gtk_tree_path_free (path);
 
698
 
 
699
        gtk_tree_model_get (model, &iter, MAPPING_BUTTON_COLUMN, &button, -1);
 
700
        if (button == NULL)
 
701
                return;
 
702
        if (button->settings == NULL)
 
703
                return;
 
704
        g_settings_set_enum (button->settings, ACTION_TYPE_KEY, type);
 
705
 
 
706
        gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 
707
}
 
708
 
 
709
static void
 
710
setup_mapping_treeview (CcWacomPage *page)
 
711
{
 
712
        CcWacomPagePrivate *priv;
 
713
        GtkTreeView *treeview;
 
714
        GtkCellRenderer *renderer;
 
715
        GtkTreeViewColumn *column;
 
716
        GtkListStore *model;
 
717
        GtkTreeIter iter;
 
718
        GList *list, *l;
 
719
        gint i;
 
720
 
 
721
        priv = page->priv;
 
722
        treeview = GTK_TREE_VIEW(MWID ("shortcut_treeview"));
 
723
 
 
724
        g_signal_connect (treeview, "button_press_event",
 
725
                          G_CALLBACK (start_editing_cb), page);
 
726
        g_signal_connect (treeview, "row-activated",
 
727
                          G_CALLBACK (start_editing_kb_cb), page);
 
728
 
 
729
        renderer = gtk_cell_renderer_text_new ();
 
730
        g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 
731
 
 
732
        column = gtk_tree_view_column_new_with_attributes (_("Button"),
 
733
                                                           renderer,
 
734
                                                           "text", MAPPING_DESCRIPTION_COLUMN,
 
735
                                                           NULL);
 
736
        gtk_tree_view_column_set_resizable (column, FALSE);
 
737
        gtk_tree_view_column_set_expand (column, TRUE);
 
738
 
 
739
        gtk_tree_view_append_column (treeview, column);
 
740
        gtk_tree_view_column_set_sort_column_id (column, MAPPING_DESCRIPTION_COLUMN);
 
741
 
 
742
        priv->action_store = gtk_list_store_new (ACTION_N_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
 
743
        for (i = 0; i < G_N_ELEMENTS (action_table); i++) {
 
744
                /* Screen tablets cannot switch monitors (as the monitor is the tablet) */
 
745
                if (action_table[i].action_type == GSD_WACOM_ACTION_TYPE_SWITCH_MONITOR &&
 
746
                    gsd_wacom_device_is_screen_tablet (priv->stylus))
 
747
                        continue;
 
748
 
 
749
                gtk_list_store_append (priv->action_store, &iter);
 
750
                gtk_list_store_set (priv->action_store, &iter,
 
751
                                    ACTION_NAME_COLUMN, WACOM_C(action_table[i].action_name),
 
752
                                    ACTION_TYPE_COLUMN, action_table[i].action_type, -1);
 
753
        }
 
754
        renderer = gtk_cell_renderer_combo_new ();
 
755
        g_object_set (renderer,
 
756
                      "text-column", ACTION_NAME_COLUMN,
 
757
                      "has-entry", FALSE,
 
758
                      "model", priv->action_store,
 
759
                      "editable", TRUE,
 
760
                      NULL);
 
761
        g_signal_connect (renderer, "changed",
 
762
                          G_CALLBACK (combo_action_cell_changed), page);
 
763
 
 
764
        column = gtk_tree_view_column_new_with_attributes (_("Type"),
 
765
                                                           renderer,
 
766
                                                           "text", MAPPING_TYPE_COLUMN,
 
767
                                                           NULL);
 
768
        gtk_tree_view_column_set_cell_data_func (column, renderer, action_set_func, NULL, NULL);
 
769
        gtk_tree_view_column_set_resizable (column, FALSE);
 
770
        gtk_tree_view_column_set_expand (column, FALSE);
 
771
 
 
772
        gtk_tree_view_append_column (treeview, column);
 
773
 
 
774
        renderer = (GtkCellRenderer *) g_object_new (GTK_TYPE_CELL_RENDERER_ACCEL,
 
775
                                                     "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
 
776
                                                     NULL);
 
777
 
 
778
        g_signal_connect (renderer, "accel_edited",
 
779
                          G_CALLBACK (accel_edited_callback),
 
780
                          page);
 
781
        g_signal_connect (renderer, "accel_cleared",
 
782
                          G_CALLBACK (accel_cleared_callback),
 
783
                          page);
 
784
 
 
785
        column = gtk_tree_view_column_new_with_attributes (_("Action"), renderer, NULL);
 
786
        gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL);
 
787
        gtk_tree_view_column_set_resizable (column, FALSE);
 
788
        gtk_tree_view_column_set_expand (column, FALSE);
 
789
 
 
790
        gtk_tree_view_append_column (treeview, column);
 
791
 
 
792
        model = gtk_list_store_new (MAPPING_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
 
793
        gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (model));
 
794
 
 
795
        /* Fill it up! */
 
796
        list = gsd_wacom_device_get_buttons (page->priv->pad);
 
797
        for (l = list; l != NULL; l = l->next) {
 
798
                GsdWacomTabletButton *button = l->data;
 
799
                GsdWacomActionType type = GSD_WACOM_ACTION_TYPE_NONE;
 
800
 
 
801
                if (button->settings)
 
802
                        type = g_settings_get_enum (button->settings, ACTION_TYPE_KEY);
 
803
 
 
804
                if (button->type == WACOM_TABLET_BUTTON_TYPE_ELEVATOR) {
 
805
                        add_button_to_store (model, button, GTK_DIR_UP, GSD_WACOM_ACTION_TYPE_CUSTOM);
 
806
                        add_button_to_store (model, button, GTK_DIR_DOWN, GSD_WACOM_ACTION_TYPE_CUSTOM);
 
807
                } else {
 
808
                        add_button_to_store (model, button, 0, type);
 
809
                }
 
810
        }
 
811
        g_list_free (list);
 
812
        g_object_unref (model);
 
813
}
 
814
 
 
815
static void
 
816
button_mapping_dialog_closed (GtkDialog   *dialog,
 
817
                              int          response_id,
 
818
                              CcWacomPage *page)
 
819
{
 
820
        CcWacomPagePrivate *priv;
 
821
 
 
822
        priv = page->priv;
 
823
        gtk_widget_destroy (MWID ("button-mapping-dialog"));
 
824
        g_object_unref (page->priv->mapping_builder);
 
825
        page->priv->mapping_builder = NULL;
 
826
}
 
827
 
 
828
static void
 
829
map_buttons_button_clicked_cb (GtkButton   *button,
 
830
                               CcWacomPage *page)
 
831
{
 
832
        GError *error = NULL;
 
833
        GtkWidget *dialog;
 
834
        CcWacomPagePrivate *priv;
 
835
        GtkWidget *toplevel;
 
836
 
 
837
        priv = page->priv;
 
838
 
 
839
        g_assert (priv->mapping_builder == NULL);
 
840
        priv->mapping_builder = gtk_builder_new ();
 
841
        gtk_builder_add_from_file (priv->mapping_builder,
 
842
                                   GNOMECC_UI_DIR "/button-mapping.ui",
 
843
                                   &error);
 
844
 
 
845
        if (error != NULL) {
 
846
                g_warning ("Error loading UI file: %s", error->message);
 
847
                g_object_unref (priv->mapping_builder);
 
848
                priv->mapping_builder = NULL;
 
849
                g_error_free (error);
 
850
                return;
 
851
        }
 
852
 
 
853
        setup_mapping_treeview (page);
 
854
 
 
855
        dialog = MWID ("button-mapping-dialog");
 
856
        toplevel = gtk_widget_get_toplevel (GTK_WIDGET (page));
 
857
        gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel));
 
858
        gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
 
859
        g_signal_connect (G_OBJECT (dialog), "response",
 
860
                          G_CALLBACK (button_mapping_dialog_closed), page);
 
861
 
 
862
        gtk_widget_show (dialog);
 
863
 
 
864
        priv->button_map = dialog;
 
865
        g_object_add_weak_pointer (G_OBJECT (dialog), (gpointer *) &priv->button_map);
 
866
}
 
867
 
 
868
static void
 
869
display_mapping_dialog_closed (GtkDialog   *dialog,
 
870
                               int          response_id,
 
871
                               CcWacomPage *page)
 
872
{
 
873
        CcWacomPagePrivate *priv;
 
874
        int layout;
 
875
 
 
876
        priv = page->priv;
 
877
        gtk_widget_destroy (priv->dialog);
 
878
        priv->dialog = NULL;
 
879
        priv->mapping = NULL;
 
880
        layout = get_layout_type (priv->stylus);
 
881
        update_tablet_ui (page, layout);
 
882
}
 
883
 
 
884
static void
 
885
display_mapping_button_clicked_cb (GtkButton   *button,
 
886
                                   CcWacomPage *page)
 
887
{
 
888
        CcWacomPagePrivate *priv;
 
889
 
 
890
        priv = page->priv;
 
891
 
 
892
        g_assert (priv->mapping == NULL);
 
893
 
 
894
        priv->dialog = gtk_dialog_new_with_buttons (_("Display Mapping"),
 
895
                                                    GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (page))),
 
896
                                                    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
 
897
                                                    GTK_STOCK_CLOSE,
 
898
                                                    GTK_RESPONSE_ACCEPT,
 
899
                                                    NULL);
 
900
        priv->mapping = cc_wacom_mapping_panel_new ();
 
901
        cc_wacom_mapping_panel_set_device (CC_WACOM_MAPPING_PANEL (priv->mapping),
 
902
                                           priv->stylus);
 
903
        gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (priv->dialog))),
 
904
                           priv->mapping);
 
905
        g_signal_connect (G_OBJECT (priv->dialog), "response",
 
906
                          G_CALLBACK (display_mapping_dialog_closed), page);
 
907
        gtk_widget_show_all (priv->dialog);
 
908
 
 
909
        g_object_add_weak_pointer (G_OBJECT (priv->mapping), (gpointer *) &priv->dialog);
 
910
}
 
911
 
 
912
static void
 
913
tabletmode_changed_cb (GtkComboBox *combo, gpointer user_data)
 
914
{
 
915
        CcWacomPagePrivate      *priv   = CC_WACOM_PAGE(user_data)->priv;
 
916
        GtkListStore            *liststore;
 
917
        GtkTreeIter             iter;
 
918
        gint                    mode;
 
919
        gboolean                is_absolute;
 
920
 
 
921
        if (!gtk_combo_box_get_active_iter (combo, &iter))
 
922
                return;
 
923
 
 
924
        liststore = GTK_LIST_STORE (WID ("liststore-tabletmode"));
 
925
        gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter,
 
926
                            MODENUMBER_COLUMN, &mode,
 
927
                            -1);
 
928
 
 
929
        is_absolute = (mode == MODE_ABSOLUTE);
 
930
        g_settings_set_boolean (priv->wacom_settings, "is-absolute", is_absolute);
 
931
}
 
932
 
 
933
static const gchar*
 
934
opposite_rotation (const gchar *rotation)
 
935
{
 
936
        /* Order matters here, if not found we return "none"  */
 
937
        static const gchar *rotations[] = { "half", "cw", "none", "ccw" };
 
938
        guint i, n;
 
939
 
 
940
        n = G_N_ELEMENTS (rotations);
 
941
        for (i = 0; i < n; i++) {
 
942
                if (strcmp (rotation, rotations[i]) == 0)
 
943
                        break;
 
944
        }
 
945
 
 
946
        return rotations[(i + n / 2) % n];
 
947
}
 
948
 
 
949
static void
 
950
left_handed_toggled_cb (GtkSwitch *sw, GParamSpec *pspec, gpointer *user_data)
 
951
{
 
952
        CcWacomPagePrivate      *priv = CC_WACOM_PAGE(user_data)->priv;
 
953
        GsdWacomDevice          *device = priv->stylus;
 
954
        GsdWacomRotation        display_rotation;
 
955
        const gchar*            rotation;
 
956
 
 
957
        display_rotation = gsd_wacom_device_get_display_rotation (device);
 
958
        rotation = gsd_wacom_device_rotation_type_to_name (display_rotation);
 
959
        if (gtk_switch_get_active (sw))
 
960
                rotation = opposite_rotation (rotation);
 
961
 
 
962
        g_settings_set_string (priv->wacom_settings, "rotation", rotation);
 
963
}
 
964
 
 
965
static void
 
966
set_left_handed_from_gsettings (CcWacomPage *page)
 
967
{
 
968
        CcWacomPagePrivate      *priv = CC_WACOM_PAGE(page)->priv;
 
969
        GsdWacomDevice          *device = priv->stylus;
 
970
        GsdWacomRotation        display_rotation;
 
971
        const gchar*            rotation;
 
972
 
 
973
        display_rotation = gsd_wacom_device_get_display_rotation (device);
 
974
        rotation = g_settings_get_string (priv->wacom_settings, "rotation");
 
975
        if (strcmp (rotation, gsd_wacom_device_rotation_type_to_name (display_rotation)) != 0)
 
976
                gtk_switch_set_active (GTK_SWITCH (WID ("switch-left-handed")), TRUE);
 
977
}
 
978
 
 
979
static void
 
980
set_mode_from_gsettings (GtkComboBox *combo, CcWacomPage *page)
 
981
{
 
982
        CcWacomPagePrivate      *priv = page->priv;
 
983
        gboolean                is_absolute;
 
984
 
 
985
        is_absolute = g_settings_get_boolean (priv->wacom_settings, "is-absolute");
 
986
 
 
987
        /* this must be kept in sync with the .ui file */
 
988
        gtk_combo_box_set_active (combo, is_absolute ? MODE_ABSOLUTE : MODE_RELATIVE);
 
989
}
 
990
 
 
991
static void
 
992
combobox_text_cellrenderer (GtkComboBox *combo, int name_column)
 
993
{
 
994
        GtkCellRenderer *renderer;
 
995
 
 
996
        renderer = gtk_cell_renderer_text_new ();
 
997
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
 
998
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
 
999
                                        "text", BUTTONNAME_COLUMN, NULL);
 
1000
}
 
1001
 
 
1002
static gboolean
 
1003
display_clicked_cb (GtkButton   *button,
 
1004
                    CcWacomPage *page)
 
1005
{
 
1006
        cc_wacom_panel_switch_to_panel (page->priv->panel, "display");
 
1007
        return TRUE;
 
1008
}
 
1009
 
 
1010
/* Boilerplate code goes below */
 
1011
 
 
1012
static void
 
1013
cc_wacom_page_get_property (GObject    *object,
 
1014
                             guint       property_id,
 
1015
                             GValue     *value,
 
1016
                             GParamSpec *pspec)
 
1017
{
 
1018
        switch (property_id)
 
1019
        {
 
1020
                default:
 
1021
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
1022
        }
 
1023
}
 
1024
 
 
1025
static void
 
1026
cc_wacom_page_set_property (GObject      *object,
 
1027
                             guint         property_id,
 
1028
                             const GValue *value,
 
1029
                             GParamSpec   *pspec)
 
1030
{
 
1031
        switch (property_id)
 
1032
        {
 
1033
                default:
 
1034
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
1035
        }
 
1036
}
 
1037
 
 
1038
static void
 
1039
cc_wacom_page_dispose (GObject *object)
 
1040
{
 
1041
        CcWacomPagePrivate *priv = CC_WACOM_PAGE (object)->priv;
 
1042
 
 
1043
        if (priv->area) {
 
1044
                calib_area_free (priv->area);
 
1045
                priv->area = NULL;
 
1046
        }
 
1047
 
 
1048
        if (priv->button_map) {
 
1049
                gtk_widget_destroy (priv->button_map);
 
1050
                priv->button_map = NULL;
 
1051
        }
 
1052
 
 
1053
        if (priv->dialog) {
 
1054
                gtk_widget_destroy (priv->dialog);
 
1055
                priv->dialog = NULL;
 
1056
        }
 
1057
 
 
1058
        if (priv->builder) {
 
1059
                g_object_unref (priv->builder);
 
1060
                priv->builder = NULL;
 
1061
        }
 
1062
 
 
1063
        priv->panel = NULL;
 
1064
 
 
1065
        G_OBJECT_CLASS (cc_wacom_page_parent_class)->dispose (object);
 
1066
}
 
1067
 
 
1068
static void
 
1069
cc_wacom_page_class_init (CcWacomPageClass *klass)
 
1070
{
 
1071
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
1072
 
 
1073
        g_type_class_add_private (klass, sizeof (CcWacomPagePrivate));
 
1074
 
 
1075
        object_class->get_property = cc_wacom_page_get_property;
 
1076
        object_class->set_property = cc_wacom_page_set_property;
 
1077
        object_class->dispose = cc_wacom_page_dispose;
 
1078
}
 
1079
 
 
1080
static void
 
1081
cc_wacom_page_init (CcWacomPage *self)
 
1082
{
 
1083
        CcWacomPagePrivate *priv;
 
1084
        GError *error = NULL;
 
1085
        GtkComboBox *combo;
 
1086
        GtkWidget *box;
 
1087
        GtkSwitch *sw;
 
1088
        char *objects[] = {
 
1089
                "main-grid",
 
1090
                "liststore-tabletmode",
 
1091
                "liststore-buttons",
 
1092
                "adjustment-tip-feel",
 
1093
                "adjustment-eraser-feel",
 
1094
                NULL
 
1095
        };
 
1096
 
 
1097
        priv = self->priv = WACOM_PAGE_PRIVATE (self);
 
1098
 
 
1099
        priv->builder = gtk_builder_new ();
 
1100
 
 
1101
        gtk_builder_add_objects_from_file (priv->builder,
 
1102
                                           GNOMECC_UI_DIR "/gnome-wacom-properties.ui",
 
1103
                                           objects,
 
1104
                                           &error);
 
1105
        if (error != NULL) {
 
1106
                g_warning ("Error loading UI file: %s", error->message);
 
1107
                g_object_unref (priv->builder);
 
1108
                g_error_free (error);
 
1109
                return;
 
1110
        }
 
1111
 
 
1112
        box = WID ("main-grid");
 
1113
        gtk_container_add (GTK_CONTAINER (self), box);
 
1114
        gtk_widget_set_vexpand (GTK_WIDGET (box), TRUE);
 
1115
 
 
1116
        self->priv->notebook = WID ("stylus-notebook");
 
1117
 
 
1118
        g_signal_connect (WID ("button-calibrate"), "clicked",
 
1119
                          G_CALLBACK (calibrate_button_clicked_cb), self);
 
1120
        g_signal_connect (WID ("map-buttons-button"), "clicked",
 
1121
                          G_CALLBACK (map_buttons_button_clicked_cb), self);
 
1122
 
 
1123
        combo = GTK_COMBO_BOX (WID ("combo-tabletmode"));
 
1124
        combobox_text_cellrenderer (combo, MODELABEL_COLUMN);
 
1125
        g_signal_connect (G_OBJECT (combo), "changed",
 
1126
                          G_CALLBACK (tabletmode_changed_cb), self);
 
1127
 
 
1128
        sw = GTK_SWITCH (WID ("switch-left-handed"));
 
1129
        g_signal_connect (G_OBJECT (sw), "notify::active",
 
1130
                          G_CALLBACK (left_handed_toggled_cb), self);
 
1131
 
 
1132
        g_signal_connect (G_OBJECT (WID ("display-link")), "activate-link",
 
1133
                          G_CALLBACK (display_clicked_cb), self);
 
1134
 
 
1135
        g_signal_connect (G_OBJECT (WID ("display-mapping-button")), "clicked",
 
1136
                          G_CALLBACK (display_mapping_button_clicked_cb), self);
 
1137
 
 
1138
        priv->nav = cc_wacom_nav_button_new ();
 
1139
        gtk_widget_set_halign (priv->nav, GTK_ALIGN_END);
 
1140
        gtk_widget_set_margin_left (priv->nav, 10);
 
1141
        gtk_grid_attach (GTK_GRID (box), priv->nav, 1, 0, 1, 1);
 
1142
}
 
1143
 
 
1144
static void
 
1145
set_icon_name (CcWacomPage *page,
 
1146
               const char  *widget_name,
 
1147
               const char  *icon_name)
 
1148
{
 
1149
        CcWacomPagePrivate *priv;
 
1150
        char *filename, *path;
 
1151
 
 
1152
        priv = page->priv;
 
1153
 
 
1154
        filename = g_strdup_printf ("%s.svg", icon_name);
 
1155
        path = g_build_filename (GNOMECC_UI_DIR, filename, NULL);
 
1156
        g_free (filename);
 
1157
 
 
1158
        gtk_image_set_from_file (GTK_IMAGE (WID (widget_name)), path);
 
1159
        g_free (path);
 
1160
}
 
1161
 
 
1162
typedef struct {
 
1163
        GsdWacomStylus *stylus;
 
1164
        GsdWacomStylus *eraser;
 
1165
} StylusPair;
 
1166
 
 
1167
static void
 
1168
add_styli (CcWacomPage *page)
 
1169
{
 
1170
        GList *styli, *l;
 
1171
        CcWacomPagePrivate *priv;
 
1172
 
 
1173
        priv = page->priv;
 
1174
 
 
1175
        styli = gsd_wacom_device_list_styli (priv->stylus);
 
1176
 
 
1177
        for (l = styli; l; l = l->next) {
 
1178
                GsdWacomStylus *stylus, *eraser;
 
1179
                GtkWidget *page;
 
1180
 
 
1181
                stylus = l->data;
 
1182
 
 
1183
                if (gsd_wacom_stylus_get_stylus_type (stylus) == WACOM_STYLUS_TYPE_PUCK)
 
1184
                        continue;
 
1185
 
 
1186
                if (gsd_wacom_stylus_get_has_eraser (stylus)) {
 
1187
                        GsdWacomDeviceType type;
 
1188
                        type = gsd_wacom_stylus_get_stylus_type (stylus);
 
1189
                        eraser = gsd_wacom_device_get_stylus_for_type (priv->eraser, type);
 
1190
                } else {
 
1191
                        eraser = NULL;
 
1192
                }
 
1193
 
 
1194
                page = cc_wacom_stylus_page_new (stylus, eraser);
 
1195
                cc_wacom_stylus_page_set_navigation (CC_WACOM_STYLUS_PAGE (page), GTK_NOTEBOOK (priv->notebook));
 
1196
                gtk_widget_show (page);
 
1197
                gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), page, NULL);
 
1198
        }
 
1199
        g_list_free (styli);
 
1200
}
 
1201
 
 
1202
static void
 
1203
stylus_changed (GsdWacomDevice *device,
 
1204
                GParamSpec     *pspec,
 
1205
                CcWacomPage    *page)
 
1206
{
 
1207
        GsdWacomStylus *stylus;
 
1208
        CcWacomPagePrivate *priv;
 
1209
        int num_pages;
 
1210
        guint i;
 
1211
 
 
1212
        priv = page->priv;
 
1213
        g_object_get (G_OBJECT (device), "last-stylus", &stylus, NULL);
 
1214
        if (stylus == NULL)
 
1215
                return;
 
1216
 
 
1217
        num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
 
1218
        for (i = 0; i < num_pages; i++) {
 
1219
                GsdWacomStylus *s;
 
1220
                CcWacomStylusPage *spage;
 
1221
 
 
1222
                spage = CC_WACOM_STYLUS_PAGE (gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), i));
 
1223
                s = cc_wacom_stylus_page_get_stylus (spage);
 
1224
                if (s == stylus) {
 
1225
                        gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), i);
 
1226
                        return;
 
1227
                }
 
1228
        }
 
1229
 
 
1230
        g_warning ("Failed to find the page for stylus '%s'",
 
1231
                   gsd_wacom_stylus_get_name (stylus));
 
1232
}
 
1233
 
 
1234
static void
 
1235
remove_left_handed (CcWacomPagePrivate *priv)
 
1236
{
 
1237
        gtk_widget_destroy (WID ("label-left-handed"));
 
1238
        gtk_widget_destroy (WID ("switch-left-handed"));
 
1239
}
 
1240
 
 
1241
static void
 
1242
remove_display_link (CcWacomPagePrivate *priv)
 
1243
{
 
1244
        gtk_widget_destroy (WID ("display-link"));
 
1245
 
 
1246
        gtk_container_child_set (CWID ("main-grid"),
 
1247
                                 WID ("tablet-buttons-box"),
 
1248
                                 "top_attach", 2, NULL);
 
1249
}
 
1250
 
 
1251
static void
 
1252
update_tablet_ui (CcWacomPage *page,
 
1253
                  int          layout)
 
1254
{
 
1255
        CcWacomPagePrivate *priv;
 
1256
        gboolean has_monitor = FALSE;
 
1257
 
 
1258
        priv = page->priv;
 
1259
 
 
1260
        /* Hide the pad buttons if no pad is present */
 
1261
        gtk_widget_set_visible (WID ("map-buttons-button"), priv->pad != NULL);
 
1262
 
 
1263
        switch (layout) {
 
1264
        case LAYOUT_NORMAL:
 
1265
                remove_left_handed (page->priv);
 
1266
                remove_display_link (page->priv);
 
1267
                break;
 
1268
        case LAYOUT_REVERSIBLE:
 
1269
                remove_display_link (page->priv);
 
1270
                break;
 
1271
        case LAYOUT_SCREEN:
 
1272
                remove_left_handed (page->priv);
 
1273
 
 
1274
                gtk_widget_destroy (WID ("combo-tabletmode"));
 
1275
                gtk_widget_destroy (WID ("label-trackingmode"));
 
1276
                gtk_widget_destroy (WID ("display-mapping-button"));
 
1277
 
 
1278
                gtk_widget_show (WID ("button-calibrate"));
 
1279
                if (gsd_wacom_device_get_display_monitor (page->priv->stylus) >= 0)
 
1280
                        has_monitor = TRUE;
 
1281
                gtk_widget_set_sensitive (WID ("button-calibrate"), has_monitor);
 
1282
                gtk_widget_show (WID ("display-link"));
 
1283
 
 
1284
                gtk_container_child_set (CWID ("main-grid"),
 
1285
                                         WID ("tablet-buttons-box"),
 
1286
                                         "top_attach", 1, NULL);
 
1287
                gtk_container_child_set (CWID ("main-grid"),
 
1288
                                         WID ("display-link"),
 
1289
                                         "top_attach", 2, NULL);
 
1290
                break;
 
1291
        default:
 
1292
                g_assert_not_reached ();
 
1293
        }
 
1294
}
 
1295
 
 
1296
gboolean
 
1297
cc_wacom_page_update_tools (CcWacomPage    *page,
 
1298
                            GsdWacomDevice *stylus,
 
1299
                            GsdWacomDevice *eraser,
 
1300
                            GsdWacomDevice *pad)
 
1301
{
 
1302
        CcWacomPagePrivate *priv;
 
1303
        int layout;
 
1304
        gboolean changed;
 
1305
 
 
1306
        /* Type of layout */
 
1307
        layout = get_layout_type (stylus);
 
1308
 
 
1309
        priv = page->priv;
 
1310
        changed = (priv->stylus != stylus || priv->eraser != eraser || priv->pad != pad);
 
1311
        if (!changed)
 
1312
                return FALSE;
 
1313
 
 
1314
        priv->stylus = stylus;
 
1315
        priv->eraser = eraser;
 
1316
        priv->pad = pad;
 
1317
 
 
1318
        update_tablet_ui (CC_WACOM_PAGE (page), layout);
 
1319
 
 
1320
        return TRUE;
 
1321
}
 
1322
 
 
1323
GtkWidget *
 
1324
cc_wacom_page_new (CcWacomPanel   *panel,
 
1325
                   GsdWacomDevice *stylus,
 
1326
                   GsdWacomDevice *eraser,
 
1327
                   GsdWacomDevice *pad)
 
1328
{
 
1329
        CcWacomPage *page;
 
1330
        CcWacomPagePrivate *priv;
 
1331
 
 
1332
        g_return_val_if_fail (GSD_IS_WACOM_DEVICE (stylus), NULL);
 
1333
        g_return_val_if_fail (gsd_wacom_device_get_device_type (stylus) == WACOM_TYPE_STYLUS, NULL);
 
1334
 
 
1335
        g_return_val_if_fail (GSD_IS_WACOM_DEVICE (eraser), NULL);
 
1336
        g_return_val_if_fail (gsd_wacom_device_get_device_type (eraser) == WACOM_TYPE_ERASER, NULL);
 
1337
 
 
1338
        if (pad != NULL)
 
1339
                g_return_val_if_fail (gsd_wacom_device_get_device_type (pad) == WACOM_TYPE_PAD, NULL);
 
1340
 
 
1341
        page = g_object_new (CC_TYPE_WACOM_PAGE, NULL);
 
1342
 
 
1343
        priv = page->priv;
 
1344
        priv->panel = panel;
 
1345
 
 
1346
        cc_wacom_page_update_tools (page, stylus, eraser, pad);
 
1347
 
 
1348
        /* FIXME move this to construct */
 
1349
        priv->wacom_settings  = gsd_wacom_device_get_settings (stylus);
 
1350
        set_mode_from_gsettings (GTK_COMBO_BOX (WID ("combo-tabletmode")), page);
 
1351
 
 
1352
        /* Tablet name */
 
1353
        gtk_label_set_text (GTK_LABEL (WID ("label-tabletmodel")), gsd_wacom_device_get_name (stylus));
 
1354
 
 
1355
        /* Left-handedness */
 
1356
        if (gsd_wacom_device_reversible (stylus))
 
1357
                set_left_handed_from_gsettings (page);
 
1358
 
 
1359
        /* Tablet icon */
 
1360
        set_icon_name (page, "image-tablet", gsd_wacom_device_get_icon_name (stylus));
 
1361
 
 
1362
        /* Add styli */
 
1363
        add_styli (page);
 
1364
 
 
1365
        /* Get the current stylus and switch to its page */
 
1366
        stylus_changed (priv->stylus, NULL, page);
 
1367
        g_signal_connect (G_OBJECT (priv->stylus), "notify::last-stylus",
 
1368
                          G_CALLBACK (stylus_changed), page);
 
1369
 
 
1370
        return GTK_WIDGET (page);
 
1371
}
 
1372
 
 
1373
void
 
1374
cc_wacom_page_set_navigation (CcWacomPage *page,
 
1375
                              GtkNotebook *notebook,
 
1376
                              gboolean     ignore_first_page)
 
1377
{
 
1378
        CcWacomPagePrivate *priv;
 
1379
 
 
1380
        g_return_if_fail (CC_IS_WACOM_PAGE (page));
 
1381
 
 
1382
        priv = page->priv;
 
1383
 
 
1384
        g_object_set (G_OBJECT (priv->nav),
 
1385
                      "notebook", notebook,
 
1386
                      "ignore-first", ignore_first_page,
 
1387
                      NULL);
 
1388
}