[mutter/wip/input-devices-config: 7/7] input-settings: Handle device-to-output mapping



commit 51f51ad61bd1c96cb0a889c6d714c3f4e889df8f
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Dec 11 18:14:08 2014 +0100

    input-settings: Handle device-to-output mapping
    
    For each device that can be mapped (touchscreens, tablets), the output
    will be fetched from settings and matched with the currently connected
    ones. If a match is found, the device matrix will be found out from the
    output configuration and set on the device.
    
    This is also updated both individually for newly connected devices, and
    collectively on output configuration changes.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=739397

 src/backends/meta-input-settings.c |  214 ++++++++++++++++++++++++++++++++++++
 1 files changed, 214 insertions(+), 0 deletions(-)
---
diff --git a/src/backends/meta-input-settings.c b/src/backends/meta-input-settings.c
index f314867..dc792e0 100644
--- a/src/backends/meta-input-settings.c
+++ b/src/backends/meta-input-settings.c
@@ -41,14 +41,27 @@
 #include <meta/util.h>
 
 typedef struct _MetaInputSettingsPrivate MetaInputSettingsPrivate;
+typedef struct _DeviceMappingInfo DeviceMappingInfo;
+
+struct _DeviceMappingInfo
+{
+  MetaInputSettings *input_settings;
+  ClutterInputDevice *device;
+  GSettings *settings;
+};
 
 struct _MetaInputSettingsPrivate
 {
   ClutterDeviceManager *device_manager;
+  MetaMonitorManager *monitor_manager;
+  guint monitors_changed_id;
+
   GSettings *mouse_settings;
   GSettings *touchpad_settings;
   GSettings *trackball_settings;
   GSettings *keyboard_settings;
+
+  GHashTable *mappable_devices;
 };
 
 typedef void (*ConfigBoolFunc)   (MetaInputSettings  *input_settings,
@@ -98,6 +111,17 @@ meta_input_settings_dispose (GObject *object)
   g_clear_object (&priv->touchpad_settings);
   g_clear_object (&priv->trackball_settings);
   g_clear_object (&priv->keyboard_settings);
+  g_clear_pointer (&priv->mappable_devices, g_hash_table_unref);
+
+  if (priv->monitors_changed_id && priv->monitor_manager)
+    {
+      g_signal_handler_disconnect (priv->monitor_manager,
+                                   priv->monitors_changed_id);
+      priv->monitors_changed_id = 0;
+    }
+
+  g_clear_object (&priv->monitor_manager);
+
   G_OBJECT_CLASS (meta_input_settings_parent_class)->dispose (object);
 }
 
@@ -451,6 +475,65 @@ update_keyboard_repeat (MetaInputSettings *input_settings)
                                              repeat, delay, interval);
 }
 
