Port the X11 backend to the Device Manager
authorEmmanuele Bassi <ebassi@linux.intel.com>
Fri, 20 Nov 2009 15:36:43 +0000 (15:36 +0000)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Wed, 20 Jan 2010 00:38:07 +0000 (00:38 +0000)
Use the device manager to store the input devices. Also, provide
two fallback devices when initializing the X11 backend: device 0
for the pointer and device 1 for the keyboard.

clutter/clutter-private.h
clutter/x11/clutter-backend-x11.c
clutter/x11/clutter-backend-x11.h
clutter/x11/clutter-event-x11.c
clutter/x11/clutter-x11.h

index 2567eaa..9100ebf 100644 (file)
@@ -153,9 +153,6 @@ struct _ClutterMainContext
   PangoContext     *pango_context;      /* Global Pango context */
   CoglPangoFontMap *font_map;           /* Global font map */
 
-  GSList              *input_devices;   /* For extra input devices, i.e
-                                           MultiTouch */
-
   ClutterEvent *current_event;
   guint32 last_event_time;
 
index 4eaf081..47ba733 100644 (file)
 #include <X11/extensions/XInput.h>
 #endif
 
+#include "cogl/cogl.h"
+
+#include "../clutter-debug.h"
+#include "../clutter-device-manager.h"
 #include "../clutter-event.h"
 #include "../clutter-main.h"
-#include "../clutter-debug.h"
 #include "../clutter-private.h"
 
-#include "cogl/cogl.h"
-
 G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND);
 
+/* a specific X11 input device */
 struct _ClutterX11XInputDevice
 {
   ClutterInputDevice device;
@@ -66,11 +68,6 @@ struct _ClutterX11XInputDevice
 #endif
 };
 
