diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h index 2567eaae9..9100ebfd7 100644 --- a/clutter/clutter-private.h +++ b/clutter/clutter-private.h @@ -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; diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index 4eaf08106..47ba733c7 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -46,15 +46,17 @@ #include #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); @@ -644,234 +856,27 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func, } } -void -_clutter_x11_register_xinput () -{ -#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; - - GSList *input_devices = NULL; - - if (!backend_singleton) - { - 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 () -{ - -} - void _clutter_x11_select_events (Window xwin) { #ifdef HAVE_XINPUT - GSList *list_it; - ClutterX11XInputDevice *device = NULL; + ClutterDeviceManager *manager; + const GSList *l; - ClutterMainContext *context; - - context = _clutter_context_get_default (); - - if (!backend_singleton) + if (G_UNLIKELY (backend_singleton == NULL)) { g_critical ("X11 backend has not been initialised"); + return; } - for (list_it = context->input_devices; - list_it != NULL; - list_it = list_it->next) + manager = clutter_device_manager_get_default (); + + 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; diff --git a/clutter/x11/clutter-backend-x11.h b/clutter/x11/clutter-backend-x11.h index 0958eb4cf..95cd4c3fa 100644 --- a/clutter/x11/clutter-backend-x11.h +++ b/clutter/x11/clutter-backend-x11.h @@ -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); diff --git a/clutter/x11/clutter-event-x11.c b/clutter/x11/clutter-event-x11.c index 6b3ea67ce..a5886aec8 100644 --- a/clutter/x11/clutter-event-x11.c +++ b/clutter/x11/clutter-event-x11.c @@ -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; diff --git a/clutter/x11/clutter-x11.h b/clutter/x11/clutter-x11.h index 66bea5863..30c71ada6 100644 --- a/clutter/x11/clutter-x11.h +++ b/clutter/x11/clutter-x11.h @@ -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);