evdev: Support hotplug (addition/removal) of evdev devices
authorDamien Lespiau <damien.lespiau@intel.com>
Tue, 9 Nov 2010 16:56:26 +0000 (11:56 -0500)
committerDamien Lespiau <damien.lespiau@intel.com>
Tue, 30 Nov 2010 14:40:37 +0000 (14:40 +0000)
Just connect to the GUdevClient "uevent" signal and deals with
"add"/"remove" commands. This drives the installation/removal of
GSource to listen to the device.

clutter/evdev/clutter-device-manager-evdev.c
clutter/evdev/clutter-event-evdev.c

index 0b7f379..3fbd913 100644 (file)
@@ -130,6 +130,65 @@ evdev_add_device (ClutterDeviceManagerEvdev *manager_evdev,
                 device_file, type, sysfs_path);
 }
 
+static ClutterInputDeviceEvdev *
+find_device_by_udev_device (ClutterDeviceManagerEvdev *manager_evdev,
+                            GUdevDevice               *udev_device)
+{
+  ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv;
+  GSList *l;
+  const gchar *sysfs_path;
+
+  sysfs_path = g_udev_device_get_sysfs_path (udev_device);
+  if (sysfs_path == NULL)
+    {
+      g_message ("device file is NULL");
+      return NULL;
+    }
+
+  for (l = priv->devices; l; l = g_slist_next (l))
+    {
+      ClutterInputDeviceEvdev *device = l->data;
+
+      if (strcmp (sysfs_path,
+                  _clutter_input_device_evdev_get_sysfs_path (device)) == 0)
+        {
+          return device;
+        }
+    }
+
+  return NULL;
+}
+
+static void
+evdev_remove_device (ClutterDeviceManagerEvdev *manager_evdev,
+                     GUdevDevice               *device)
+{
+  ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (manager_evdev);
+  ClutterInputDeviceEvdev *device_evdev;
+  ClutterInputDevice *input_device;
+
+  device_evdev = find_device_by_udev_device (manager_evdev, device);
+  if (device_evdev == NULL)
+      return;
+
+  input_device = CLUTTER_INPUT_DEVICE (device_evdev);
+  _clutter_device_manager_remove_device (manager, input_device);
+}
+
+static void
+on_uevent (GUdevClient *client,
+           gchar       *action,
+           GUdevDevice *device,
+           gpointer     data)
+{
+  ClutterDeviceManagerEvdev *manager = CLUTTER_DEVICE_MANAGER_EVDEV (data);
+
+  if (g_strcmp0 (action, "add") == 0)
+    evdev_add_device (manager, device);
+  else if (g_strcmp0 (action, "remove") == 0)
+    evdev_remove_device (manager, device);
+}
+
 /*
  * ClutterDeviceManager implementation
  */
index 0a33357..b714fd3 100644 (file)
@@ -282,6 +282,49 @@ _clutter_event_evdev_remove_source (ClutterEventSource *source)
   event_sources = g_slist_remove (event_sources, source);
 }
 
+static void
+on_device_added (ClutterDeviceManager *manager,
+                 ClutterInputDevice   *device,
+                 gpointer              data)
+{
+  ClutterInputDeviceEvdev *input_device = CLUTTER_INPUT_DEVICE_EVDEV (device);
+
+  _clutter_event_evdev_add_source (input_device);
+}
+
+static ClutterEventSource *
+find_source_by_device (ClutterInputDevice *device)
+{
+  GSList *l;
+
+  for (l = event_sources; l; l = g_slist_next (l))
+    {
+      ClutterEventSource *source = l->data;
+
+      if (source->device == (ClutterInputDeviceEvdev *) device)
+        return source;
+    }
+
+  return NULL;
+}
+
+static void
+on_device_removed (ClutterDeviceManager *manager,
+                   ClutterInputDevice   *device,
+                   gpointer              data)
+{
+  ClutterEventSource *source;
+
+  source = find_source_by_device (device);
+  if (G_UNLIKELY (source == NULL))
+    {
+      g_warning ("Trying to remove a device without a source installed ?!");
+      return;
+    }
+
+  _clutter_event_evdev_remove_source (source);
+}
+
 void
 _clutter_events_evdev_init (ClutterBackend *backend)
 {
@@ -301,6 +344,12 @@ _clutter_events_evdev_init (ClutterBackend *backend)
 
       _clutter_event_evdev_add_source (input_device);
     }
+
+  /* make sure to add/remove sources when devices are added/removed */
+  g_signal_connect (device_manager, "device-added",
+                    G_CALLBACK (on_device_added), NULL);
+  g_signal_connect (device_manager, "device-removed",
+                    G_CALLBACK (on_device_removed), NULL);
 }
 
 void