-#ifdef HAVE_XINPUT
-void  _clutter_x11_register_xinput ();
-#endif
-
-
 /* atoms; remember to add the code that assigns the atom value to
  * the member of the ClutterBackendX11 structure if you add an
  * atom name here. do not change the order!
@@ -109,6 +106,222 @@ static gboolean clutter_synchronise = FALSE;
 static int TrappedErrorCode = 0;
 static int (* old_error_handler) (Display *, XErrorEvent *);
 
+static void
+clutter_x11_register_input_devices (ClutterBackendX11 *backend)
+{
+  ClutterDeviceManager *manager;
+  gboolean have_an_xpointer = FALSE;
+#ifdef HAVE_XINPUT
+  XDeviceInfo *x_devices = NULL;
+  int res, opcode, event, error;
+  int i, n_devices;
+  GSList *devices = NULL;
+#endif /* HAVE_XINPUT */
+
+  manager = clutter_device_manager_get_default ();
+
+  if (!clutter_enable_xinput)
+    {
+      CLUTTER_NOTE (BACKEND, "XInput support not enabled");
+      goto default_device;
+    }
+
+#ifdef HAVE_XINPUT
+  res = XQueryExtension (backend->xdpy, "XInputExtension",
+                         &opcode,
+                         &event,
+                         &error);
+  if (!res)
+    {
+      CLUTTER_NOTE (BACKEND, "No XInput extension available");
+      goto default_device;
+    }
+
+  x_devices = XListInputDevices (backend->xdpy, &n_devices);
+  if (n_devices == 0)
+    {
+      CLUTTER_NOTE (BACKEND, "No XInput devices found");
+      goto default_device;
+    }
+
+  for (i = 0; i < n_devices; i++)
+    {
+      XDeviceInfo *info = x_devices + i;
+
+      CLUTTER_NOTE (BACKEND,
+                    "Considering device %li with type %d, %d of %d",
+                    info->id,
+                    info->use,
+                    i, n_devices);
+
+      /* we only want 'raw' devices, not virtual ones */
+      if (info->use == IsXExtensionPointer ||
+       /* info->use == IsXExtensionKeyboard || XInput1 is broken */
+          info->use == IsXExtensionDevice)
+        {
+          ClutterInputDevice *device;
+          XDevice *x_device;
+          int n_events = 0;
+          int j;
+
+          clutter_x11_trap_x_errors ();
+          x_device = XOpenDevice (backend->xdpy, info->id);
+          if (clutter_x11_untrap_x_errors () || x_device == NULL)
+            {
+              CLUTTER_NOTE (BACKEND, "Unable to open device %li", info->id);
+              continue;
+            }
+
+          device = g_slice_new0 (ClutterX11XInputDevice);
+          device->device.id = info->id;
+          device->device.click_count = 0;
+          device->device.previous_time = CLUTTER_CURRENT_TIME;
+          device->device.previous_x = -1;
+          device->device.previous_y = -1;
+          device->device.previous_button_number = -1;
+
+          switch (info->use)
+            {
+            case IsXExtensionPointer:
+              device->device.device_type = CLUTTER_POINTER_DEVICE;
+              have_an_xpointer = TRUE;
+              break;
+
+#if 0
+            /* XInput1 is broken for keyboards */
+            case IsXExtensionKeyboard:
+              device->device.device_type = CLUTTER_KEYBOARD_DEVICE;
+              break;
+#endif
+
+            case IsXExtensionDevice:
+              device->device.device_type = CLUTTER_EXTENSION_DEVICE;
+              break;
+            }
+
+          device->xdevice = x_device;
+
+          CLUTTER_NOTE (BACKEND, "Registering XINPUT device with XID: %li",
+                        x_device->device_id);
+
+          /* We must go through all the classes supported by this device and
+           * register the appropriate events we want. Each class only appears
+           * once. We need to store the types with the stage since they are
+           * created dynamically by the server. They are not device specific.
+           */
+          for (j = 0; j < xdevice->num_classes; j++)
+            {
+              XInputClassInfo *xclass_info = xdevice->classes + j;
+
+              switch (xclass_info->input_class)
+                {
+#if 0
+                /* XInput 1.x is broken for keyboards: */
+                case KeyClass:
+                  DeviceKeyPress (xdevice,
+                                  x11b->event_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT],
+                                  device->xevent_list [num_events]);
+                  n_events++;
+
+                  DeviceKeyRelease (xdevice,
+                                    x11b->event_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT],
+                                    device->xevent_list [num_events]);
+                  n_events++;
+                  break;
+#endif
+
+                case ButtonClass:
+                  DeviceButtonPress (xdevice,
+                                     x11b->event_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT],
+                                     device->xevent_list [num_events]);
+                  n_events++;
+
+                  DeviceButtonRelease (xdevice,
+                                       x11b->event_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT],
+                                       device->xevent_list [num_events]);
+                  n_events++;
+                  break;
+
+                case ValuatorClass:
+                  DeviceMotionNotify (xdevice,
+                                      x11b->event_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT],
+                                      device->xevent_list [num_events]);
+                  n_events++;
+                  break;
+                }
+            }
+
+          if (info->use == IsXExtensionPointer && num_events > 0)
+            have_an_xpointer = TRUE;
+
+          device->num_events = n_events;
+
+          /* add it to a temporary list; we don't add the device
+           * straight to the device manager because the XInput
+           * initialization might still fail
+           */
+          devices = g_slist_prepend (devices, device);
+        }
+    }
+
+  XFree (x_devices);
+
+  devices = g_slist_reverse (devices);
+
+  if (have_an_xpointer)
+    {
+      GSList *l;
+
+      for (l = devices; l != NULL; l = l->next)
+        _clutter_device_manager_add_device (manager, l->data);
+    }
+  else
+    {
+      GSList *l;
+
+      g_warning ("No usable XInput pointer devices found");
+
+      for (l = devices; l != NULL; l = l->next)
+        g_slice_free (ClutterX11XInputDevice, l->data);
+    }
+
+  g_slist_free (devices);
+
+  backend->have_xinput = TRUE;
+#endif /* HAVE_XINPUT */
+
+default_device:
+  /* fallback code in case:
+   *
+   *  - we do not have XInput support compiled in
+   *  - we do not have XInput support enabled
+   *  - we do not have the XInput extension
+   *  - we do not have a XInput pointer device
+   *
+   * we register two default devices, one for the pointer
+   * and one for the keyboard
+   */
+  if (!have_an_xpointer)
+    {
+      ClutterInputDevice *d;
+
+      d = g_slice_new0 (ClutterInputDevice);
+      d->id = 0;
+      d->device_type = CLUTTER_POINTER_DEVICE;
+      d->click_count = 0;
+      d->previous_time = CLUTTER_CURRENT_TIME;
+      d->previous_x = -1;
+      d->previous_y = -1;
+      d->previous_button_number = -1;
+      _clutter_device_manager_add_device (manager, d);
+
+      d = g_slice_new0 (ClutterInputDevice);
+      d->id = 1;
+      d->device_type = CLUTTER_KEYBOARD_DEVICE;
+      _clutter_device_manager_add_device (manager, d);
+    }
+}
+
 gboolean
 clutter_backend_x11_pre_parse (ClutterBackend  *backend,
                                GError         **error)