+static MetaOutput *
+meta_input_settings_find_output (MetaInputSettings  *input_settings,
+                                 GSettings          *settings,
+                                 ClutterInputDevice *device)
+{
+  MetaInputSettingsPrivate *priv;
+  guint n_values, n_outputs, i;
+  MetaOutput *outputs;
+  gchar **edid;
+
+  priv = meta_input_settings_get_instance_private (input_settings);
+  edid = g_settings_get_strv (settings, "display");
+  n_values = g_strv_length (edid);
+
+  if (n_values != 3)
+    {
+      g_warning ("EDID configuration for device '%s' "
+                 "is incorrect, must have 3 values",
+                 clutter_input_device_get_device_name (device));
+      return NULL;
+    }
+
+  if (!*edid[0] && !*edid[1] && !*edid[2])
+    return NULL;
+
+  outputs = meta_monitor_manager_get_outputs (priv->monitor_manager,
+                                              &n_outputs);
+  for (i = 0; i < n_outputs; i++)
+    {
+      if (g_strcmp0 (outputs[i].vendor, edid[0]) == 0 &&
+          g_strcmp0 (outputs[i].product, edid[1]) == 0 &&
+          g_strcmp0 (outputs[i].serial, edid[2]) == 0)
+        return &outputs[i];
+    }
+
+  return NULL;
+}
+
+static void
+update_device_display (MetaInputSettings  *input_settings,
+                       GSettings          *settings,
+                       ClutterInputDevice *device)
+{
+  MetaInputSettingsClass *input_settings_class;
+  MetaInputSettingsPrivate *priv;
+  gfloat matrix[6] = { 1, 0, 0, 0, 1, 0 };
+  MetaOutput *output;
+
+  priv = meta_input_settings_get_instance_private (input_settings);
+  input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
+  output = meta_input_settings_find_output (input_settings, settings, device);
+
+  if (output)
+    meta_monitor_manager_get_monitor_matrix (priv->monitor_manager,
+                                             output, matrix);
+
+  input_settings_class->set_matrix (input_settings, device, matrix);
+}
+
 static void
 meta_input_settings_changed_cb (GSettings  *settings,
                                 const char *key,
@@ -502,6 +585,100 @@ meta_input_settings_changed_cb (GSettings  *settings,
 }
 
 static void
+mapped_device_changed_cb (GSettings         *settings,
+                          const gchar       *key,
+                          DeviceMappingInfo *info)
+{
+  if (strcmp (key, "display") == 0)
+    update_device_display (info->input_settings, settings, info->device);
+}
+
+static GSettings *
+lookup_device_settings (ClutterInputDevice *device)
+{
+  const gchar *group, *schema, *vendor, *product;
+  ClutterInputDeviceType type;
+  GSettings *settings;
+  gchar *path;
+
+  type = clutter_input_device_get_device_type (device);
+
+  if (type == CLUTTER_TOUCHSCREEN_DEVICE)
+    {
+      group = "touchscreens";
+      schema = "org.gnome.desktop.peripherals.touchscreen";
+    }
+  else if (type == CLUTTER_TABLET_DEVICE ||
+           type == CLUTTER_PEN_DEVICE ||
+           type == CLUTTER_ERASER_DEVICE ||
+           type == CLUTTER_CURSOR_DEVICE)
+    {
+      group = "tablets";
+      schema = "org.gnome.desktop.peripherals.tablet";
+    }
+  else
+    return NULL;
+
+  vendor = clutter_input_device_get_vendor_id (device);
+  product = clutter_input_device_get_product_id (device);
+  path = g_strdup_printf ("/org/gnome/desktop/peripherals/%s/%s:%s/",
+                          group, vendor, product);
+
+  settings = g_settings_new_with_path (schema, path);
+  g_free (path);
+
+  return settings;
+}
+
+static void
+monitors_changed_cb (MetaMonitorManager *monitor_manager,
+                     MetaInputSettings  *input_settings)
+{
+  MetaInputSettingsPrivate *priv;
+  ClutterInputDevice *device;
+  GSettings *settings;
+  GHashTableIter iter;
+
+  priv = meta_input_settings_get_instance_private (input_settings);
+  g_hash_table_iter_init (&iter, priv->mappable_devices);
+
+  while (g_hash_table_iter_next (&iter, (gpointer *) &device,
+                                 (gpointer *) &settings))
+    update_device_display (input_settings, settings, device);
+}
+
+static gboolean
+check_add_mappable_device (MetaInputSettings  *input_settings,
+                           ClutterInputDevice *device)
+{
+  MetaInputSettingsPrivate *priv;
+  DeviceMappingInfo *info;
+  GSettings *settings;
+
+  settings = lookup_device_settings (device);
+
+  if (!settings)
+    return FALSE;
+
+  priv = meta_input_settings_get_instance_private (input_settings);
+
+  info = g_new0 (DeviceMappingInfo, 1);
+  info->input_settings = input_settings;
+  info->device = device;
+  info->settings = settings;
+
+  g_signal_connect_data (settings, "changed",
+                         G_CALLBACK (mapped_device_changed_cb),
+                         info, (GClosureNotify) g_free, 0);
+
+  g_hash_table_insert (priv->mappable_devices, device, settings);
+
+  update_device_display (input_settings, settings, device);
+
+  return TRUE;
+}
+
+static void
 meta_input_settings_device_added (ClutterDeviceManager *device_manager,
                                   ClutterInputDevice   *device,
                                   MetaInputSettings    *input_settings)
@@ -535,6 +712,10 @@ meta_input_settings_device_added (ClutterDeviceManager *device_manager,
       update_device_natural_scroll (input_settings, priv->touchpad_settings,
                                     device, type);
     }
+  else
+    {
+      check_add_mappable_device (input_settings, device);
+    }
 }
 
 static void
@@ -542,6 +723,30 @@ meta_input_settings_device_removed (ClutterDeviceManager *device_manager,
                                     ClutterInputDevice   *device,
                                     MetaInputSettings    *input_settings)
 {
+  MetaInputSettingsPrivate *priv;
+
+  priv = meta_input_settings_get_instance_private (input_settings);
+  g_hash_table_remove (priv->mappable_devices, device);
+}
+
+static void
+check_mappable_devices (MetaInputSettings *input_settings)
+{
+  MetaInputSettingsPrivate *priv;
+  const GSList *devices, *l;
+
+  priv = meta_input_settings_get_instance_private (input_settings);
+  devices = clutter_device_manager_peek_devices (priv->device_manager);
+
+  for (l = devices; l; l = l->next)
+    {
+      ClutterInputDevice *device = l->data;
+
+      if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_MASTER)
+        continue;
+
+      check_add_mappable_device (input_settings, device);
+    }
 }
 
 static void
@@ -566,6 +771,8 @@ meta_input_settings_constructed (GObject *object)
                        CLUTTER_POINTER_DEVICE);
 
   update_keyboard_repeat (input_settings);
+
+  check_mappable_devices (input_settings);
 }
 
 static void
@@ -604,6 +811,13 @@ meta_input_settings_init (MetaInputSettings *settings)
   priv->keyboard_settings = g_settings_new ("org.gnome.desktop.peripherals.keyboard");
   g_signal_connect (priv->keyboard_settings, "changed",
                     G_CALLBACK (meta_input_settings_changed_cb), settings);
+
+  priv->mappable_devices =
+    g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref);
+
+  priv->monitor_manager = g_object_ref (meta_monitor_manager_get ());
+  g_signal_connect (priv->monitor_manager, "monitors-changed",
+                    G_CALLBACK (monitors_changed_cb), settings);
 }
 
 MetaInputSettings *


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]