1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2014 Carlos Garnacho <carlosg@gnome.org>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
#include <X11/Xatom.h>
27
#include <libwacom/libwacom.h>
30
#include "gsd-device-mapper.h"
31
#include "gsd-input-helper.h"
32
#include "gsd-enums.h"
34
typedef struct _GsdInputInfo GsdInputInfo;
35
typedef struct _GsdOutputInfo GsdOutputInfo;
36
typedef struct _MappingHelper MappingHelper;
37
typedef struct _DeviceMapHelper DeviceMapHelper;
39
#define NUM_ELEMS_MATRIX 9
40
#define KEY_DISPLAY "display"
41
#define KEY_ROTATION "rotation"
44
GSD_INPUT_IS_SYSTEM_INTEGRATED = 1 << 0, /* eg. laptop tablets/touchscreens */
45
GSD_INPUT_IS_SCREEN_INTEGRATED = 1 << 1, /* eg. Wacom Cintiq devices */
46
GSD_INPUT_IS_TOUCH = 1 << 2, /* touch device, either touchscreen or tablet */
47
GSD_INPUT_IS_PEN = 1 << 3, /* pen device, either touchscreen or tablet */
48
GSD_INPUT_IS_ERASER = 1 << 4, /* eraser device, either touchscreen or tablet */
49
GSD_INPUT_IS_PAD = 1 << 5 /* pad device, most usually in tablets */
50
} GsdInputCapabilityFlags;
53
GSD_PRIO_BUILTIN, /* Output is builtin, applies mainly to system-integrated devices */
54
GSD_PRIO_EDID_MATCH_FULL, /* Full EDID model match, eg. "Cintiq 12WX" */
55
GSD_PRIO_EDID_MATCH_PARTIAL, /* Partial EDID model match, eg. "Cintiq" */
56
GSD_PRIO_EDID_MATCH_VENDOR, /* EDID vendor match, eg. "WAC" for Wacom */
60
struct _GsdInputInfo {
63
GsdDeviceMapper *mapper;
64
GsdOutputInfo *output;
65
GsdOutputInfo *guessed_output;
67
GsdInputCapabilityFlags capabilities;
70
struct _GsdOutputInfo {
71
GnomeRROutput *output;
75
struct _DeviceMapHelper {
77
GnomeRROutput *candidates[N_OUTPUT_PRIORITIES];
78
GsdOutputPriority highest_prio;
82
struct _MappingHelper {
86
struct _GsdDeviceMapper {
87
GObject parent_instance;
89
GnomeRRScreen *rr_screen;
90
GHashTable *input_devices; /* GdkDevice -> GsdInputInfo */
91
GHashTable *output_devices; /* GnomeRROutput -> GsdOutputInfo */
93
WacomDeviceDatabase *wacom_db;
97
struct _GsdDeviceMapperClass {
98
GObjectClass parent_class;
101
/* Array order matches GsdWacomRotation */
103
GnomeRRRotation rotation;
104
/* Coordinate Transformation Matrix */
105
gfloat matrix[NUM_ELEMS_MATRIX];
106
} rotation_matrices[] = {
107
{ GNOME_RR_ROTATION_0, { 1, 0, 0, 0, 1, 0, 0, 0, 1 } },
108
{ GNOME_RR_ROTATION_90, { 0, -1, 1, 1, 0, 0, 0, 0, 1 } },
109
{ GNOME_RR_ROTATION_270, { 0, 1, 0, -1, 0, 1, 0, 0, 1 } },
110
{ GNOME_RR_ROTATION_180, { -1, 0, 1, 0, -1, 1, 0, 0, 1 } }
123
static guint signals[N_SIGNALS] = { 0 };
125
static void gsd_device_mapper_initable_iface_init (GInitableIface *iface);
127
G_DEFINE_TYPE_WITH_CODE (GsdDeviceMapper, gsd_device_mapper, G_TYPE_OBJECT,
128
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
129
gsd_device_mapper_initable_iface_init))
132
open_device (GdkDevice *device)
137
id = gdk_x11_device_get_id (device);
139
gdk_error_trap_push ();
140
xdev = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id);
141
if (gdk_error_trap_pop () || (xdev == NULL))
148
device_apply_property (GdkDevice *device,
149
PropertyHelper *property)
154
xdev = open_device (device);
159
retval = device_set_property (xdev, gdk_device_get_name (device), property);
160
XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev);
165
device_set_matrix (GdkDevice *device,
166
gfloat matrix[NUM_ELEMS_MATRIX])
168
PropertyHelper property = {
169
.name = "Coordinate Transformation Matrix",
172
.type = gdk_x11_get_xatom_by_name ("FLOAT"),
173
.data.i = (int *) matrix,
176
g_debug ("Setting '%s' matrix to:\n %f,%f,%f,\n %f,%f,%f,\n %f,%f,%f",
177
gdk_device_get_name (device),
178
matrix[0], matrix[1], matrix[2],
179
matrix[3], matrix[4], matrix[5],
180
matrix[6], matrix[7], matrix[8]);
182
return device_apply_property (device, &property);
185
/* Finds an output which matches the given EDID information. Any NULL
186
* parameter will be interpreted to match any value. */
187
static GnomeRROutput *
188
find_output_by_edid (GnomeRRScreen *rr_screen,
189
const gchar *edid[3])
191
GnomeRROutput **outputs;
192
GnomeRROutput *retval = NULL;
195
outputs = gnome_rr_screen_list_outputs (rr_screen);
197
for (i = 0; outputs[i] != NULL; i++) {
198
gchar *vendor, *product, *serial;
201
gnome_rr_output_get_ids_from_edid (outputs[i], &vendor,
204
g_debug ("Checking for match between ['%s','%s','%s'] and ['%s','%s','%s']", \
205
edid[0], edid[1], edid[2], vendor, product, serial);
207
match = (edid[0] == NULL || g_strcmp0 (edid[0], vendor) == 0) && \
208
(edid[1] == NULL || g_strcmp0 (edid[1], product) == 0) && \
209
(edid[2] == NULL || g_strcmp0 (edid[2], serial) == 0);
222
g_debug ("Did not find a matching output for EDID '%s,%s,%s'",
223
edid[0], edid[1], edid[2]);
227
static GnomeRROutput *
228
find_builtin_output (GnomeRRScreen *rr_screen)
230
GnomeRROutput **outputs;
233
outputs = gnome_rr_screen_list_outputs (rr_screen);
235
for (i = 0; outputs[i] != NULL; i++) {
236
if (!gnome_rr_output_is_builtin_display (outputs[i]))
242
g_debug ("Did not find a built-in monitor");
246
static GnomeRROutput *
247
monitor_to_output (GsdDeviceMapper *mapper,
250
GnomeRROutput **outputs;
253
outputs = gnome_rr_screen_list_outputs (mapper->rr_screen);
255
for (i = 0; outputs[i] != NULL; i++) {
256
GnomeRRCrtc *crtc = gnome_rr_output_get_crtc (outputs[i]);
262
gnome_rr_crtc_get_position (crtc, &x, &y);
264
if (monitor_num == gdk_screen_get_monitor_at_point (mapper->screen, x, y))
271
static MappingHelper *
272
mapping_helper_new (void)
274
MappingHelper *helper;
276
helper = g_new0 (MappingHelper, 1);
277
helper->device_maps = g_array_new (FALSE, FALSE, sizeof (DeviceMapHelper));
283
mapping_helper_free (MappingHelper *helper)
285
g_array_unref (helper->device_maps);
290
mapping_helper_add (MappingHelper *helper,
292
GnomeRROutput *outputs[N_OUTPUT_PRIORITIES])
294
guint i, pos, highest = N_OUTPUT_PRIORITIES;
295
DeviceMapHelper info = { 0 }, *prev;
299
for (i = 0; i < N_OUTPUT_PRIORITIES; i++) {
300
if (outputs[i] == NULL)
306
info.candidates[i] = outputs[i];
310
info.highest_prio = highest;
311
pos = helper->device_maps->len;
313
for (i = 0; i < helper->device_maps->len; i++) {
314
prev = &g_array_index (helper->device_maps, DeviceMapHelper, i);
316
if (prev->highest_prio < info.highest_prio)
320
if (pos >= helper->device_maps->len)
321
g_array_append_val (helper->device_maps, info);
323
g_array_insert_val (helper->device_maps, pos, info);
326
/* This function gets a map of outputs, sorted by confidence, for a given device,
327
* the array can actually contain NULLs if no output matched a priority. */
329
input_info_guess_candidates (GsdInputInfo *input,
330
GnomeRROutput *outputs[N_OUTPUT_PRIORITIES])
332
gboolean found = FALSE;
336
name = gdk_device_get_name (input->device);
337
split = g_strsplit (name, " ", -1);
339
/* On Wacom devices that are integrated on a not-in-system screen (eg. Cintiqs),
340
* there is usually a minimal relation between the input device name and the EDID
341
* vendor/model fields. Attempt to find matching outputs and fill in the map
342
* from GSD_PRIO_EDID_MATCH_FULL to GSD_PRIO_EDID_MATCH_VENDOR.
344
if (input->capabilities & GSD_INPUT_IS_SCREEN_INTEGRATED &&
345
g_str_has_prefix (name, "Wacom ")) {
346
gchar *product = g_strdup_printf ("%s %s", split[1], split[2]);
347
const gchar *edids[][3] = {
348
{ "WAC", product, NULL },
349
{ "WAC", split[1], NULL },
350
{ "WAC", NULL, NULL }
354
for (i = 0; i < G_N_ELEMENTS (edids); i++) {
355
/* i + 1 matches the desired priority, we skip GSD_PRIO_BUILTIN here */
357
find_output_by_edid (input->mapper->rr_screen,
359
found |= outputs[i + 1] != NULL;
365
/* For input devices that we certainly know that are system-integrated, or
366
* for screen-integrated devices we weren't able to find an output for,
367
* find the builtin screen.
369
if ((input->capabilities & GSD_INPUT_IS_SYSTEM_INTEGRATED) ||
370
(!found && input->capabilities & GSD_INPUT_IS_SCREEN_INTEGRATED)) {
371
outputs[GSD_PRIO_BUILTIN] =
372
find_builtin_output (input->mapper->rr_screen);
379
output_has_input_type (GsdOutputInfo *info,
384
for (devices = info->input_devices; devices; devices = devices->next) {
385
GsdInputInfo *input = devices->data;
387
if (input->capabilities == capabilities)
394
static GnomeRROutput *
395
settings_get_display (GSettings *settings,
396
GsdDeviceMapper *mapper)
398
GnomeRROutput *output = NULL;
402
edid = g_settings_get_strv (settings, KEY_DISPLAY);
403
nvalues = g_strv_length (edid);
406
output = find_output_by_edid (mapper->rr_screen, (const gchar **) edid);
408
g_warning ("Unable to get display property. Got %d items, "
409
"expected %d items.\n", nvalues, 3);
418
settings_set_display (GSettings *settings,
419
GnomeRROutput *output)
421
gchar **prev, *edid[4] = { NULL, NULL, NULL, NULL };
425
prev = g_settings_get_strv (settings, KEY_DISPLAY);
426
nvalues = g_strv_length (prev);
429
gnome_rr_output_get_ids_from_edid (output, &edid[0],
433
g_strcmp0 (prev[0], edid[0]) != 0 ||
434
g_strcmp0 (prev[1], edid[1]) != 0 ||
435
g_strcmp0 (prev[2], edid[2]) != 0) {
436
value = g_variant_new_strv ((const gchar * const *) &edid, 3);
437
g_settings_set_value (settings, KEY_DISPLAY, value);
447
input_info_set_output (GsdInputInfo *input,
448
GsdOutputInfo *output,
452
GnomeRROutput *rr_output = NULL;
456
/* If there is already a non-guessed input, go for it */
460
ptr = &input->guessed_output;
462
/* Unset guessed output */
463
if (input->guessed_output)
464
input_info_set_output (input, NULL, TRUE, FALSE);
465
ptr = &input->output;
472
(*ptr)->input_devices = g_list_remove ((*ptr)->input_devices,
477
output->input_devices = g_list_prepend (output->input_devices,
479
rr_output = output->output;
482
if (input->settings && !guessed && save)
483
settings_set_display (input->settings, rr_output);
488
static GsdOutputInfo *
489
input_info_get_output (GsdInputInfo *input)
495
return input->output;
497
if (input->guessed_output)
498
return input->guessed_output;
500
if (g_hash_table_size (input->mapper->output_devices) == 1) {
501
GsdOutputInfo *output;
504
g_hash_table_iter_init (&iter, input->mapper->output_devices);
505
g_hash_table_iter_next (&iter, NULL, (gpointer *) &output);
514
init_device_rotation_matrix (GsdWacomRotation rotation,
515
float matrix[NUM_ELEMS_MATRIX])
517
memcpy (matrix, rotation_matrices[rotation].matrix,
518
sizeof (rotation_matrices[rotation].matrix));
522
init_output_rotation_matrix (GnomeRRRotation rotation,
523
float matrix[NUM_ELEMS_MATRIX])
527
for (i = 0; i < G_N_ELEMENTS (rotation_matrices); i++) {
528
if (rotation_matrices[i].rotation != rotation)
531
memcpy (matrix, rotation_matrices[i].matrix, sizeof (rotation_matrices[i].matrix));
535
/* We know nothing about this rotation */
536
init_device_rotation_matrix (GSD_WACOM_ROTATION_NONE, matrix);
540
multiply_matrix (float a[NUM_ELEMS_MATRIX],
541
float b[NUM_ELEMS_MATRIX],
542
float res[NUM_ELEMS_MATRIX])
544
float result[NUM_ELEMS_MATRIX];
546
result[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6];
547
result[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7];
548
result[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8];
549
result[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6];
550
result[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7];
551
result[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8];
552
result[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6];
553
result[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7];
554
result[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8];
556
memcpy (res, result, sizeof (result));
560
calculate_viewport_matrix (const GdkRectangle mapped,
561
const GdkRectangle desktop,
562
float viewport[NUM_ELEMS_MATRIX])
564
float x_scale = (float) mapped.x / desktop.width;
565
float y_scale = (float) mapped.y / desktop.height;
566
float width_scale = (float) mapped.width / desktop.width;
567
float height_scale = (float) mapped.height / desktop.height;
569
viewport[0] = width_scale;
571
viewport[2] = x_scale;
574
viewport[4] = height_scale;
575
viewport[5] = y_scale;
583
monitor_for_output (GnomeRROutput *output)
585
GdkScreen *screen = gdk_screen_get_default ();
586
GnomeRRCrtc *crtc = gnome_rr_output_get_crtc (output);
592
gnome_rr_crtc_get_position (crtc, &x, &y);
594
return gdk_screen_get_monitor_at_point (screen, x, y);
598
input_info_get_matrix (GsdInputInfo *input,
599
float matrix[NUM_ELEMS_MATRIX])
601
GsdOutputInfo *output;
603
output = input_info_get_output (input);
606
init_output_rotation_matrix (GNOME_RR_ROTATION_0, matrix);
608
GdkScreen *screen = gdk_screen_get_default ();
609
float viewport[NUM_ELEMS_MATRIX];
610
float output_rot[NUM_ELEMS_MATRIX];
611
GdkRectangle display, desktop = { 0 };
612
GnomeRRRotation rotation;
616
g_debug ("Mapping '%s' to output '%s'",
617
gdk_device_get_name (input->device),
618
gnome_rr_output_get_name (output->output));
620
crtc = gnome_rr_output_get_crtc (output->output);
621
rotation = gnome_rr_crtc_get_current_rotation (crtc);
622
init_output_rotation_matrix (rotation, output_rot);
624
desktop.width = gdk_screen_get_width (screen);
625
desktop.height = gdk_screen_get_height (screen);
627
monitor = monitor_for_output (output->output);
628
gdk_screen_get_monitor_geometry (screen, monitor, &display);
629
calculate_viewport_matrix (display, desktop, viewport);
631
multiply_matrix (viewport, output_rot, matrix);
634
/* Apply device rotation after output rotation */
635
if (input->settings &&
636
(input->capabilities &
637
(GSD_INPUT_IS_SYSTEM_INTEGRATED | GSD_INPUT_IS_SCREEN_INTEGRATED)) == 0) {
640
rotation = g_settings_get_enum (input->settings, KEY_ROTATION);
643
float device_rot[NUM_ELEMS_MATRIX];
645
g_debug ("Applying device rotation %d to '%s'",
646
rotation, gdk_device_get_name (input->device));
648
init_device_rotation_matrix (rotation, device_rot);
649
multiply_matrix (matrix, device_rot, matrix);
655
input_info_remap (GsdInputInfo *input)
657
float matrix[NUM_ELEMS_MATRIX] = { 0 };
659
if (input->capabilities & GSD_INPUT_IS_PAD)
662
input_info_get_matrix (input, matrix);
664
g_debug ("About to remap device '%s'",
665
gdk_device_get_name (input->device));
667
if (!device_set_matrix (input->device, matrix)) {
668
g_warning ("Failed to map device '%s'",
669
gdk_device_get_name (input->device));
672
g_signal_emit (input->mapper, signals[DEVICE_CHANGED], 0, input->device);
676
mapper_apply_helper_info (GsdDeviceMapper *mapper,
677
MappingHelper *helper)
681
/* Now, decide which input claims which output */
682
for (i = 0; i < helper->device_maps->len; i++) {
683
GsdOutputInfo *last = NULL, *output = NULL;
684
DeviceMapHelper *info;
686
info = &g_array_index (helper->device_maps, DeviceMapHelper, i);
688
for (j = 0; j < N_OUTPUT_PRIORITIES; j++) {
689
if (!info->candidates[j])
692
output = g_hash_table_lookup (mapper->output_devices,
693
info->candidates[j]);
700
if ((info->input->capabilities &
701
(GSD_INPUT_IS_SYSTEM_INTEGRATED | GSD_INPUT_IS_SCREEN_INTEGRATED))) {
702
/* A single output is hardly going to have multiple integrated input
703
* devices with the same capabilities, so punt to any next output.
705
if (output_has_input_type (output, info->input->capabilities))
709
input_info_set_output (info->input, output, TRUE, FALSE);
713
/* Assign the last candidate if we came up empty */
714
if (!info->input->guessed_output && last)
715
input_info_set_output (info->input, last, TRUE, FALSE);
717
input_info_remap (info->input);
722
mapper_recalculate_candidates (GsdDeviceMapper *mapper)
724
MappingHelper *helper;
728
helper = mapping_helper_new ();
729
g_hash_table_iter_init (&iter, mapper->input_devices);
731
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &input)) {
732
GnomeRROutput *outputs[N_OUTPUT_PRIORITIES] = { 0 };
734
/* Device has an output from settings */
738
input_info_guess_candidates (input, outputs);
739
mapping_helper_add (helper, input, outputs);
742
mapper_apply_helper_info (mapper, helper);
743
mapping_helper_free (helper);
747
mapper_recalculate_input (GsdDeviceMapper *mapper,
750
GnomeRROutput *outputs[N_OUTPUT_PRIORITIES] = { 0 };
751
MappingHelper *helper;
753
/* Device has an output from settings */
757
helper = mapping_helper_new ();
758
input_info_guess_candidates (input, outputs);
759
mapping_helper_add (helper, input, outputs);
761
mapper_apply_helper_info (mapper, helper);
762
mapping_helper_free (helper);
766
input_info_update_capabilities_from_tool_type (GsdInputInfo *info)
768
const char *tool_type;
771
deviceid = gdk_x11_device_get_id (info->device);
772
tool_type = xdevice_get_wacom_tool_type (deviceid);
777
if (g_str_equal (tool_type, "STYLUS"))
778
info->capabilities |= GSD_INPUT_IS_PEN;
779
else if (g_str_equal (tool_type, "ERASER"))
780
info->capabilities |= GSD_INPUT_IS_ERASER;
781
else if (g_str_equal (tool_type, "PAD"))
782
info->capabilities |= GSD_INPUT_IS_PAD;
788
input_info_update_capabilities (GsdInputInfo *info)
791
WacomDevice *wacom_device;
794
info->capabilities = 0;
795
devpath = xdevice_get_device_node (gdk_x11_device_get_id (info->device));
796
wacom_device = libwacom_new_from_path (info->mapper->wacom_db, devpath,
797
WFALLBACK_GENERIC, NULL);
800
WacomIntegrationFlags integration_flags;
802
integration_flags = libwacom_get_integration_flags (wacom_device);
804
if (integration_flags & WACOM_DEVICE_INTEGRATED_DISPLAY)
805
info->capabilities |= GSD_INPUT_IS_SCREEN_INTEGRATED;
807
if (integration_flags & WACOM_DEVICE_INTEGRATED_SYSTEM)
808
info->capabilities |= GSD_INPUT_IS_SYSTEM_INTEGRATED;
810
libwacom_destroy (wacom_device);
815
info->capabilities = 0;
816
#endif /* HAVE_WACOM */
818
if (!input_info_update_capabilities_from_tool_type (info)) {
819
GdkInputSource source;
821
/* Fallback to GdkInputSource */
822
source = gdk_device_get_source (info->device);
824
if (source == GDK_SOURCE_TOUCHSCREEN)
825
info->capabilities |= GSD_INPUT_IS_TOUCH | GSD_INPUT_IS_SCREEN_INTEGRATED;
826
else if (source == GDK_SOURCE_PEN)
827
info->capabilities |= GSD_INPUT_IS_PEN;
828
else if (source == GDK_SOURCE_ERASER)
829
info->capabilities |= GSD_INPUT_IS_ERASER;
834
device_settings_changed_cb (GSettings *settings,
838
if (g_str_equal (key, KEY_DISPLAY)) {
839
GnomeRROutput *rr_output;
840
GsdOutputInfo *output;
842
rr_output = settings_get_display (settings, input->mapper);
845
output = g_hash_table_lookup (input->mapper->output_devices,
847
input_info_set_output (input, output, FALSE, FALSE);
848
input_info_remap (input);
850
/* Guess an output for this device */
851
mapper_recalculate_input (input->mapper, input);
853
} else if (g_str_equal (key, KEY_ROTATION)) {
854
/* Remap the device so the new rotation is applied */
855
input_info_remap (input);
859
static GsdInputInfo *
860
input_info_new (GdkDevice *device,
862
GsdDeviceMapper *mapper)
864
GnomeRROutput *rr_output = NULL;
865
GsdOutputInfo *output = NULL;
868
info = g_new0 (GsdInputInfo, 1);
869
info->device = device;
870
info->settings = (settings) ? g_object_ref (settings) : NULL;
871
info->mapper = mapper;
873
if (info->settings) {
874
info->changed_id = g_signal_connect (info->settings, "changed",
875
G_CALLBACK (device_settings_changed_cb),
878
/* Assign output from config */
879
rr_output = settings_get_display (settings, mapper);
882
input_info_update_capabilities (info);
885
output = g_hash_table_lookup (mapper->output_devices,
887
input_info_set_output (info, output, FALSE, FALSE);
888
input_info_remap (info);
890
mapper_recalculate_input (mapper, info);
897
input_info_free (GsdInputInfo *info)
899
input_info_set_output (info, NULL, FALSE, FALSE);
900
input_info_set_output (info, NULL, TRUE, FALSE);
902
if (info->settings && info->changed_id)
903
g_signal_handler_disconnect (info->settings, info->changed_id);
906
g_object_unref (info->settings);
911
static GsdOutputInfo *
912
output_info_new (GnomeRROutput *output)
916
info = g_new0 (GsdOutputInfo, 1);
917
info->output = output;
923
output_info_free (GsdOutputInfo *info)
925
while (info->input_devices) {
926
GsdInputInfo *input = info->input_devices->data;
928
if (input->output == info)
929
input_info_set_output (input, NULL, FALSE, FALSE);
930
if (input->guessed_output == info)
931
input_info_set_output (input, NULL, TRUE, FALSE);
938
gsd_device_mapper_finalize (GObject *object)
940
GsdDeviceMapper *mapper = GSD_DEVICE_MAPPER (object);
942
g_hash_table_unref (mapper->input_devices);
944
if (mapper->output_devices)
945
g_hash_table_unref (mapper->output_devices);
948
libwacom_database_destroy (mapper->wacom_db);
951
G_OBJECT_CLASS (gsd_device_mapper_parent_class)->finalize (object);
955
_device_mapper_update_outputs (GsdDeviceMapper *mapper)
957
GnomeRROutput **outputs;
961
map = g_hash_table_new_full (NULL, NULL, NULL,
962
(GDestroyNotify) output_info_free);
963
outputs = gnome_rr_screen_list_outputs (mapper->rr_screen);
966
GsdOutputInfo *info = NULL;
968
if (mapper->output_devices) {
969
info = g_hash_table_lookup (mapper->output_devices,
973
g_hash_table_steal (mapper->output_devices,
978
info = output_info_new (outputs[i]);
980
g_hash_table_insert (map, outputs[i], info);
984
if (mapper->output_devices)
985
g_hash_table_unref (mapper->output_devices);
987
mapper->output_devices = map;
988
mapper_recalculate_candidates (mapper);
992
outputs_changed_cb (GnomeRRScreen *rr_screen,
993
GnomeRROutput *output,
994
GsdDeviceMapper *mapper)
996
_device_mapper_update_outputs (mapper);
1000
screen_changed_cb (GnomeRRScreen *rr_screen,
1001
GsdDeviceMapper *mapper)
1003
_device_mapper_update_outputs (mapper);
1007
gsd_device_mapper_initable_init (GInitable *initable,
1008
GCancellable *cancellable,
1011
GsdDeviceMapper *mapper;
1013
mapper = GSD_DEVICE_MAPPER (initable);
1014
mapper->rr_screen = gnome_rr_screen_new (mapper->screen, error);
1016
if (!mapper->rr_screen)
1019
g_signal_connect (mapper->rr_screen, "changed",
1020
G_CALLBACK (screen_changed_cb), initable);
1021
g_signal_connect (mapper->rr_screen, "output-connected",
1022
G_CALLBACK (outputs_changed_cb), initable);
1023
g_signal_connect (mapper->rr_screen, "output-disconnected",
1024
G_CALLBACK (outputs_changed_cb), initable);
1025
_device_mapper_update_outputs (GSD_DEVICE_MAPPER (initable));
1030
gsd_device_mapper_initable_iface_init (GInitableIface *iface)
1032
iface->init = gsd_device_mapper_initable_init;
1036
gsd_device_mapper_set_property (GObject *object,
1038
const GValue *value,
1041
GsdDeviceMapper *mapper = GSD_DEVICE_MAPPER (object);
1045
mapper->screen = g_value_get_object (value);
1048
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1053
gsd_device_mapper_get_property (GObject *object,
1058
GsdDeviceMapper *mapper = GSD_DEVICE_MAPPER (object);
1062
g_value_set_object (value, mapper->screen);
1065
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1070
gsd_device_mapper_class_init (GsdDeviceMapperClass *klass)
1072
GObjectClass *object_class = G_OBJECT_CLASS (klass);
1074
object_class->set_property = gsd_device_mapper_set_property;
1075
object_class->get_property = gsd_device_mapper_get_property;
1076
object_class->finalize = gsd_device_mapper_finalize;
1078
g_object_class_install_property (object_class,
1080
g_param_spec_object ("screen",
1084
G_PARAM_CONSTRUCT_ONLY |
1085
G_PARAM_READWRITE));
1086
signals[DEVICE_CHANGED] =
1087
g_signal_new ("device-changed",
1088
GSD_TYPE_DEVICE_MAPPER,
1089
G_SIGNAL_RUN_LAST, 0,
1091
G_TYPE_NONE, 1, GDK_TYPE_DEVICE);
1095
gsd_device_mapper_init (GsdDeviceMapper *mapper)
1097
mapper->input_devices = g_hash_table_new_full (NULL, NULL, NULL,
1098
(GDestroyNotify) input_info_free);
1100
mapper->wacom_db = libwacom_database_new ();
1105
gsd_device_mapper_get (void)
1107
GsdDeviceMapper *mapper;
1110
screen = gdk_screen_get_default ();
1111
g_return_val_if_fail (screen != NULL, NULL);
1113
mapper = g_object_get_data (G_OBJECT (screen), "gsd-device-mapper-data");
1116
GError *error = NULL;
1118
mapper = g_initable_new (GSD_TYPE_DEVICE_MAPPER, NULL, &error,
1119
"screen", screen, NULL);
1121
g_critical ("Could not create device mapper: %s", error->message);
1122
g_error_free (error);
1124
g_object_set_data_full (G_OBJECT (screen), "gsd-device-mapper-data",
1125
mapper, (GDestroyNotify) g_object_unref);
1133
gsd_device_mapper_add_input (GsdDeviceMapper *mapper,
1135
GSettings *settings)
1139
g_return_if_fail (mapper != NULL);
1140
g_return_if_fail (GDK_IS_DEVICE (device));
1141
g_return_if_fail (!settings || G_IS_SETTINGS (settings));
1143
if (g_hash_table_contains (mapper->input_devices, device))
1146
info = input_info_new (device, settings, mapper);
1147
g_hash_table_insert (mapper->input_devices, device, info);
1151
gsd_device_mapper_remove_input (GsdDeviceMapper *mapper,
1154
g_return_if_fail (mapper != NULL);
1155
g_return_if_fail (GDK_IS_DEVICE (device));
1157
g_hash_table_remove (mapper->input_devices, device);
1161
gsd_device_mapper_get_device_output (GsdDeviceMapper *mapper,
1164
GsdOutputInfo *output;
1165
GsdInputInfo *input;
1167
g_return_val_if_fail (mapper != NULL, NULL);
1168
g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
1170
input = g_hash_table_lookup (mapper->input_devices, device);
1171
output = input_info_get_output (input);
1176
return output->output;
1180
gsd_device_mapper_get_device_monitor (GsdDeviceMapper *mapper,
1183
GsdOutputInfo *output;
1184
GsdInputInfo *input;
1186
g_return_val_if_fail (GSD_IS_DEVICE_MAPPER (mapper), -1);
1187
g_return_val_if_fail (GDK_IS_DEVICE (device), -1);
1189
input = g_hash_table_lookup (mapper->input_devices, device);
1194
output = input_info_get_output (input);
1199
return monitor_for_output (output->output);
1203
gsd_device_mapper_set_device_output (GsdDeviceMapper *mapper,
1205
GnomeRROutput *output)
1207
GsdInputInfo *input_info;
1208
GsdOutputInfo *output_info;
1210
g_return_if_fail (mapper != NULL);
1211
g_return_if_fail (GDK_IS_DEVICE (device));
1213
input_info = g_hash_table_lookup (mapper->input_devices, device);
1214
output_info = g_hash_table_lookup (mapper->output_devices, output);
1216
if (!input_info || !output_info)
1219
input_info_set_output (input_info, output_info, FALSE, TRUE);
1220
input_info_remap (input_info);
1224
gsd_device_mapper_set_device_monitor (GsdDeviceMapper *mapper,
1228
GnomeRROutput *output;
1230
g_return_if_fail (GSD_IS_DEVICE_MAPPER (mapper));
1231
g_return_if_fail (GDK_IS_DEVICE (device));
1233
output = monitor_to_output (mapper, monitor_num);
1234
gsd_device_mapper_set_device_output (mapper, device, output);