@@ -199,9 +412,8 @@ clutter_backend_x11_post_parse (ClutterBackend  *backend,
 
       clutter_backend_set_resolution (backend, dpi);
 
-#ifdef HAVE_XINPUT
-      _clutter_x11_register_xinput ();
-#endif
+      /* register input devices */
+      clutter_x11_register_input_devices (backend_x11);
 
       if (clutter_synchronise)
         XSynchronize (backend_x11->xdpy, True);
@@ -645,233 +857,26 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func,
 }
 
 void
-_clutter_x11_register_xinput ()
+_clutter_x11_select_events (Window xwin)
 {
 #ifdef HAVE_XINPUT
-  XDeviceInfo *xdevices = NULL;
-  XDeviceInfo *info = NULL;
-
-  XDevice *xdevice = NULL;
-
-  XInputClassInfo *xclass_info = NULL;
-
-  gint opcode, event, error;
-  gint res;
-  gint num_devices = 0;
-  gint num_events = 0;
-  gint i = 0, j = 0;
-  gboolean have_an_xpointer = FALSE;
-
-  ClutterBackendX11      *x11b;
-  ClutterX11XInputDevice *device = NULL;
-
-  ClutterMainContext  *context;
+  ClutterDeviceManager *manager;
+  const GSList *l;
 
-  GSList *input_devices = NULL;
-
-  if (!backend_singleton)
+  if (G_UNLIKELY (backend_singleton == NULL))
     {
       g_critical ("X11 backend has not been initialised");
-      return;
-    }
-
-  if (!clutter_enable_xinput)
-    {
-      CLUTTER_NOTE (BACKEND, "Not enabling XInput");
-      return;
-    }
-
-  context = _clutter_context_get_default ();
-
-  backend_singleton->have_xinput = FALSE;
-
-  /* is the XInput extension available? */
-  res = XQueryExtension (backend_singleton->xdpy, "XInputExtension",
-                         &opcode, &event,
-                         &error);
-  if (!res)
-    {
-      CLUTTER_NOTE (BACKEND, "X Input extension not available");
-      return;
-    }
-
-  x11b = backend_singleton;
-
-  xdevices = XListInputDevices (x11b->xdpy, &num_devices);
-
-  CLUTTER_NOTE (BACKEND, "%d XINPUT devices found", num_devices);
-
-  if (num_devices == 0)
-    return;
-
-  for (i = 0; i < num_devices; i++)
-    {
-      info = xdevices + i;
-      num_events = 0;
-
-      CLUTTER_NOTE (BACKEND, "Considering %li with type %d",
-                    info->id,
-                    info->use);
-
-      /* Only want 'raw' devices themselves not virtual ones */
-      if (info->use == IsXExtensionPointer ||
-        /*info->use == IsXExtensionKeyboard || XInput 1.x is broken */
-          info->use == IsXExtensionDevice)
-        {
-          clutter_x11_trap_x_errors ();
-          xdevice = XOpenDevice (backend_singleton->xdpy, info->id);
-          if (clutter_x11_untrap_x_errors () || xdevice == NULL)
-            continue;
-
-          /* Create the appropriate Clutter device */
-          device = g_slice_new0 (ClutterX11XInputDevice);
-
-          device->device.id = info->id;
-
-          switch (info->use)
-            {
-            case IsXExtensionPointer:
-              device->device.device_type = CLUTTER_POINTER_DEVICE;
-              have_an_xpointer = TRUE;
-              break;
-
-#if 0
-            /* XInput 1.x is broken for keyboards: */
-            case IsXExtensionKeyboard:
-              device->device.type = CLUTTER_KEYBOARD_DEVICE;
-              break;
-#endif
-
-            case IsXExtensionDevice:
-              device->device.device_type = CLUTTER_EXTENSION_DEVICE;
-              break;
-            }
-
-          /* FIXME: some kind of general device_init() call should do below */
-          device->device.click_count = 0;
-          device->device.previous_time = 0;
-          device->device.previous_x = -1;
-          device->device.previous_y = -1;
-          device->device.previous_button_number = -1;
-
-          device->num_events = 0;
-          device->xdevice = xdevice;
-
-          CLUTTER_NOTE (BACKEND, "Registering XINPUT device with XID: %li",
-                        xdevice->device_id);
-
-          /* We must go through all the classes supported by this device and
-           * register the appropriate events we want. Each class only appears
-           * once. We need to store the types with the stage since they are
-           * created dynamically by the server. They are not device specific.
-           */
-          for (j = 0; j < xdevice->num_classes; j++)
-            {
-              xclass_info = xdevice->classes + j;
-
-              switch (xclass_info->input_class)
-                {
-#if 0
-                /* XInput 1.x is broken for keyboards: */
-                case KeyClass:
-                  DeviceKeyPress (xdevice,
-                                  x11b->event_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT],
-                                  device->xevent_list [num_events]);
-                  num_events++;
-
-                  DeviceKeyRelease (xdevice,
-                                    x11b->event_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT],
-                                    device->xevent_list [num_events]);
-                  num_events++;
-                  break;
-#endif
-
-                case ButtonClass:
-                  DeviceButtonPress (xdevice,
-                                     x11b->event_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT],
-                                     device->xevent_list [num_events]);
-                  num_events++;
-
-                  DeviceButtonRelease (xdevice,
-                                       x11b->event_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT],
-                                       device->xevent_list [num_events]);
-                  num_events++;
-                  break;
-
-                case ValuatorClass:
-                  DeviceMotionNotify (xdevice,
-                                      x11b->event_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT],
-                                      device->xevent_list [num_events]);
-                  num_events++;
-                  break;
-                }
-            }
-
-          if (info->use == IsXExtensionPointer && num_events > 0)
-            have_an_xpointer = TRUE;
-
-          device->num_events  = num_events;
-
-          input_devices = g_slist_prepend (input_devices, device);
-        }
-    }
-
-  XFree (xdevices);
-
-  if (!have_an_xpointer)
-    {
-      GSList *l;
-
-      /* Something is likely wrong with Xinput setup so we basically
-       * abort here and fall back to lofi regular xinput.
-      */
-      g_warning ("No usuable XInput pointing devices found");
-
-      for (l = input_devices; l != NULL; l = l->next)
-        g_slice_free (ClutterX11XInputDevice, l->data);
-
-      g_slist_free (input_devices);
-      context->input_devices = NULL;
 
       return;
     }
 
-  /* store the list of input devices */
-  context->input_devices = g_slist_reverse (input_devices);
-
-  /* why yes, we are awesome */
-  backend_singleton->have_xinput = TRUE;
-#endif /* HAVE_XINPUT */
-}
-
-void
-_clutter_x11_unregister_xinput ()
-{
-
-}
+  manager = clutter_device_manager_get_default ();
 
-void
-_clutter_x11_select_events (Window xwin)
-{
-#ifdef HAVE_XINPUT
-  GSList *list_it;
-  ClutterX11XInputDevice *device = NULL;
-
-  ClutterMainContext  *context;
-
-  context = _clutter_context_get_default ();
-
-  if (!backend_singleton)
-    {
-      g_critical ("X11 backend has not been initialised");
-      return;
-    }
-
-  for (list_it = context->input_devices;
-       list_it != NULL;
-       list_it = list_it->next)
+  for (l = clutter_device_manager_peek_devices (manager);
+       l != NULL;
+       l = l->next)
   {
-    device = (ClutterX11XInputDevice *)list_it->data;
+    ClutterX11XInputDevice *device = l->data;
 
     XSelectExtensionEvent (backend_singleton->xdpy,
                            xwin,
@@ -884,49 +889,34 @@ _clutter_x11_select_events (Window xwin)
 ClutterInputDevice *
 _clutter_x11_get_device_for_xid (XID id)
 {
-#ifdef HAVE_XINPUT
-  ClutterMainContext *context;
-  GSList *l;
+  ClutterDeviceManager *manager;
 
-  context = _clutter_context_get_default ();
+  manager = clutter_device_manager_get_default ();
 
-  if (!backend_singleton)
-    {
-      g_critical ("X11 backend has not been initialised");
-      return NULL;
-    }
-
-  for (l = context->input_devices; l != NULL; l = l->next)
-    {
-      ClutterX11XInputDevice *device = l->data;
-
-      if (device->xdevice->device_id == id)
-        return (ClutterInputDevice *) device;
-    }
-#endif /* HAVE_XINPUT */
-
-  return NULL;
+  return clutter_device_manager_get_device (manager, (gint) id);
 }
 
-/* FIXME: This nasty little func needs moving elsewhere.. */
+/**
+ * clutter_x11_get_input_devices:
+ *
+ * Retrieves a pointer to the list of input devices
+ *
+ * Deprecated: 1.2: Use clutter_device_manager_peek_devices() instead
+ *
+ * Since: 0.8
+ *
+ * Return value: a pointer to the internal list of input devices; the
+ *   returned list is owned by Clutter and should not be modified or
+ *   freed
+ */
 G_CONST_RETURN GSList *
 clutter_x11_get_input_devices (void)
 {
-#ifdef HAVE_XINPUT
-  ClutterMainContext  *context;
+  ClutterDeviceManager *manager;
 
-  if (!backend_singleton)
-    {
-      g_critical ("X11 backend has not been initialised");
-      return NULL;
-    }
+  manager = clutter_device_manager_get_default ();
 
-  context = _clutter_context_get_default ();
-
-  return context->input_devices;
-#else /* !HAVE_XINPUT */
-  return NULL;
-#endif /* HAVE_XINPUT */
+  return clutter_device_manager_peek_devices (manager);
 }
 
 /**
@@ -943,7 +933,7 @@ gboolean
 clutter_x11_has_xinput (void)
 {
 #ifdef HAVE_XINPUT
-  if (!backend_singleton)
+  if (backend_singleton == NULL)
     {
       g_critical ("X11 backend has not been initialised");
       return FALSE;
index 0958eb4..95cd4c3 100644 (file)
@@ -125,12 +125,6 @@ clutter_backend_x11_get_features (ClutterBackend *backend);
 XVisualInfo *
 clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11);
 
-void
-_clutter_x11_register_xinput (void);
-
-void
-_clutter_x11_unregister_xinput (void);
-
 ClutterInputDevice *
 _clutter_x11_get_device_for_xid (XID id);
 
index 6b3ea67..a5886ae 100644 (file)
@@ -696,8 +696,8 @@ event_translate (ClutterBackend *backend,
                   event->scroll.x = xevent->xbutton.x;
                   event->scroll.y = xevent->xbutton.y;
                   event->scroll.modifier_state = xevent->xbutton.state;
-                  
                   break;
+
                 default:
                   event->button.type = event->type = CLUTTER_BUTTON_PRESS;
                   event->button.time = xevent->xbutton.time;
@@ -705,10 +705,9 @@ event_translate (ClutterBackend *backend,
                   event->button.y = xevent->xbutton.y;
                   event->button.modifier_state = xevent->xbutton.state;
                   event->button.button = xevent->xbutton.button;
-                  
                   break;
                 }
-              
+
               set_user_time (backend_x11, &xwindow, event->button.time);
               break;
               
index 66bea58..30c71ad 100644 (file)
@@ -121,7 +121,9 @@ gboolean clutter_x11_has_event_retrieval (void);
 
 ClutterStage *clutter_x11_get_stage_from_window (Window win);
 
+#ifndef CLUTTER_DISABLE_DEPRECATED
 G_CONST_RETURN GSList* clutter_x11_get_input_devices (void);
+#endif
 
 void     clutter_x11_enable_xinput (void);
 gboolean clutter_x11_has_xinput (void);