diff --git a/clutter/clutter/clutter-backend.c b/clutter/clutter/clutter-backend.c index 5e98a2bbe55b43cde0e262804303e348eaa69446..91298c964c1e0ec4f304af252307e501c1df2e3a 100644 --- a/clutter/clutter/clutter-backend.c +++ b/clutter/clutter/clutter-backend.c @@ -111,7 +111,7 @@ clutter_backend_finalize (GObject *gobject) g_source_destroy (backend->cogl_source); g_free (backend->font_name); - clutter_backend_set_font_options (backend, NULL); + g_clear_pointer (&backend->font_options, cairo_font_options_destroy); g_clear_object (&backend->input_method); G_OBJECT_CLASS (clutter_backend_parent_class)->finalize (gobject); diff --git a/clutter/clutter/clutter-enums.h b/clutter/clutter/clutter-enums.h index 04cc52a271b25fe04238bbf19434129e0b590ff4..9b0c29fa0cc0596e59712b616e603b1ad1be91e1 100644 --- a/clutter/clutter/clutter-enums.h +++ b/clutter/clutter/clutter-enums.h @@ -387,44 +387,6 @@ typedef enum CLUTTER_MODIFIER_MASK = 0x5c001fff } ClutterModifierType; -/** - * ClutterKeyboardA11yFlags: - * @CLUTTER_A11Y_KEYBOARD_ENABLED: - * @CLUTTER_A11Y_TIMEOUT_ENABLED: - * @CLUTTER_A11Y_MOUSE_KEYS_ENABLED: - * @CLUTTER_A11Y_SLOW_KEYS_ENABLED: - * @CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS: - * @CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT: - * @CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT: - * @CLUTTER_A11Y_BOUNCE_KEYS_ENABLED: - * @CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT: - * @CLUTTER_A11Y_TOGGLE_KEYS_ENABLED: - * @CLUTTER_A11Y_STICKY_KEYS_ENABLED: - * @CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF: - * @CLUTTER_A11Y_STICKY_KEYS_BEEP: - * @CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP: - * - * Keyboard accessibility features applied to a ClutterInputDevice keyboard. - * - */ -typedef enum -{ - CLUTTER_A11Y_KEYBOARD_ENABLED = 1 << 0, - CLUTTER_A11Y_TIMEOUT_ENABLED = 1 << 1, - CLUTTER_A11Y_MOUSE_KEYS_ENABLED = 1 << 2, - CLUTTER_A11Y_SLOW_KEYS_ENABLED = 1 << 3, - CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS = 1 << 4, - CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT = 1 << 5, - CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT = 1 << 6, - CLUTTER_A11Y_BOUNCE_KEYS_ENABLED = 1 << 7, - CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT = 1 << 8, - CLUTTER_A11Y_TOGGLE_KEYS_ENABLED = 1 << 9, - CLUTTER_A11Y_STICKY_KEYS_ENABLED = 1 << 10, - CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF = 1 << 11, - CLUTTER_A11Y_STICKY_KEYS_BEEP = 1 << 12, - CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP = 1 << 13, -} ClutterKeyboardA11yFlags; - /** * ClutterPointerA11yFlags: * @CLUTTER_A11Y_POINTER_ENABLED: @@ -1088,6 +1050,20 @@ typedef enum CLUTTER_INPUT_AXIS_LAST } ClutterInputAxis; +typedef enum +{ + CLUTTER_INPUT_AXIS_FLAG_NONE = 0, + CLUTTER_INPUT_AXIS_FLAG_X = 1 << CLUTTER_INPUT_AXIS_X, + CLUTTER_INPUT_AXIS_FLAG_Y = 1 << CLUTTER_INPUT_AXIS_Y, + CLUTTER_INPUT_AXIS_FLAG_PRESSURE = 1 << CLUTTER_INPUT_AXIS_PRESSURE, + CLUTTER_INPUT_AXIS_FLAG_XTILT = 1 << CLUTTER_INPUT_AXIS_XTILT, + CLUTTER_INPUT_AXIS_FLAG_YTILT = 1 << CLUTTER_INPUT_AXIS_YTILT, + CLUTTER_INPUT_AXIS_FLAG_WHEEL = 1 << CLUTTER_INPUT_AXIS_WHEEL, + CLUTTER_INPUT_AXIS_FLAG_DISTANCE = 1 << CLUTTER_INPUT_AXIS_DISTANCE, + CLUTTER_INPUT_AXIS_FLAG_ROTATION = 1 << CLUTTER_INPUT_AXIS_ROTATION, + CLUTTER_INPUT_AXIS_FLAG_SLIDER = 1 << CLUTTER_INPUT_AXIS_SLIDER, +} ClutterInputAxisFlags; + /** * ClutterSnapEdge: * @CLUTTER_SNAP_EDGE_TOP: the top edge @@ -1635,6 +1611,13 @@ typedef enum CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER, } ClutterInputDevicePadSource; +typedef enum +{ + CLUTTER_PAD_FEATURE_BUTTON, + CLUTTER_PAD_FEATURE_RING, + CLUTTER_PAD_FEATURE_STRIP, +} ClutterInputDevicePadFeature; + typedef enum { CLUTTER_INPUT_CONTENT_HINT_COMPLETION = 1 << 0, diff --git a/clutter/clutter/clutter-event.c b/clutter/clutter/clutter-event.c index 44a6651ddbb28f517c2acdd5076c54b57e10b654..dba5d2588de73e00a6b49ea0de985b73bb9a84ac 100644 --- a/clutter/clutter/clutter-event.c +++ b/clutter/clutter/clutter-event.c @@ -1302,9 +1302,7 @@ clutter_event_copy (const ClutterEvent *event) { ClutterEvent *new_event; ClutterEventPrivate *new_real_event; - ClutterInputDevice *device; ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; - gint n_axes = 0; g_return_val_if_fail (event != NULL, NULL); @@ -1324,29 +1322,25 @@ clutter_event_copy (const ClutterEvent *event) new_real_event->locked_state = real_event->locked_state; new_real_event->tool = real_event->tool; - device = clutter_event_get_device (event); - if (device != NULL) - n_axes = clutter_input_device_get_n_axes (device); - switch (event->type) { case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_RELEASE: if (event->button.axes != NULL) new_event->button.axes = g_memdup (event->button.axes, - sizeof (gdouble) * n_axes); + sizeof (gdouble) * CLUTTER_INPUT_AXIS_LAST); break; case CLUTTER_SCROLL: if (event->scroll.axes != NULL) new_event->scroll.axes = g_memdup (event->scroll.axes, - sizeof (gdouble) * n_axes); + sizeof (gdouble) * CLUTTER_INPUT_AXIS_LAST); break; case CLUTTER_MOTION: if (event->motion.axes != NULL) new_event->motion.axes = g_memdup (event->motion.axes, - sizeof (gdouble) * n_axes); + sizeof (gdouble) * CLUTTER_INPUT_AXIS_LAST); break; case CLUTTER_TOUCH_BEGIN: @@ -1355,7 +1349,7 @@ clutter_event_copy (const ClutterEvent *event) case CLUTTER_TOUCH_CANCEL: if (event->touch.axes != NULL) new_event->touch.axes = g_memdup (event->touch.axes, - sizeof (gdouble) * n_axes); + sizeof (gdouble) * CLUTTER_INPUT_AXIS_LAST); break; case CLUTTER_DEVICE_ADDED: @@ -1445,14 +1439,11 @@ ClutterEvent * clutter_event_get (void) { ClutterMainContext *context = _clutter_context_get_default (); + ClutterEvent *event; - if (context->events_queue == NULL) - return NULL; - - if (g_queue_is_empty (context->events_queue)) - return NULL; + event = g_async_queue_try_pop (context->events_queue); - return g_queue_pop_tail (context->events_queue); + return event; } void @@ -1460,23 +1451,9 @@ _clutter_event_push (const ClutterEvent *event, gboolean do_copy) { ClutterMainContext *context = _clutter_context_get_default (); - ClutterInputDevice *device; g_assert (context != NULL); - if (context->events_queue == NULL) - context->events_queue = g_queue_new (); - - /* disabled devices don't propagate events */ - device = clutter_event_get_device (event); - if (device != NULL) - { - if (event->type != CLUTTER_DEVICE_ADDED && - event->type != CLUTTER_DEVICE_REMOVED && - !clutter_input_device_get_enabled (device)) - return; - } - if (do_copy) { ClutterEvent *copy; @@ -1485,7 +1462,8 @@ _clutter_event_push (const ClutterEvent *event, event = copy; } - g_queue_push_head (context->events_queue, (gpointer) event); + g_async_queue_push (context->events_queue, (gpointer) event); + g_main_context_wakeup (NULL); } /** @@ -1522,10 +1500,7 @@ clutter_events_pending (void) g_return_val_if_fail (context != NULL, FALSE); - if (context->events_queue == NULL) - return FALSE; - - return g_queue_is_empty (context->events_queue) == FALSE; + return g_async_queue_length (context->events_queue) > 0; } /** @@ -1643,7 +1618,6 @@ clutter_event_get_axes (const ClutterEvent *event, guint *n_axes) { gdouble *retval = NULL; - guint len = 0; switch (event->type) { @@ -1694,19 +1668,8 @@ clutter_event_get_axes (const ClutterEvent *event, break; } - if (retval != NULL) - { - ClutterInputDevice *device; - - device = clutter_event_get_device (event); - if (device != NULL) - len = clutter_input_device_get_n_axes (device); - else - retval = NULL; - } - if (n_axes) - *n_axes = len; + *n_axes = CLUTTER_INPUT_AXIS_LAST; return retval; } diff --git a/clutter/clutter/clutter-input-device-private.h b/clutter/clutter/clutter-input-device-private.h index 9ceb22c2bb20d9f1ce27e3972456a14621041fc5..672f3cf79de2796a6f84a018be045ad71799e9b8 100644 --- a/clutter/clutter/clutter-input-device-private.h +++ b/clutter/clutter/clutter-input-device-private.h @@ -32,44 +32,6 @@ G_BEGIN_DECLS -typedef struct _ClutterAxisInfo -{ - ClutterInputAxis axis; - - double min_axis; - double max_axis; - - double min_value; - double max_value; - - double resolution; -} ClutterAxisInfo; - -typedef struct _ClutterKeyInfo -{ - guint keyval; - ClutterModifierType modifiers; -} ClutterKeyInfo; - -typedef struct _ClutterScrollInfo -{ - guint axis_id; - ClutterScrollDirection direction; - double increment; - - double last_value; - guint last_value_valid : 1; -} ClutterScrollInfo; - -typedef struct _ClutterTouchInfo -{ - ClutterEventSequence *sequence; - ClutterActor *actor; - - float current_x; - float current_y; -} ClutterTouchInfo; - typedef struct _ClutterPtrA11yData { int n_btn_pressed; @@ -91,20 +53,6 @@ struct _ClutterInputDevice { GObject parent_instance; - ClutterInputDeviceType device_type; - ClutterInputMode device_mode; - - char *device_name; - - ClutterSeat *seat; - - ClutterBackend *backend; - - /* the associated device */ - ClutterInputDevice *associated; - - GList *physical_devices; - /* the actor underneath the pointer */ ClutterActor *cursor_actor; GHashTable *inv_touch_sequence_actors; @@ -117,15 +65,10 @@ struct _ClutterInputDevice /* the current click count */ int click_count; - - /* the current state */ - float current_x; - float current_y; int current_button_number; - ClutterModifierType current_state; - /* the current touch points states */ - GHashTable *touch_sequences_info; + /* the current touch points targets */ + GHashTable *touch_sequence_actors; /* the previous state, used for click count generation */ int previous_x; @@ -133,117 +76,19 @@ struct _ClutterInputDevice uint32_t previous_time; int previous_button_number; - GArray *axes; - - guint n_keys; - GArray *keys; - - GArray *scroll_info; - - char *vendor_id; - char *product_id; - char *node_path; - - GPtrArray *tools; - - int n_rings; - int n_strips; - int n_mode_groups; - - guint has_cursor : 1; - guint is_enabled : 1; - /* Accessiblity */ ClutterVirtualInputDevice *accessibility_virtual_device; ClutterPtrA11yData *ptr_a11y_data; }; -CLUTTER_EXPORT -void _clutter_input_device_set_associated_device (ClutterInputDevice *device, - ClutterInputDevice *associated); -CLUTTER_EXPORT -void _clutter_input_device_add_physical_device (ClutterInputDevice *logical, - ClutterInputDevice *physical); -CLUTTER_EXPORT -void _clutter_input_device_remove_physical_device (ClutterInputDevice *logical, - ClutterInputDevice *physical); -CLUTTER_EXPORT -void clutter_input_device_update_from_tool (ClutterInputDevice *device, - ClutterInputDeviceTool *tool); -CLUTTER_EXPORT -void _clutter_input_device_set_coords (ClutterInputDevice *device, - ClutterEventSequence *sequence, - gfloat x, - gfloat y); -CLUTTER_EXPORT -void _clutter_input_device_set_state (ClutterInputDevice *device, - ClutterModifierType state); CLUTTER_EXPORT ClutterActor * clutter_input_device_update (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterStage *stage, gboolean emit_crossing, - uint32_t time_ms); -CLUTTER_EXPORT -void _clutter_input_device_add_event_sequence (ClutterInputDevice *device, - ClutterEvent *event); + ClutterEvent *for_event); CLUTTER_EXPORT void _clutter_input_device_remove_event_sequence (ClutterInputDevice *device, ClutterEvent *event); -CLUTTER_EXPORT -void _clutter_input_device_set_n_keys (ClutterInputDevice *device, - guint n_keys); -CLUTTER_EXPORT -void clutter_input_device_set_key (ClutterInputDevice *device, - guint index_, - guint keyval, - ClutterModifierType modifiers); - -CLUTTER_EXPORT -gboolean _clutter_input_device_translate_axis (ClutterInputDevice *device, - guint index_, - gdouble value, - gdouble *axis_value); -CLUTTER_EXPORT -guint _clutter_input_device_add_axis (ClutterInputDevice *device, - ClutterInputAxis axis, - gdouble minimum, - gdouble maximum, - gdouble resolution); - -CLUTTER_EXPORT -void _clutter_input_device_reset_axes (ClutterInputDevice *device); - -CLUTTER_EXPORT -void _clutter_input_device_add_scroll_info (ClutterInputDevice *device, - guint index_, - ClutterScrollDirection direction, - gdouble increment); -CLUTTER_EXPORT -gboolean _clutter_input_device_get_scroll_delta (ClutterInputDevice *device, - guint index_, - gdouble value, - ClutterScrollDirection *direction_p, - gdouble *delta_p); -CLUTTER_EXPORT -void _clutter_input_device_reset_scroll_info (ClutterInputDevice *device); - -CLUTTER_EXPORT -void clutter_input_device_add_tool (ClutterInputDevice *device, - ClutterInputDeviceTool *tool); - -CLUTTER_EXPORT -ClutterInputDeviceTool * - clutter_input_device_lookup_tool (ClutterInputDevice *device, - guint64 serial, - ClutterInputDeviceToolType type); - -CLUTTER_EXPORT -void clutter_input_device_update_from_event (ClutterInputDevice *device, - ClutterEvent *event); -CLUTTER_EXPORT -gboolean clutter_input_device_keycode_to_evdev (ClutterInputDevice *device, - guint hardware_keycode, - guint *evdev_keycode); #endif /* CLUTTER_INPUT_DEVICE_PRIVATE_H */ diff --git a/clutter/clutter/clutter-input-device-tool.c b/clutter/clutter/clutter-input-device-tool.c index 982d94ce4067dca7b19179b5e8644837b1455498..2582a695c34584ba7f953b2648fb3564794a42ed 100644 --- a/clutter/clutter/clutter-input-device-tool.c +++ b/clutter/clutter/clutter-input-device-tool.c @@ -33,6 +33,7 @@ struct _ClutterInputDeviceToolPrivate ClutterInputDeviceToolType type; guint64 serial; guint64 id; + ClutterInputAxisFlags axes; }; enum @@ -41,6 +42,7 @@ enum PROP_TYPE, PROP_SERIAL, PROP_ID, + PROP_AXES, PROP_LAST }; @@ -70,6 +72,9 @@ clutter_input_device_tool_set_property (GObject *object, case PROP_ID: priv->id = g_value_get_uint64 (value); break; + case PROP_AXES: + priv->axes = g_value_get_flags (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -97,6 +102,9 @@ clutter_input_device_tool_get_property (GObject *object, case PROP_ID: g_value_set_uint64 (value, priv->id); break; + case PROP_AXES: + g_value_set_flags (value, priv->axes); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -129,6 +137,13 @@ clutter_input_device_tool_class_init (ClutterInputDeviceToolClass *klass) P_("Tool ID"), 0, G_MAXUINT64, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + props[PROP_AXES] = + g_param_spec_flags ("axes", + P_("Axes"), + P_("Axes"), + CLUTTER_TYPE_INPUT_AXIS_FLAGS, + CLUTTER_INPUT_AXIS_FLAG_NONE, + CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (gobject_class, PROP_LAST, props); } @@ -204,3 +219,15 @@ clutter_input_device_tool_get_id (ClutterInputDeviceTool *tool) return priv->id; } + +ClutterInputAxisFlags +clutter_input_device_tool_get_axes (ClutterInputDeviceTool *tool) +{ + ClutterInputDeviceToolPrivate *priv; + + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool), 0); + + priv = clutter_input_device_tool_get_instance_private (tool); + + return priv->axes; +} diff --git a/clutter/clutter/clutter-input-device-tool.h b/clutter/clutter/clutter-input-device-tool.h index 36c8add8396f88a5a0f2466b378f0149da1cb66e..df5c8201d77a76727201b9c429c6f17c38c5010b 100644 --- a/clutter/clutter/clutter-input-device-tool.h +++ b/clutter/clutter/clutter-input-device-tool.h @@ -64,6 +64,9 @@ ClutterInputDeviceToolType clutter_input_device_tool_get_tool_type (ClutterInput CLUTTER_EXPORT guint64 clutter_input_device_tool_get_id (ClutterInputDeviceTool *tool); +CLUTTER_EXPORT +ClutterInputAxisFlags clutter_input_device_tool_get_axes (ClutterInputDeviceTool *tool); + G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_TOOL_H__ */ diff --git a/clutter/clutter/clutter-input-device.c b/clutter/clutter/clutter-input-device.c index 52613317fe33a7947ec2ae67a3b06c7958846e13..a6df00643802a6b0db80c9ea8cf35367e66665cc 100644 --- a/clutter/clutter/clutter-input-device.c +++ b/clutter/clutter/clutter-input-device.c @@ -60,9 +60,6 @@ enum PROP_DEVICE_MODE, PROP_HAS_CURSOR, - PROP_ENABLED, - - PROP_N_AXES, PROP_VENDOR_ID, PROP_PRODUCT_ID, @@ -70,12 +67,12 @@ enum PROP_N_STRIPS, PROP_N_RINGS, PROP_N_MODE_GROUPS, + PROP_N_BUTTONS, PROP_DEVICE_NODE, PROP_LAST }; -static void _clutter_input_device_free_touch_info (gpointer data); static void on_cursor_actor_destroy (ClutterActor *actor, ClutterInputDevice *device); static void on_cursor_actor_reactive_changed (ClutterActor *actor, @@ -84,35 +81,49 @@ static void on_cursor_actor_reactive_changed (ClutterActor *actor, static GParamSpec *obj_props[PROP_LAST] = { NULL, }; -G_DEFINE_TYPE (ClutterInputDevice, clutter_input_device, G_TYPE_OBJECT); +typedef struct _ClutterInputDevicePrivate ClutterInputDevicePrivate; + +struct _ClutterInputDevicePrivate +{ + ClutterInputDeviceType device_type; + ClutterInputMode device_mode; + + char *device_name; + + ClutterSeat *seat; + + ClutterBackend *backend; + + char *vendor_id; + char *product_id; + char *node_path; + + int n_rings; + int n_strips; + int n_mode_groups; + int n_buttons; + + gboolean has_cursor; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (ClutterInputDevice, clutter_input_device, G_TYPE_OBJECT); static void clutter_input_device_dispose (GObject *gobject) { ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject); + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); - g_clear_pointer (&device->device_name, g_free); - g_clear_pointer (&device->vendor_id, g_free); - g_clear_pointer (&device->product_id, g_free); - g_clear_pointer (&device->node_path, g_free); - - if (device->associated != NULL) - { - if (device->device_mode == CLUTTER_INPUT_MODE_PHYSICAL) - _clutter_input_device_remove_physical_device (device->associated, device); - - _clutter_input_device_set_associated_device (device->associated, NULL); - g_object_unref (device->associated); - device->associated = NULL; - } + g_clear_pointer (&priv->device_name, g_free); + g_clear_pointer (&priv->vendor_id, g_free); + g_clear_pointer (&priv->product_id, g_free); + g_clear_pointer (&priv->node_path, g_free); if (device->accessibility_virtual_device) g_clear_object (&device->accessibility_virtual_device); - g_clear_pointer (&device->axes, g_array_unref); - g_clear_pointer (&device->keys, g_array_unref); - g_clear_pointer (&device->scroll_info, g_array_unref); - g_clear_pointer (&device->touch_sequences_info, g_hash_table_unref); + g_clear_pointer (&device->touch_sequence_actors, g_hash_table_unref); if (device->cursor_actor) { @@ -158,59 +169,61 @@ clutter_input_device_set_property (GObject *gobject, GParamSpec *pspec) { ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject); + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (self); switch (prop_id) { case PROP_DEVICE_TYPE: - self->device_type = g_value_get_enum (value); + priv->device_type = g_value_get_enum (value); break; case PROP_SEAT: - self->seat = g_value_get_object (value); + priv->seat = g_value_get_object (value); break; case PROP_DEVICE_MODE: - self->device_mode = g_value_get_enum (value); + priv->device_mode = g_value_get_enum (value); break; case PROP_BACKEND: - self->backend = g_value_get_object (value); + priv->backend = g_value_get_object (value); break; case PROP_NAME: - self->device_name = g_value_dup_string (value); + priv->device_name = g_value_dup_string (value); break; case PROP_HAS_CURSOR: - self->has_cursor = g_value_get_boolean (value); - break; - - case PROP_ENABLED: - clutter_input_device_set_enabled (self, g_value_get_boolean (value)); + priv->has_cursor = g_value_get_boolean (value); break; case PROP_VENDOR_ID: - self->vendor_id = g_value_dup_string (value); + priv->vendor_id = g_value_dup_string (value); break; case PROP_PRODUCT_ID: - self->product_id = g_value_dup_string (value); + priv->product_id = g_value_dup_string (value); break; case PROP_N_RINGS: - self->n_rings = g_value_get_int (value); + priv->n_rings = g_value_get_int (value); break; case PROP_N_STRIPS: - self->n_strips = g_value_get_int (value); + priv->n_strips = g_value_get_int (value); break; case PROP_N_MODE_GROUPS: - self->n_mode_groups = g_value_get_int (value); + priv->n_mode_groups = g_value_get_int (value); + break; + + case PROP_N_BUTTONS: + priv->n_buttons = g_value_get_int (value); break; case PROP_DEVICE_NODE: - self->node_path = g_value_dup_string (value); + priv->node_path = g_value_dup_string (value); break; default: @@ -226,63 +239,61 @@ clutter_input_device_get_property (GObject *gobject, GParamSpec *pspec) { ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject); + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (self); switch (prop_id) { case PROP_DEVICE_TYPE: - g_value_set_enum (value, self->device_type); + g_value_set_enum (value, priv->device_type); break; case PROP_SEAT: - g_value_set_object (value, self->seat); + g_value_set_object (value, priv->seat); break; case PROP_DEVICE_MODE: - g_value_set_enum (value, self->device_mode); + g_value_set_enum (value, priv->device_mode); break; case PROP_BACKEND: - g_value_set_object (value, self->backend); + g_value_set_object (value, priv->backend); break; case PROP_NAME: - g_value_set_string (value, self->device_name); + g_value_set_string (value, priv->device_name); break; case PROP_HAS_CURSOR: - g_value_set_boolean (value, self->has_cursor); - break; - - case PROP_N_AXES: - g_value_set_uint (value, clutter_input_device_get_n_axes (self)); - break; - - case PROP_ENABLED: - g_value_set_boolean (value, self->is_enabled); + g_value_set_boolean (value, priv->has_cursor); break; case PROP_VENDOR_ID: - g_value_set_string (value, self->vendor_id); + g_value_set_string (value, priv->vendor_id); break; case PROP_PRODUCT_ID: - g_value_set_string (value, self->product_id); + g_value_set_string (value, priv->product_id); break; case PROP_N_RINGS: - g_value_set_int (value, self->n_rings); + g_value_set_int (value, priv->n_rings); break; case PROP_N_STRIPS: - g_value_set_int (value, self->n_strips); + g_value_set_int (value, priv->n_strips); break; case PROP_N_MODE_GROUPS: - g_value_set_int (value, self->n_mode_groups); + g_value_set_int (value, priv->n_mode_groups); + break; + + case PROP_N_BUTTONS: + g_value_set_int (value, priv->n_buttons); break; case PROP_DEVICE_NODE: - g_value_set_string (value, self->node_path); + g_value_set_string (value, priv->node_path); break; default: @@ -368,40 +379,6 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass) FALSE, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - /** - * ClutterInputDevice:enabled: - * - * Whether the device is enabled. - * - * A device with the #ClutterInputDevice:device-mode property set - * to %CLUTTER_INPUT_MODE_LOGICAL cannot be disabled. - * - * A device must be enabled in order to receive events from it. - * - * Since: 1.6 - */ - obj_props[PROP_ENABLED] = - g_param_spec_boolean ("enabled", - P_("Enabled"), - P_("Whether the device is enabled"), - FALSE, - CLUTTER_PARAM_READWRITE); - - /** - * ClutterInputDevice:n-axes: - * - * The number of axes of the device. - * - * Since: 1.6 - */ - obj_props[PROP_N_AXES] = - g_param_spec_uint ("n-axes", - P_("Number of Axes"), - P_("The number of axes on the device"), - 0, G_MAXUINT, - 0, - CLUTTER_PARAM_READABLE); - /** * ClutterInputDevice:backend: * @@ -465,6 +442,13 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass) 0, G_MAXINT, 0, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + obj_props[PROP_N_BUTTONS] = + g_param_spec_int ("n-buttons", + P_("Number of buttons"), + P_("Number of buttons"), + 0, G_MAXINT, 0, + CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + obj_props[PROP_DEVICE_NODE] = g_param_spec_string ("device-node", P_("Device node path"), @@ -481,115 +465,22 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass) static void clutter_input_device_init (ClutterInputDevice *self) { - self->device_type = CLUTTER_POINTER_DEVICE; + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (self); + + priv->device_type = CLUTTER_POINTER_DEVICE; self->click_count = 0; self->previous_time = CLUTTER_CURRENT_TIME; - self->current_x = self->previous_x = -1; - self->current_y = self->previous_y = -1; + self->previous_x = -1; + self->previous_y = -1; self->current_button_number = self->previous_button_number = -1; - self->current_state = 0; - self->touch_sequences_info = - g_hash_table_new_full (NULL, NULL, - NULL, _clutter_input_device_free_touch_info); + self->touch_sequence_actors = g_hash_table_new (NULL, NULL); self->inv_touch_sequence_actors = g_hash_table_new (NULL, NULL); } -static ClutterTouchInfo * -_clutter_input_device_ensure_touch_info (ClutterInputDevice *device, - ClutterEventSequence *sequence) -{ - ClutterTouchInfo *info; - - info = g_hash_table_lookup (device->touch_sequences_info, sequence); - - if (info == NULL) - { - info = g_slice_new0 (ClutterTouchInfo); - info->sequence = sequence; - g_hash_table_insert (device->touch_sequences_info, sequence, info); - } - - return info; -} - -/*< private > - * clutter_input_device_set_coords: - * @device: a #ClutterInputDevice - * @sequence: a #ClutterEventSequence or NULL - * @x: X coordinate of the device - * @y: Y coordinate of the device - * - * Stores the last known coordinates of the device - */ -void -_clutter_input_device_set_coords (ClutterInputDevice *device, - ClutterEventSequence *sequence, - gfloat x, - gfloat y) -{ - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - - if (sequence == NULL) - { - if (device->current_x != x) - device->current_x = x; - - if (device->current_y != y) - device->current_y = y; - } - else - { - ClutterTouchInfo *info; - info = _clutter_input_device_ensure_touch_info (device, sequence); - info->current_x = x; - info->current_y = y; - } -} - -/*< private > - * clutter_input_device_set_state: - * @device: a #ClutterInputDevice - * @state: a bitmask of modifiers - * - * Stores the last known modifiers state of the device - */ -void -_clutter_input_device_set_state (ClutterInputDevice *device, - ClutterModifierType state) -{ - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - - device->current_state = state; -} - -/** - * clutter_input_device_get_modifier_state: - * @device: a #ClutterInputDevice - * - * Retrieves the current modifiers state of the device, as seen - * by the last event Clutter processed. - * - * Return value: the last known modifier state - * - * Since: 1.16 - */ -ClutterModifierType -clutter_input_device_get_modifier_state (ClutterInputDevice *device) -{ - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); - - return device->current_state; -} - -static void -_clutter_input_device_free_touch_info (gpointer data) -{ - g_slice_free (ClutterTouchInfo, data); -} - static void _clutter_input_device_associate_actor (ClutterInputDevice *device, ClutterEventSequence *sequence, @@ -601,11 +492,8 @@ _clutter_input_device_associate_actor (ClutterInputDevice *device, { GList *sequences = g_hash_table_lookup (device->inv_touch_sequence_actors, actor); - ClutterTouchInfo *info; - - info = _clutter_input_device_ensure_touch_info (device, sequence); - info->actor = actor; + g_hash_table_insert (device->touch_sequence_actors, sequence, actor); g_hash_table_insert (device->inv_touch_sequence_actors, actor, g_list_prepend (sequences, sequence)); } @@ -633,13 +521,7 @@ _clutter_input_device_unassociate_actor (ClutterInputDevice *device, actor); for (l = sequences; l != NULL; l = l->next) - { - ClutterTouchInfo *info = - g_hash_table_lookup (device->touch_sequences_info, l->data); - - if (info) - info->actor = NULL; - } + g_hash_table_remove (device->touch_sequence_actors, l->data); g_list_free (sequences); g_hash_table_remove (device->inv_touch_sequence_actors, actor); @@ -698,6 +580,7 @@ _clutter_input_device_set_actor (ClutterInputDevice *device, ClutterStage *stage, ClutterActor *actor, gboolean emit_crossing, + graphene_point_t coords, uint32_t time_ms) { ClutterActor *old_actor = clutter_input_device_get_actor (device, sequence); @@ -718,8 +601,8 @@ _clutter_input_device_set_actor (ClutterInputDevice *device, event->crossing.flags = 0; event->crossing.stage = stage; event->crossing.source = old_actor; - event->crossing.x = device->current_x; - event->crossing.y = device->current_y; + event->crossing.x = coords.x; + event->crossing.y = coords.y; event->crossing.related = actor; event->crossing.sequence = sequence; clutter_event_set_device (event, device); @@ -754,8 +637,8 @@ _clutter_input_device_set_actor (ClutterInputDevice *device, event->crossing.time = time_ms; event->crossing.flags = 0; event->crossing.stage = stage; - event->crossing.x = device->current_x; - event->crossing.y = device->current_y; + event->crossing.x = coords.x; + event->crossing.y = coords.y; event->crossing.source = actor; event->crossing.related = old_actor; event->crossing.sequence = sequence; @@ -782,104 +665,13 @@ _clutter_input_device_set_actor (ClutterInputDevice *device, ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), CLUTTER_POINTER_DEVICE); - return device->device_type; -} - -/** - * clutter_input_device_set_enabled: - * @device: a #ClutterInputDevice - * @enabled: %TRUE to enable the @device - * - * Enables or disables a #ClutterInputDevice. - * - * Only devices with a #ClutterInputDevice:device-mode property set - * to %CLUTTER_INPUT_MODE_PHYSICAL or %CLUTTER_INPUT_MODE_FLOATING can - * be disabled. - * - * Since: 1.6 - */ -void -clutter_input_device_set_enabled (ClutterInputDevice *device, - gboolean enabled) -{ - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - - enabled = !!enabled; - - if (!enabled && device->device_mode == CLUTTER_INPUT_MODE_LOGICAL) - return; - - if (device->is_enabled == enabled) - return; - - device->is_enabled = enabled; - - g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_ENABLED]); -} - -/** - * clutter_input_device_get_enabled: - * @device: a #ClutterInputDevice - * - * Retrieves whether @device is enabled. - * - * Return value: %TRUE if the device is enabled - * - * Since: 1.6 - */ -gboolean -clutter_input_device_get_enabled (ClutterInputDevice *device) -{ - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); - - return device->is_enabled; -} - -/** - * clutter_input_device_get_coords: - * @device: a #ClutterInputDevice - * @sequence: (allow-none): a #ClutterEventSequence, or %NULL if - * the device is not touch-based - * @point: (out caller-allocates): return location for the pointer - * or touch point - * - * Retrieves the latest coordinates of a pointer or touch point of - * @device. - * - * Return value: %FALSE if the device's sequence hasn't been found, - * and %TRUE otherwise. - * - * Since: 1.12 - */ -gboolean -clutter_input_device_get_coords (ClutterInputDevice *device, - ClutterEventSequence *sequence, - graphene_point_t *point) -{ - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); - g_return_val_if_fail (point != NULL, FALSE); - - if (sequence == NULL) - { - point->x = device->current_x; - point->y = device->current_y; - } - else - { - ClutterTouchInfo *info = - g_hash_table_lookup (device->touch_sequences_info, sequence); - - if (info == NULL) - return FALSE; - - point->x = info->current_x; - point->y = info->current_y; - } - - return TRUE; + return priv->device_type; } /* @@ -901,17 +693,30 @@ clutter_input_device_update (ClutterInputDevice *device, ClutterEventSequence *sequence, ClutterStage *stage, gboolean emit_crossing, - uint32_t time_ms) + ClutterEvent *for_event) { ClutterActor *new_cursor_actor; ClutterActor *old_cursor_actor; graphene_point_t point = GRAPHENE_POINT_INIT (-1.0f, -1.0f); - ClutterInputDeviceType device_type = device->device_type; + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + ClutterInputDeviceType device_type = priv->device_type; + uint32_t time_ms; g_assert (device_type != CLUTTER_KEYBOARD_DEVICE && device_type != CLUTTER_PAD_DEVICE); - clutter_input_device_get_coords (device, sequence, &point); + if (for_event) + { + clutter_event_get_coords (for_event, &point.x, &point.y); + time_ms = clutter_event_get_time (for_event); + } + else + { + clutter_seat_query_state (clutter_input_device_get_seat (device), + device, NULL, &point, NULL); + time_ms = CLUTTER_CURRENT_TIME; + } old_cursor_actor = clutter_input_device_get_actor (device, sequence); new_cursor_actor = @@ -940,7 +745,7 @@ clutter_input_device_update (ClutterInputDevice *device, stage, new_cursor_actor, emit_crossing, - time_ms); + point, time_ms); return new_cursor_actor; } @@ -961,18 +766,12 @@ ClutterActor * clutter_input_device_get_actor (ClutterInputDevice *device, ClutterEventSequence *sequence) { - ClutterTouchInfo *info; - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); if (sequence == NULL) return device->cursor_actor; - info = g_hash_table_lookup (device->touch_sequences_info, sequence); - - g_return_val_if_fail (info != NULL, NULL); - - return info->actor; + return g_hash_table_lookup (device->touch_sequence_actors, sequence); } /** @@ -990,9 +789,12 @@ clutter_input_device_get_actor (ClutterInputDevice *device, const gchar * clutter_input_device_get_device_name (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); - return device->device_name; + return priv->device_name; } /** @@ -1009,9 +811,12 @@ clutter_input_device_get_device_name (ClutterInputDevice *device) gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); - return device->has_cursor; + return priv->has_cursor; } /** @@ -1027,799 +832,114 @@ clutter_input_device_get_has_cursor (ClutterInputDevice *device) ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), CLUTTER_INPUT_MODE_FLOATING); - return device->device_mode; + return priv->device_mode; } -/** - * clutter_input_device_update_from_event: +/*< private > + * clutter_input_device_remove_sequence: * @device: a #ClutterInputDevice - * @event: a #ClutterEvent - * @update_stage: whether to update the #ClutterStage of the @device - * using the stage of the event - * - * Forcibly updates the state of the @device using a #ClutterEvent - * - * This function should never be used by applications: it is meant - * for integration with embedding toolkits, like clutter-gtk - * - * Embedding toolkits that disable the event collection inside Clutter - * need to use this function to update the state of input devices depending - * on a #ClutterEvent that they are going to submit to the event handling code - * in Clutter though clutter_do_event(). Since the input devices hold the state - * that is going to be used to fill in fields like the #ClutterButtonEvent - * click count, or to emit synthesized events like %CLUTTER_ENTER and - * %CLUTTER_LEAVE, it is necessary for embedding toolkits to also be - * responsible of updating the input device state. - * - * For instance, this might be the code to translate an embedding toolkit - * native motion notification into a Clutter #ClutterMotionEvent and ask - * Clutter to process it: - * - * |[ - * ClutterEvent c_event; - * - * translate_native_event_to_clutter (native_event, &c_event); - * - * clutter_do_event (&c_event); - * ]| - * - * Before letting clutter_do_event() process the event, it is necessary to call - * clutter_input_device_update_from_event(): - * - * |[ - * ClutterEvent c_event; - * ClutterDeviceManager *manager; - * ClutterInputDevice *device; - * - * translate_native_event_to_clutter (native_event, &c_event); - * - * // get the seat - * seat = clutter_backend_get_deafult_seat (clutter_get_default_backend ()); - * - * // use the default Core Pointer that Clutter backends register by default - * device = clutter_seat_get_pointer (seat); - * - * // update the state of the input device - * clutter_input_device_update_from_event (device, &c_event); - * - * clutter_do_event (&c_event); - * ]| - * - * The @update_stage boolean argument should be used when the input device - * enters and leaves a #ClutterStage; it will use the #ClutterStage field - * of the passed @event to update the stage associated to the input device. + * @sequence: a #ClutterEventSequence * - * Since: 1.2 + * Stop tracking information related to a touch point. */ void -clutter_input_device_update_from_event (ClutterInputDevice *device, - ClutterEvent *event) +_clutter_input_device_remove_event_sequence (ClutterInputDevice *device, + ClutterEvent *event) { - ClutterModifierType event_state; - ClutterEventSequence *sequence; - gfloat event_x, event_y; - - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - g_return_if_fail (event != NULL); - - event_state = clutter_event_get_state (event); - sequence = clutter_event_get_event_sequence (event); - clutter_event_get_coords (event, &event_x, &event_y); + ClutterEventSequence *sequence = clutter_event_get_event_sequence (event); + ClutterActor *actor; - _clutter_input_device_set_coords (device, sequence, event_x, event_y); - _clutter_input_device_set_state (device, event_state); -} + actor = g_hash_table_lookup (device->touch_sequence_actors, sequence); -/*< private > - * clutter_input_device_reset_axes: - * @device: a #ClutterInputDevice - * - * Resets the axes on @device - */ -void -_clutter_input_device_reset_axes (ClutterInputDevice *device) -{ - if (device->axes != NULL) + if (actor != NULL) { - g_array_free (device->axes, TRUE); - device->axes = NULL; + GList *sequences = + g_hash_table_lookup (device->inv_touch_sequence_actors, actor); + ClutterStage *stage = + CLUTTER_STAGE (clutter_actor_get_stage (actor)); + graphene_point_t point; + + sequences = g_list_remove (sequences, sequence); - g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]); + g_hash_table_replace (device->inv_touch_sequence_actors, + actor, sequences); + clutter_event_get_coords (event, &point.x, &point.y); + _clutter_input_device_set_actor (device, sequence, stage, + NULL, TRUE, point, + clutter_event_get_time (event)); + g_hash_table_remove (device->touch_sequence_actors, sequence); } } -/*< private > - * clutter_input_device_add_axis: - * @device: a #ClutterInputDevice - * @axis: the axis type - * @minimum: the minimum axis value - * @maximum: the maximum axis value - * @resolution: the axis resolution - * - * Adds an axis of type @axis on @device. - */ -guint -_clutter_input_device_add_axis (ClutterInputDevice *device, - ClutterInputAxis axis, - gdouble minimum, - gdouble maximum, - gdouble resolution) +static void +on_grab_actor_destroy (ClutterActor *actor, + ClutterInputDevice *device) { - ClutterAxisInfo info; - guint pos; - - if (device->axes == NULL) - device->axes = g_array_new (FALSE, TRUE, sizeof (ClutterAxisInfo)); - - info.axis = axis; - info.min_value = minimum; - info.max_value = maximum; - info.resolution = resolution; + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); - switch (axis) + switch (priv->device_type) { - case CLUTTER_INPUT_AXIS_X: - case CLUTTER_INPUT_AXIS_Y: - info.min_axis = 0; - info.max_axis = 0; + case CLUTTER_POINTER_DEVICE: + case CLUTTER_TABLET_DEVICE: + device->pointer_grab_actor = NULL; break; - case CLUTTER_INPUT_AXIS_XTILT: - case CLUTTER_INPUT_AXIS_YTILT: - info.min_axis = -1; - info.max_axis = 1; + case CLUTTER_KEYBOARD_DEVICE: + device->keyboard_grab_actor = NULL; break; default: - info.min_axis = 0; - info.max_axis = 1; - break; + g_assert_not_reached (); } - - device->axes = g_array_append_val (device->axes, info); - pos = device->axes->len - 1; - - g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]); - - return pos; } -/*< private > - * clutter_input_translate_axis: +/** + * clutter_input_device_grab: * @device: a #ClutterInputDevice - * @index_: the index of the axis - * @gint: the absolute value of the axis - * @axis_value: (out): the translated value of the axis + * @actor: a #ClutterActor + * + * Acquires a grab on @actor for the given @device. * - * Performs a conversion from the absolute value of the axis - * to a relative value. + * Any event coming from @device will be delivered to @actor, bypassing + * the usual event delivery mechanism, until the grab is released by + * calling clutter_input_device_ungrab(). + * + * The grab is client-side: even if the windowing system used by the Clutter + * backend has the concept of "device grabs", Clutter will not use them. * - * The axis at @index_ must not be %CLUTTER_INPUT_AXIS_X or - * %CLUTTER_INPUT_AXIS_Y. + * Only #ClutterInputDevice of types %CLUTTER_POINTER_DEVICE, + * %CLUTTER_TABLET_DEVICE and %CLUTTER_KEYBOARD_DEVICE can hold a grab. * - * Return value: %TRUE if the conversion was successful + * Since: 1.10 */ -gboolean -_clutter_input_device_translate_axis (ClutterInputDevice *device, - guint index_, - gdouble value, - gdouble *axis_value) +void +clutter_input_device_grab (ClutterInputDevice *device, + ClutterActor *actor) { - ClutterAxisInfo *info; - gdouble width; - gdouble real_value; + ClutterActor **grab_actor; + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); - if (device->axes == NULL || index_ >= device->axes->len) - return FALSE; + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); + g_return_if_fail (CLUTTER_IS_ACTOR (actor)); - info = &g_array_index (device->axes, ClutterAxisInfo, index_); + switch (priv->device_type) + { + case CLUTTER_POINTER_DEVICE: + case CLUTTER_TABLET_DEVICE: + grab_actor = &device->pointer_grab_actor; + break; - if (info->axis == CLUTTER_INPUT_AXIS_X || - info->axis == CLUTTER_INPUT_AXIS_Y) - return FALSE; - - if (fabs (info->max_value - info->min_value) < 0.0000001) - return FALSE; - - width = info->max_value - info->min_value; - real_value = (info->max_axis * (value - info->min_value) - + info->min_axis * (info->max_value - value)) - / width; - - if (axis_value) - *axis_value = real_value; - - return TRUE; -} - -/** - * clutter_input_device_get_axis: - * @device: a #ClutterInputDevice - * @index_: the index of the axis - * - * Retrieves the type of axis on @device at the given index. - * - * Return value: the axis type - * - * Since: 1.6 - */ -ClutterInputAxis -clutter_input_device_get_axis (ClutterInputDevice *device, - guint index_) -{ - ClutterAxisInfo *info; - - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), - CLUTTER_INPUT_AXIS_IGNORE); - - if (device->axes == NULL) - return CLUTTER_INPUT_AXIS_IGNORE; - - if (index_ >= device->axes->len) - return CLUTTER_INPUT_AXIS_IGNORE; - - info = &g_array_index (device->axes, ClutterAxisInfo, index_); - - return info->axis; -} - -/** - * clutter_input_device_get_axis_value: - * @device: a #ClutterInputDevice - * @axes: (array): an array of axes values, typically - * coming from clutter_event_get_axes() - * @axis: the axis to extract - * @value: (out): return location for the axis value - * - * Extracts the value of the given @axis of a #ClutterInputDevice from - * an array of axis values. - * - * An example of typical usage for this function is: - * - * |[ - * ClutterInputDevice *device = clutter_event_get_device (event); - * gdouble *axes = clutter_event_get_axes (event, NULL); - * gdouble pressure_value = 0; - * - * clutter_input_device_get_axis_value (device, axes, - * CLUTTER_INPUT_AXIS_PRESSURE, - * &pressure_value); - * ]| - * - * Return value: %TRUE if the value was set, and %FALSE otherwise - * - * Since: 1.6 - */ -gboolean -clutter_input_device_get_axis_value (ClutterInputDevice *device, - gdouble *axes, - ClutterInputAxis axis, - gdouble *value) -{ - gint i; - - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); - g_return_val_if_fail (device->axes != NULL, FALSE); - - for (i = 0; i < device->axes->len; i++) - { - ClutterAxisInfo *info; - - info = &g_array_index (device->axes, ClutterAxisInfo, i); - - if (info->axis == axis) - { - if (value) - *value = axes[i]; - - return TRUE; - } - } - - return FALSE; -} - -/** - * clutter_input_device_get_n_axes: - * @device: a #ClutterInputDevice - * - * Retrieves the number of axes available on @device. - * - * Return value: the number of axes on the device - * - * Since: 1.6 - */ -guint -clutter_input_device_get_n_axes (ClutterInputDevice *device) -{ - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); - - if (device->axes != NULL) - return device->axes->len; - - return 0; -} - -/*< private > - * clutter_input_device_set_n_keys: - * @device: a #ClutterInputDevice - * @n_keys: the number of keys of the device - * - * Initializes the keys of @device. - * - * Call clutter_input_device_set_key() on each key to set the keyval - * and modifiers. - */ -void -_clutter_input_device_set_n_keys (ClutterInputDevice *device, - guint n_keys) -{ - if (device->keys != NULL) - g_array_free (device->keys, TRUE); - - device->n_keys = n_keys; - device->keys = g_array_sized_new (FALSE, TRUE, - sizeof (ClutterKeyInfo), - n_keys); -} - -/** - * clutter_input_device_get_n_keys: - * @device: a #ClutterInputDevice - * - * Retrieves the number of keys registered for @device. - * - * Return value: the number of registered keys - * - * Since: 1.6 - */ -guint -clutter_input_device_get_n_keys (ClutterInputDevice *device) -{ - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); - - return device->n_keys; -} - -/** - * clutter_input_device_set_key: - * @device: a #ClutterInputDevice - * @index_: the index of the key - * @keyval: the keyval - * @modifiers: a bitmask of modifiers - * - * Sets the keyval and modifiers at the given @index_ for @device. - * - * Clutter will use the keyval and modifiers set when filling out - * an event coming from the same input device. - * - * Since: 1.6 - */ -void -clutter_input_device_set_key (ClutterInputDevice *device, - guint index_, - guint keyval, - ClutterModifierType modifiers) -{ - ClutterKeyInfo *key_info; - - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - g_return_if_fail (index_ < device->n_keys); - - key_info = &g_array_index (device->keys, ClutterKeyInfo, index_); - key_info->keyval = keyval; - key_info->modifiers = modifiers; -} - -/** - * clutter_input_device_get_key: - * @device: a #ClutterInputDevice - * @index_: the index of the key - * @keyval: (out): return location for the keyval at @index_ - * @modifiers: (out): return location for the modifiers at @index_ - * - * Retrieves the key set using clutter_input_device_set_key() - * - * Return value: %TRUE if a key was set at the given index - * - * Since: 1.6 - */ -gboolean -clutter_input_device_get_key (ClutterInputDevice *device, - guint index_, - guint *keyval, - ClutterModifierType *modifiers) -{ - ClutterKeyInfo *key_info; - - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); - - if (device->keys == NULL) - return FALSE; - - if (index_ > device->keys->len) - return FALSE; - - key_info = &g_array_index (device->keys, ClutterKeyInfo, index_); - - if (!key_info->keyval && !key_info->modifiers) - return FALSE; - - if (keyval) - *keyval = key_info->keyval; - - if (modifiers) - *modifiers = key_info->modifiers; - - return TRUE; -} - -/*< private > - * clutter_input_device_add_physical_device: - * @logical: a #ClutterInputDevice - * @physical: a #ClutterInputDevice - * - * Adds @physical to the list of physical devices of @logical - * - * This function does not increase the reference count of either @logical - * or @physical. - */ -void -_clutter_input_device_add_physical_device (ClutterInputDevice *logical, - ClutterInputDevice *physical) -{ - if (g_list_find (logical->physical_devices, physical) == NULL) - logical->physical_devices = g_list_prepend (logical->physical_devices, physical); -} - -/*< private > - * clutter_input_device_remove_physical_device: - * @logical: a #ClutterInputDevice - * @physical: a #ClutterInputDevice - * - * Removes @physical from the list of physical devices of @logical. - * - * This function does not decrease the reference count of either @logical - * or @physical. - */ -void -_clutter_input_device_remove_physical_device (ClutterInputDevice *logical, - ClutterInputDevice *physical) -{ - if (g_list_find (logical->physical_devices, physical) != NULL) - logical->physical_devices = g_list_remove (logical->physical_devices, physical); -} - -/*< private > - * clutter_input_device_add_sequence: - * @device: a #ClutterInputDevice - * @sequence: a #ClutterEventSequence - * - * Start tracking information related to a touch point (position, - * actor underneath the touch point). - */ -void -_clutter_input_device_add_event_sequence (ClutterInputDevice *device, - ClutterEvent *event) -{ - ClutterEventSequence *sequence = clutter_event_get_event_sequence (event); - - if (sequence == NULL) - return; - - _clutter_input_device_ensure_touch_info (device, sequence); -} - -/*< private > - * clutter_input_device_remove_sequence: - * @device: a #ClutterInputDevice - * @sequence: a #ClutterEventSequence - * - * Stop tracking information related to a touch point. - */ -void -_clutter_input_device_remove_event_sequence (ClutterInputDevice *device, - ClutterEvent *event) -{ - ClutterEventSequence *sequence = clutter_event_get_event_sequence (event); - ClutterTouchInfo *info = - g_hash_table_lookup (device->touch_sequences_info, sequence); - - if (info == NULL) - return; - - if (info->actor != NULL) - { - GList *sequences = - g_hash_table_lookup (device->inv_touch_sequence_actors, info->actor); - ClutterStage *stage = - CLUTTER_STAGE (clutter_actor_get_stage (info->actor)); - - sequences = g_list_remove (sequences, sequence); - - g_hash_table_replace (device->inv_touch_sequence_actors, - info->actor, sequences); - _clutter_input_device_set_actor (device, sequence, stage, NULL, TRUE, - clutter_event_get_time (event)); - } - - g_hash_table_remove (device->touch_sequences_info, sequence); -} - -/** - * clutter_input_device_get_physical_devices: - * @device: a #ClutterInputDevice - * - * Retrieves the physical devices attached to @device. - * - * Return value: (transfer container) (element-type Clutter.InputDevice): a - * list of #ClutterInputDevice, or %NULL. The contents of the list are - * owned by the device. Use g_list_free() when done - * - * Since: 1.6 - */ -GList * -clutter_input_device_get_physical_devices (ClutterInputDevice *device) -{ - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); - - return g_list_copy (device->physical_devices); -} - -/*< internal > - * clutter_input_device_set_associated_device: - * @device: a #ClutterInputDevice - * @associated: (allow-none): a #ClutterInputDevice, or %NULL - * - * Sets the associated device for @device. - * - * This function keeps a reference on the associated device. - */ -void -_clutter_input_device_set_associated_device (ClutterInputDevice *device, - ClutterInputDevice *associated) -{ - if (device->associated == associated) - return; - - if (device->associated != NULL) - g_object_unref (device->associated); - - device->associated = associated; - if (device->associated != NULL) - g_object_ref (device->associated); - - CLUTTER_NOTE (MISC, "Associating device '%s' to device '%s'", - clutter_input_device_get_device_name (device), - device->associated != NULL - ? clutter_input_device_get_device_name (device->associated) - : "(none)"); - - if (device->device_mode != CLUTTER_INPUT_MODE_LOGICAL) - { - if (device->associated != NULL) - device->device_mode = CLUTTER_INPUT_MODE_PHYSICAL; - else - device->device_mode = CLUTTER_INPUT_MODE_FLOATING; - - g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_DEVICE_MODE]); - } -} - -/** - * clutter_input_device_get_associated_device: - * @device: a #ClutterInputDevice - * - * Retrieves a pointer to the #ClutterInputDevice that has been - * associated to @device. - * - * If the #ClutterInputDevice:device-mode property of @device is - * set to %CLUTTER_INPUT_MODE_LOGICAL, this function will return - * %NULL. - * - * Return value: (transfer none): a #ClutterInputDevice, or %NULL - * - * Since: 1.6 - */ -ClutterInputDevice * -clutter_input_device_get_associated_device (ClutterInputDevice *device) -{ - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); - - return device->associated; -} - -/** - * clutter_input_device_keycode_to_evdev: - * @device: A #ClutterInputDevice - * @hardware_keycode: The hardware keycode from a #ClutterKeyEvent - * @evdev_keycode: The return location for the evdev keycode - * - * Translates a hardware keycode from a #ClutterKeyEvent to the - * equivalent evdev keycode. Note that depending on the input backend - * used by Clutter this function can fail if there is no obvious - * mapping between the key codes. The hardware keycode can be taken - * from the #ClutterKeyEvent.hardware_keycode member of #ClutterKeyEvent. - * - * Return value: %TRUE if the conversion succeeded, %FALSE otherwise. - * - * Since: 1.10 - */ -gboolean -clutter_input_device_keycode_to_evdev (ClutterInputDevice *device, - guint hardware_keycode, - guint *evdev_keycode) -{ - ClutterInputDeviceClass *device_class; - - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); - - device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); - if (device_class->keycode_to_evdev == NULL) - return FALSE; - else - return device_class->keycode_to_evdev (device, - hardware_keycode, - evdev_keycode); -} - -void -_clutter_input_device_add_scroll_info (ClutterInputDevice *device, - guint index_, - ClutterScrollDirection direction, - gdouble increment) -{ - ClutterScrollInfo info; - - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - g_return_if_fail (index_ < clutter_input_device_get_n_axes (device)); - - info.axis_id = index_; - info.direction = direction; - info.increment = increment; - info.last_value_valid = FALSE; - - if (device->scroll_info == NULL) - { - device->scroll_info = g_array_new (FALSE, - FALSE, - sizeof (ClutterScrollInfo)); - } - - g_array_append_val (device->scroll_info, info); -} - -gboolean -_clutter_input_device_get_scroll_delta (ClutterInputDevice *device, - guint index_, - gdouble value, - ClutterScrollDirection *direction_p, - gdouble *delta_p) -{ - guint i; - - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); - g_return_val_if_fail (index_ < clutter_input_device_get_n_axes (device), FALSE); - - if (device->scroll_info == NULL) - return FALSE; - - for (i = 0; i < device->scroll_info->len; i++) - { - ClutterScrollInfo *info = &g_array_index (device->scroll_info, - ClutterScrollInfo, - i); - - if (info->axis_id == index_) - { - if (direction_p != NULL) - *direction_p = info->direction; - - if (delta_p != NULL) - *delta_p = 0.0; - - if (info->last_value_valid) - { - if (delta_p != NULL) - { - *delta_p = (value - info->last_value) - / info->increment; - } - - info->last_value = value; - } - else - { - info->last_value = value; - info->last_value_valid = TRUE; - } - - return TRUE; - } - } - - return FALSE; -} - -void -_clutter_input_device_reset_scroll_info (ClutterInputDevice *device) -{ - guint i; - - if (device->scroll_info == NULL) - return; - - for (i = 0; i < device->scroll_info->len; i++) - { - ClutterScrollInfo *info = &g_array_index (device->scroll_info, - ClutterScrollInfo, - i); - - info->last_value_valid = FALSE; - } -} - -static void -on_grab_actor_destroy (ClutterActor *actor, - ClutterInputDevice *device) -{ - switch (device->device_type) - { - case CLUTTER_POINTER_DEVICE: - case CLUTTER_TABLET_DEVICE: - device->pointer_grab_actor = NULL; - break; - - case CLUTTER_KEYBOARD_DEVICE: - device->keyboard_grab_actor = NULL; - break; - - default: - g_assert_not_reached (); - } -} - -/** - * clutter_input_device_grab: - * @device: a #ClutterInputDevice - * @actor: a #ClutterActor - * - * Acquires a grab on @actor for the given @device. - * - * Any event coming from @device will be delivered to @actor, bypassing - * the usual event delivery mechanism, until the grab is released by - * calling clutter_input_device_ungrab(). - * - * The grab is client-side: even if the windowing system used by the Clutter - * backend has the concept of "device grabs", Clutter will not use them. - * - * Only #ClutterInputDevice of types %CLUTTER_POINTER_DEVICE, - * %CLUTTER_TABLET_DEVICE and %CLUTTER_KEYBOARD_DEVICE can hold a grab. - * - * Since: 1.10 - */ -void -clutter_input_device_grab (ClutterInputDevice *device, - ClutterActor *actor) -{ - ClutterActor **grab_actor; - - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - g_return_if_fail (CLUTTER_IS_ACTOR (actor)); - - switch (device->device_type) - { - case CLUTTER_POINTER_DEVICE: - case CLUTTER_TABLET_DEVICE: - grab_actor = &device->pointer_grab_actor; - break; - - case CLUTTER_KEYBOARD_DEVICE: - grab_actor = &device->keyboard_grab_actor; - break; + case CLUTTER_KEYBOARD_DEVICE: + grab_actor = &device->keyboard_grab_actor; + break; default: g_critical ("Only pointer and keyboard devices can grab an actor"); @@ -1853,10 +973,12 @@ void clutter_input_device_ungrab (ClutterInputDevice *device) { ClutterActor **grab_actor; + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - switch (device->device_type) + switch (priv->device_type) { case CLUTTER_POINTER_DEVICE: case CLUTTER_TABLET_DEVICE: @@ -1895,9 +1017,12 @@ clutter_input_device_ungrab (ClutterInputDevice *device) ClutterActor * clutter_input_device_get_grabbed_actor (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); - switch (device->device_type) + switch (priv->device_type) { case CLUTTER_POINTER_DEVICE: case CLUTTER_TABLET_DEVICE: @@ -2062,10 +1187,13 @@ clutter_input_device_sequence_get_grabbed_actor (ClutterInputDevice *device, const gchar * clutter_input_device_get_vendor_id (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_LOGICAL, NULL); - return device->vendor_id; + return priv->vendor_id; } /** @@ -2081,90 +1209,61 @@ clutter_input_device_get_vendor_id (ClutterInputDevice *device) const gchar * clutter_input_device_get_product_id (ClutterInputDevice *device) { - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); - g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_LOGICAL, NULL); - - return device->product_id; -} - -void -clutter_input_device_add_tool (ClutterInputDevice *device, - ClutterInputDeviceTool *tool) -{ - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - g_return_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_LOGICAL); - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool)); - - if (!device->tools) - device->tools = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - - g_ptr_array_add (device->tools, tool); -} - -ClutterInputDeviceTool * -clutter_input_device_lookup_tool (ClutterInputDevice *device, - guint64 serial, - ClutterInputDeviceToolType type) -{ - ClutterInputDeviceTool *tool; - guint i; + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_LOGICAL, NULL); - if (!device->tools) - return NULL; - - for (i = 0; i < device->tools->len; i++) - { - tool = g_ptr_array_index (device->tools, i); - - if (serial == clutter_input_device_tool_get_serial (tool) && - type == clutter_input_device_tool_get_tool_type (tool)) - return tool; - } - - return NULL; + return priv->product_id; } -void -clutter_input_device_update_from_tool (ClutterInputDevice *device, - ClutterInputDeviceTool *tool) +gint +clutter_input_device_get_n_rings (ClutterInputDevice *device) { - ClutterInputDeviceClass *device_class; + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - - device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); - if (device_class->update_from_tool) - device_class->update_from_tool (device, tool); + return priv->n_rings; } gint -clutter_input_device_get_n_rings (ClutterInputDevice *device) +clutter_input_device_get_n_strips (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); - return device->n_rings; + return priv->n_strips; } gint -clutter_input_device_get_n_strips (ClutterInputDevice *device) +clutter_input_device_get_n_mode_groups (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); + g_return_val_if_fail (clutter_input_device_get_device_type (device) == + CLUTTER_PAD_DEVICE, 0); - return device->n_strips; + return priv->n_mode_groups; } gint -clutter_input_device_get_n_mode_groups (ClutterInputDevice *device) +clutter_input_device_get_n_buttons (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, 0); - return device->n_mode_groups; + return priv->n_buttons; } gint @@ -2209,13 +1308,15 @@ gint clutter_input_device_get_mode_switch_button_group (ClutterInputDevice *device, guint button) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); gint group; g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), -1); g_return_val_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE, -1); - for (group = 0; group < device->n_mode_groups; group++) + for (group = 0; group < priv->n_mode_groups; group++) { if (clutter_input_device_is_mode_switch_button (device, group, button)) return group; @@ -2224,12 +1325,31 @@ clutter_input_device_get_mode_switch_button_group (ClutterInputDevice *device, return -1; } +int +clutter_input_device_get_pad_feature_group (ClutterInputDevice *device, + ClutterInputDevicePadFeature feature, + int n_feature) +{ + ClutterInputDeviceClass *device_class; + + device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); + if (!device_class->get_pad_feature_group) + return 0; + + return CLUTTER_INPUT_DEVICE_GET_CLASS (device)->get_pad_feature_group (device, + feature, + n_feature); +} + const gchar * clutter_input_device_get_device_node (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); - return device->node_path; + return priv->node_path; } gboolean @@ -2253,7 +1373,10 @@ clutter_input_device_is_grouped (ClutterInputDevice *device, ClutterSeat * clutter_input_device_get_seat (ClutterInputDevice *device) { + ClutterInputDevicePrivate *priv = + clutter_input_device_get_instance_private (device); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); - return device->seat; + return priv->seat; } diff --git a/clutter/clutter/clutter-input-device.h b/clutter/clutter/clutter-input-device.h index 51f67583c9b9f982395c8301527d29bfeb78cab8..5e377cdcc193ebffa0c963c5d116f3b1728d9170 100644 --- a/clutter/clutter/clutter-input-device.h +++ b/clutter/clutter/clutter-input-device.h @@ -34,19 +34,10 @@ G_BEGIN_DECLS -typedef void (*ClutterEmitInputDeviceEvent) (ClutterEvent *event, - ClutterInputDevice *device); - struct _ClutterInputDeviceClass { GObjectClass parent_class; - gboolean (* keycode_to_evdev) (ClutterInputDevice *device, - guint hardware_keycode, - guint *evdev_keycode); - void (* update_from_tool) (ClutterInputDevice *device, - ClutterInputDeviceTool *tool); - gboolean (* is_mode_switch_button) (ClutterInputDevice *device, guint group, guint button); @@ -56,10 +47,9 @@ struct _ClutterInputDeviceClass gboolean (* is_grouped) (ClutterInputDevice *device, ClutterInputDevice *other_device); - /* Keyboard accessbility */ - void (* process_kbd_a11y_event) (ClutterEvent *event, - ClutterInputDevice *device, - ClutterEmitInputDeviceEvent emit_event_func); + int (* get_pad_feature_group) (ClutterInputDevice *device, + ClutterInputDevicePadFeature feature, + int n_feature); }; #define CLUTTER_TYPE_INPUT_DEVICE (clutter_input_device_get_type ()) @@ -83,12 +73,6 @@ GType clutter_input_device_get_type (void) G_GNUC_CONST; CLUTTER_EXPORT ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device); -CLUTTER_EXPORT -gboolean clutter_input_device_get_coords (ClutterInputDevice *device, - ClutterEventSequence *sequence, - graphene_point_t *point); -CLUTTER_EXPORT -ClutterModifierType clutter_input_device_get_modifier_state (ClutterInputDevice *device); CLUTTER_EXPORT ClutterActor * clutter_input_device_get_actor (ClutterInputDevice *device, ClutterEventSequence *sequence); @@ -98,11 +82,6 @@ CLUTTER_EXPORT ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDevice *device); CLUTTER_EXPORT gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device); -CLUTTER_EXPORT -void clutter_input_device_set_enabled (ClutterInputDevice *device, - gboolean enabled); -CLUTTER_EXPORT -gboolean clutter_input_device_get_enabled (ClutterInputDevice *device); CLUTTER_EXPORT guint clutter_input_device_get_n_axes (ClutterInputDevice *device); @@ -115,19 +94,6 @@ gboolean clutter_input_device_get_axis_value (ClutterInputDev ClutterInputAxis axis, gdouble *value); -CLUTTER_EXPORT -guint clutter_input_device_get_n_keys (ClutterInputDevice *device); -CLUTTER_EXPORT -gboolean clutter_input_device_get_key (ClutterInputDevice *device, - guint index_, - guint *keyval, - ClutterModifierType *modifiers); - -CLUTTER_EXPORT -ClutterInputDevice * clutter_input_device_get_associated_device (ClutterInputDevice *device); -CLUTTER_EXPORT -GList * clutter_input_device_get_physical_devices (ClutterInputDevice *device); - CLUTTER_EXPORT void clutter_input_device_grab (ClutterInputDevice *device, ClutterActor *actor); @@ -158,6 +124,9 @@ CLUTTER_EXPORT gint clutter_input_device_get_n_strips (ClutterInputDevice *device); CLUTTER_EXPORT gint clutter_input_device_get_n_mode_groups (ClutterInputDevice *device); +CLUTTER_EXPORT +int clutter_input_device_get_n_buttons (ClutterInputDevice *device); + CLUTTER_EXPORT gint clutter_input_device_get_group_n_modes (ClutterInputDevice *device, @@ -180,6 +149,11 @@ gboolean clutter_input_device_is_grouped (ClutterInputDev CLUTTER_EXPORT ClutterSeat * clutter_input_device_get_seat (ClutterInputDevice *device); +CLUTTER_EXPORT +int clutter_input_device_get_pad_feature_group (ClutterInputDevice *device, + ClutterInputDevicePadFeature feature, + int n_feature); + G_END_DECLS #endif /* __CLUTTER_INPUT_DEVICE_H__ */ diff --git a/clutter/clutter/clutter-input-pointer-a11y.c b/clutter/clutter/clutter-input-pointer-a11y.c index b57ee81c0861df805446a7cbd8f7d104c8fe4bfb..365b85fd6372f20353aa73dad385aa9c15a22668 100644 --- a/clutter/clutter/clutter-input-pointer-a11y.c +++ b/clutter/clutter/clutter-input-pointer-a11y.c @@ -36,8 +36,9 @@ static gboolean is_secondary_click_enabled (ClutterInputDevice *device) { ClutterPointerA11ySettings settings; + ClutterSeat *seat = clutter_input_device_get_seat (device); - clutter_seat_get_pointer_a11y_settings (device->seat, &settings); + clutter_seat_get_pointer_a11y_settings (seat, &settings); return (settings.controls & CLUTTER_A11Y_SECONDARY_CLICK_ENABLED); } @@ -46,8 +47,9 @@ static gboolean is_dwell_click_enabled (ClutterInputDevice *device) { ClutterPointerA11ySettings settings; + ClutterSeat *seat = clutter_input_device_get_seat (device); - clutter_seat_get_pointer_a11y_settings (device->seat, &settings); + clutter_seat_get_pointer_a11y_settings (seat, &settings); return (settings.controls & CLUTTER_A11Y_DWELL_ENABLED); } @@ -56,8 +58,9 @@ static unsigned int get_secondary_click_delay (ClutterInputDevice *device) { ClutterPointerA11ySettings settings; + ClutterSeat *seat = clutter_input_device_get_seat (device); - clutter_seat_get_pointer_a11y_settings (device->seat, &settings); + clutter_seat_get_pointer_a11y_settings (seat, &settings); return settings.secondary_click_delay; } @@ -66,8 +69,9 @@ static unsigned int get_dwell_delay (ClutterInputDevice *device) { ClutterPointerA11ySettings settings; + ClutterSeat *seat = clutter_input_device_get_seat (device); - clutter_seat_get_pointer_a11y_settings (device->seat, &settings); + clutter_seat_get_pointer_a11y_settings (seat, &settings); return settings.dwell_delay; } @@ -76,8 +80,9 @@ static unsigned int get_dwell_threshold (ClutterInputDevice *device) { ClutterPointerA11ySettings settings; + ClutterSeat *seat = clutter_input_device_get_seat (device); - clutter_seat_get_pointer_a11y_settings (device->seat, &settings); + clutter_seat_get_pointer_a11y_settings (seat, &settings); return settings.dwell_threshold; } @@ -86,8 +91,9 @@ static ClutterPointerA11yDwellMode get_dwell_mode (ClutterInputDevice *device) { ClutterPointerA11ySettings settings; + ClutterSeat *seat = clutter_input_device_get_seat (device); - clutter_seat_get_pointer_a11y_settings (device->seat, &settings); + clutter_seat_get_pointer_a11y_settings (seat, &settings); return settings.dwell_mode; } @@ -96,8 +102,9 @@ static ClutterPointerA11yDwellClickType get_dwell_click_type (ClutterInputDevice *device) { ClutterPointerA11ySettings settings; + ClutterSeat *seat = clutter_input_device_get_seat (device); - clutter_seat_get_pointer_a11y_settings (device->seat, &settings); + clutter_seat_get_pointer_a11y_settings (seat, &settings); return settings.dwell_click_type; } @@ -107,8 +114,9 @@ get_dwell_click_type_for_direction (ClutterInputDevice *device, ClutterPointerA11yDwellDirection direction) { ClutterPointerA11ySettings settings; + ClutterSeat *seat = clutter_input_device_get_seat (device); - clutter_seat_get_pointer_a11y_settings (device->seat, &settings); + clutter_seat_get_pointer_a11y_settings (seat, &settings); if (direction == settings.dwell_gesture_single) return CLUTTER_A11Y_DWELL_CLICK_TYPE_PRIMARY; @@ -163,11 +171,12 @@ static gboolean trigger_secondary_click (gpointer data) { ClutterInputDevice *device = data; + ClutterSeat *seat = clutter_input_device_get_seat (device); device->ptr_a11y_data->secondary_click_triggered = TRUE; device->ptr_a11y_data->secondary_click_timer = 0; - g_signal_emit_by_name (device->seat, + g_signal_emit_by_name (seat, "ptr-a11y-timeout-stopped", device, CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK, @@ -180,11 +189,12 @@ static void start_secondary_click_timeout (ClutterInputDevice *device) { unsigned int delay = get_secondary_click_delay (device); + ClutterSeat *seat = clutter_input_device_get_seat (device); device->ptr_a11y_data->secondary_click_timer = clutter_threads_add_timeout (delay, trigger_secondary_click, device); - g_signal_emit_by_name (device->seat, + g_signal_emit_by_name (seat, "ptr-a11y-timeout-started", device, CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK, @@ -194,12 +204,14 @@ start_secondary_click_timeout (ClutterInputDevice *device) static void stop_secondary_click_timeout (ClutterInputDevice *device) { + ClutterSeat *seat = clutter_input_device_get_seat (device); + if (device->ptr_a11y_data->secondary_click_timer) { g_clear_handle_id (&device->ptr_a11y_data->secondary_click_timer, g_source_remove); - g_signal_emit_by_name (device->seat, + g_signal_emit_by_name (seat, "ptr-a11y-timeout-stopped", device, CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK, @@ -302,8 +314,9 @@ update_dwell_click_type (ClutterInputDevice *device) { ClutterPointerA11ySettings settings; ClutterPointerA11yDwellClickType dwell_click_type; + ClutterSeat *seat = clutter_input_device_get_seat (device); - clutter_seat_get_pointer_a11y_settings (device->seat, &settings); + clutter_seat_get_pointer_a11y_settings (seat, &settings); dwell_click_type = settings.dwell_click_type; switch (dwell_click_type) @@ -328,9 +341,9 @@ update_dwell_click_type (ClutterInputDevice *device) if (dwell_click_type != settings.dwell_click_type) { settings.dwell_click_type = dwell_click_type; - clutter_seat_set_pointer_a11y_settings (device->seat, &settings); + clutter_seat_set_pointer_a11y_settings (seat, &settings); - g_signal_emit_by_name (device->seat, + g_signal_emit_by_name (seat, "ptr-a11y-dwell-click-type-changed", dwell_click_type); } @@ -424,6 +437,7 @@ trigger_dwell_gesture (gpointer data) ClutterInputDevice *device = data; ClutterPointerA11yDwellDirection direction; unsigned int delay = get_dwell_delay (device); + ClutterSeat *seat = clutter_input_device_get_seat (device); restore_dwell_position (device); direction = get_dwell_direction (device); @@ -435,7 +449,7 @@ trigger_dwell_gesture (gpointer data) device->ptr_a11y_data->dwell_timer = clutter_threads_add_timeout (delay, trigger_clear_dwell_gesture, device); - g_signal_emit_by_name (device->seat, + g_signal_emit_by_name (seat, "ptr-a11y-timeout-stopped", device, CLUTTER_A11Y_TIMEOUT_TYPE_GESTURE, @@ -448,12 +462,13 @@ static void start_dwell_gesture_timeout (ClutterInputDevice *device) { unsigned int delay = get_dwell_delay (device); + ClutterSeat *seat = clutter_input_device_get_seat (device); device->ptr_a11y_data->dwell_timer = clutter_threads_add_timeout (delay, trigger_dwell_gesture, device); device->ptr_a11y_data->dwell_gesture_started = TRUE; - g_signal_emit_by_name (device->seat, + g_signal_emit_by_name (seat, "ptr-a11y-timeout-started", device, CLUTTER_A11Y_TIMEOUT_TYPE_GESTURE, @@ -464,10 +479,11 @@ static gboolean trigger_dwell_click (gpointer data) { ClutterInputDevice *device = data; + ClutterSeat *seat = clutter_input_device_get_seat (device); device->ptr_a11y_data->dwell_timer = 0; - g_signal_emit_by_name (device->seat, + g_signal_emit_by_name (seat, "ptr-a11y-timeout-stopped", device, CLUTTER_A11Y_TIMEOUT_TYPE_DWELL, @@ -493,11 +509,12 @@ static void start_dwell_timeout (ClutterInputDevice *device) { unsigned int delay = get_dwell_delay (device); + ClutterSeat *seat = clutter_input_device_get_seat (device); device->ptr_a11y_data->dwell_timer = clutter_threads_add_timeout (delay, trigger_dwell_click, device); - g_signal_emit_by_name (device->seat, + g_signal_emit_by_name (seat, "ptr-a11y-timeout-started", device, CLUTTER_A11Y_TIMEOUT_TYPE_DWELL, @@ -507,12 +524,14 @@ start_dwell_timeout (ClutterInputDevice *device) static void stop_dwell_timeout (ClutterInputDevice *device) { + ClutterSeat *seat = clutter_input_device_get_seat (device); + if (device->ptr_a11y_data->dwell_timer) { g_clear_handle_id (&device->ptr_a11y_data->dwell_timer, g_source_remove); device->ptr_a11y_data->dwell_gesture_started = FALSE; - g_signal_emit_by_name (device->seat, + g_signal_emit_by_name (seat, "ptr-a11y-timeout-stopped", device, CLUTTER_A11Y_TIMEOUT_TYPE_DWELL, @@ -570,8 +589,9 @@ static gboolean is_device_core_pointer (ClutterInputDevice *device) { ClutterInputDevice *core_pointer; + ClutterSeat *seat = clutter_input_device_get_seat (device); - core_pointer = clutter_seat_get_pointer (device->seat); + core_pointer = clutter_seat_get_pointer (seat); if (core_pointer == NULL) return FALSE; @@ -581,11 +601,13 @@ is_device_core_pointer (ClutterInputDevice *device) void _clutter_input_pointer_a11y_add_device (ClutterInputDevice *device) { + ClutterSeat *seat = clutter_input_device_get_seat (device); + if (!is_device_core_pointer (device)) return; device->accessibility_virtual_device = - clutter_seat_create_virtual_device (device->seat, + clutter_seat_create_virtual_device (seat, CLUTTER_POINTER_DEVICE); device->ptr_a11y_data = g_new0 (ClutterPtrA11yData, 1); diff --git a/clutter/clutter/clutter-main.c b/clutter/clutter/clutter-main.c index 0606d2e4a1bdcf176931f7f3d1763e80ee0ddd25..e21d3d3fa04022ff963646c6b9cf8830ae9bcb49 100644 --- a/clutter/clutter/clutter-main.c +++ b/clutter/clutter/clutter-main.c @@ -697,6 +697,8 @@ _clutter_context_get_default (void) ctx->settings = clutter_settings_get_default (); _clutter_settings_set_backend (ctx->settings, ctx->backend); + ctx->events_queue = g_async_queue_new (); + ctx->last_repaint_id = 1; } @@ -1486,8 +1488,8 @@ emit_touch_event (ClutterEvent *event, } static inline void -emit_keyboard_event (ClutterEvent *event, - ClutterInputDevice *device) +process_key_event (ClutterEvent *event, + ClutterInputDevice *device) { if (_clutter_event_process_filters (event)) return; @@ -1498,21 +1500,6 @@ emit_keyboard_event (ClutterEvent *event, emit_event_chain (event); } -static inline void -process_key_event (ClutterEvent *event, - ClutterInputDevice *device) -{ - ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device); - - if (device_class->process_kbd_a11y_event) - { - device_class->process_kbd_a11y_event (event, device, emit_keyboard_event); - return; - } - - emit_keyboard_event (event, device); -} - static gboolean is_off_stage (ClutterActor *stage, gfloat x, @@ -1626,7 +1613,7 @@ _clutter_process_event_details (ClutterActor *stage, actor = clutter_input_device_update (device, NULL, CLUTTER_STAGE (stage), FALSE, - clutter_event_get_time (event)); + event); if (actor != stage) { ClutterEvent *crossing; @@ -1777,8 +1764,7 @@ _clutter_process_event_details (ClutterActor *stage, actor = clutter_input_device_update (device, NULL, CLUTTER_STAGE (stage), - TRUE, - clutter_event_get_time (event)); + TRUE, event); if (actor == NULL) break; @@ -1854,9 +1840,6 @@ _clutter_process_event_details (ClutterActor *stage, sequence = clutter_event_get_event_sequence (event); - if (event->type == CLUTTER_TOUCH_BEGIN) - _clutter_input_device_add_event_sequence (device, event); - clutter_event_get_coords (event, &x, &y); /* Only do a pick to find the source if source is not already set @@ -1888,8 +1871,7 @@ _clutter_process_event_details (ClutterActor *stage, actor = clutter_input_device_update (device, sequence, CLUTTER_STAGE (stage), - TRUE, - clutter_event_get_time (event)); + TRUE, event); if (actor == NULL) break; @@ -1917,9 +1899,6 @@ _clutter_process_event_details (ClutterActor *stage, case CLUTTER_PROXIMITY_IN: case CLUTTER_PROXIMITY_OUT: - clutter_input_device_update_from_tool (clutter_event_get_source_device (event), - clutter_event_get_device_tool (event)); - if (_clutter_event_process_filters (event)) break; @@ -1943,13 +1922,7 @@ _clutter_process_event_details (ClutterActor *stage, case CLUTTER_DEVICE_ADDED: case CLUTTER_DEVICE_REMOVED: - if (!_clutter_event_process_filters (event)) - { - ClutterSeat *seat; - - seat = clutter_backend_get_default_seat (context->backend); - clutter_seat_handle_device_event (seat, event); - } + _clutter_event_process_filters (event); break; case CLUTTER_EVENT_LAST: @@ -2300,15 +2273,22 @@ void _clutter_clear_events_queue (void) { ClutterMainContext *context = _clutter_context_get_default (); + ClutterEvent *event; + GAsyncQueue *events_queue; - if (context->events_queue != NULL) - { - g_queue_foreach (context->events_queue, - (GFunc) clutter_event_free, - NULL); - g_queue_free (context->events_queue); - context->events_queue = NULL; - } + if (!context->events_queue) + return; + + g_async_queue_lock (context->events_queue); + + while ((event = g_async_queue_try_pop_unlocked (context->events_queue))) + clutter_event_free (event); + + events_queue = context->events_queue; + context->events_queue = NULL; + + g_async_queue_unlock (events_queue); + g_async_queue_unref (events_queue); } /** diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h index 654c6dac0ede3b0e5fc4dc13156d251288463914..9c75ad6a25665bc1d88b6fd082d00d0f99813afb 100644 --- a/clutter/clutter/clutter-mutter.h +++ b/clutter/clutter/clutter-mutter.h @@ -71,6 +71,9 @@ gboolean clutter_actor_has_transitions (ClutterActor *actor); CLUTTER_EXPORT ClutterFrameClock * clutter_actor_pick_frame_clock (ClutterActor *self, ClutterActor **out_actor); +CLUTTER_EXPORT +gboolean clutter_seat_handle_event_post (ClutterSeat *seat, + const ClutterEvent *event); #undef __CLUTTER_H_INSIDE__ diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h index 08a8c3f8c276e9839482d0fd69412a98b037eb2e..4c6f32282b935109df5329f5504b2acc3d7f2432 100644 --- a/clutter/clutter/clutter-private.h +++ b/clutter/clutter/clutter-private.h @@ -121,7 +121,7 @@ struct _ClutterMainContext ClutterStageManager *stage_manager; /* the main event queue */ - GQueue *events_queue; + GAsyncQueue *events_queue; /* the event filters added via clutter_event_add_filter. these are * ordered from least recently added to most recently added */ diff --git a/clutter/clutter/clutter-seat.c b/clutter/clutter/clutter-seat.c index 96bb0e9303e8ba93d371464df2add4e81cca7cd3..f4309787c562b9949bf37f77a1a4650919530579 100644 --- a/clutter/clutter/clutter-seat.c +++ b/clutter/clutter/clutter-seat.c @@ -27,6 +27,7 @@ #include "clutter-input-device-tool.h" #include "clutter-input-pointer-a11y-private.h" #include "clutter-marshal.h" +#include "clutter-mutter.h" #include "clutter-private.h" #include "clutter-seat.h" #include "clutter-virtual-input-device.h" @@ -35,7 +36,6 @@ enum { DEVICE_ADDED, DEVICE_REMOVED, - TOOL_CHANGED, KBD_A11Y_MASK_CHANGED, KBD_A11Y_FLAGS_CHANGED, PTR_A11Y_DWELL_CLICK_TYPE_CHANGED, @@ -65,9 +65,6 @@ struct _ClutterSeatPrivate unsigned int inhibit_unfocus_count; - /* Keyboard a11y */ - ClutterKbdA11ySettings kbd_a11y_settings; - /* Pointer a11y */ ClutterPointerA11ySettings pointer_a11y_settings; }; @@ -151,18 +148,6 @@ clutter_seat_class_init (ClutterSeatClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 1, CLUTTER_TYPE_INPUT_DEVICE); - signals[TOOL_CHANGED] = - g_signal_new (I_("tool-changed"), - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, - _clutter_marshal_VOID__OBJECT_OBJECT, - G_TYPE_NONE, 2, - CLUTTER_TYPE_INPUT_DEVICE, - CLUTTER_TYPE_INPUT_DEVICE_TOOL); - g_signal_set_va_marshaller (signals[TOOL_CHANGED], - G_TYPE_FROM_CLASS (object_class), - _clutter_marshal_VOID__OBJECT_OBJECTv); /** * ClutterSeat::kbd-a11y-mods-state-changed: @@ -404,43 +389,6 @@ clutter_seat_get_keymap (ClutterSeat *seat) return CLUTTER_SEAT_GET_CLASS (seat)->get_keymap (seat); } -static gboolean -are_kbd_a11y_settings_equal (ClutterKbdA11ySettings *a, - ClutterKbdA11ySettings *b) -{ - return (memcmp (a, b, sizeof (ClutterKbdA11ySettings)) == 0); -} - -void -clutter_seat_set_kbd_a11y_settings (ClutterSeat *seat, - ClutterKbdA11ySettings *settings) -{ - ClutterSeatClass *seat_class; - ClutterSeatPrivate *priv = clutter_seat_get_instance_private (seat); - - g_return_if_fail (CLUTTER_IS_SEAT (seat)); - - if (are_kbd_a11y_settings_equal (&priv->kbd_a11y_settings, settings)) - return; - - priv->kbd_a11y_settings = *settings; - - seat_class = CLUTTER_SEAT_GET_CLASS (seat); - if (seat_class->apply_kbd_a11y_settings) - seat_class->apply_kbd_a11y_settings (seat, settings); -} - -void -clutter_seat_get_kbd_a11y_settings (ClutterSeat *seat, - ClutterKbdA11ySettings *settings) -{ - ClutterSeatPrivate *priv = clutter_seat_get_instance_private (seat); - - g_return_if_fail (CLUTTER_IS_SEAT (seat)); - - *settings = priv->kbd_a11y_settings; -} - void clutter_seat_ensure_a11y_state (ClutterSeat *seat) { @@ -675,8 +623,8 @@ clutter_seat_compress_motion (ClutterSeat *seat, } gboolean -clutter_seat_handle_device_event (ClutterSeat *seat, - ClutterEvent *event) +clutter_seat_handle_event_post (ClutterSeat *seat, + const ClutterEvent *event) { ClutterSeatClass *seat_class; ClutterInputDevice *device; @@ -684,16 +632,10 @@ clutter_seat_handle_device_event (ClutterSeat *seat, g_return_val_if_fail (CLUTTER_IS_SEAT (seat), FALSE); g_return_val_if_fail (event, FALSE); - g_assert (event->type == CLUTTER_DEVICE_ADDED || - event->type == CLUTTER_DEVICE_REMOVED); - seat_class = CLUTTER_SEAT_GET_CLASS (seat); - if (seat_class->handle_device_event) - { - if (!seat_class->handle_device_event (seat, event)) - return FALSE; - } + if (seat_class->handle_event_post) + seat_class->handle_event_post (seat, event); device = clutter_event_get_source_device (event); g_assert_true (CLUTTER_IS_INPUT_DEVICE (device)); @@ -776,3 +718,20 @@ clutter_seat_has_touchscreen (ClutterSeat *seat) return has_touchscreen; } + +gboolean +clutter_seat_query_state (ClutterSeat *seat, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t *coords, + ClutterModifierType *modifiers) +{ + g_return_val_if_fail (CLUTTER_IS_SEAT (seat), FALSE); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE); + + return CLUTTER_SEAT_GET_CLASS (seat)->query_state (seat, + device, + sequence, + coords, + modifiers); +} diff --git a/clutter/clutter/clutter-seat.h b/clutter/clutter/clutter-seat.h index 33497a43fc93f7049b1eda10166e84c685db782f..6ef748fddd00a2d381b69a3cb414644f6e6c3f7a 100644 --- a/clutter/clutter/clutter-seat.h +++ b/clutter/clutter/clutter-seat.h @@ -37,24 +37,6 @@ CLUTTER_EXPORT G_DECLARE_DERIVABLE_TYPE (ClutterSeat, clutter_seat, CLUTTER, SEAT, GObject) -/** - * ClutterKbdA11ySettings: - * - * The #ClutterKbdA11ySettings structure contains keyboard accessibility - * settings - * - */ -typedef struct _ClutterKbdA11ySettings -{ - ClutterKeyboardA11yFlags controls; - gint slowkeys_delay; - gint debounce_delay; - gint timeout_delay; - gint mousekeys_init_delay; - gint mousekeys_max_speed; - gint mousekeys_accel_time; -} ClutterKbdA11ySettings; - /** * ClutterPointerA11ySettings: * @@ -106,13 +88,19 @@ struct _ClutterSeatClass ClutterEvent *event, const ClutterEvent *to_discard); - gboolean (* handle_device_event) (ClutterSeat *seat, - ClutterEvent *event); + gboolean (* handle_event_post) (ClutterSeat *seat, + const ClutterEvent *event); void (* warp_pointer) (ClutterSeat *seat, int x, int y); + gboolean (* query_state) (ClutterSeat *seat, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t *coords, + ClutterModifierType *modifiers); + /* Event platform data */ void (* copy_event_data) (ClutterSeat *seat, const ClutterEvent *src, @@ -120,10 +108,6 @@ struct _ClutterSeatClass void (* free_event_data) (ClutterSeat *seat, ClutterEvent *event); - /* Keyboard accessibility */ - void (* apply_kbd_a11y_settings) (ClutterSeat *seat, - ClutterKbdA11ySettings *settings); - /* Virtual devices */ ClutterVirtualInputDevice * (* create_virtual_device) (ClutterSeat *seat, ClutterInputDeviceType device_type); @@ -143,12 +127,6 @@ void clutter_seat_bell_notify (ClutterSeat *seat); CLUTTER_EXPORT ClutterKeymap * clutter_seat_get_keymap (ClutterSeat *seat); -CLUTTER_EXPORT -void clutter_seat_set_kbd_a11y_settings (ClutterSeat *seat, - ClutterKbdA11ySettings *settings); -CLUTTER_EXPORT -void clutter_seat_get_kbd_a11y_settings (ClutterSeat *seat, - ClutterKbdA11ySettings *settings); CLUTTER_EXPORT void clutter_seat_ensure_a11y_state (ClutterSeat *seat); @@ -184,9 +162,6 @@ void clutter_seat_compress_motion (ClutterSeat *seat, ClutterEvent *event, const ClutterEvent *to_discard); -gboolean clutter_seat_handle_device_event (ClutterSeat *seat, - ClutterEvent *event); - CLUTTER_EXPORT void clutter_seat_warp_pointer (ClutterSeat *seat, int x, @@ -197,4 +172,11 @@ gboolean clutter_seat_get_touch_mode (ClutterSeat *seat); CLUTTER_EXPORT gboolean clutter_seat_has_touchscreen (ClutterSeat *seat); +CLUTTER_EXPORT +gboolean clutter_seat_query_state (ClutterSeat *seat, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t *coords, + ClutterModifierType *modifiers); + #endif /* CLUTTER_SEAT_H */ diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index f4277803257264edabcf35233e412a1f8a97aa25..a7261d36dd084eba657ec61a5707f6d586fc0311 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -648,7 +648,6 @@ _clutter_stage_queue_event (ClutterStage *stage, { ClutterStagePrivate *priv; gboolean first_event; - ClutterInputDevice *device; g_return_if_fail (CLUTTER_IS_STAGE (stage)); @@ -659,23 +658,6 @@ _clutter_stage_queue_event (ClutterStage *stage, if (copy_event) event = clutter_event_copy (event); - /* if needed, update the state of the input device of the event. - * we do it here to avoid calling the same code from every backend - * event processing function - */ - device = clutter_event_get_device (event); - if (device != NULL && - event->type != CLUTTER_PROXIMITY_IN && - event->type != CLUTTER_PROXIMITY_OUT) - { - ClutterEventSequence *sequence = clutter_event_get_event_sequence (event); - gfloat event_x, event_y; - - clutter_event_get_coords (event, &event_x, &event_y); - - _clutter_input_device_set_coords (device, sequence, event_x, event_y); - } - if (first_event) { gboolean compressible = event->type == CLUTTER_MOTION || @@ -927,7 +909,8 @@ clutter_stage_find_updated_devices (ClutterStage *stage) case CLUTTER_PEN_DEVICE: case CLUTTER_ERASER_DEVICE: case CLUTTER_CURSOR_DEVICE: - if (!clutter_input_device_get_coords (dev, NULL, &point)) + if (!clutter_seat_query_state (seat, dev, NULL, + &point, NULL)) continue; view = clutter_stage_get_view_at (stage, point.x, point.y); @@ -996,8 +979,7 @@ clutter_stage_update_devices (ClutterStage *stage, for (l = devices; l; l = l->next) { ClutterInputDevice *device = l->data; - clutter_input_device_update (device, NULL, stage, TRUE, - CLUTTER_CURRENT_TIME); + clutter_input_device_update (device, NULL, stage, TRUE, NULL); } } diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h index 0b62ed4bf2e32000a32489d175e78e75058977b4..80df654bc679e4abc819e1188d3093488e5dd89a 100644 --- a/src/backends/meta-backend-private.h +++ b/src/backends/meta-backend-private.h @@ -34,6 +34,7 @@ #include "backends/meta-backend-types.h" #include "backends/meta-cursor-renderer.h" #include "backends/meta-egl.h" +#include "backends/meta-input-mapper-private.h" #include "backends/meta-input-settings-private.h" #include "backends/meta-monitor-manager-private.h" #include "backends/meta-orientation-manager.h" @@ -63,11 +64,12 @@ struct _MetaBackendClass MetaMonitorManager * (* create_monitor_manager) (MetaBackend *backend, GError **error); - MetaCursorRenderer * (* create_cursor_renderer) (MetaBackend *backend); + MetaCursorRenderer * (* get_cursor_renderer) (MetaBackend *backend, + ClutterInputDevice *device); MetaCursorTracker * (* create_cursor_tracker) (MetaBackend *backend); MetaRenderer * (* create_renderer) (MetaBackend *backend, GError **error); - MetaInputSettings * (* create_input_settings) (MetaBackend *backend); + MetaInputSettings * (* get_input_settings) (MetaBackend *backend); gboolean (* grab_device) (MetaBackend *backend, int device_id, @@ -98,9 +100,8 @@ struct _MetaBackendClass void (* update_screen_size) (MetaBackend *backend, int width, int height); void (* select_stage_events) (MetaBackend *backend); - void (* set_numlock) (MetaBackend *backend, - gboolean numlock_state); - + void (* set_pointer_constraint) (MetaBackend *backend, + MetaPointerConstraint *constraint); }; void meta_init_backend (GType backend_gtype); @@ -126,6 +127,8 @@ META_EXPORT_TEST MetaMonitorManager * meta_backend_get_monitor_manager (MetaBackend *backend); MetaOrientationManager * meta_backend_get_orientation_manager (MetaBackend *backend); MetaCursorTracker * meta_backend_get_cursor_tracker (MetaBackend *backend); +MetaCursorRenderer * meta_backend_get_cursor_renderer_for_device (MetaBackend *backend, + ClutterInputDevice *device); MetaCursorRenderer * meta_backend_get_cursor_renderer (MetaBackend *backend); META_EXPORT_TEST MetaRenderer * meta_backend_get_renderer (MetaBackend *backend); @@ -170,6 +173,7 @@ gboolean meta_is_stage_views_enabled (void); gboolean meta_is_stage_views_scaled (void); +MetaInputMapper *meta_backend_get_input_mapper (MetaBackend *backend); MetaInputSettings *meta_backend_get_input_settings (MetaBackend *backend); void meta_backend_notify_keymap_changed (MetaBackend *backend); @@ -190,4 +194,12 @@ GList * meta_backend_get_gpus (MetaBackend *backend); WacomDeviceDatabase * meta_backend_get_wacom_database (MetaBackend *backend); #endif +void meta_backend_add_hw_cursor_inhibitor (MetaBackend *backend, + MetaHwCursorInhibitor *inhibitor); + +void meta_backend_remove_hw_cursor_inhibitor (MetaBackend *backend, + MetaHwCursorInhibitor *inhibitor); + +gboolean meta_backend_is_hw_cursors_inhibited (MetaBackend *backend); + #endif /* META_BACKEND_PRIVATE_H */ diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 1770ad795a97490826a7f0a9f8a4d5a53c7a903a..aca0d6fc995f8266b44ff3d80454c0592bdd10f5 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -53,8 +53,10 @@ #include +#include "backends/meta-cursor-renderer.h" #include "backends/meta-cursor-tracker-private.h" #include "backends/meta-idle-monitor-private.h" +#include "backends/meta-input-mapper-private.h" #include "backends/meta-input-settings-private.h" #include "backends/meta-logical-monitor.h" #include "backends/meta-monitor-manager-dummy.h" @@ -120,8 +122,7 @@ struct _MetaBackendPrivate MetaMonitorManager *monitor_manager; MetaOrientationManager *orientation_manager; MetaCursorTracker *cursor_tracker; - MetaCursorRenderer *cursor_renderer; - MetaInputSettings *input_settings; + MetaInputMapper *input_mapper; MetaRenderer *renderer; #ifdef HAVE_EGL MetaEgl *egl; @@ -150,11 +151,11 @@ struct _MetaBackendPrivate ClutterActor *stage; GList *gpus; + GList *hw_cursor_inhibitors; gboolean is_pointer_position_initialized; guint device_update_idle_id; - gulong keymap_state_changed_id; GHashTable *device_monitors; @@ -173,6 +174,14 @@ struct _MetaBackendPrivate }; typedef struct _MetaBackendPrivate MetaBackendPrivate; +typedef struct _MetaBackendSource MetaBackendSource; + +struct _MetaBackendSource +{ + GSource parent; + MetaBackend *backend; +}; + static void initable_iface_init (GInitableIface *initable_iface); @@ -187,22 +196,11 @@ meta_backend_finalize (GObject *object) MetaBackend *backend = META_BACKEND (object); MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); - if (priv->keymap_state_changed_id) - { - ClutterSeat *seat; - ClutterKeymap *keymap; - - seat = clutter_backend_get_default_seat (priv->clutter_backend); - keymap = clutter_seat_get_keymap (seat); - g_clear_signal_handler (&priv->keymap_state_changed_id, keymap); - } - g_list_free_full (priv->gpus, g_object_unref); g_clear_object (&priv->current_device); g_clear_object (&priv->monitor_manager); g_clear_object (&priv->orientation_manager); - g_clear_object (&priv->input_settings); #ifdef HAVE_REMOTE_DESKTOP g_clear_object (&priv->remote_desktop); g_clear_object (&priv->screen_cast); @@ -233,6 +231,8 @@ meta_backend_finalize (GObject *object) g_clear_object (&priv->profiler); #endif + g_clear_object (&priv->clutter_backend); + G_OBJECT_CLASS (meta_backend_parent_class)->finalize (object); } @@ -265,6 +265,53 @@ reset_pointer_position (MetaBackend *backend) primary->rect.y + primary->rect.height * 0.9); } +static gboolean +should_have_cursor_renderer (ClutterInputDevice *device) +{ + switch (clutter_input_device_get_device_type (device)) + { + case CLUTTER_POINTER_DEVICE: + if (clutter_input_device_get_device_mode (device) == + CLUTTER_INPUT_MODE_LOGICAL) + return TRUE; + + return FALSE; + case CLUTTER_TABLET_DEVICE: + return TRUE; + default: + return FALSE; + } +} + +static void +update_cursors (MetaBackend *backend) +{ + MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); + ClutterSeat *seat = clutter_backend_get_default_seat (priv->clutter_backend); + MetaCursorRenderer *cursor_renderer; + ClutterInputDevice *pointer, *device; + GList *devices, *l; + + pointer = clutter_seat_get_pointer (seat); + devices = clutter_seat_list_devices (seat); + devices = g_list_prepend (devices, pointer); + + for (l = devices; l; l = l->next) + { + device = l->data; + + if (!should_have_cursor_renderer (device)) + continue; + + cursor_renderer = meta_backend_get_cursor_renderer_for_device (backend, + device); + if (cursor_renderer) + meta_cursor_renderer_force_update (cursor_renderer); + } + + g_list_free (devices); +} + void meta_backend_monitors_changed (MetaBackend *backend) { @@ -277,7 +324,7 @@ meta_backend_monitors_changed (MetaBackend *backend) meta_backend_sync_screen_size (backend); - if (clutter_input_device_get_coords (device, NULL, &point)) + if (clutter_seat_query_state (seat, device, NULL, &point, NULL)) { /* If we're outside all monitors, warp the pointer back inside */ if ((!meta_monitor_manager_get_logical_monitor_at (monitor_manager, @@ -290,7 +337,7 @@ meta_backend_monitors_changed (MetaBackend *backend) } } - meta_cursor_renderer_force_update (priv->cursor_renderer); + update_cursors (backend); } void @@ -391,11 +438,22 @@ on_device_added (ClutterSeat *seat, { MetaBackend *backend = META_BACKEND (user_data); MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); + ClutterInputDeviceType device_type; create_device_monitor (backend, device); if (device_is_physical_touchscreen (device)) meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, FALSE); + + device_type = clutter_input_device_get_device_type (device); + + if (device_type == CLUTTER_TOUCHSCREEN_DEVICE || + device_type == CLUTTER_TABLET_DEVICE || + device_type == CLUTTER_PEN_DEVICE || + device_type == CLUTTER_ERASER_DEVICE || + device_type == CLUTTER_CURSOR_DEVICE || + device_type == CLUTTER_PAD_DEVICE) + meta_input_mapper_add_device (priv->input_mapper, device); } static void @@ -408,6 +466,8 @@ on_device_removed (ClutterSeat *seat, destroy_device_monitor (backend, device); + meta_input_mapper_remove_device (priv->input_mapper, device); + /* If the device the user last interacted goes away, check again pointer * visibility. */ @@ -461,10 +521,39 @@ create_device_monitors (MetaBackend *backend, g_list_free (devices); } -static MetaInputSettings * -meta_backend_create_input_settings (MetaBackend *backend) +static void +input_mapper_device_mapped_cb (MetaInputMapper *mapper, + ClutterInputDevice *device, + float matrix[6], + MetaInputSettings *input_settings) { - return META_BACKEND_GET_CLASS (backend)->create_input_settings (backend); + meta_input_settings_set_device_matrix (input_settings, device, matrix); +} + +static void +input_mapper_device_enabled_cb (MetaInputMapper *mapper, + ClutterInputDevice *device, + gboolean enabled, + MetaInputSettings *input_settings) +{ + meta_input_settings_set_device_enabled (input_settings, device, enabled); +} + +static void +input_mapper_device_aspect_ratio_cb (MetaInputMapper *mapper, + ClutterInputDevice *device, + double aspect_ratio, + MetaInputSettings *input_settings) +{ + meta_input_settings_set_device_aspect_ratio (input_settings, device, aspect_ratio); +} + +static void +on_stage_shown_cb (MetaBackend *backend) +{ + MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); + + meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, TRUE); } static void @@ -472,18 +561,19 @@ meta_backend_real_post_init (MetaBackend *backend) { MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); ClutterSeat *seat = clutter_backend_get_default_seat (priv->clutter_backend); - ClutterKeymap *keymap = clutter_seat_get_keymap (seat); + MetaInputSettings *input_settings; priv->stage = meta_stage_new (backend); clutter_actor_realize (priv->stage); META_BACKEND_GET_CLASS (backend)->select_stage_events (backend); + g_signal_connect_object (priv->stage, "show", + G_CALLBACK (on_stage_shown_cb), backend, + G_CONNECT_SWAPPED); meta_monitor_manager_setup (priv->monitor_manager); meta_backend_sync_screen_size (backend); - priv->cursor_renderer = META_BACKEND_GET_CLASS (backend)->create_cursor_renderer (backend); - priv->device_monitors = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref); @@ -495,15 +585,21 @@ meta_backend_real_post_init (MetaBackend *backend) G_CALLBACK (on_device_removed), backend, G_CONNECT_AFTER); - priv->input_settings = meta_backend_create_input_settings (backend); + priv->input_mapper = meta_input_mapper_new (); + + input_settings = meta_backend_get_input_settings (backend); - if (priv->input_settings) + if (input_settings) { - priv->keymap_state_changed_id = - g_signal_connect_swapped (keymap, "state-changed", - G_CALLBACK (meta_input_settings_maybe_save_numlock_state), - priv->input_settings); - meta_input_settings_maybe_restore_numlock_state (priv->input_settings); + g_signal_connect (priv->input_mapper, "device-mapped", + G_CALLBACK (input_mapper_device_mapped_cb), + input_settings); + g_signal_connect (priv->input_mapper, "device-enabled", + G_CALLBACK (input_mapper_device_enabled_cb), + input_settings); + g_signal_connect (priv->input_mapper, "device-aspect-ratio", + G_CALLBACK (input_mapper_device_aspect_ratio_cb), + input_settings); } #ifdef HAVE_REMOTE_DESKTOP @@ -880,10 +976,18 @@ clutter_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { + MetaBackendSource *backend_source = (MetaBackendSource *) source; + MetaBackendPrivate *priv = + meta_backend_get_instance_private (backend_source->backend); ClutterEvent *event = clutter_event_get (); + ClutterSeat *seat; if (event) { + event->any.stage = + CLUTTER_STAGE (meta_backend_get_stage (backend_source->backend)); + seat = clutter_backend_get_default_seat (priv->clutter_backend); + clutter_seat_handle_event_post (seat, event); clutter_do_event (event); clutter_event_free (event); } @@ -909,6 +1013,7 @@ static gboolean init_clutter (MetaBackend *backend, GError **error) { + MetaBackendSource *backend_source; GSource *source; clutter_set_custom_backend_func (meta_get_clutter_backend); @@ -920,7 +1025,9 @@ init_clutter (MetaBackend *backend, return FALSE; } - source = g_source_new (&clutter_source_funcs, sizeof (GSource)); + source = g_source_new (&clutter_source_funcs, sizeof (MetaBackendSource)); + backend_source = (MetaBackendSource *) source; + backend_source->backend = backend; g_source_attach (source, NULL); g_source_unref (source); @@ -1045,8 +1152,26 @@ MetaCursorRenderer * meta_backend_get_cursor_renderer (MetaBackend *backend) { MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); + ClutterInputDevice *pointer; + ClutterSeat *seat; + + seat = clutter_backend_get_default_seat (priv->clutter_backend); + pointer = clutter_seat_get_pointer (seat); + + return meta_backend_get_cursor_renderer_for_device (backend, pointer); +} + +MetaCursorRenderer * +meta_backend_get_cursor_renderer_for_device (MetaBackend *backend, + ClutterInputDevice *device) +{ + g_return_val_if_fail (META_IS_BACKEND (backend), NULL); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); + g_return_val_if_fail (clutter_input_device_get_device_type (device) != + CLUTTER_KEYBOARD_DEVICE, NULL); - return priv->cursor_renderer; + return META_BACKEND_GET_CLASS (backend)->get_cursor_renderer (backend, + device); } /** @@ -1215,14 +1340,6 @@ meta_backend_lock_layout_group (MetaBackend *backend, META_BACKEND_GET_CLASS (backend)->lock_layout_group (backend, idx); } -void -meta_backend_set_numlock (MetaBackend *backend, - gboolean numlock_state) -{ - META_BACKEND_GET_CLASS (backend)->set_numlock (backend, numlock_state); -} - - /** * meta_backend_get_stage: * @backend: A #MetaBackend @@ -1313,11 +1430,8 @@ meta_backend_set_client_pointer_constraint (MetaBackend *backend, { MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); - g_assert (!constraint || !priv->client_pointer_constraint); - - g_clear_object (&priv->client_pointer_constraint); - if (constraint) - priv->client_pointer_constraint = g_object_ref (constraint); + META_BACKEND_GET_CLASS (backend)->set_pointer_constraint (backend, constraint); + g_set_object (&priv->client_pointer_constraint, constraint); } ClutterBackend * @@ -1389,12 +1503,18 @@ meta_is_stage_views_scaled (void) return layout_mode == META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL; } -MetaInputSettings * -meta_backend_get_input_settings (MetaBackend *backend) +MetaInputMapper * +meta_backend_get_input_mapper (MetaBackend *backend) { MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); - return priv->input_settings; + return priv->input_mapper; +} + +MetaInputSettings * +meta_backend_get_input_settings (MetaBackend *backend) +{ + return META_BACKEND_GET_CLASS (backend)->get_input_settings (backend); } /** @@ -1455,3 +1575,40 @@ meta_backend_get_wacom_database (MetaBackend *backend) return priv->wacom_db; } #endif + +void +meta_backend_add_hw_cursor_inhibitor (MetaBackend *backend, + MetaHwCursorInhibitor *inhibitor) +{ + MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); + + priv->hw_cursor_inhibitors = g_list_prepend (priv->hw_cursor_inhibitors, + inhibitor); +} + +void +meta_backend_remove_hw_cursor_inhibitor (MetaBackend *backend, + MetaHwCursorInhibitor *inhibitor) +{ + MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); + + priv->hw_cursor_inhibitors = g_list_remove (priv->hw_cursor_inhibitors, + inhibitor); +} + +gboolean +meta_backend_is_hw_cursors_inhibited (MetaBackend *backend) +{ + MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); + GList *l; + + for (l = priv->hw_cursor_inhibitors; l; l = l->next) + { + MetaHwCursorInhibitor *inhibitor = l->data; + + if (meta_hw_cursor_inhibitor_is_cursor_inhibited (inhibitor)) + return TRUE; + } + + return FALSE; +} diff --git a/src/backends/meta-cursor-renderer.c b/src/backends/meta-cursor-renderer.c index ac81deff66c39f99de59021dac6b2e40c26e7522..46f561fe33d0cce0bbb0161d40d2788b4a847dd7 100644 --- a/src/backends/meta-cursor-renderer.c +++ b/src/backends/meta-cursor-renderer.c @@ -28,6 +28,8 @@ #include +#include "backends/meta-backend-private.h" +#include "backends/meta-logical-monitor.h" #include "backends/meta-stage-private.h" #include "clutter/clutter.h" #include "clutter/clutter-mutter.h" @@ -44,6 +46,7 @@ enum PROP_0, PROP_BACKEND, + PROP_DEVICE, N_PROPS }; @@ -57,6 +60,7 @@ struct _MetaCursorRendererPrivate float current_x; float current_y; + ClutterInputDevice *device; MetaCursorSprite *displayed_cursor; MetaCursorSprite *overlay_cursor; @@ -77,14 +81,13 @@ static guint signals[LAST_SIGNAL]; G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRenderer, meta_cursor_renderer, G_TYPE_OBJECT); -static gboolean -meta_hw_cursor_inhibitor_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor, - MetaCursorSprite *cursor_sprite) +gboolean +meta_hw_cursor_inhibitor_is_cursor_inhibited (MetaHwCursorInhibitor *inhibitor) { MetaHwCursorInhibitorInterface *iface = META_HW_CURSOR_INHIBITOR_GET_IFACE (inhibitor); - return iface->is_cursor_sprite_inhibited (inhibitor, cursor_sprite); + return iface->is_cursor_inhibited (inhibitor); } static void @@ -203,6 +206,9 @@ meta_cursor_renderer_get_property (GObject *object, case PROP_BACKEND: g_value_set_object (value, priv->backend); break; + case PROP_DEVICE: + g_value_set_object (value, priv->device); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -224,6 +230,9 @@ meta_cursor_renderer_set_property (GObject *object, case PROP_BACKEND: priv->backend = g_value_get_object (value); break; + case PROP_DEVICE: + priv->device = g_value_get_object (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -284,6 +293,14 @@ meta_cursor_renderer_class_init (MetaCursorRendererClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_props[PROP_DEVICE] = + g_param_spec_object ("device", + "device", + "Input device", + CLUTTER_TYPE_INPUT_DEVICE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, obj_props); signals[CURSOR_PAINTED] = g_signal_new ("cursor-painted", @@ -332,6 +349,41 @@ meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer, }; } +static float +find_highest_logical_monitor_scale (MetaBackend *backend, + MetaCursorSprite *cursor_sprite) +{ + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + graphene_rect_t cursor_rect; + GList *logical_monitors; + GList *l; + float highest_scale = 0.0f; + + cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer, + cursor_sprite); + + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + for (l = logical_monitors; l; l = l->next) + { + MetaLogicalMonitor *logical_monitor = l->data; + graphene_rect_t logical_monitor_rect = + meta_rectangle_to_graphene_rect (&logical_monitor->rect); + + if (!graphene_rect_intersection (&cursor_rect, + &logical_monitor_rect, + NULL)) + continue; + + highest_scale = MAX (highest_scale, logical_monitor->scale); + } + + return highest_scale; +} + static void meta_cursor_renderer_update_cursor (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite) @@ -340,9 +392,14 @@ meta_cursor_renderer_update_cursor (MetaCursorRenderer *renderer, gboolean handled_by_backend; if (cursor_sprite) - meta_cursor_sprite_prepare_at (cursor_sprite, - (int) priv->current_x, - (int) priv->current_y); + { + float scale = find_highest_logical_monitor_scale (priv->backend, + cursor_sprite); + meta_cursor_sprite_prepare_at (cursor_sprite, + MAX (1, scale), + (int) priv->current_x, + (int) priv->current_y); + } handled_by_backend = META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer, @@ -354,10 +411,12 @@ meta_cursor_renderer_update_cursor (MetaCursorRenderer *renderer, } MetaCursorRenderer * -meta_cursor_renderer_new (MetaBackend *backend) +meta_cursor_renderer_new (MetaBackend *backend, + ClutterInputDevice *device) { return g_object_new (META_TYPE_CURSOR_RENDERER, "backend", backend, + "device", device, NULL); } @@ -384,30 +443,19 @@ meta_cursor_renderer_force_update (MetaCursorRenderer *renderer) } void -meta_cursor_renderer_set_position (MetaCursorRenderer *renderer, - float x, - float y) +meta_cursor_renderer_update_position (MetaCursorRenderer *renderer) { MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer); + graphene_point_t pos; - priv->current_x = x; - priv->current_y = y; + clutter_seat_query_state (clutter_input_device_get_seat (priv->device), + priv->device, NULL, &pos, NULL); + priv->current_x = pos.x; + priv->current_y = pos.y; meta_cursor_renderer_update_cursor (renderer, priv->displayed_cursor); } -graphene_point_t -meta_cursor_renderer_get_position (MetaCursorRenderer *renderer) -{ - MetaCursorRendererPrivate *priv = - meta_cursor_renderer_get_instance_private (renderer); - - return (graphene_point_t) { - .x = priv->current_x, - .y = priv->current_y - }; -} - MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer) { @@ -428,44 +476,11 @@ meta_cursor_renderer_is_overlay_visible (MetaCursorRenderer *renderer) return meta_overlay_is_visible (priv->stage_overlay); } -void -meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer *renderer, - MetaHwCursorInhibitor *inhibitor) -{ - MetaCursorRendererPrivate *priv = - meta_cursor_renderer_get_instance_private (renderer); - - priv->hw_cursor_inhibitors = g_list_prepend (priv->hw_cursor_inhibitors, - inhibitor); -} - -void -meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer *renderer, - MetaHwCursorInhibitor *inhibitor) -{ - MetaCursorRendererPrivate *priv = - meta_cursor_renderer_get_instance_private (renderer); - - priv->hw_cursor_inhibitors = g_list_remove (priv->hw_cursor_inhibitors, - inhibitor); -} - -gboolean -meta_cursor_renderer_is_hw_cursors_inhibited (MetaCursorRenderer *renderer, - MetaCursorSprite *cursor_sprite) +ClutterInputDevice * +meta_cursor_renderer_get_input_device (MetaCursorRenderer *renderer) { MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer); - GList *l; - - for (l = priv->hw_cursor_inhibitors; l; l = l->next) - { - MetaHwCursorInhibitor *inhibitor = l->data; - if (meta_hw_cursor_inhibitor_is_cursor_sprite_inhibited (inhibitor, - cursor_sprite)) - return TRUE; - } - - return FALSE; + return priv->device; } diff --git a/src/backends/meta-cursor-renderer.h b/src/backends/meta-cursor-renderer.h index 7d89af48744e08dce59498afc1c3c7425af53d0e..8d23cc6f564fd8179956b10f60e6a62c20bdc464 100644 --- a/src/backends/meta-cursor-renderer.h +++ b/src/backends/meta-cursor-renderer.h @@ -38,10 +38,11 @@ struct _MetaHwCursorInhibitorInterface { GTypeInterface parent_iface; - gboolean (* is_cursor_sprite_inhibited) (MetaHwCursorInhibitor *inhibitor, - MetaCursorSprite *cursor_sprite); + gboolean (* is_cursor_inhibited) (MetaHwCursorInhibitor *inhibitor); }; +gboolean meta_hw_cursor_inhibitor_is_cursor_inhibited (MetaHwCursorInhibitor *inhibitor); + #define META_TYPE_CURSOR_RENDERER (meta_cursor_renderer_get_type ()) G_DECLARE_DERIVABLE_TYPE (MetaCursorRenderer, meta_cursor_renderer, META, CURSOR_RENDERER, GObject); @@ -54,35 +55,25 @@ struct _MetaCursorRendererClass MetaCursorSprite *cursor_sprite); }; -MetaCursorRenderer * meta_cursor_renderer_new (MetaBackend *backend); +MetaCursorRenderer * meta_cursor_renderer_new (MetaBackend *backend, + ClutterInputDevice *device); void meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite); -void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer, - float x, - float y); -graphene_point_t meta_cursor_renderer_get_position (MetaCursorRenderer *renderer); +void meta_cursor_renderer_update_position (MetaCursorRenderer *renderer); void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer); MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer); gboolean meta_cursor_renderer_is_overlay_visible (MetaCursorRenderer *renderer); -void meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer *renderer, - MetaHwCursorInhibitor *inhibitor); - -void meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer *renderer, - MetaHwCursorInhibitor *inhibitor); - -gboolean meta_cursor_renderer_is_hw_cursors_inhibited (MetaCursorRenderer *renderer, - MetaCursorSprite *cursor_sprite); - graphene_rect_t meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite); void meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite); +ClutterInputDevice * meta_cursor_renderer_get_input_device (MetaCursorRenderer *renderer); void meta_cursor_renderer_update_stage_overlay (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite); diff --git a/src/backends/meta-cursor-tracker-private.h b/src/backends/meta-cursor-tracker-private.h index 779c2fe521a1274294c0e731984c482708f3f147..6d3c88c35593c9eed441c3090cefcfd27cbc4ebd 100644 --- a/src/backends/meta-cursor-tracker-private.h +++ b/src/backends/meta-cursor-tracker-private.h @@ -41,9 +41,7 @@ void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker); void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, MetaCursorSprite *cursor_sprite); -void meta_cursor_tracker_update_position (MetaCursorTracker *tracker, - float new_x, - float new_y); +void meta_cursor_tracker_invalidate_position (MetaCursorTracker *tracker); void meta_cursor_tracker_track_position (MetaCursorTracker *tracker); diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c index caac5827da355a3cc3d66cbf41f77e2fed3384de..d2bd22606afdac9f933e57961471005a167efabc 100644 --- a/src/backends/meta-cursor-tracker.c +++ b/src/backends/meta-cursor-tracker.c @@ -31,15 +31,12 @@ #include "backends/meta-cursor-tracker-private.h" -#include -#include #include #include "backends/meta-backend-private.h" #include "cogl/cogl.h" #include "core/display-private.h" #include "clutter/clutter.h" -#include "meta-marshal.h" #include "meta/main.h" #include "meta/util.h" @@ -85,7 +82,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorTracker, meta_cursor_tracker, enum { CURSOR_CHANGED, - CURSOR_MOVED, + POSITION_INVALIDATED, VISIBILITY_CHANGED, LAST_SIGNAL }; @@ -199,7 +196,7 @@ meta_cursor_tracker_init (MetaCursorTracker *tracker) MetaCursorTrackerPrivate *priv = meta_cursor_tracker_get_instance_private (tracker); - priv->is_showing = TRUE; + priv->is_showing = FALSE; priv->x = -1.0; priv->y = -1.0; } @@ -291,26 +288,12 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass) NULL, NULL, NULL, G_TYPE_NONE, 0); - /** - * MetaCursorTracker::cursor-moved: - * @cursor: The #MetaCursorTracker - * @x: The new X coordinate of the cursor - * @y: The new Y coordinate of the cursor - * - * Notifies when the cursor has moved to a new location. - */ - signals[CURSOR_MOVED] = g_signal_new ("cursor-moved", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - meta_marshal_VOID__FLOAT_FLOAT, - G_TYPE_NONE, 2, - G_TYPE_FLOAT, - G_TYPE_FLOAT); - g_signal_set_va_marshaller (signals[CURSOR_MOVED], - G_TYPE_FROM_CLASS (klass), - meta_marshal_VOID__FLOAT_FLOATv); + signals[POSITION_INVALIDATED] = g_signal_new ("position-invalidated", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); signals[VISIBILITY_CHANGED] = g_signal_new ("visibility-changed", G_TYPE_FROM_CLASS (klass), @@ -437,63 +420,15 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker, } void -meta_cursor_tracker_update_position (MetaCursorTracker *tracker, - float new_x, - float new_y) +meta_cursor_tracker_invalidate_position (MetaCursorTracker *tracker) { - MetaCursorTrackerPrivate *priv = - meta_cursor_tracker_get_instance_private (tracker); - MetaCursorRenderer *cursor_renderer = - meta_backend_get_cursor_renderer (priv->backend); - gboolean position_changed; - - if (priv->x != new_x || priv->y != new_y) - { - position_changed = TRUE; - priv->x = new_x; - priv->y = new_y; - } - else - { - position_changed = FALSE; - } - - meta_cursor_renderer_set_position (cursor_renderer, new_x, new_y); - - if (position_changed) - g_signal_emit (tracker, signals[CURSOR_MOVED], 0, new_x, new_y); + g_signal_emit (tracker, signals[POSITION_INVALIDATED], 0); } -static void -get_pointer_position_gdk (graphene_point_t *point, - int *mods) -{ - GdkSeat *gseat; - GdkDevice *gdevice; - GdkScreen *gscreen; - double x, y; - - gseat = gdk_display_get_default_seat (gdk_display_get_default ()); - gdevice = gdk_seat_get_pointer (gseat); - - /* Even if point is NULL we need this to get gscreen */ - gdk_device_get_position_double (gdevice, &gscreen, &x, &y); - - if (point) - { - point->x = x; - point->y = y; - } - - if (mods) - gdk_device_get_state (gdevice, - gdk_screen_get_root_window (gscreen), - NULL, (GdkModifierType*)mods); -} - -static void -get_pointer_position_clutter (graphene_point_t *point, - int *mods) +void +meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker, + graphene_point_t *coords, + ClutterModifierType *mods) { ClutterSeat *seat; ClutterInputDevice *cdevice; @@ -501,27 +436,7 @@ get_pointer_position_clutter (graphene_point_t *point, seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); cdevice = clutter_seat_get_pointer (seat); - if (point) - clutter_input_device_get_coords (cdevice, NULL, point); - - if (mods) - *mods = clutter_input_device_get_modifier_state (cdevice); -} - -void -meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker, - graphene_point_t *coords, - ClutterModifierType *mods) -{ - /* We can't use the clutter interface when not running as a wayland compositor, - because we need to query the server, rather than using the last cached value. - OTOH, on wayland we can't use GDK, because that only sees the events - we forward to xwayland. - */ - if (meta_is_wayland_compositor ()) - get_pointer_position_clutter (coords, (int *) mods); - else - get_pointer_position_gdk (coords, (int *) mods); + clutter_seat_query_state (seat, cdevice, NULL, coords, mods); } void diff --git a/src/backends/meta-cursor.c b/src/backends/meta-cursor.c index 874593d5ad46254a64a83717abc6e8688daea3e5..d0fb2ba68685d6b59750ee6c3a057cdfcf7fafc5 100644 --- a/src/backends/meta-cursor.c +++ b/src/backends/meta-cursor.c @@ -179,11 +179,12 @@ meta_cursor_sprite_get_texture_transform (MetaCursorSprite *sprite) } void -meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite, - int x, - int y) +meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite, + float best_scale, + int x, + int y) { - g_signal_emit (sprite, signals[PREPARE_AT], 0, x, y); + g_signal_emit (sprite, signals[PREPARE_AT], 0, best_scale, x, y); } void @@ -226,7 +227,8 @@ meta_cursor_sprite_class_init (MetaCursorSpriteClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, + G_TYPE_NONE, 3, + G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT); signals[TEXTURE_CHANGED] = g_signal_new ("texture-changed", diff --git a/src/backends/meta-cursor.h b/src/backends/meta-cursor.h index 80eaa313c195af6d0f4d99682e8072aafc2e89c1..a65e128c485bc9ad80d48a0c2494dc5bff94e8b9 100644 --- a/src/backends/meta-cursor.h +++ b/src/backends/meta-cursor.h @@ -43,6 +43,7 @@ struct _MetaCursorSpriteClass }; void meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite, + float best_scale, int x, int y); diff --git a/src/backends/meta-input-mapper-private.h b/src/backends/meta-input-mapper-private.h index cdfdccde9fbae67515e58087fb362e5d908d57ca..63d480dba77696adb8014767596b22b104dbd6c3 100644 --- a/src/backends/meta-input-mapper-private.h +++ b/src/backends/meta-input-mapper-private.h @@ -23,7 +23,8 @@ #define META_INPUT_MAPPER_H #include -#include "meta-monitor-manager-private.h" + +#include "backends/meta-backend-types.h" #define META_TYPE_INPUT_MAPPER (meta_input_mapper_get_type ()) @@ -33,10 +34,9 @@ G_DECLARE_FINAL_TYPE (MetaInputMapper, meta_input_mapper, MetaInputMapper * meta_input_mapper_new (void); void meta_input_mapper_add_device (MetaInputMapper *mapper, - ClutterInputDevice *device, - gboolean builtin); + ClutterInputDevice *device); void meta_input_mapper_remove_device (MetaInputMapper *mapper, - ClutterInputDevice *device); + ClutterInputDevice *device); ClutterInputDevice * meta_input_mapper_get_logical_monitor_device (MetaInputMapper *mapper, @@ -46,4 +46,7 @@ MetaLogicalMonitor * meta_input_mapper_get_device_logical_monitor (MetaInputMapper *mapper, ClutterInputDevice *device); +GSettings * meta_input_mapper_get_tablet_settings (MetaInputMapper *mapper, + ClutterInputDevice *device); + #endif /* META_INPUT_MAPPER_H */ diff --git a/src/backends/meta-input-mapper.c b/src/backends/meta-input-mapper.c index db85d0926eb220c3a8939f0546f4d1bc5d38e8f7..756cd1126f4c964fde159796e79f49059a7f3444 100644 --- a/src/backends/meta-input-mapper.c +++ b/src/backends/meta-input-mapper.c @@ -24,6 +24,7 @@ #include #endif +#include "backends/meta-input-device-private.h" #include "meta-input-mapper-private.h" #include "meta-monitor-manager-private.h" #include "meta-logical-monitor.h" @@ -65,6 +66,7 @@ typedef enum META_MATCH_EDID_FULL, /* Full EDID model match, eg. "Cintiq 12WX" */ META_MATCH_SIZE, /* Size from input device and output match */ META_MATCH_IS_BUILTIN, /* Output is builtin, applies mainly to system-integrated devices */ + META_MATCH_CONFIG, /* Specified by config */ N_OUTPUT_MATCHES } MetaOutputMatchType; @@ -73,6 +75,7 @@ struct _MetaMapperInputInfo ClutterInputDevice *device; MetaInputMapper *mapper; MetaMapperOutputInfo *output; + GSettings *settings; guint builtin : 1; }; @@ -106,24 +109,79 @@ struct _DeviceCandidates enum { DEVICE_MAPPED, + DEVICE_ENABLED, + DEVICE_ASPECT_RATIO, N_SIGNALS }; static guint signals[N_SIGNALS] = { 0, }; +static void mapper_recalculate_input (MetaInputMapper *mapper, + MetaMapperInputInfo *input); + G_DEFINE_TYPE (MetaInputMapper, meta_input_mapper, G_TYPE_OBJECT) +static GSettings * +get_device_settings (ClutterInputDevice *device) +{ + const char *group, *schema, *vendor, *product; + ClutterInputDeviceType type; + GSettings *settings; + char *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 || + type == CLUTTER_PAD_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 +settings_output_changed_cb (GSettings *settings, + const char *key, + MetaMapperInputInfo *info) +{ + mapper_recalculate_input (info->mapper, info); +} + static MetaMapperInputInfo * mapper_input_info_new (ClutterInputDevice *device, - MetaInputMapper *mapper, - gboolean builtin) + MetaInputMapper *mapper) { MetaMapperInputInfo *info; info = g_new0 (MetaMapperInputInfo, 1); info->mapper = mapper; info->device = device; - info->builtin = builtin; + info->settings = get_device_settings (device); + + g_signal_connect (info->settings, "changed::output", + G_CALLBACK (settings_output_changed_cb), info); return info; } @@ -131,6 +189,7 @@ mapper_input_info_new (ClutterInputDevice *device, static void mapper_input_info_free (MetaMapperInputInfo *info) { + g_object_unref (info->settings); g_free (info); } @@ -181,13 +240,36 @@ mapper_input_info_set_output (MetaMapperInputInfo *input, MetaMapperOutputInfo *output, MetaMonitor *monitor) { + MetaInputMapper *mapper = input->mapper; + float matrix[6] = { 1, 0, 0, 0, 1, 0 }; + double aspect_ratio; + int width, height; + if (input->output == output) return; input->output = output; + + if (output && monitor) + { + meta_monitor_manager_get_monitor_matrix (mapper->monitor_manager, + monitor, + output->logical_monitor, + matrix); + meta_monitor_get_current_resolution (monitor, &width, &height); + } + else + { + meta_monitor_manager_get_screen_size (mapper->monitor_manager, + &width, &height); + } + + aspect_ratio = (double) width / height; + g_signal_emit (input->mapper, signals[DEVICE_MAPPED], 0, - input->device, - output ? output->logical_monitor : NULL, monitor); + input->device, matrix); + g_signal_emit (input->mapper, signals[DEVICE_ASPECT_RATIO], 0, + input->device, aspect_ratio); } static void @@ -346,6 +428,38 @@ match_builtin (MetaInputMapper *mapper, return monitor == meta_monitor_manager_get_laptop_panel (mapper->monitor_manager); } +static gboolean +match_config (MetaMapperInputInfo *info, + MetaMonitor *monitor) +{ + gboolean match = FALSE; + char **edid; + guint n_values; + + edid = g_settings_get_strv (info->settings, "output"); + 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 (info->device)); + goto out; + } + + if (!*edid[0] && !*edid[1] && !*edid[2]) + goto out; + + match = (g_strcmp0 (meta_monitor_get_vendor (monitor), edid[0]) == 0 && + g_strcmp0 (meta_monitor_get_product (monitor), edid[1]) == 0 && + g_strcmp0 (meta_monitor_get_serial (monitor), edid[2]) == 0); + + out: + g_strfreev (edid); + + return match; +} + static int sort_by_score (DeviceMatch *match1, DeviceMatch *match2) @@ -359,6 +473,32 @@ guess_candidates (MetaInputMapper *mapper, DeviceCandidates *info) { GList *monitors, *l; + gboolean builtin = FALSE; + gboolean integrated = TRUE; + +#ifdef HAVE_LIBWACOM + if (clutter_input_device_get_device_type (input->device) != CLUTTER_TOUCHSCREEN_DEVICE) + { + WacomDevice *wacom_device; + WacomIntegrationFlags flags = 0; + + wacom_device = + meta_input_device_get_wacom_device (META_INPUT_DEVICE (input->device)); + + if (wacom_device) + { + flags = libwacom_get_integration_flags (wacom_device); + + if ((flags & (WACOM_DEVICE_INTEGRATED_SYSTEM | + WACOM_DEVICE_INTEGRATED_DISPLAY)) == 0) + return; + + integrated = (flags & (WACOM_DEVICE_INTEGRATED_SYSTEM | + WACOM_DEVICE_INTEGRATED_DISPLAY)) != 0; + builtin = (flags & WACOM_DEVICE_INTEGRATED_SYSTEM) != 0; + } + } +#endif monitors = meta_monitor_manager_get_monitors (mapper->monitor_manager); @@ -372,12 +512,15 @@ guess_candidates (MetaInputMapper *mapper, if (match_edid (input, l->data, &edid_match)) match.score |= 1 << edid_match; - if (match_size (input, l->data)) + if (integrated && match_size (input, l->data)) match.score |= 1 << META_MATCH_SIZE; - if (input->builtin && match_builtin (mapper, l->data)) + if (builtin && match_builtin (mapper, l->data)) match.score |= 1 << META_MATCH_IS_BUILTIN; + if (match_config (input, l->data)) + match.score |= 1 << META_MATCH_CONFIG; + if (match.score > 0) g_array_append_val (info->matches, match); } @@ -547,6 +690,38 @@ input_mapper_monitors_changed_cb (MetaMonitorManager *monitor_manager, mapper_update_outputs (mapper); } +static void +input_mapper_power_save_mode_changed_cb (MetaMonitorManager *monitor_manager, + MetaInputMapper *mapper) +{ + ClutterInputDevice *device; + MetaLogicalMonitor *logical_monitor; + MetaMonitor *builtin; + MetaPowerSave power_save_mode; + gboolean on; + + power_save_mode = + meta_monitor_manager_get_power_save_mode (mapper->monitor_manager); + on = power_save_mode == META_POWER_SAVE_ON; + + builtin = meta_monitor_manager_get_laptop_panel (monitor_manager); + if (!builtin) + return; + + logical_monitor = meta_monitor_get_logical_monitor (builtin); + if (!logical_monitor) + return; + + device = + meta_input_mapper_get_logical_monitor_device (mapper, + logical_monitor, + CLUTTER_TOUCHSCREEN_DEVICE); + if (!device) + return; + + g_signal_emit (mapper, signals[DEVICE_ENABLED], 0, device, on); +} + static void input_mapper_device_removed_cb (ClutterSeat *seat, ClutterInputDevice *device, @@ -599,6 +774,9 @@ meta_input_mapper_constructed (GObject *object) mapper->monitor_manager = meta_backend_get_monitor_manager (backend); g_signal_connect (mapper->monitor_manager, "monitors-changed-internal", G_CALLBACK (input_mapper_monitors_changed_cb), mapper); + g_signal_connect (mapper->monitor_manager, "power-save-mode-changed", + G_CALLBACK (input_mapper_power_save_mode_changed_cb), + mapper); mapper_update_outputs (mapper); } @@ -617,9 +795,27 @@ meta_input_mapper_class_init (MetaInputMapperClass *klass) G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 3, + G_TYPE_NONE, 2, CLUTTER_TYPE_INPUT_DEVICE, - G_TYPE_POINTER, G_TYPE_POINTER); + G_TYPE_POINTER); + signals[DEVICE_ENABLED] = + g_signal_new ("device-enabled", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 2, + CLUTTER_TYPE_INPUT_DEVICE, + G_TYPE_BOOLEAN); + signals[DEVICE_ASPECT_RATIO] = + g_signal_new ("device-aspect-ratio", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 2, + CLUTTER_TYPE_INPUT_DEVICE, + G_TYPE_DOUBLE); } static void @@ -641,8 +837,7 @@ meta_input_mapper_new (void) void meta_input_mapper_add_device (MetaInputMapper *mapper, - ClutterInputDevice *device, - gboolean builtin) + ClutterInputDevice *device) { MetaMapperInputInfo *info; @@ -652,7 +847,7 @@ meta_input_mapper_add_device (MetaInputMapper *mapper, if (g_hash_table_contains (mapper->input_devices, device)) return; - info = mapper_input_info_new (device, mapper, builtin); + info = mapper_input_info_new (device, mapper); g_hash_table_insert (mapper->input_devices, device, info); mapper_recalculate_input (mapper, info); } @@ -699,6 +894,43 @@ meta_input_mapper_get_logical_monitor_device (MetaInputMapper *mapper, return NULL; } +static ClutterInputDevice * +find_grouped_pen (ClutterInputDevice *device) +{ + GList *l, *devices; + ClutterInputDeviceType device_type; + ClutterInputDevice *pen = NULL; + ClutterSeat *seat; + + device_type = clutter_input_device_get_device_type (device); + + if (device_type == CLUTTER_TABLET_DEVICE || + device_type == CLUTTER_PEN_DEVICE) + return device; + + seat = clutter_input_device_get_seat (device); + devices = clutter_seat_list_devices (seat); + + for (l = devices; l; l = l->next) + { + ClutterInputDevice *other_device = l->data; + + device_type = clutter_input_device_get_device_type (other_device); + + if ((device_type == CLUTTER_TABLET_DEVICE || + device_type == CLUTTER_PEN_DEVICE) && + clutter_input_device_is_grouped (device, other_device)) + { + pen = other_device; + break; + } + } + + g_list_free (devices); + + return pen; +} + MetaLogicalMonitor * meta_input_mapper_get_device_logical_monitor (MetaInputMapper *mapper, ClutterInputDevice *device) @@ -708,6 +940,13 @@ meta_input_mapper_get_device_logical_monitor (MetaInputMapper *mapper, GHashTableIter iter; GList *l; + if (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE) + { + device = find_grouped_pen (device); + if (!device) + return NULL; + } + g_hash_table_iter_init (&iter, mapper->output_devices); while (g_hash_table_iter_next (&iter, (gpointer *) &logical_monitor, @@ -724,3 +963,19 @@ meta_input_mapper_get_device_logical_monitor (MetaInputMapper *mapper, return NULL; } + +GSettings * +meta_input_mapper_get_tablet_settings (MetaInputMapper *mapper, + ClutterInputDevice *device) +{ + MetaMapperInputInfo *input; + + g_return_val_if_fail (META_IS_INPUT_MAPPER (mapper), NULL); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); + + input = g_hash_table_lookup (mapper->input_devices, device); + if (!input) + return NULL; + + return input->settings; +} diff --git a/src/backends/meta-input-settings-private.h b/src/backends/meta-input-settings-private.h index 3cf7b5f0e4384f11ae4fe17e88a2d02055f8e389..10de61d78322850d284eeda9a0a800c6f6fc9eb0 100644 --- a/src/backends/meta-input-settings-private.h +++ b/src/backends/meta-input-settings-private.h @@ -36,6 +36,42 @@ G_DECLARE_DERIVABLE_TYPE (MetaInputSettings, meta_input_settings, META, INPUT_SETTINGS, GObject) +typedef enum +{ + META_A11Y_KEYBOARD_ENABLED = 1 << 0, + META_A11Y_TIMEOUT_ENABLED = 1 << 1, + META_A11Y_MOUSE_KEYS_ENABLED = 1 << 2, + META_A11Y_SLOW_KEYS_ENABLED = 1 << 3, + META_A11Y_SLOW_KEYS_BEEP_PRESS = 1 << 4, + META_A11Y_SLOW_KEYS_BEEP_ACCEPT = 1 << 5, + META_A11Y_SLOW_KEYS_BEEP_REJECT = 1 << 6, + META_A11Y_BOUNCE_KEYS_ENABLED = 1 << 7, + META_A11Y_BOUNCE_KEYS_BEEP_REJECT = 1 << 8, + META_A11Y_TOGGLE_KEYS_ENABLED = 1 << 9, + META_A11Y_STICKY_KEYS_ENABLED = 1 << 10, + META_A11Y_STICKY_KEYS_TWO_KEY_OFF = 1 << 11, + META_A11Y_STICKY_KEYS_BEEP = 1 << 12, + META_A11Y_FEATURE_STATE_CHANGE_BEEP = 1 << 13, +} MetaKeyboardA11yFlags; + +/** + * MetaKbdA11ySettings: + * + * The #MetaKbdA11ySettings structure contains keyboard accessibility + * settings + * + */ +typedef struct _MetaKbdA11ySettings +{ + MetaKeyboardA11yFlags controls; + int slowkeys_delay; + int debounce_delay; + int timeout_delay; + int mousekeys_init_delay; + int mousekeys_max_speed; + int mousekeys_accel_time; +} MetaKbdA11ySettings; + struct _MetaInputSettingsClass { GObjectClass parent_class; @@ -93,10 +129,9 @@ struct _MetaInputSettingsClass void (* set_tablet_mapping) (MetaInputSettings *settings, ClutterInputDevice *device, GDesktopTabletMapping mapping); - void (* set_tablet_keep_aspect) (MetaInputSettings *settings, + void (* set_tablet_aspect_ratio) (MetaInputSettings *settings, ClutterInputDevice *device, - MetaLogicalMonitor *logical_monitor, - gboolean keep_aspect); + double ratio); void (* set_tablet_area) (MetaInputSettings *settings, ClutterInputDevice *device, gdouble padding_left, @@ -138,23 +173,32 @@ struct _MetaInputSettingsClass ClutterInputDevice *device); }; -GSettings * meta_input_settings_get_tablet_settings (MetaInputSettings *settings, - ClutterInputDevice *device); -MetaLogicalMonitor * meta_input_settings_get_tablet_logical_monitor (MetaInputSettings *settings, - ClutterInputDevice *device); - -gboolean meta_input_settings_is_pad_button_grabbed (MetaInputSettings *input_settings, - ClutterInputDevice *pad, - guint button); - -gboolean meta_input_settings_handle_pad_event (MetaInputSettings *input_settings, - const ClutterEvent *event); -gchar * meta_input_settings_get_pad_action_label (MetaInputSettings *input_settings, - ClutterInputDevice *pad, - MetaPadActionType action, - guint number); +void meta_input_settings_maybe_save_numlock_state (MetaInputSettings *input_settings, + gboolean numlock_state); +gboolean meta_input_settings_maybe_restore_numlock_state (MetaInputSettings *input_settings); -void meta_input_settings_maybe_save_numlock_state (MetaInputSettings *input_settings); -void meta_input_settings_maybe_restore_numlock_state (MetaInputSettings *input_settings); +void meta_input_settings_set_device_matrix (MetaInputSettings *input_settings, + ClutterInputDevice *device, + float matrix[6]); +void meta_input_settings_set_device_enabled (MetaInputSettings *input_settings, + ClutterInputDevice *device, + gboolean enabled); +void meta_input_settings_set_device_aspect_ratio (MetaInputSettings *input_settings, + ClutterInputDevice *device, + double aspect_ratio); + +void meta_input_settings_get_kbd_a11y_settings (MetaInputSettings *input_settings, + MetaKbdA11ySettings *a11y_settings); + +void meta_input_settings_add_device (MetaInputSettings *input_settings, + ClutterInputDevice *device); +void meta_input_settings_remove_device (MetaInputSettings *input_settings, + ClutterInputDevice *device); +void meta_input_settings_notify_tool_change (MetaInputSettings *input_settings, + ClutterInputDevice *device, + ClutterInputDeviceTool *tool); +void meta_input_settings_notify_kbd_a11y_change (MetaInputSettings *input_settings, + MetaKeyboardA11yFlags new_flags, + MetaKeyboardA11yFlags what_changed); #endif /* META_INPUT_SETTINGS_PRIVATE_H */ diff --git a/src/backends/meta-input-settings.c b/src/backends/meta-input-settings.c index 0fcac9095ccc73da2d962df7ac396a34ac06210c..5780fb9dee4b11da220c7cf625bcbb520a0c3791 100644 --- a/src/backends/meta-input-settings.c +++ b/src/backends/meta-input-settings.c @@ -61,12 +61,12 @@ struct _DeviceMappingInfo GSettings *settings; gulong changed_id; guint *group_modes; + double aspect_ratio; }; struct _MetaInputSettingsPrivate { ClutterSeat *seat; - MetaMonitorManager *monitor_manager; gulong monitors_changed_id; GSettings *mouse_settings; @@ -77,24 +77,14 @@ struct _MetaInputSettingsPrivate GSettings *keyboard_a11y_settings; GSettings *mouse_a11y_settings; + GList *devices; GHashTable *mappable_devices; GHashTable *current_tools; - ClutterVirtualInputDevice *virtual_pad_keyboard; - GHashTable *two_finger_devices; - /* Pad ring/strip emission */ - struct { - ClutterInputDevice *pad; - MetaPadActionType action; - guint number; - gdouble value; - } last_pad_action_info; - - /* For absolute devices with no mapping in settings */ - MetaInputMapper *input_mapper; + MetaKbdA11ySettings kbd_a11y_settings; }; typedef gboolean (* ConfigBoolMappingFunc) (MetaInputSettings *input_settings, @@ -111,29 +101,36 @@ typedef void (*ConfigUintFunc) (MetaInputSettings *input_settings, ClutterInputDevice *device, guint value); -typedef enum +G_DEFINE_TYPE_WITH_PRIVATE (MetaInputSettings, meta_input_settings, G_TYPE_OBJECT) + +enum { - META_PAD_DIRECTION_NONE = -1, - META_PAD_DIRECTION_UP = 0, - META_PAD_DIRECTION_DOWN, - META_PAD_DIRECTION_CW, - META_PAD_DIRECTION_CCW, -} MetaPadDirection; + KBD_A11Y_CHANGED, + N_SIGNALS +}; -G_DEFINE_TYPE_WITH_PRIVATE (MetaInputSettings, meta_input_settings, G_TYPE_OBJECT) +static guint signals[N_SIGNALS] = { 0 }; + +enum +{ + PROP_0, + PROP_SEAT, + N_PROPS, +}; + +static GParamSpec *props[N_PROPS] = { 0 }; static GSList * meta_input_settings_get_devices (MetaInputSettings *settings, ClutterInputDeviceType type) { MetaInputSettingsPrivate *priv; - GList *l, *devices; + GList *l; GSList *list = NULL; priv = meta_input_settings_get_instance_private (settings); - devices = clutter_seat_list_devices (priv->seat); - for (l = devices; l; l = l->next) + for (l = priv->devices; l; l = l->next) { ClutterInputDevice *device = l->data; @@ -142,8 +139,6 @@ meta_input_settings_get_devices (MetaInputSettings *settings, list = g_slist_prepend (list, device); } - g_list_free (devices); - return list; } @@ -155,8 +150,6 @@ meta_input_settings_dispose (GObject *object) g_signal_handlers_disconnect_by_data (priv->seat, settings); - g_clear_object (&priv->virtual_pad_keyboard); - g_clear_object (&priv->mouse_settings); g_clear_object (&priv->touchpad_settings); g_clear_object (&priv->trackball_settings); @@ -164,20 +157,57 @@ meta_input_settings_dispose (GObject *object) g_clear_object (&priv->gsd_settings); g_clear_object (&priv->keyboard_a11y_settings); g_clear_object (&priv->mouse_a11y_settings); - g_clear_object (&priv->input_mapper); g_clear_pointer (&priv->mappable_devices, g_hash_table_unref); g_clear_pointer (&priv->current_tools, g_hash_table_unref); - if (priv->monitor_manager) - g_clear_signal_handler (&priv->monitors_changed_id, priv->monitor_manager); - - g_clear_object (&priv->monitor_manager); - g_clear_pointer (&priv->two_finger_devices, g_hash_table_destroy); + g_clear_object (&priv->seat); G_OBJECT_CLASS (meta_input_settings_parent_class)->dispose (object); } +static void +meta_input_settings_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaInputSettings *input_settings = META_INPUT_SETTINGS (object); + MetaInputSettingsPrivate *priv = + meta_input_settings_get_instance_private (input_settings); + + switch (prop_id) + { + case PROP_SEAT: + priv->seat = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +meta_input_settings_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaInputSettings *input_settings = META_INPUT_SETTINGS (object); + MetaInputSettingsPrivate *priv = + meta_input_settings_get_instance_private (input_settings); + + switch (prop_id) + { + case PROP_SEAT: + g_value_set_object (value, priv->seat); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void settings_device_set_bool_setting (MetaInputSettings *input_settings, ClutterInputDevice *device, @@ -384,10 +414,9 @@ update_pointer_accel_profile (MetaInputSettings *input_settings, { MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings); - GList *l, *devices; + GList *l; - devices = clutter_seat_list_devices (priv->seat); - for (l = devices; l; l = l->next) + for (l = priv->devices; l; l = l->next) { device = l->data; @@ -398,8 +427,6 @@ update_pointer_accel_profile (MetaInputSettings *input_settings, do_update_pointer_accel_profile (input_settings, settings, device, profile); } - - g_list_free (devices); } } @@ -877,19 +904,15 @@ update_trackball_scroll_button (MetaInputSettings *input_settings, } else if (!device) { - GList *l, *devices; - - devices = clutter_seat_list_devices (priv->seat); + GList *l; - for (l = devices; l; l = l->next) + for (l = priv->devices; l; l = l->next) { device = l->data; if (input_settings_class->is_trackball_device (input_settings, device)) input_settings_class->set_scroll_button (input_settings, device, button, button_lock); } - - g_list_free (devices); } } @@ -914,131 +937,28 @@ update_keyboard_repeat (MetaInputSettings *input_settings) repeat, delay, interval); } -static MetaMonitor * -logical_monitor_find_monitor (MetaLogicalMonitor *logical_monitor, - const char *vendor, - const char *product, - const char *serial) -{ - GList *monitors; - GList *l; - - monitors = meta_logical_monitor_get_monitors (logical_monitor); - for (l = monitors; l; l = l->next) - { - MetaMonitor *monitor = l->data; - - if (g_strcmp0 (meta_monitor_get_vendor (monitor), vendor) == 0 && - g_strcmp0 (meta_monitor_get_product (monitor), product) == 0 && - g_strcmp0 (meta_monitor_get_serial (monitor), serial) == 0) - return monitor; - } - - return NULL; -} - -static void -meta_input_settings_find_monitor (MetaInputSettings *input_settings, - GSettings *settings, - ClutterInputDevice *device, - MetaMonitor **out_monitor, - MetaLogicalMonitor **out_logical_monitor) -{ - MetaInputSettingsPrivate *priv; - MetaMonitorManager *monitor_manager; - MetaMonitor *monitor; - guint n_values; - GList *logical_monitors; - GList *l; - gchar **edid; - - priv = meta_input_settings_get_instance_private (input_settings); - edid = g_settings_get_strv (settings, "output"); - 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)); - goto out; - } - - if (!*edid[0] && !*edid[1] && !*edid[2]) - goto out; - - monitor_manager = priv->monitor_manager; - logical_monitors = - meta_monitor_manager_get_logical_monitors (monitor_manager); - for (l = logical_monitors; l; l = l->next) - { - MetaLogicalMonitor *logical_monitor = l->data; - - monitor = logical_monitor_find_monitor (logical_monitor, - edid[0], edid[1], edid[2]); - if (monitor) - { - if (out_monitor) - *out_monitor = monitor; - if (out_logical_monitor) - *out_logical_monitor = logical_monitor; - break; - } - } - -out: - g_strfreev (edid); -} - -static gboolean -meta_input_settings_delegate_on_mapper (MetaInputSettings *input_settings, - ClutterInputDevice *device) -{ - MetaInputSettingsPrivate *priv; - gboolean builtin = FALSE; - - priv = meta_input_settings_get_instance_private (input_settings); - -#ifdef HAVE_LIBWACOM - if (clutter_input_device_get_device_type (device) != CLUTTER_TOUCHSCREEN_DEVICE) - { - WacomDevice *wacom_device; - WacomIntegrationFlags flags = 0; - - wacom_device = - meta_input_device_get_wacom_device (META_INPUT_DEVICE (device)); - - if (wacom_device) - { - flags = libwacom_get_integration_flags (wacom_device); - - if ((flags & (WACOM_DEVICE_INTEGRATED_SYSTEM | - WACOM_DEVICE_INTEGRATED_DISPLAY)) == 0) - return FALSE; - - builtin = (flags & WACOM_DEVICE_INTEGRATED_SYSTEM) != 0; - } - } -#endif - - meta_input_mapper_add_device (priv->input_mapper, device, builtin); - return TRUE; -} - static void update_tablet_keep_aspect (MetaInputSettings *input_settings, GSettings *settings, ClutterInputDevice *device) { + MetaInputSettingsPrivate *priv; MetaInputSettingsClass *input_settings_class; - MetaLogicalMonitor *logical_monitor = NULL; + DeviceMappingInfo *info; gboolean keep_aspect; + double aspect_ratio; if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE && clutter_input_device_get_device_type (device) != CLUTTER_PEN_DEVICE && clutter_input_device_get_device_type (device) != CLUTTER_ERASER_DEVICE) return; + priv = meta_input_settings_get_instance_private (input_settings); + + info = g_hash_table_lookup (priv->mappable_devices, device); + if (!info) + return; + #ifdef HAVE_LIBWACOM { WacomDevice *wacom_device; @@ -1052,55 +972,15 @@ update_tablet_keep_aspect (MetaInputSettings *input_settings, } #endif - input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings); - keep_aspect = g_settings_get_boolean (settings, "keep-aspect"); - meta_input_settings_find_monitor (input_settings, settings, device, - NULL, &logical_monitor); - - input_settings_class->set_tablet_keep_aspect (input_settings, device, - logical_monitor, keep_aspect); -} - -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 }; - MetaMonitor *monitor = NULL; - MetaLogicalMonitor *logical_monitor = NULL; - if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE && - clutter_input_device_get_device_type (device) != CLUTTER_PEN_DEVICE && - clutter_input_device_get_device_type (device) != CLUTTER_ERASER_DEVICE && - clutter_input_device_get_device_type (device) != CLUTTER_TOUCHSCREEN_DEVICE) - return; - - priv = meta_input_settings_get_instance_private (input_settings); - input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings); - - meta_input_settings_find_monitor (input_settings, settings, device, - &monitor, &logical_monitor); - if (monitor) - { - meta_input_mapper_remove_device (priv->input_mapper, device); - meta_monitor_manager_get_monitor_matrix (priv->monitor_manager, - monitor, logical_monitor, - matrix); - } + if (keep_aspect) + aspect_ratio = info->aspect_ratio; else - { - if (meta_input_settings_delegate_on_mapper (input_settings, device)) - return; - } - - input_settings_class->set_matrix (input_settings, device, matrix); + aspect_ratio = 0; - /* Ensure the keep-aspect mapping is updated */ - update_tablet_keep_aspect (input_settings, settings, device); + input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings); + input_settings_class->set_tablet_aspect_ratio (input_settings, device, aspect_ratio); } static void @@ -1135,10 +1015,6 @@ update_tablet_mapping (MetaInputSettings *input_settings, settings_device_set_uint_setting (input_settings, device, input_settings_class->set_tablet_mapping, mapping); - - /* Relative mapping disables keep-aspect/display */ - update_tablet_keep_aspect (input_settings, settings, device); - update_device_display (input_settings, settings, device); } static void @@ -1285,8 +1161,6 @@ meta_input_settings_changed_cb (GSettings *settings, strcmp (key, "repeat-interval") == 0 || strcmp (key, "delay") == 0) update_keyboard_repeat (input_settings); - else if (strcmp (key, "remember-numlock-state") == 0) - meta_input_settings_maybe_save_numlock_state (input_settings); } } @@ -1295,9 +1169,7 @@ mapped_device_changed_cb (GSettings *settings, const gchar *key, DeviceMappingInfo *info) { - if (strcmp (key, "output") == 0) - update_device_display (info->input_settings, settings, info->device); - else if (strcmp (key, "mapping") == 0) + if (strcmp (key, "mapping") == 0) update_tablet_mapping (info->input_settings, settings, info->device); else if (strcmp (key, "area") == 0) update_tablet_area (info->input_settings, settings, info->device); @@ -1313,7 +1185,6 @@ apply_mappable_device_settings (MetaInputSettings *input_settings, { ClutterInputDeviceType device_type; - update_device_display (input_settings, info->settings, info->device); device_type = clutter_input_device_get_device_type (info->device); if (device_type == CLUTTER_TABLET_DEVICE || @@ -1330,39 +1201,31 @@ apply_mappable_device_settings (MetaInputSettings *input_settings, struct _keyboard_a11y_settings_flags_pair { const char *name; - ClutterKeyboardA11yFlags flag; + MetaKeyboardA11yFlags flag; } keyboard_a11y_settings_flags_pair[] = { - { "enable", CLUTTER_A11Y_KEYBOARD_ENABLED }, - { "timeout-enable", CLUTTER_A11Y_TIMEOUT_ENABLED }, - { "mousekeys-enable", CLUTTER_A11Y_MOUSE_KEYS_ENABLED }, - { "slowkeys-enable", CLUTTER_A11Y_SLOW_KEYS_ENABLED }, - { "slowkeys-beep-press", CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS }, - { "slowkeys-beep-accept", CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT }, - { "slowkeys-beep-reject", CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT }, - { "bouncekeys-enable", CLUTTER_A11Y_BOUNCE_KEYS_ENABLED }, - { "bouncekeys-beep-reject", CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT }, - { "togglekeys-enable", CLUTTER_A11Y_TOGGLE_KEYS_ENABLED }, - { "stickykeys-enable", CLUTTER_A11Y_STICKY_KEYS_ENABLED }, - { "stickykeys-modifier-beep", CLUTTER_A11Y_STICKY_KEYS_BEEP }, - { "stickykeys-two-key-off", CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF }, - { "feature-state-change-beep", CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP }, + { "enable", META_A11Y_KEYBOARD_ENABLED }, + { "timeout-enable", META_A11Y_TIMEOUT_ENABLED }, + { "mousekeys-enable", META_A11Y_MOUSE_KEYS_ENABLED }, + { "slowkeys-enable", META_A11Y_SLOW_KEYS_ENABLED }, + { "slowkeys-beep-press", META_A11Y_SLOW_KEYS_BEEP_PRESS }, + { "slowkeys-beep-accept", META_A11Y_SLOW_KEYS_BEEP_ACCEPT }, + { "slowkeys-beep-reject", META_A11Y_SLOW_KEYS_BEEP_REJECT }, + { "bouncekeys-enable", META_A11Y_BOUNCE_KEYS_ENABLED }, + { "bouncekeys-beep-reject", META_A11Y_BOUNCE_KEYS_BEEP_REJECT }, + { "togglekeys-enable", META_A11Y_TOGGLE_KEYS_ENABLED }, + { "stickykeys-enable", META_A11Y_STICKY_KEYS_ENABLED }, + { "stickykeys-modifier-beep", META_A11Y_STICKY_KEYS_BEEP }, + { "stickykeys-two-key-off", META_A11Y_STICKY_KEYS_TWO_KEY_OFF }, + { "feature-state-change-beep", META_A11Y_FEATURE_STATE_CHANGE_BEEP }, }; static void -load_keyboard_a11y_settings (MetaInputSettings *input_settings, - ClutterInputDevice *device) +load_keyboard_a11y_settings (MetaInputSettings *input_settings) { MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings); - ClutterKbdA11ySettings kbd_a11y_settings = { 0 }; - ClutterInputDevice *core_keyboard; - ClutterBackend *backend = clutter_get_default_backend (); - ClutterSeat *seat = clutter_backend_get_default_seat (backend); + MetaKbdA11ySettings kbd_a11y_settings = { 0 }; guint i; - core_keyboard = clutter_seat_get_keyboard (priv->seat); - if (device && device != core_keyboard) - return; - kbd_a11y_settings.controls = 0; for (i = 0; i < G_N_ELEMENTS (keyboard_a11y_settings_flags_pair); i++) { @@ -1383,14 +1246,14 @@ load_keyboard_a11y_settings (MetaInputSettings *input_settings, kbd_a11y_settings.mousekeys_accel_time = g_settings_get_int (priv->keyboard_a11y_settings, "mousekeys-accel-time"); - clutter_seat_set_kbd_a11y_settings (seat, &kbd_a11y_settings); + priv->kbd_a11y_settings = kbd_a11y_settings; + g_signal_emit (input_settings, signals[KBD_A11Y_CHANGED], 0, &priv->kbd_a11y_settings); } -static void -on_keyboard_a11y_settings_changed (ClutterSeat *seat, - ClutterKeyboardA11yFlags new_flags, - ClutterKeyboardA11yFlags what_changed, - MetaInputSettings *input_settings) +void +meta_input_settings_notify_kbd_a11y_change (MetaInputSettings *input_settings, + MetaKeyboardA11yFlags new_flags, + MetaKeyboardA11yFlags what_changed) { MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings); guint i; @@ -1411,7 +1274,7 @@ meta_input_keyboard_a11y_settings_changed (GSettings *settings, { MetaInputSettings *input_settings = META_INPUT_SETTINGS (user_data); - load_keyboard_a11y_settings (input_settings, NULL); + load_keyboard_a11y_settings (input_settings); } struct _pointer_a11y_settings_flags_pair { @@ -1451,19 +1314,13 @@ pointer_a11y_dwell_direction_from_setting (MetaInputSettings *input_settings, } static void -load_pointer_a11y_settings (MetaInputSettings *input_settings, - ClutterInputDevice *device) +load_pointer_a11y_settings (MetaInputSettings *input_settings) { MetaInputSettingsPrivate *priv = meta_input_settings_get_instance_private (input_settings); ClutterPointerA11ySettings pointer_a11y_settings; - ClutterInputDevice *core_pointer; GDesktopMouseDwellMode dwell_mode; guint i; - core_pointer = clutter_seat_get_pointer (priv->seat); - if (device && device != core_pointer) - return; - clutter_seat_get_pointer_a11y_settings (CLUTTER_SEAT (priv->seat), &pointer_a11y_settings); pointer_a11y_settings.controls = 0; @@ -1508,7 +1365,7 @@ meta_input_mouse_a11y_settings_changed (GSettings *settings, { MetaInputSettings *input_settings = META_INPUT_SETTINGS (user_data); - load_pointer_a11y_settings (input_settings, NULL); + load_pointer_a11y_settings (input_settings); } static GSettings * @@ -1587,103 +1444,6 @@ lookup_tool_settings (ClutterInputDeviceTool *tool, return tool_settings; } -static GSettings * -lookup_pad_action_settings (ClutterInputDevice *device, - MetaPadActionType action, - guint number, - MetaPadDirection direction, - gint mode) -{ - const gchar *vendor, *product, *action_type, *detail_type = NULL; - GSettings *settings; - GString *path; - gchar action_label; - - vendor = clutter_input_device_get_vendor_id (device); - product = clutter_input_device_get_product_id (device); - - action_label = 'A' + number; - - switch (action) - { - case META_PAD_ACTION_BUTTON: - action_type = "button"; - break; - case META_PAD_ACTION_RING: - g_assert (direction == META_PAD_DIRECTION_CW || - direction == META_PAD_DIRECTION_CCW); - action_type = "ring"; - detail_type = (direction == META_PAD_DIRECTION_CW) ? "cw" : "ccw"; - break; - case META_PAD_ACTION_STRIP: - g_assert (direction == META_PAD_DIRECTION_UP || - direction == META_PAD_DIRECTION_DOWN); - action_type = "strip"; - detail_type = (direction == META_PAD_DIRECTION_UP) ? "up" : "down"; - break; - default: - return NULL; - } - - path = g_string_new (NULL); - g_string_append_printf (path, "/org/gnome/desktop/peripherals/tablets/%s:%s/%s%c", - vendor, product, action_type, action_label); - - if (detail_type) - g_string_append_printf (path, "-%s", detail_type); - - if (mode >= 0) - g_string_append_printf (path, "-mode-%d", mode); - - g_string_append_c (path, '/'); - - settings = g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet.pad-button", - path->str); - g_string_free (path, TRUE); - - return settings; -} - -static void -monitors_changed_cb (MetaMonitorManager *monitor_manager, - MetaInputSettings *input_settings) -{ - MetaInputSettingsPrivate *priv; - ClutterInputDevice *device; - DeviceMappingInfo *info; - 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 *) &info)) - update_device_display (input_settings, info->settings, device); -} - -static void -input_mapper_device_mapped_cb (MetaInputMapper *mapper, - ClutterInputDevice *device, - MetaLogicalMonitor *logical_monitor, - MetaMonitor *monitor, - MetaInputSettings *input_settings) -{ - MetaInputSettingsPrivate *priv; - float matrix[6] = { 1, 0, 0, 0, 1, 0 }; - - priv = meta_input_settings_get_instance_private (input_settings); - - if (monitor && logical_monitor) - { - meta_monitor_manager_get_monitor_matrix (priv->monitor_manager, - monitor, logical_monitor, - matrix); - } - - META_INPUT_SETTINGS_GET_CLASS (input_settings)->set_matrix (input_settings, - device, matrix); -} - static void device_mapping_info_free (DeviceMappingInfo *info) { @@ -1770,8 +1530,6 @@ apply_device_settings (MetaInputSettings *input_settings, update_pointer_accel_profile (input_settings, priv->trackball_settings, device); - load_keyboard_a11y_settings (input_settings, device); - load_pointer_a11y_settings (input_settings, device); update_middle_click_emulation (input_settings, priv->mouse_settings, device); update_middle_click_emulation (input_settings, priv->touchpad_settings, device); @@ -1867,35 +1625,38 @@ evaluate_two_finger_scrolling (MetaInputSettings *input_settings, g_hash_table_add (priv->two_finger_devices, device); } -static void -meta_input_settings_device_added (ClutterSeat *seat, - ClutterInputDevice *device, - MetaInputSettings *input_settings) +void +meta_input_settings_add_device (MetaInputSettings *input_settings, + ClutterInputDevice *device) { + MetaInputSettingsPrivate *priv = + meta_input_settings_get_instance_private (input_settings); + if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_LOGICAL) return; + priv->devices = g_list_prepend (priv->devices, device); evaluate_two_finger_scrolling (input_settings, device); apply_device_settings (input_settings, device); check_add_mappable_device (input_settings, device); } -static void -meta_input_settings_device_removed (ClutterSeat *seat, - ClutterInputDevice *device, - MetaInputSettings *input_settings) +void +meta_input_settings_remove_device (MetaInputSettings *input_settings, + ClutterInputDevice *device) { MetaInputSettingsPrivate *priv; priv = meta_input_settings_get_instance_private (input_settings); - meta_input_mapper_remove_device (priv->input_mapper, device); g_hash_table_remove (priv->mappable_devices, device); g_hash_table_remove (priv->current_tools, device); if (g_hash_table_remove (priv->two_finger_devices, device) && g_hash_table_size (priv->two_finger_devices) == 0) apply_device_settings (input_settings, NULL); + + priv->devices = g_list_remove (priv->devices, device); } static void @@ -1934,11 +1695,10 @@ current_tool_info_free (CurrentToolInfo *info) g_free (info); } -static void -meta_input_settings_tool_changed (ClutterSeat *seat, - ClutterInputDevice *device, - ClutterInputDeviceTool *tool, - MetaInputSettings *input_settings) +void +meta_input_settings_notify_tool_change (MetaInputSettings *input_settings, + ClutterInputDevice *device, + ClutterInputDeviceTool *tool) { MetaInputSettingsPrivate *priv; @@ -1962,12 +1722,11 @@ static void check_mappable_devices (MetaInputSettings *input_settings) { MetaInputSettingsPrivate *priv; - GList *l, *devices; + GList *l; priv = meta_input_settings_get_instance_private (input_settings); - devices = clutter_seat_list_devices (priv->seat); - for (l = devices; l; l = l->next) + for (l = priv->devices; l; l = l->next) { ClutterInputDevice *device = l->data; @@ -1976,41 +1735,6 @@ check_mappable_devices (MetaInputSettings *input_settings) check_add_mappable_device (input_settings, device); } - - g_list_free (devices); -} - -static void -power_save_mode_changed_cb (MetaMonitorManager *manager, - gpointer user_data) -{ - MetaInputSettingsPrivate *priv; - ClutterInputDevice *device; - MetaLogicalMonitor *logical_monitor; - MetaMonitor *builtin; - MetaPowerSave power_save_mode; - gboolean on; - - power_save_mode = meta_monitor_manager_get_power_save_mode (manager); - on = power_save_mode == META_POWER_SAVE_ON; - priv = meta_input_settings_get_instance_private (user_data); - - builtin = meta_monitor_manager_get_laptop_panel (manager); - if (!builtin) - return; - - logical_monitor = meta_monitor_get_logical_monitor (builtin); - if (!logical_monitor) - return; - - device = - meta_input_mapper_get_logical_monitor_device (priv->input_mapper, - logical_monitor, - CLUTTER_TOUCHSCREEN_DEVICE); - if (!device) - return; - - clutter_input_device_set_enabled (device, on); } static void @@ -2028,6 +1752,9 @@ meta_input_settings_constructed (GObject *object) apply_device_settings (input_settings, NULL); update_keyboard_repeat (input_settings); check_mappable_devices (input_settings); + + load_keyboard_a11y_settings (input_settings); + load_pointer_a11y_settings (input_settings); } static void @@ -2037,9 +1764,29 @@ meta_input_settings_class_init (MetaInputSettingsClass *klass) object_class->dispose = meta_input_settings_dispose; object_class->constructed = meta_input_settings_constructed; + object_class->set_property = meta_input_settings_set_property; + object_class->get_property = meta_input_settings_get_property; quark_tool_settings = g_quark_from_static_string ("meta-input-settings-tool-settings"); + + signals[KBD_A11Y_CHANGED] = + g_signal_new ("kbd-a11y-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + props[PROP_SEAT] = + g_param_spec_object ("seat", + "Seat", + "Seat", + CLUTTER_TYPE_SEAT, + CLUTTER_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, N_PROPS, props); } static void @@ -2048,13 +1795,6 @@ meta_input_settings_init (MetaInputSettings *settings) MetaInputSettingsPrivate *priv; priv = meta_input_settings_get_instance_private (settings); - priv->seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); - g_signal_connect (priv->seat, "device-added", - G_CALLBACK (meta_input_settings_device_added), settings); - g_signal_connect (priv->seat, "device-removed", - G_CALLBACK (meta_input_settings_device_removed), settings); - g_signal_connect (priv->seat, "tool-changed", - G_CALLBACK (meta_input_settings_tool_changed), settings); priv->mouse_settings = g_settings_new ("org.gnome.desktop.peripherals.mouse"); g_signal_connect (priv->mouse_settings, "changed", @@ -2081,8 +1821,6 @@ meta_input_settings_init (MetaInputSettings *settings) priv->keyboard_a11y_settings = g_settings_new ("org.gnome.desktop.a11y.keyboard"); g_signal_connect (priv->keyboard_a11y_settings, "changed", G_CALLBACK (meta_input_keyboard_a11y_settings_changed), settings); - g_signal_connect (priv->seat, "kbd-a11y-flags-changed", - G_CALLBACK (on_keyboard_a11y_settings_changed), settings); priv->mouse_a11y_settings = g_settings_new ("org.gnome.desktop.a11y.mouse"); g_signal_connect (priv->mouse_a11y_settings, "changed", @@ -2094,702 +1832,102 @@ meta_input_settings_init (MetaInputSettings *settings) priv->current_tools = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) current_tool_info_free); - priv->monitor_manager = g_object_ref (meta_monitor_manager_get ()); - g_signal_connect (priv->monitor_manager, "monitors-changed-internal", - G_CALLBACK (monitors_changed_cb), settings); - g_signal_connect (priv->monitor_manager, "power-save-mode-changed", - G_CALLBACK (power_save_mode_changed_cb), settings); - priv->two_finger_devices = g_hash_table_new (NULL, NULL); - - priv->input_mapper = meta_input_mapper_new (); - g_signal_connect (priv->input_mapper, "device-mapped", - G_CALLBACK (input_mapper_device_mapped_cb), settings); } -GSettings * -meta_input_settings_get_tablet_settings (MetaInputSettings *settings, - ClutterInputDevice *device) -{ - MetaInputSettingsPrivate *priv; - DeviceMappingInfo *info; - - g_return_val_if_fail (META_IS_INPUT_SETTINGS (settings), NULL); - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); - - priv = meta_input_settings_get_instance_private (settings); - info = g_hash_table_lookup (priv->mappable_devices, device); - - return info ? g_object_ref (info->settings) : NULL; -} - -static ClutterInputDevice * -find_grouped_pen (MetaInputSettings *settings, - ClutterInputDevice *device) -{ - MetaInputSettingsPrivate *priv; - GList *l, *devices; - ClutterInputDeviceType device_type; - ClutterInputDevice *pen = NULL; - - device_type = clutter_input_device_get_device_type (device); - - if (device_type == CLUTTER_TABLET_DEVICE || - device_type == CLUTTER_PEN_DEVICE) - return device; - - priv = meta_input_settings_get_instance_private (settings); - devices = clutter_seat_list_devices (priv->seat); - - for (l = devices; l; l = l->next) - { - ClutterInputDevice *other_device = l->data; - - device_type = clutter_input_device_get_device_type (other_device); - - if ((device_type == CLUTTER_TABLET_DEVICE || - device_type == CLUTTER_PEN_DEVICE) && - clutter_input_device_is_grouped (device, other_device)) - { - pen = other_device; - break; - } - } - - g_list_free (devices); - - return pen; -} - -MetaLogicalMonitor * -meta_input_settings_get_tablet_logical_monitor (MetaInputSettings *settings, - ClutterInputDevice *device) -{ - MetaLogicalMonitor *logical_monitor = NULL; - MetaInputSettingsPrivate *priv; - DeviceMappingInfo *info; - - g_return_val_if_fail (META_IS_INPUT_SETTINGS (settings), NULL); - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL); - - if (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE) - { - device = find_grouped_pen (settings, device); - if (!device) - return NULL; - } - - priv = meta_input_settings_get_instance_private (settings); - info = g_hash_table_lookup (priv->mappable_devices, device); - if (!info) - return NULL; - - logical_monitor = - meta_input_mapper_get_device_logical_monitor (priv->input_mapper, device); - - if (!logical_monitor) - { - meta_input_settings_find_monitor (settings, info->settings, device, - NULL, &logical_monitor); - } - - return logical_monitor; -} - -static GDesktopPadButtonAction -meta_input_settings_get_pad_button_action (MetaInputSettings *input_settings, - ClutterInputDevice *pad, - guint button) -{ - GDesktopPadButtonAction action; - GSettings *settings; - - g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), - G_DESKTOP_PAD_BUTTON_ACTION_NONE); - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), - G_DESKTOP_PAD_BUTTON_ACTION_NONE); - - settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON, - button, META_PAD_DIRECTION_NONE, -1); - action = g_settings_get_enum (settings, "action"); - g_object_unref (settings); - - return action; -} - -static gboolean -cycle_logical_monitors (MetaInputSettings *settings, - gboolean skip_all_monitors, - MetaLogicalMonitor *current_logical_monitor, - MetaLogicalMonitor **next_logical_monitor) -{ - MetaInputSettingsPrivate *priv = - meta_input_settings_get_instance_private (settings); - MetaMonitorManager *monitor_manager = priv->monitor_manager; - GList *logical_monitors; - - /* We cycle between: - * - the span of all monitors (current_logical_monitor = NULL), only for - * non-integrated devices. - * - each monitor individually. - */ - - logical_monitors = - meta_monitor_manager_get_logical_monitors (monitor_manager); - - if (!current_logical_monitor) - { - *next_logical_monitor = logical_monitors->data; - } - else - { - GList *l; - - l = g_list_find (logical_monitors, current_logical_monitor); - if (l->next) - *next_logical_monitor = l->next->data; - else if (skip_all_monitors) - *next_logical_monitor = logical_monitors->data; - else - *next_logical_monitor = NULL; - } - - return TRUE; -} - -static void -meta_input_settings_cycle_tablet_output (MetaInputSettings *input_settings, - ClutterInputDevice *device) +void +meta_input_settings_maybe_save_numlock_state (MetaInputSettings *input_settings, + gboolean numlock_state) { MetaInputSettingsPrivate *priv; - DeviceMappingInfo *info; - MetaLogicalMonitor *logical_monitor = NULL; - const gchar *edid[4] = { 0 }, *pretty_name = NULL; - gboolean is_integrated_device = FALSE; -#ifdef HAVE_LIBWACOM - WacomDevice *wacom_device; -#endif - - g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings)); - g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - g_return_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE || - clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE); priv = meta_input_settings_get_instance_private (input_settings); - info = g_hash_table_lookup (priv->mappable_devices, device); - g_return_if_fail (info != NULL); -#ifdef HAVE_LIBWACOM - wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (device)); - - if (wacom_device) - { - pretty_name = libwacom_get_name (wacom_device); - is_integrated_device = - libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE; - } -#endif - - meta_input_settings_find_monitor (input_settings, info->settings, device, - NULL, &logical_monitor); - - if (!cycle_logical_monitors (input_settings, - is_integrated_device, - logical_monitor, - &logical_monitor)) + if (!g_settings_get_boolean (priv->keyboard_settings, "remember-numlock-state")) return; - if (logical_monitor) - { - MetaMonitor *monitor; - - /* Pick an arbitrary monitor in the logical monitor to represent it. */ - monitor = meta_logical_monitor_get_monitors (logical_monitor)->data; - edid[0] = meta_monitor_get_vendor (monitor); - edid[1] = meta_monitor_get_product (monitor); - edid[2] = meta_monitor_get_serial (monitor); - } - else - { - edid[0] = ""; - edid[1] = ""; - edid[2] = ""; - } - g_settings_set_strv (info->settings, "output", edid); - - meta_display_show_tablet_mapping_notification (meta_get_display (), - device, pretty_name); -} - -static void -emulate_modifiers (ClutterVirtualInputDevice *device, - ClutterModifierType mods, - ClutterKeyState state) -{ - guint i; - struct { - ClutterModifierType mod; - guint keyval; - } mod_map[] = { - { CLUTTER_SHIFT_MASK, CLUTTER_KEY_Shift_L }, - { CLUTTER_CONTROL_MASK, CLUTTER_KEY_Control_L }, - { CLUTTER_MOD1_MASK, CLUTTER_KEY_Meta_L } - }; - - for (i = 0; i < G_N_ELEMENTS (mod_map); i++) - { - if ((mods & mod_map[i].mod) == 0) - continue; - - clutter_virtual_input_device_notify_keyval (device, - clutter_get_current_event_time (), - mod_map[i].keyval, state); - } -} - -static void -meta_input_settings_emulate_keybinding (MetaInputSettings *input_settings, - const gchar *accel, - gboolean is_press) -{ - MetaInputSettingsPrivate *priv; - ClutterKeyState state; - guint key, mods; - - if (!accel || !*accel) + if (numlock_state == g_settings_get_boolean (priv->keyboard_settings, "numlock-state")) return; - priv = meta_input_settings_get_instance_private (input_settings); - - /* FIXME: This is appalling */ - gtk_accelerator_parse (accel, &key, &mods); - - if (!priv->virtual_pad_keyboard) - { - ClutterBackend *backend; - ClutterSeat *seat; - - backend = clutter_get_default_backend (); - seat = clutter_backend_get_default_seat (backend); - - priv->virtual_pad_keyboard = - clutter_seat_create_virtual_device (seat, - CLUTTER_KEYBOARD_DEVICE); - } - - state = is_press ? CLUTTER_KEY_STATE_PRESSED : CLUTTER_KEY_STATE_RELEASED; - - if (is_press) - emulate_modifiers (priv->virtual_pad_keyboard, mods, state); - - clutter_virtual_input_device_notify_keyval (priv->virtual_pad_keyboard, - clutter_get_current_event_time (), - key, state); - if (!is_press) - emulate_modifiers (priv->virtual_pad_keyboard, mods, state); + g_settings_set_boolean (priv->keyboard_settings, "numlock-state", numlock_state); } gboolean -meta_input_settings_is_pad_button_grabbed (MetaInputSettings *input_settings, - ClutterInputDevice *pad, - guint button) -{ - g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), FALSE); - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), FALSE); - g_return_val_if_fail (clutter_input_device_get_device_type (pad) == - CLUTTER_PAD_DEVICE, FALSE); - - return (meta_input_settings_get_pad_button_action (input_settings, pad, button) != - G_DESKTOP_PAD_BUTTON_ACTION_NONE); -} - -static gboolean -meta_input_settings_handle_pad_button (MetaInputSettings *input_settings, - ClutterInputDevice *pad, - const ClutterPadButtonEvent *event) -{ - GDesktopPadButtonAction action; - gint button, group, mode; - gboolean is_press; - GSettings *settings; - gchar *accel; - - g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), FALSE); - g_return_val_if_fail (event->type == CLUTTER_PAD_BUTTON_PRESS || - event->type == CLUTTER_PAD_BUTTON_RELEASE, FALSE); - - button = event->button; - mode = event->mode; - group = clutter_input_device_get_mode_switch_button_group (pad, button); - is_press = event->type == CLUTTER_PAD_BUTTON_PRESS; - - if (is_press && group >= 0) - { - guint n_modes = clutter_input_device_get_group_n_modes (pad, group); - const gchar *pretty_name = NULL; - MetaInputSettingsPrivate *priv; - DeviceMappingInfo *info; -#ifdef HAVE_LIBWACOM - WacomDevice *wacom_device; -#endif - - priv = meta_input_settings_get_instance_private (input_settings); - info = g_hash_table_lookup (priv->mappable_devices, pad); - -#ifdef HAVE_LIBWACOM - wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (pad)); - - if (wacom_device) - pretty_name = libwacom_get_name (wacom_device); -#endif - meta_display_notify_pad_group_switch (meta_get_display (), pad, - pretty_name, group, mode, n_modes); - info->group_modes[group] = mode; - } - - action = meta_input_settings_get_pad_button_action (input_settings, pad, button); - - switch (action) - { - case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR: - if (is_press) - meta_input_settings_cycle_tablet_output (input_settings, pad); - return TRUE; - case G_DESKTOP_PAD_BUTTON_ACTION_HELP: - if (is_press) - meta_display_request_pad_osd (meta_get_display (), pad, FALSE); - return TRUE; - case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING: - settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON, - button, META_PAD_DIRECTION_NONE, -1); - accel = g_settings_get_string (settings, "keybinding"); - meta_input_settings_emulate_keybinding (input_settings, accel, is_press); - g_object_unref (settings); - g_free (accel); - return TRUE; - case G_DESKTOP_PAD_BUTTON_ACTION_NONE: - default: - return FALSE; - } -} - -static gboolean -meta_input_settings_handle_pad_action (MetaInputSettings *input_settings, - ClutterInputDevice *pad, - MetaPadActionType action, - guint number, - MetaPadDirection direction, - guint mode) -{ - GSettings *settings; - gboolean handled = FALSE; - gchar *accel; - - settings = lookup_pad_action_settings (pad, action, number, direction, mode); - accel = g_settings_get_string (settings, "keybinding"); - - if (accel && *accel) - { - meta_input_settings_emulate_keybinding (input_settings, accel, TRUE); - meta_input_settings_emulate_keybinding (input_settings, accel, FALSE); - handled = TRUE; - } - - g_object_unref (settings); - g_free (accel); - - return handled; -} - -static gboolean -meta_input_settings_get_pad_action_direction (MetaInputSettings *input_settings, - const ClutterEvent *event, - MetaPadDirection *direction) +meta_input_settings_maybe_restore_numlock_state (MetaInputSettings *input_settings) { MetaInputSettingsPrivate *priv; - ClutterInputDevice *pad = clutter_event_get_device (event); - MetaPadActionType pad_action; - gboolean has_direction = FALSE; - MetaPadDirection inc_dir, dec_dir; - guint number; - gdouble value; + gboolean numlock_state = FALSE; priv = meta_input_settings_get_instance_private (input_settings); - *direction = META_PAD_DIRECTION_NONE; - - switch (event->type) - { - case CLUTTER_PAD_RING: - pad_action = META_PAD_ACTION_RING; - number = event->pad_ring.ring_number; - value = event->pad_ring.angle; - inc_dir = META_PAD_DIRECTION_CW; - dec_dir = META_PAD_DIRECTION_CCW; - break; - case CLUTTER_PAD_STRIP: - pad_action = META_PAD_ACTION_STRIP; - number = event->pad_strip.strip_number; - value = event->pad_strip.value; - inc_dir = META_PAD_DIRECTION_DOWN; - dec_dir = META_PAD_DIRECTION_UP; - break; - default: - return FALSE; - } - - if (priv->last_pad_action_info.pad == pad && - priv->last_pad_action_info.action == pad_action && - priv->last_pad_action_info.number == number && - value >= 0 && priv->last_pad_action_info.value >= 0) - { - *direction = (value - priv->last_pad_action_info.value) > 0 ? - inc_dir : dec_dir; - has_direction = TRUE; - } - - priv->last_pad_action_info.pad = pad; - priv->last_pad_action_info.action = pad_action; - priv->last_pad_action_info.number = number; - priv->last_pad_action_info.value = value; - return has_direction; -} - -gboolean -meta_input_settings_handle_pad_event (MetaInputSettings *input_settings, - const ClutterEvent *event) -{ - ClutterInputDevice *pad; - MetaPadDirection direction = META_PAD_DIRECTION_NONE; - - pad = clutter_event_get_source_device ((ClutterEvent *) event); - - switch (event->type) - { - case CLUTTER_PAD_BUTTON_PRESS: - case CLUTTER_PAD_BUTTON_RELEASE: - return meta_input_settings_handle_pad_button (input_settings, pad, - &event->pad_button); - case CLUTTER_PAD_RING: - if (!meta_input_settings_get_pad_action_direction (input_settings, - event, &direction)) - return FALSE; - return meta_input_settings_handle_pad_action (input_settings, pad, - META_PAD_ACTION_RING, - event->pad_ring.ring_number, - direction, - event->pad_ring.mode); - case CLUTTER_PAD_STRIP: - if (!meta_input_settings_get_pad_action_direction (input_settings, - event, &direction)) - return FALSE; - return meta_input_settings_handle_pad_action (input_settings, pad, - META_PAD_ACTION_STRIP, - event->pad_strip.strip_number, - direction, - event->pad_strip.mode); - default: - return FALSE; - } -} - -static gchar * -compose_directional_action_label (GSettings *direction1, - GSettings *direction2) -{ - gchar *accel1, *accel2, *str = NULL; - - accel1 = g_settings_get_string (direction1, "keybinding"); - accel2 = g_settings_get_string (direction2, "keybinding"); - - if (accel1 && *accel1 && accel2 && *accel2) - str = g_strdup_printf ("%s / %s", accel1, accel2); - g_free (accel1); - g_free (accel2); + if (g_settings_get_boolean (priv->keyboard_settings, "remember-numlock-state")) + numlock_state = g_settings_get_boolean (priv->keyboard_settings, "numlock-state"); - return str; + return numlock_state; } -static gchar * -meta_input_settings_get_ring_label (MetaInputSettings *settings, - ClutterInputDevice *pad, - guint number, - guint mode) -{ - GSettings *settings1, *settings2; - gchar *label; - - /* We only allow keybinding actions with those */ - settings1 = lookup_pad_action_settings (pad, META_PAD_ACTION_RING, number, - META_PAD_DIRECTION_CW, mode); - settings2 = lookup_pad_action_settings (pad, META_PAD_ACTION_RING, number, - META_PAD_DIRECTION_CCW, mode); - label = compose_directional_action_label (settings1, settings2); - g_object_unref (settings1); - g_object_unref (settings2); - - return label; -} - -static gchar * -meta_input_settings_get_strip_label (MetaInputSettings *settings, - ClutterInputDevice *pad, - guint number, - guint mode) +void +meta_input_settings_set_device_matrix (MetaInputSettings *input_settings, + ClutterInputDevice *device, + float matrix[6]) { - GSettings *settings1, *settings2; - gchar *label; - - /* We only allow keybinding actions with those */ - settings1 = lookup_pad_action_settings (pad, META_PAD_ACTION_STRIP, number, - META_PAD_DIRECTION_UP, mode); - settings2 = lookup_pad_action_settings (pad, META_PAD_ACTION_STRIP, number, - META_PAD_DIRECTION_DOWN, mode); - label = compose_directional_action_label (settings1, settings2); - g_object_unref (settings1); - g_object_unref (settings2); + g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings)); + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - return label; + META_INPUT_SETTINGS_GET_CLASS (input_settings)->set_matrix (input_settings, + device, + matrix); } -static gchar * -meta_input_settings_get_button_label (MetaInputSettings *input_settings, - ClutterInputDevice *pad, - guint button) +void +meta_input_settings_set_device_enabled (MetaInputSettings *input_settings, + ClutterInputDevice *device, + gboolean enabled) { - GDesktopPadButtonAction action; - gint group; - - g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), NULL); - g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), NULL); - g_return_val_if_fail (clutter_input_device_get_device_type (pad) == - CLUTTER_PAD_DEVICE, NULL); - - group = clutter_input_device_get_mode_switch_button_group (pad, button); + GDesktopDeviceSendEvents mode; - if (group >= 0) - { - /* TRANSLATORS: This string refers to a button that switches between - * different modes. - */ - return g_strdup_printf (_("Mode Switch (Group %d)"), group); - } + g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings)); + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); - action = meta_input_settings_get_pad_button_action (input_settings, pad, button); + mode = enabled ? + G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED : + G_DESKTOP_DEVICE_SEND_EVENTS_DISABLED; - switch (action) - { - case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING: - { - GSettings *settings; - gchar *accel; - - settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON, - button, META_PAD_DIRECTION_NONE, -1); - accel = g_settings_get_string (settings, "keybinding"); - g_object_unref (settings); - - return accel; - } - case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR: - /* TRANSLATORS: This string refers to an action, cycles drawing tablets' - * mapping through the available outputs. - */ - return g_strdup (_("Switch monitor")); - case G_DESKTOP_PAD_BUTTON_ACTION_HELP: - return g_strdup (_("Show on-screen help")); - case G_DESKTOP_PAD_BUTTON_ACTION_NONE: - default: - return NULL; - } + META_INPUT_SETTINGS_GET_CLASS (input_settings)->set_send_events (input_settings, + device, + mode); } -static guint -get_current_pad_mode (MetaInputSettings *input_settings, - ClutterInputDevice *pad, - MetaPadActionType action_type, - guint number) +void +meta_input_settings_set_device_aspect_ratio (MetaInputSettings *input_settings, + ClutterInputDevice *device, + double aspect_ratio) { MetaInputSettingsPrivate *priv; DeviceMappingInfo *info; - guint group = 0, n_groups; - - priv = meta_input_settings_get_instance_private (input_settings); - info = g_hash_table_lookup (priv->mappable_devices, pad); - n_groups = clutter_input_device_get_n_mode_groups (pad); - - if (!info->group_modes || n_groups == 0) - return 0; - - if (action_type == META_PAD_ACTION_RING || - action_type == META_PAD_ACTION_STRIP) - { - /* Assume features are evenly distributed in groups */ - group = number % n_groups; - } - return info->group_modes[group]; -} - -gchar * -meta_input_settings_get_pad_action_label (MetaInputSettings *input_settings, - ClutterInputDevice *pad, - MetaPadActionType action_type, - guint number) -{ - guint mode; - - switch (action_type) - { - case META_PAD_ACTION_BUTTON: - return meta_input_settings_get_button_label (input_settings, pad, number); - case META_PAD_ACTION_RING: - mode = get_current_pad_mode (input_settings, pad, action_type, number); - return meta_input_settings_get_ring_label (input_settings, pad, - number, mode); - case META_PAD_ACTION_STRIP: - mode = get_current_pad_mode (input_settings, pad, action_type, number); - return meta_input_settings_get_strip_label (input_settings, pad, - number, mode); - } - - return NULL; -} - -void -meta_input_settings_maybe_save_numlock_state (MetaInputSettings *input_settings) -{ - MetaInputSettingsPrivate *priv; - ClutterSeat *seat; - ClutterKeymap *keymap; - gboolean numlock_state; + g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings)); + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); priv = meta_input_settings_get_instance_private (input_settings); - if (!g_settings_get_boolean (priv->keyboard_settings, "remember-numlock-state")) - return; - - seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); - keymap = clutter_seat_get_keymap (seat); - numlock_state = clutter_keymap_get_num_lock_state (keymap); - - if (numlock_state == g_settings_get_boolean (priv->keyboard_settings, "numlock-state")) + info = g_hash_table_lookup (priv->mappable_devices, device); + if (!info) return; - g_settings_set_boolean (priv->keyboard_settings, "numlock-state", numlock_state); + info->aspect_ratio = aspect_ratio; + update_tablet_keep_aspect (input_settings, info->settings, device); } void -meta_input_settings_maybe_restore_numlock_state (MetaInputSettings *input_settings) +meta_input_settings_get_kbd_a11y_settings (MetaInputSettings *input_settings, + MetaKbdA11ySettings *a11y_settings) { MetaInputSettingsPrivate *priv; - gboolean numlock_state; - priv = meta_input_settings_get_instance_private (input_settings); + g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings)); - if (!g_settings_get_boolean (priv->keyboard_settings, "remember-numlock-state")) - return; + priv = meta_input_settings_get_instance_private (input_settings); - numlock_state = g_settings_get_boolean (priv->keyboard_settings, "numlock-state"); - meta_backend_set_numlock (meta_get_backend (), numlock_state); + *a11y_settings = priv->kbd_a11y_settings; } diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index b9c68aad473bce221a8ce9f72785af7d7ab8754a..eaad2c4ce795ee7d4054f9608ed934cb1a7a9a84 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -31,6 +31,7 @@ #include "backends/meta-cursor.h" #include "backends/meta-display-config-shared.h" #include "backends/meta-monitor-transform.h" +#include "backends/meta-viewport-info.h" #include "core/util-private.h" #include "meta/display.h" #include "meta/meta-monitor-manager.h" @@ -404,4 +405,6 @@ meta_find_output_assignment (MetaOutputAssignment **outputs, void meta_monitor_manager_post_init (MetaMonitorManager *manager); +MetaViewportInfo * meta_monitor_manager_get_viewports (MetaMonitorManager *manager); + #endif /* META_MONITOR_MANAGER_PRIVATE_H */ diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 4488ab32ac851032a4c948e6b21b9e06ee5b1be4..dbf799975f337693ba4a954cef541665a100edd2 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -3250,3 +3250,37 @@ meta_monitor_manager_post_init (MetaMonitorManager *manager) G_CALLBACK (update_panel_orientation_managed), manager, G_CONNECT_SWAPPED); } + +MetaViewportInfo * +meta_monitor_manager_get_viewports (MetaMonitorManager *manager) +{ + MetaViewportInfo *info; + GArray *views, *scales; + GList *logical_monitors, *l; + + views = g_array_new (FALSE, FALSE, sizeof (cairo_rectangle_int_t)); + scales = g_array_new (FALSE, FALSE, sizeof (float)); + + logical_monitors = meta_monitor_manager_get_logical_monitors (manager); + + for (l = logical_monitors; l; l = l->next) + { + MetaLogicalMonitor *logical_monitor = l->data; + cairo_rectangle_int_t rect; + float scale; + + rect = logical_monitor->rect; + g_array_append_val (views, rect); + + scale = logical_monitor->scale; + g_array_append_val (scales, scale); + } + + info = meta_viewport_info_new ((cairo_rectangle_int_t *) views->data, + (float *) scales->data, + views->len); + g_array_unref (views); + g_array_unref (scales); + + return info; +} diff --git a/src/backends/meta-pointer-constraint.c b/src/backends/meta-pointer-constraint.c index 55ca9f023976f348d87e466fdece0b39aec2f648..7682b14b0566d153131e8df246634652b6ec6670 100644 --- a/src/backends/meta-pointer-constraint.c +++ b/src/backends/meta-pointer-constraint.c @@ -39,10 +39,34 @@ #include "backends/meta-pointer-constraint.h" +#ifdef HAVE_NATIVE_BACKEND +#include "backends/native/meta-backend-native.h" +#include "backends/native/meta-pointer-constraint-native.h" +#endif + #include +struct _MetaPointerConstraint +{ + GObject parent_instance; + cairo_region_t *region; +}; + G_DEFINE_TYPE (MetaPointerConstraint, meta_pointer_constraint, G_TYPE_OBJECT); +G_DEFINE_TYPE (MetaPointerConstraintImpl, meta_pointer_constraint_impl, + G_TYPE_OBJECT); + +static void +meta_pointer_constraint_finalize (GObject *object) +{ + MetaPointerConstraint *constraint = META_POINTER_CONSTRAINT (object); + + g_clear_pointer (&constraint->region, cairo_region_destroy); + + G_OBJECT_CLASS (meta_pointer_constraint_parent_class)->finalize (object); +} + static void meta_pointer_constraint_init (MetaPointerConstraint *constraint) { @@ -50,12 +74,43 @@ meta_pointer_constraint_init (MetaPointerConstraint *constraint) static void meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_pointer_constraint_finalize; +} + + +MetaPointerConstraint * +meta_pointer_constraint_new (const cairo_region_t *region) +{ + MetaPointerConstraint *constraint; + + constraint = g_object_new (META_TYPE_POINTER_CONSTRAINT, NULL); + constraint->region = cairo_region_copy (region); + + return constraint; +} + +cairo_region_t * +meta_pointer_constraint_get_region (MetaPointerConstraint *constraint) +{ + return constraint->region; +} + +static void +meta_pointer_constraint_impl_init (MetaPointerConstraintImpl *constraint_impl) +{ +} + +static void +meta_pointer_constraint_impl_class_init (MetaPointerConstraintImplClass *klass) { } /** - * meta_pointer_constraint_constrain: - * @constraint: a #MetaPointerConstraint. + * meta_pointer_constraint_impl_constrain: + * @constraint_impl: a #MetaPointerConstraintImpl. * @device; the device of the pointer. * @time: the timestamp (in ms) of the event. * @prev_x: X-coordinate of the previous pointer position. @@ -67,17 +122,25 @@ meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass) * if needed. */ void -meta_pointer_constraint_constrain (MetaPointerConstraint *constraint, - ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y) +meta_pointer_constraint_impl_constrain (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device, + uint32_t time, + float prev_x, + float prev_y, + float *x, + float *y) +{ + META_POINTER_CONSTRAINT_IMPL_GET_CLASS (constraint_impl)->constrain (constraint_impl, + device, + time, + prev_x, prev_y, + x, y); +} + +void +meta_pointer_constraint_impl_ensure_constrained (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device) { - META_POINTER_CONSTRAINT_GET_CLASS (constraint)->constrain (constraint, - device, - time, - prev_x, prev_y, - x, y); + META_POINTER_CONSTRAINT_IMPL_GET_CLASS (constraint_impl)->ensure_constrained (constraint_impl, + device); } diff --git a/src/backends/meta-pointer-constraint.h b/src/backends/meta-pointer-constraint.h index ed0b025b568afea8f3b4d45a6deb44db3165caf3..b47eda4903f78ecd619e454f85166c00078da968 100644 --- a/src/backends/meta-pointer-constraint.h +++ b/src/backends/meta-pointer-constraint.h @@ -32,34 +32,45 @@ G_BEGIN_DECLS #define META_TYPE_POINTER_CONSTRAINT (meta_pointer_constraint_get_type ()) -G_DECLARE_DERIVABLE_TYPE (MetaPointerConstraint, meta_pointer_constraint, - META, POINTER_CONSTRAINT, GObject); +G_DECLARE_FINAL_TYPE (MetaPointerConstraint, meta_pointer_constraint, + META, POINTER_CONSTRAINT, GObject); + +MetaPointerConstraint * meta_pointer_constraint_new (const cairo_region_t *region); +cairo_region_t * meta_pointer_constraint_get_region (MetaPointerConstraint *constraint); + +#define META_TYPE_POINTER_CONSTRAINT_IMPL (meta_pointer_constraint_impl_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaPointerConstraintImpl, meta_pointer_constraint_impl, + META, POINTER_CONSTRAINT_IMPL, GObject); /** - * MetaPointerConstraintClass: + * MetaPointerConstraintImplClass: * @constrain: the virtual function pointer for - * meta_pointer_constraint_constrain(). + * meta_pointer_constraint_impl_constrain(). */ -struct _MetaPointerConstraintClass +struct _MetaPointerConstraintImplClass { GObjectClass parent_class; - void (*constrain) (MetaPointerConstraint *constraint, - ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y); + void (* constrain) (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device, + uint32_t time, + float prev_x, + float prev_y, + float *x, + float *y); + void (* ensure_constrained) (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device); }; -void meta_pointer_constraint_constrain (MetaPointerConstraint *constraint, - ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y); +void meta_pointer_constraint_impl_constrain (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device, + uint32_t time, + float prev_x, + float prev_y, + float *x, + float *y); +void meta_pointer_constraint_impl_ensure_constrained (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device); G_END_DECLS diff --git a/src/backends/meta-screen-cast-area-stream-src.c b/src/backends/meta-screen-cast-area-stream-src.c index e7d42d432a33bbfef3178dd22956ebd97cc28d41..1b0da7be2efbfea7cebbda6c68872f202327bcd0 100644 --- a/src/backends/meta-screen-cast-area-stream-src.c +++ b/src/backends/meta-screen-cast-area-stream-src.c @@ -42,7 +42,7 @@ struct _MetaScreenCastAreaStreamSrc GList *watches; - gulong cursor_moved_handler_id; + gulong position_invalidated_handler_id; gulong cursor_changed_handler_id; guint maybe_record_idle_id; @@ -83,19 +83,6 @@ get_backend (MetaScreenCastAreaStreamSrc *area_src) return meta_screen_cast_get_backend (screen_cast); } -static MetaCursorRenderer * -get_cursor_renderer (MetaScreenCastAreaStreamSrc *area_src) -{ - MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (area_src); - MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); - MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream); - MetaScreenCast *screen_cast = - meta_screen_cast_session_get_screen_cast (session); - MetaBackend *backend = meta_screen_cast_get_backend (screen_cast); - - return meta_backend_get_cursor_renderer (backend); -} - static void meta_screen_cast_area_stream_src_get_specs (MetaScreenCastStreamSrc *src, int *width, @@ -142,9 +129,11 @@ is_cursor_in_stream (MetaScreenCastAreaStreamSrc *area_src) } else { + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); graphene_point_t cursor_position; - cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); return graphene_rect_contains_point (&area_rect, &cursor_position); } } @@ -180,10 +169,8 @@ sync_cursor_state (MetaScreenCastAreaStreamSrc *area_src) } static void -cursor_moved (MetaCursorTracker *cursor_tracker, - float x, - float y, - MetaScreenCastAreaStreamSrc *area_src) +pointer_position_invalidated (MetaCursorTracker *cursor_tracker, + MetaScreenCastAreaStreamSrc *area_src) { sync_cursor_state (area_src); } @@ -199,14 +186,14 @@ cursor_changed (MetaCursorTracker *cursor_tracker, static void inhibit_hw_cursor (MetaScreenCastAreaStreamSrc *area_src) { - MetaCursorRenderer *cursor_renderer; MetaHwCursorInhibitor *inhibitor; + MetaBackend *backend; g_return_if_fail (!area_src->hw_cursor_inhibited); - cursor_renderer = get_cursor_renderer (area_src); + backend = get_backend (area_src); inhibitor = META_HW_CURSOR_INHIBITOR (area_src); - meta_cursor_renderer_add_hw_cursor_inhibitor (cursor_renderer, inhibitor); + meta_backend_add_hw_cursor_inhibitor (backend, inhibitor); area_src->hw_cursor_inhibited = TRUE; } @@ -214,14 +201,14 @@ inhibit_hw_cursor (MetaScreenCastAreaStreamSrc *area_src) static void uninhibit_hw_cursor (MetaScreenCastAreaStreamSrc *area_src) { - MetaCursorRenderer *cursor_renderer; MetaHwCursorInhibitor *inhibitor; + MetaBackend *backend; g_return_if_fail (area_src->hw_cursor_inhibited); - cursor_renderer = get_cursor_renderer (area_src); + backend = get_backend (area_src); inhibitor = META_HW_CURSOR_INHIBITOR (area_src); - meta_cursor_renderer_remove_hw_cursor_inhibitor (cursor_renderer, inhibitor); + meta_backend_remove_hw_cursor_inhibitor (backend, inhibitor); area_src->hw_cursor_inhibited = FALSE; } @@ -332,9 +319,9 @@ meta_screen_cast_area_stream_src_enable (MetaScreenCastStreamSrc *src) switch (meta_screen_cast_stream_get_cursor_mode (stream)) { case META_SCREEN_CAST_CURSOR_MODE_METADATA: - area_src->cursor_moved_handler_id = - g_signal_connect_after (cursor_tracker, "cursor-moved", - G_CALLBACK (cursor_moved), + area_src->position_invalidated_handler_id = + g_signal_connect_after (cursor_tracker, "position-invalidated", + G_CALLBACK (pointer_position_invalidated), area_src); area_src->cursor_changed_handler_id = g_signal_connect_after (cursor_tracker, "cursor-changed", @@ -383,7 +370,7 @@ meta_screen_cast_area_stream_src_disable (MetaScreenCastStreamSrc *src) if (area_src->hw_cursor_inhibited) uninhibit_hw_cursor (area_src); - g_clear_signal_handler (&area_src->cursor_moved_handler_id, + g_clear_signal_handler (&area_src->position_invalidated_handler_id, cursor_tracker); g_clear_signal_handler (&area_src->cursor_changed_handler_id, cursor_tracker); @@ -526,7 +513,7 @@ meta_screen_cast_area_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *s area = meta_screen_cast_area_stream_get_area (area_stream); scale = meta_screen_cast_area_stream_get_scale (area_stream); - cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); cursor_position.x -= area->x; cursor_position.y -= area->y; cursor_position.x *= scale; @@ -568,8 +555,7 @@ meta_screen_cast_area_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *s } static gboolean -meta_screen_cast_area_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor, - MetaCursorSprite *cursor_sprite) +meta_screen_cast_area_stream_src_is_cursor_inhibited (MetaHwCursorInhibitor *inhibitor) { MetaScreenCastAreaStreamSrc *area_src = META_SCREEN_CAST_AREA_STREAM_SRC (inhibitor); @@ -580,8 +566,8 @@ meta_screen_cast_area_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhibit static void hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface) { - iface->is_cursor_sprite_inhibited = - meta_screen_cast_area_stream_src_is_cursor_sprite_inhibited; + iface->is_cursor_inhibited = + meta_screen_cast_area_stream_src_is_cursor_inhibited; } MetaScreenCastAreaStreamSrc * diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c index ab3be968365a44e31f11244de2e0e855d5e92939..52661033d0a31e03c85bc0afc6f05fcfd3b70c25 100644 --- a/src/backends/meta-screen-cast-monitor-stream-src.c +++ b/src/backends/meta-screen-cast-monitor-stream-src.c @@ -46,7 +46,7 @@ struct _MetaScreenCastMonitorStreamSrc GList *watches; - gulong cursor_moved_handler_id; + gulong position_invalidated_handler_id; gulong cursor_changed_handler_id; }; @@ -189,9 +189,11 @@ is_cursor_in_stream (MetaScreenCastMonitorStreamSrc *monitor_src) } else { + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); graphene_point_t cursor_position; - cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); return graphene_rect_contains_point (&logical_monitor_rect, &cursor_position); } @@ -236,10 +238,8 @@ sync_cursor_state (MetaScreenCastMonitorStreamSrc *monitor_src) } static void -cursor_moved (MetaCursorTracker *cursor_tracker, - float x, - float y, - MetaScreenCastMonitorStreamSrc *monitor_src) +pointer_position_invalidated (MetaCursorTracker *cursor_tracker, + MetaScreenCastMonitorStreamSrc *monitor_src) { sync_cursor_state (monitor_src); } @@ -252,30 +252,17 @@ cursor_changed (MetaCursorTracker *cursor_tracker, sync_cursor_state (monitor_src); } -static MetaCursorRenderer * -get_cursor_renderer (MetaScreenCastMonitorStreamSrc *monitor_src) -{ - MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src); - MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); - MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream); - MetaScreenCast *screen_cast = - meta_screen_cast_session_get_screen_cast (session); - MetaBackend *backend = meta_screen_cast_get_backend (screen_cast); - - return meta_backend_get_cursor_renderer (backend); -} - static void inhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src) { - MetaCursorRenderer *cursor_renderer; MetaHwCursorInhibitor *inhibitor; + MetaBackend *backend; g_return_if_fail (!monitor_src->hw_cursor_inhibited); - cursor_renderer = get_cursor_renderer (monitor_src); + backend = get_backend (monitor_src); inhibitor = META_HW_CURSOR_INHIBITOR (monitor_src); - meta_cursor_renderer_add_hw_cursor_inhibitor (cursor_renderer, inhibitor); + meta_backend_add_hw_cursor_inhibitor (backend, inhibitor); monitor_src->hw_cursor_inhibited = TRUE; } @@ -283,14 +270,14 @@ inhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src) static void uninhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src) { - MetaCursorRenderer *cursor_renderer; MetaHwCursorInhibitor *inhibitor; + MetaBackend *backend; g_return_if_fail (monitor_src->hw_cursor_inhibited); - cursor_renderer = get_cursor_renderer (monitor_src); + backend = get_backend (monitor_src); inhibitor = META_HW_CURSOR_INHIBITOR (monitor_src); - meta_cursor_renderer_remove_hw_cursor_inhibitor (cursor_renderer, inhibitor); + meta_backend_remove_hw_cursor_inhibitor (backend, inhibitor); monitor_src->hw_cursor_inhibited = FALSE; } @@ -352,9 +339,9 @@ meta_screen_cast_monitor_stream_src_enable (MetaScreenCastStreamSrc *src) switch (meta_screen_cast_stream_get_cursor_mode (stream)) { case META_SCREEN_CAST_CURSOR_MODE_METADATA: - monitor_src->cursor_moved_handler_id = - g_signal_connect_after (cursor_tracker, "cursor-moved", - G_CALLBACK (cursor_moved), + monitor_src->position_invalidated_handler_id = + g_signal_connect_after (cursor_tracker, "position-invalidated", + G_CALLBACK (pointer_position_invalidated), monitor_src); monitor_src->cursor_changed_handler_id = g_signal_connect_after (cursor_tracker, "cursor-changed", @@ -408,7 +395,7 @@ meta_screen_cast_monitor_stream_src_disable (MetaScreenCastStreamSrc *src) if (monitor_src->hw_cursor_inhibited) uninhibit_hw_cursor (monitor_src); - g_clear_signal_handler (&monitor_src->cursor_moved_handler_id, + g_clear_signal_handler (&monitor_src->position_invalidated_handler_id, cursor_tracker); g_clear_signal_handler (&monitor_src->cursor_changed_handler_id, cursor_tracker); @@ -667,7 +654,7 @@ meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc else view_scale = 1.0; - cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); cursor_position.x -= logical_monitor_rect.origin.x; cursor_position.y -= logical_monitor_rect.origin.y; cursor_position.x *= view_scale; @@ -709,8 +696,7 @@ meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc } static gboolean -meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor, - MetaCursorSprite *cursor_sprite) +meta_screen_cast_monitor_stream_src_is_cursor_inhibited (MetaHwCursorInhibitor *inhibitor) { MetaScreenCastMonitorStreamSrc *monitor_src = META_SCREEN_CAST_MONITOR_STREAM_SRC (inhibitor); @@ -721,8 +707,8 @@ meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhi static void hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface) { - iface->is_cursor_sprite_inhibited = - meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited; + iface->is_cursor_inhibited = + meta_screen_cast_monitor_stream_src_is_cursor_inhibited; } MetaScreenCastMonitorStreamSrc * diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c index a00bf867ab9a058fc069bdb2fdc1098e56cdffa0..76f53d1600e9014582cd06c5b013cb8177792159 100644 --- a/src/backends/meta-screen-cast-window-stream-src.c +++ b/src/backends/meta-screen-cast-window-stream-src.c @@ -37,7 +37,7 @@ struct _MetaScreenCastWindowStreamSrc unsigned long screen_cast_window_damaged_handler_id; unsigned long screen_cast_window_destroyed_handler_id; - unsigned long cursor_moved_handler_id; + unsigned long position_invalidated_handler_id; unsigned long cursor_changed_handler_id; gboolean cursor_bitmap_invalid; @@ -110,6 +110,8 @@ maybe_draw_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src, MetaBackend *backend = get_backend (window_src); MetaCursorRenderer *cursor_renderer = meta_backend_get_cursor_renderer (backend); + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); MetaCursorSprite *cursor_sprite; CoglTexture *cursor_texture; MetaScreenCastWindow *screen_cast_window; @@ -133,7 +135,7 @@ maybe_draw_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src, return; screen_cast_window = window_src->screen_cast_window; - cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); if (!meta_screen_cast_window_transform_cursor_position (screen_cast_window, cursor_sprite, &cursor_position, @@ -189,6 +191,8 @@ maybe_blit_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src, clutter_backend_get_cogl_context (clutter_get_default_backend ()); MetaCursorRenderer *cursor_renderer = meta_backend_get_cursor_renderer (backend); + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); MetaScreenCastWindow *screen_cast_window; MetaCursorSprite *cursor_sprite; graphene_point_t relative_cursor_position; @@ -209,7 +213,7 @@ maybe_blit_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src, return; screen_cast_window = window_src->screen_cast_window; - cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); if (!meta_screen_cast_window_transform_cursor_position (screen_cast_window, cursor_sprite, &cursor_position, @@ -319,7 +323,7 @@ meta_screen_cast_window_stream_src_stop (MetaScreenCastWindowStreamSrc *window_s window_src->screen_cast_window); g_clear_signal_handler (&window_src->screen_cast_window_destroyed_handler_id, window_src->screen_cast_window); - g_clear_signal_handler (&window_src->cursor_moved_handler_id, + g_clear_signal_handler (&window_src->position_invalidated_handler_id, cursor_tracker); g_clear_signal_handler (&window_src->cursor_changed_handler_id, cursor_tracker); @@ -368,10 +372,8 @@ sync_cursor_state (MetaScreenCastWindowStreamSrc *window_src) } static void -cursor_moved (MetaCursorTracker *cursor_tracker, - float x, - float y, - MetaScreenCastWindowStreamSrc *window_src) +pointer_position_invalidated (MetaCursorTracker *cursor_tracker, + MetaScreenCastWindowStreamSrc *window_src) { sync_cursor_state (window_src); } @@ -418,9 +420,9 @@ meta_screen_cast_window_stream_src_enable (MetaScreenCastStreamSrc *src) { case META_SCREEN_CAST_CURSOR_MODE_METADATA: case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: - window_src->cursor_moved_handler_id = - g_signal_connect_after (cursor_tracker, "cursor-moved", - G_CALLBACK (cursor_moved), + window_src->position_invalidated_handler_id = + g_signal_connect_after (cursor_tracker, "position-invalidated", + G_CALLBACK (pointer_position_invalidated), window_src); window_src->cursor_changed_handler_id = g_signal_connect_after (cursor_tracker, "cursor-changed", @@ -526,7 +528,7 @@ meta_screen_cast_window_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc int x, y; cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); - cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); if (!meta_cursor_tracker_get_pointer_visible (cursor_tracker) || !meta_screen_cast_window_transform_cursor_position (screen_cast_window, diff --git a/src/backends/meta-viewport-info.c b/src/backends/meta-viewport-info.c new file mode 100644 index 0000000000000000000000000000000000000000..c8474f3fad1839c6b304eb6b6129e293405ac784 --- /dev/null +++ b/src/backends/meta-viewport-info.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2020 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Carlos Garnacho + */ + +#include "config.h" + +#include "backends/meta-viewport-info.h" +#include "core/main-private.h" +#include "core/boxes-private.h" + +typedef struct _ViewInfo ViewInfo; + +struct _ViewInfo +{ + MetaRectangle rect; + float scale; +}; + +struct _MetaViewportInfo +{ + GObject parent; + GArray *views; +}; + +G_DEFINE_TYPE (MetaViewportInfo, meta_viewport_info, G_TYPE_OBJECT) + +static void +meta_viewport_info_finalize (GObject *object) +{ + MetaViewportInfo *info = META_VIEWPORT_INFO (object); + + g_array_unref (info->views); + + G_OBJECT_CLASS (meta_viewport_info_parent_class)->finalize (object); +} + +static void +meta_viewport_info_class_init (MetaViewportInfoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_viewport_info_finalize; +} + +static void +meta_viewport_info_init (MetaViewportInfo *info) +{ + info->views = g_array_new (FALSE, FALSE, sizeof (ViewInfo)); +} + +MetaViewportInfo * +meta_viewport_info_new (cairo_rectangle_int_t *views, + float *scales, + int n_views) +{ + MetaViewportInfo *viewport_info; + int i; + + viewport_info = g_object_new (META_TYPE_VIEWPORT_INFO, NULL); + + for (i = 0; i < n_views; i++) + { + ViewInfo info; + + info.rect = views[i]; + info.scale = scales[i]; + g_array_append_val (viewport_info->views, info); + } + + return viewport_info; +} + +int +meta_viewport_info_get_view_at (MetaViewportInfo *viewport_info, + float x, + float y) +{ + int i; + + for (i = 0; i < viewport_info->views->len; i++) + { + ViewInfo *info = &g_array_index (viewport_info->views, ViewInfo, i); + + if (META_POINT_IN_RECT (x, y, info->rect)) + return i; + } + + return -1; +} + +gboolean +meta_viewport_info_get_view_info (MetaViewportInfo *viewport_info, + int idx, + cairo_rectangle_int_t *rect, + float *scale) +{ + ViewInfo *info; + + if (idx < 0 || idx >= viewport_info->views->len) + return FALSE; + + info = &g_array_index (viewport_info->views, ViewInfo, idx); + if (rect) + *rect = info->rect; + if (scale) + *scale = info->scale; + + return TRUE; +} + +static gboolean +view_has_neighbor (cairo_rectangle_int_t *view, + cairo_rectangle_int_t *neighbor, + MetaDisplayDirection neighbor_direction) +{ + switch (neighbor_direction) + { + case META_DISPLAY_RIGHT: + if (neighbor->x == (view->x + view->width) && + meta_rectangle_vert_overlap (neighbor, view)) + return TRUE; + break; + case META_DISPLAY_LEFT: + if (view->x == (neighbor->x + neighbor->width) && + meta_rectangle_vert_overlap (neighbor, view)) + return TRUE; + break; + case META_DISPLAY_UP: + if (view->y == (neighbor->y + neighbor->height) && + meta_rectangle_horiz_overlap (neighbor, view)) + return TRUE; + break; + case META_DISPLAY_DOWN: + if (neighbor->y == (view->y + view->height) && + meta_rectangle_horiz_overlap (neighbor, view)) + return TRUE; + break; + } + + return FALSE; +} + +int +meta_viewport_info_get_neighbor (MetaViewportInfo *viewport_info, + int idx, + MetaDisplayDirection direction) +{ + cairo_rectangle_int_t rect; + int i; + + if (!meta_viewport_info_get_view_info (viewport_info, idx, &rect, NULL)) + return -1; + + for (i = 0; i < viewport_info->views->len; i++) + { + ViewInfo *info = &g_array_index (viewport_info->views, ViewInfo, i); + + if (idx == i) + continue; + if (view_has_neighbor (&rect, &info->rect, direction)) + return i; + } + + return -1; +} + +int +meta_viewport_info_get_num_views (MetaViewportInfo *info) +{ + return info->views->len; +} + +void +meta_viewport_info_get_extents (MetaViewportInfo *viewport_info, + float *width, + float *height) +{ + int min_x = G_MAXINT, min_y = G_MAXINT, max_x = G_MININT, max_y = G_MININT, i; + + g_return_if_fail (viewport_info != NULL); + + for (i = 0; i < viewport_info->views->len; i++) + { + ViewInfo *info = &g_array_index (viewport_info->views, ViewInfo, i); + + min_x = MIN (min_x, info->rect.x); + max_x = MAX (max_x, info->rect.x + info->rect.width); + min_y = MIN (min_y, info->rect.y); + max_y = MAX (max_y, info->rect.y + info->rect.height); + } + + if (width) + *width = (float) max_x - min_x; + if (height) + *height = (float) max_y - min_y; +} diff --git a/src/backends/meta-viewport-info.h b/src/backends/meta-viewport-info.h new file mode 100644 index 0000000000000000000000000000000000000000..ea9b8af80cee74e2ae8e7103ef12c253750858e0 --- /dev/null +++ b/src/backends/meta-viewport-info.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Carlos Garnacho + */ + +#ifndef META_VIEWPORT_INFO_H +#define META_VIEWPORT_INFO_H + +#include +#include + +#include "meta/display.h" + +#define META_TYPE_VIEWPORT_INFO (meta_viewport_info_get_type ()) +G_DECLARE_FINAL_TYPE (MetaViewportInfo, meta_viewport_info, + META, VIEWPORT_INFO, GObject) + +MetaViewportInfo * meta_viewport_info_new (cairo_rectangle_int_t *views, + float *scales, + int n_views); + +int meta_viewport_info_get_view_at (MetaViewportInfo *info, + float x, + float y); + +gboolean meta_viewport_info_get_view_info (MetaViewportInfo *viewport_info, + int idx, + cairo_rectangle_int_t *rect, + float *scale); + +int meta_viewport_info_get_neighbor (MetaViewportInfo *info, + int idx, + MetaDisplayDirection direction); + +int meta_viewport_info_get_num_views (MetaViewportInfo *info); + +void meta_viewport_info_get_extents (MetaViewportInfo *info, + float *width, + float *height); + +#endif /* META_VIEWPORT_INFO_H */ diff --git a/src/backends/native/meta-backend-native-types.h b/src/backends/native/meta-backend-native-types.h index 3112e915d69d5f80d9e239b452bc2429dafa6ba1..ba73b4a563c4dce7e94a57bbb77a92df8558e670 100644 --- a/src/backends/native/meta-backend-native-types.h +++ b/src/backends/native/meta-backend-native-types.h @@ -22,5 +22,8 @@ #define META_BACKEND_NATIVE_TYPES_H typedef struct _MetaBackendNative MetaBackendNative; +typedef struct _MetaSeatNative MetaSeatNative; +typedef struct _MetaSeatImpl MetaSeatImpl; +typedef struct _MetaKeymapNative MetaKeymapNative; #endif /* META_BACKEND_NATIVE_TYPES_H */ diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index 73093cb038e9e60812fc63c4930fecf1902a8165..939885a64a24ec1f08e4c942eceeb4f69cb4c2cf 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -36,6 +36,7 @@ #include "backends/native/meta-backend-native.h" #include "backends/native/meta-backend-native-private.h" +#include "backends/native/meta-input-thread.h" #include #include @@ -49,9 +50,7 @@ #include "backends/meta-settings-private.h" #include "backends/meta-stage-private.h" #include "backends/native/meta-clutter-backend-native.h" -#include "backends/native/meta-cursor-renderer-native.h" #include "backends/native/meta-event-native.h" -#include "backends/native/meta-input-settings-native.h" #include "backends/native/meta-kms.h" #include "backends/native/meta-kms-device.h" #include "backends/native/meta-launcher.h" @@ -105,38 +104,6 @@ meta_backend_native_finalize (GObject *object) G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object); } -static void -constrain_to_client_constraint (ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y) -{ - MetaBackend *backend = meta_get_backend (); - MetaPointerConstraint *constraint = - meta_backend_get_client_pointer_constraint (backend); - - if (!constraint) - return; - - meta_pointer_constraint_constrain (constraint, device, - time, prev_x, prev_y, x, y); -} - -static void -pointer_constrain_callback (ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *new_x, - float *new_y, - gpointer user_data) -{ - /* Constrain to pointer lock */ - constrain_to_client_constraint (device, time, prev_x, prev_y, new_x, new_y); -} - static ClutterBackend * meta_backend_native_create_clutter_backend (MetaBackend *backend) { @@ -179,15 +146,24 @@ maybe_disable_screen_cast_dma_bufs (MetaBackendNative *native) #endif /* HAVE_REMOTE_DESKTOP */ static void -meta_backend_native_post_init (MetaBackend *backend) +update_viewports (MetaBackend *backend) { + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); - ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); - MetaSettings *settings = meta_backend_get_settings (backend); + MetaSeatNative *seat = + META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend)); + MetaViewportInfo *viewports; - meta_seat_native_set_pointer_constrain_callback (META_SEAT_NATIVE (seat), - pointer_constrain_callback, - NULL, NULL); + viewports = meta_monitor_manager_get_viewports (monitor_manager); + meta_seat_native_set_viewports (seat, viewports); + g_object_unref (viewports); +} + +static void +meta_backend_native_post_init (MetaBackend *backend) +{ + MetaSettings *settings = meta_backend_get_settings (backend); META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend); @@ -209,6 +185,8 @@ meta_backend_native_post_init (MetaBackend *backend) maybe_disable_screen_cast_dma_bufs (META_BACKEND_NATIVE (backend)); #endif + update_viewports (backend); + #ifdef HAVE_WAYLAND meta_backend_init_wayland (backend); #endif @@ -218,15 +196,26 @@ static MetaMonitorManager * meta_backend_native_create_monitor_manager (MetaBackend *backend, GError **error) { - return g_initable_new (META_TYPE_MONITOR_MANAGER_KMS, NULL, error, - "backend", backend, - NULL); + MetaMonitorManager *manager; + + manager = g_initable_new (META_TYPE_MONITOR_MANAGER_KMS, NULL, error, + "backend", backend, + NULL); + g_signal_connect_swapped (manager, "monitors-changed-internal", + G_CALLBACK (update_viewports), backend); + + return manager; } static MetaCursorRenderer * -meta_backend_native_create_cursor_renderer (MetaBackend *backend) +meta_backend_native_get_cursor_renderer (MetaBackend *backend, + ClutterInputDevice *device) { - return META_CURSOR_RENDERER (meta_cursor_renderer_native_new (backend)); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + MetaSeatNative *seat_native = + META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend)); + + return meta_seat_native_maybe_ensure_cursor_renderer (seat_native, device); } static MetaRenderer * @@ -244,9 +233,13 @@ meta_backend_native_create_renderer (MetaBackend *backend, } static MetaInputSettings * -meta_backend_native_create_input_settings (MetaBackend *backend) +meta_backend_native_get_input_settings (MetaBackend *backend) { - return g_object_new (META_TYPE_INPUT_SETTINGS_NATIVE, NULL); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + MetaSeatNative *seat_native = + META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend)); + + return meta_seat_impl_get_input_settings (seat_native->impl); } static MetaLogicalMonitor * @@ -269,35 +262,13 @@ meta_backend_native_set_keymap (MetaBackend *backend, const char *options) { ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); - struct xkb_rule_names names; - struct xkb_keymap *keymap; - struct xkb_context *context; ClutterSeat *seat; - names.rules = DEFAULT_XKB_RULES_FILE; - names.model = DEFAULT_XKB_MODEL; - names.layout = layouts; - names.variant = variants; - names.options = options; - - context = meta_create_xkb_context (); - keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS); - xkb_context_unref (context); - - if (keymap == NULL) - { - g_warning ("Unable to load configured keymap: rules=%s, model=%s, layout=%s, variant=%s, options=%s", - DEFAULT_XKB_RULES_FILE, DEFAULT_XKB_MODEL, layouts, - variants, options); - return; - } - seat = clutter_backend_get_default_seat (clutter_backend); - meta_seat_native_set_keyboard_map (META_SEAT_NATIVE (seat), keymap); + meta_seat_native_set_keyboard_map (META_SEAT_NATIVE (seat), + layouts, variants, options); meta_backend_notify_keymap_changed (backend); - - xkb_keymap_unref (keymap); } static struct xkb_keymap * @@ -338,15 +309,23 @@ meta_backend_native_lock_layout_group (MetaBackend *backend, } static void -meta_backend_native_set_numlock (MetaBackend *backend, - gboolean numlock_state) +meta_backend_native_set_pointer_constraint (MetaBackend *backend, + MetaPointerConstraint *constraint) { ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); - ClutterSeat *seat; + ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); + MetaPointerConstraintImpl *constraint_impl = NULL; + cairo_region_t *region; - seat = clutter_backend_get_default_seat (clutter_backend); - meta_seat_native_set_keyboard_numlock (META_SEAT_NATIVE (seat), - numlock_state); + if (constraint) + { + region = meta_pointer_constraint_get_region (constraint); + constraint_impl = meta_pointer_constraint_impl_native_new (constraint, + region); + } + + meta_seat_native_set_pointer_constraint (META_SEAT_NATIVE (seat), + constraint_impl); } static void @@ -550,9 +529,9 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass) backend_class->post_init = meta_backend_native_post_init; backend_class->create_monitor_manager = meta_backend_native_create_monitor_manager; - backend_class->create_cursor_renderer = meta_backend_native_create_cursor_renderer; + backend_class->get_cursor_renderer = meta_backend_native_get_cursor_renderer; backend_class->create_renderer = meta_backend_native_create_renderer; - backend_class->create_input_settings = meta_backend_native_create_input_settings; + backend_class->get_input_settings = meta_backend_native_get_input_settings; backend_class->get_current_logical_monitor = meta_backend_native_get_current_logical_monitor; @@ -561,7 +540,8 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass) backend_class->get_keymap_layout_group = meta_backend_native_get_keymap_layout_group; backend_class->lock_layout_group = meta_backend_native_lock_layout_group; backend_class->update_screen_size = meta_backend_native_update_screen_size; - backend_class->set_numlock = meta_backend_native_set_numlock; + + backend_class->set_pointer_constraint = meta_backend_native_set_pointer_constraint; } static void @@ -658,12 +638,12 @@ void meta_backend_native_resume (MetaBackendNative *native) meta_backend_get_monitor_manager (backend); MetaMonitorManagerKms *monitor_manager_kms = META_MONITOR_MANAGER_KMS (monitor_manager); - MetaInputSettings *input_settings; MetaIdleMonitor *idle_monitor; ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); MetaSeatNative *seat = META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend)); MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaInputSettings *input_settings; COGL_TRACE_BEGIN_SCOPED (MetaBackendNativeResume, "Backend (resume)"); diff --git a/src/backends/native/meta-barrier-native.c b/src/backends/native/meta-barrier-native.c index bdb006fb13975858a4226244dfe1b2303743b196..bc0620ae9df3ca61bc9171d5baa6c11a42ffc372 100644 --- a/src/backends/native/meta-barrier-native.c +++ b/src/backends/native/meta-barrier-native.c @@ -43,6 +43,7 @@ struct _MetaBarrierManagerNative { GHashTable *barriers; + GMutex mutex; }; typedef enum @@ -77,6 +78,7 @@ struct _MetaBarrierImplNative int trigger_serial; guint32 last_event_time; MetaBarrierDirection blocked_dir; + GMainContext *main_context; }; G_DEFINE_TYPE (MetaBarrierImplNative, @@ -340,6 +342,49 @@ typedef struct _MetaBarrierEventData float dy; } MetaBarrierEventData; +typedef struct +{ + MetaBarrierEvent *event; + MetaBarrier *barrier; + MetaBarrierState state; +} MetaBarrierIdleData; + +static gboolean +emit_event_idle (MetaBarrierIdleData *idle_data) +{ + if (idle_data->state == META_BARRIER_STATE_HELD) + _meta_barrier_emit_hit_signal (idle_data->barrier, idle_data->event); + else + _meta_barrier_emit_left_signal (idle_data->barrier, idle_data->event); + + meta_barrier_event_unref (idle_data->event); + + return G_SOURCE_REMOVE; +} + +static void +queue_event (MetaBarrierImplNative *self, + MetaBarrierEvent *event) +{ + MetaBarrierIdleData *idle_data; + GSource *source; + + idle_data = g_new0 (MetaBarrierIdleData, 1); + idle_data->state = self->state; + idle_data->barrier = self->barrier; + idle_data->event = event; + + source = g_idle_source_new (); + g_source_set_priority (source, G_PRIORITY_HIGH); + g_source_set_callback (source, + (GSourceFunc) emit_event_idle, + idle_data, + g_free); + + g_source_attach (source, self->main_context); + g_source_unref (source); +} + static void emit_barrier_event (MetaBarrierImplNative *self, guint32 time, @@ -350,7 +395,6 @@ emit_barrier_event (MetaBarrierImplNative *self, float dx, float dy) { - MetaBarrier *barrier = self->barrier; MetaBarrierEvent *event = g_slice_new0 (MetaBarrierEvent); MetaBarrierState old_state = self->state; @@ -389,12 +433,7 @@ emit_barrier_event (MetaBarrierImplNative *self, self->last_event_time = time; - if (self->state == META_BARRIER_STATE_HELD) - _meta_barrier_emit_hit_signal (barrier, event); - else - _meta_barrier_emit_left_signal (barrier, event); - - meta_barrier_event_unref (event); + queue_event (self, event); } static void @@ -461,11 +500,11 @@ clamp_to_barrier (MetaBarrierImplNative *self, } void -meta_barrier_manager_native_process (MetaBarrierManagerNative *manager, - ClutterInputDevice *device, - guint32 time, - float *x, - float *y) +meta_barrier_manager_native_process_in_impl (MetaBarrierManagerNative *manager, + ClutterInputDevice *device, + guint32 time, + float *x, + float *y) { graphene_point_t prev_pos; float prev_x; @@ -476,9 +515,12 @@ meta_barrier_manager_native_process (MetaBarrierManagerNative *manager, MetaBarrierEventData barrier_event_data; MetaBarrierImplNative *barrier_impl; - if (!clutter_input_device_get_coords (device, NULL, &prev_pos)) + if (!clutter_seat_query_state (clutter_input_device_get_seat (device), + device, NULL, &prev_pos, NULL)) return; + g_mutex_lock (&manager->mutex); + prev_x = prev_pos.x; prev_y = prev_pos.y; @@ -523,6 +565,8 @@ meta_barrier_manager_native_process (MetaBarrierManagerNative *manager, g_hash_table_foreach (manager->barriers, maybe_emit_barrier_event, &barrier_event_data); + + g_mutex_unlock (&manager->mutex); } static gboolean @@ -549,7 +593,10 @@ _meta_barrier_impl_native_destroy (MetaBarrierImpl *impl) { MetaBarrierImplNative *self = META_BARRIER_IMPL_NATIVE (impl); + g_mutex_lock (&self->manager->mutex); g_hash_table_remove (self->manager->barriers, self); + g_mutex_unlock (&self->manager->mutex); + g_main_context_unref (self->main_context); self->is_active = FALSE; } @@ -565,10 +612,13 @@ meta_barrier_impl_native_new (MetaBarrier *barrier) self->barrier = barrier; self->is_active = TRUE; + self->main_context = g_main_context_ref_thread_default (); manager = meta_seat_native_get_barrier_manager (META_SEAT_NATIVE (seat)); self->manager = manager; + g_mutex_lock (&manager->mutex); g_hash_table_add (manager->barriers, self); + g_mutex_unlock (&manager->mutex); return META_BARRIER_IMPL (self); } @@ -596,6 +646,7 @@ meta_barrier_manager_native_new (void) manager = g_new0 (MetaBarrierManagerNative, 1); manager->barriers = g_hash_table_new (NULL, NULL); + g_mutex_init (&manager->mutex); return manager; } diff --git a/src/backends/native/meta-barrier-native.h b/src/backends/native/meta-barrier-native.h index 2853cfa80da686e5b3cb8a92d240ff24025b9f54..1bcf56c7c771195ae4df6b560aa66017e6671848 100644 --- a/src/backends/native/meta-barrier-native.h +++ b/src/backends/native/meta-barrier-native.h @@ -41,11 +41,11 @@ typedef struct _MetaBarrierManagerNative MetaBarrierManagerNative; MetaBarrierImpl *meta_barrier_impl_native_new (MetaBarrier *barrier); MetaBarrierManagerNative *meta_barrier_manager_native_new (void); -void meta_barrier_manager_native_process (MetaBarrierManagerNative *manager, - ClutterInputDevice *device, - guint32 time, - float *x, - float *y); +void meta_barrier_manager_native_process_in_impl (MetaBarrierManagerNative *manager, + ClutterInputDevice *device, + guint32 time, + float *x, + float *y); G_END_DECLS diff --git a/src/backends/native/meta-clutter-backend-native.c b/src/backends/native/meta-clutter-backend-native.c index 58d6afa44fc9b7e695d7d6b5e4785fe873f4194c..a1d0d097168379520279932a8c246d0eb2bba39f 100644 --- a/src/backends/native/meta-clutter-backend-native.c +++ b/src/backends/native/meta-clutter-backend-native.c @@ -125,6 +125,17 @@ meta_clutter_backend_native_is_display_server (ClutterBackend *backend) return TRUE; } +static void +meta_clutter_backend_native_finalize (GObject *object) +{ + MetaClutterBackendNative *backend_native = META_CLUTTER_BACKEND_NATIVE (object); + + g_clear_object (&backend_native->main_seat); + g_clear_object (&backend_native->stage_native); + + G_OBJECT_CLASS (meta_clutter_backend_native_parent_class)->finalize (object); +} + static void meta_clutter_backend_native_init (MetaClutterBackendNative *clutter_backend_nativen) { @@ -133,8 +144,11 @@ meta_clutter_backend_native_init (MetaClutterBackendNative *clutter_backend_nati static void meta_clutter_backend_native_class_init (MetaClutterBackendNativeClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterBackendClass *clutter_backend_class = CLUTTER_BACKEND_CLASS (klass); + object_class->finalize = meta_clutter_backend_native_finalize; + clutter_backend_class->get_renderer = meta_clutter_backend_native_get_renderer; clutter_backend_class->create_stage = meta_clutter_backend_native_create_stage; clutter_backend_class->init_events = meta_clutter_backend_native_init_events; diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c index 3c6688df426cd6fe3b9b1c4de89dee9c6e7654cb..ccf0434ee74ed3528bf065db24820988e01dc951 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -872,6 +872,10 @@ should_have_hw_cursor (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite, GList *gpus) { + MetaCursorRendererNative *cursor_renderer_native = + META_CURSOR_RENDERER_NATIVE (renderer); + MetaCursorRendererNativePrivate *priv = + meta_cursor_renderer_native_get_instance_private (cursor_renderer_native); CoglTexture *texture; MetaMonitorTransform transform; float scale; @@ -880,8 +884,7 @@ should_have_hw_cursor (MetaCursorRenderer *renderer, if (!cursor_sprite) return FALSE; - if (meta_cursor_renderer_is_hw_cursors_inhibited (renderer, - cursor_sprite)) + if (meta_backend_is_hw_cursors_inhibited (priv->backend)) return FALSE; for (l = gpus; l; l = l->next) @@ -1724,7 +1727,8 @@ init_hw_cursor_support (MetaCursorRendererNative *cursor_renderer_native) } MetaCursorRendererNative * -meta_cursor_renderer_native_new (MetaBackend *backend) +meta_cursor_renderer_native_new (MetaBackend *backend, + ClutterInputDevice *device) { MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); @@ -1733,6 +1737,7 @@ meta_cursor_renderer_native_new (MetaBackend *backend) cursor_renderer_native = g_object_new (META_TYPE_CURSOR_RENDERER_NATIVE, "backend", backend, + "device", device, NULL); priv = meta_cursor_renderer_native_get_instance_private (cursor_renderer_native); diff --git a/src/backends/native/meta-cursor-renderer-native.h b/src/backends/native/meta-cursor-renderer-native.h index d3560e48f67b7d2c83ca407be28c10619bf0b2bd..26c698cda53d7885814386ecae81ce80a8420137 100644 --- a/src/backends/native/meta-cursor-renderer-native.h +++ b/src/backends/native/meta-cursor-renderer-native.h @@ -33,6 +33,7 @@ G_DECLARE_FINAL_TYPE (MetaCursorRendererNative, meta_cursor_renderer_native, META, CURSOR_RENDERER_NATIVE, MetaCursorRenderer) -MetaCursorRendererNative * meta_cursor_renderer_native_new (MetaBackend *backend); +MetaCursorRendererNative * meta_cursor_renderer_native_new (MetaBackend *backend, + ClutterInputDevice *device); #endif /* META_CURSOR_RENDERER_NATIVE_H */ diff --git a/src/backends/native/meta-event-native.c b/src/backends/native/meta-event-native.c index 61603d19efa7d04da50403aebda87542b59f4e91..8a1d8f3482ca736e7152afa6a57aa289d7743c4a 100644 --- a/src/backends/native/meta-event-native.c +++ b/src/backends/native/meta-event-native.c @@ -21,7 +21,7 @@ #include "config.h" #include "backends/native/meta-event-native.h" -#include "backends/native/meta-input-device-native.h" +#include "backends/native/meta-input-thread.h" #include "clutter/clutter-mutter.h" typedef struct _MetaEventNative MetaEventNative; diff --git a/src/backends/native/meta-input-device-native.c b/src/backends/native/meta-input-device-native.c index fbbe931c2cc02148d93366a4650d6e2dee25f91f..2878675f236613037eb427dc8987034c8a51ba26 100644 --- a/src/backends/native/meta-input-device-native.c +++ b/src/backends/native/meta-input-device-native.c @@ -24,9 +24,8 @@ #include #include -#include "backends/native/meta-input-device-tool-native.h" -#include "backends/native/meta-input-device-native.h" -#include "backends/native/meta-seat-native.h" +#include "backends/meta-backend-private.h" +#include "backends/native/meta-input-thread.h" #include "clutter/clutter-mutter.h" G_DEFINE_TYPE (MetaInputDeviceNative, @@ -47,10 +46,18 @@ typedef struct _SlowKeysEventPending { MetaInputDeviceNative *device; ClutterEvent *event; - ClutterEmitInputDeviceEvent emit_event_func; - guint timer; + GSource *timer; } SlowKeysEventPending; +typedef struct _PadFeature PadFeature; + +struct _PadFeature +{ + ClutterInputDevicePadFeature feature; + int n_feature; + int group; +}; + static void clear_slow_keys (MetaInputDeviceNative *device); static void stop_bounce_keys (MetaInputDeviceNative *device); static void stop_toggle_slowkeys (MetaInputDeviceNative *device); @@ -69,6 +76,8 @@ meta_input_device_native_finalize (GObject *object) stop_toggle_slowkeys (device_evdev); stop_mousekeys_move (device_evdev); + g_clear_pointer (&device_evdev->pad_features, g_array_unref); + G_OBJECT_CLASS (meta_input_device_native_parent_class)->finalize (object); } @@ -119,58 +128,6 @@ meta_input_device_native_get_property (GObject *object, } } -static gboolean -meta_input_device_native_keycode_to_evdev (ClutterInputDevice *device, - uint32_t hardware_keycode, - uint32_t *evdev_keycode) -{ - /* The hardware keycodes from the evdev backend are almost evdev - keycodes: we use the evdev keycode file, but xkb rules have an - offset by 8. See the comment in _clutter_key_event_new_from_evdev() - */ - *evdev_keycode = hardware_keycode - 8; - return TRUE; -} - -static void -meta_input_device_native_update_from_tool (ClutterInputDevice *device, - ClutterInputDeviceTool *tool) -{ - MetaInputDeviceToolNative *evdev_tool; - - evdev_tool = META_INPUT_DEVICE_TOOL_NATIVE (tool); - - g_object_freeze_notify (G_OBJECT (device)); - - _clutter_input_device_reset_axes (device); - - _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_X, 0, 0, 0); - _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_Y, 0, 0, 0); - - if (libinput_tablet_tool_has_distance (evdev_tool->tool)) - _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_DISTANCE, 0, 1, 0); - - if (libinput_tablet_tool_has_pressure (evdev_tool->tool)) - _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_PRESSURE, 0, 1, 0); - - if (libinput_tablet_tool_has_tilt (evdev_tool->tool)) - { - _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_XTILT, -90, 90, 0); - _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_YTILT, -90, 90, 0); - } - - if (libinput_tablet_tool_has_rotation (evdev_tool->tool)) - _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_ROTATION, 0, 360, 0); - - if (libinput_tablet_tool_has_slider (evdev_tool->tool)) - _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_SLIDER, -1, 1, 0); - - if (libinput_tablet_tool_has_wheel (evdev_tool->tool)) - _clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_WHEEL, -180, 180, 0); - - g_object_thaw_notify (G_OBJECT (device)); -} - static gboolean meta_input_device_native_is_mode_switch_button (ClutterInputDevice *device, uint32_t group, @@ -211,10 +168,35 @@ meta_input_device_native_is_grouped (ClutterInputDevice *device, libinput_device_get_device_group (other_libinput_device); } +static int +meta_input_device_native_get_pad_feature_group (ClutterInputDevice *device, + ClutterInputDevicePadFeature feature, + int n_feature) +{ + MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device); + int i; + + if (!device_native->pad_features) + return -1; + + for (i = 0; i < device_native->pad_features->len; i++) + { + PadFeature *pad_feature; + + pad_feature = &g_array_index (device_native->pad_features, PadFeature, i); + + if (pad_feature->feature == feature && + pad_feature->n_feature == n_feature) + return pad_feature->group; + } + + return -1; +} + static void meta_input_device_native_bell_notify (MetaInputDeviceNative *device) { - clutter_seat_bell_notify (CLUTTER_SEAT (device->seat)); + meta_seat_impl_notify_bell_in_impl (device->seat_impl); } static void @@ -223,7 +205,7 @@ meta_input_device_native_free_pending_slow_key (gpointer data) SlowKeysEventPending *slow_keys_event = data; clutter_event_free (slow_keys_event->event); - g_clear_handle_id (&slow_keys_event->timer, g_source_remove); + g_clear_pointer (&slow_keys_event->timer, g_source_destroy); g_free (slow_keys_event); } @@ -239,10 +221,11 @@ static guint get_slow_keys_delay (ClutterInputDevice *device) { MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device); - ClutterKbdA11ySettings a11y_settings; + MetaKbdA11ySettings a11y_settings; + MetaInputSettings *input_settings; - clutter_seat_get_kbd_a11y_settings (CLUTTER_SEAT (device_native->seat), - &a11y_settings); + input_settings = meta_seat_impl_get_input_settings (device_native->seat_impl); + meta_input_settings_get_kbd_a11y_settings (input_settings, &a11y_settings); /* Settings use int, we use uint, make sure we dont go negative */ return MAX (0, a11y_settings.slowkeys_delay); } @@ -256,14 +239,13 @@ trigger_slow_keys (gpointer data) /* Alter timestamp and emit the event */ key_event->time = us2ms (g_get_monotonic_time ()); - slow_keys_event->emit_event_func (slow_keys_event->event, - CLUTTER_INPUT_DEVICE (device)); + _clutter_event_push (slow_keys_event->event, TRUE); /* Then remote the pending event */ device->slow_keys_list = g_list_remove (device->slow_keys_list, slow_keys_event); meta_input_device_native_free_pending_slow_key (slow_keys_event); - if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT) + if (device->a11y_flags & META_A11Y_SLOW_KEYS_BEEP_ACCEPT) meta_input_device_native_bell_notify (device); return G_SOURCE_REMOVE; @@ -280,35 +262,53 @@ find_pending_event_by_keycode (gconstpointer a, return kb->hardware_keycode - ka->hardware_keycode; } -static void -start_slow_keys (ClutterEvent *event, - MetaInputDeviceNative *device, - ClutterEmitInputDeviceEvent emit_event_func) +static GSource * +timeout_source_new (MetaSeatImpl *seat_impl, + guint interval, + GSourceFunc func, + gpointer user_data) +{ + GSource *source; + + source = g_timeout_source_new (interval); + g_source_set_callback (source, + func, + user_data, NULL); + g_source_attach (source, seat_impl->input_context); + g_source_unref (source); + + return source; +} + +static gboolean +start_slow_keys (ClutterEvent *event, + MetaInputDeviceNative *device) { SlowKeysEventPending *slow_keys_event; ClutterKeyEvent *key_event = (ClutterKeyEvent *) event; if (key_event->flags & CLUTTER_EVENT_FLAG_REPEATED) - return; + return TRUE; slow_keys_event = g_new0 (SlowKeysEventPending, 1); slow_keys_event->device = device; slow_keys_event->event = clutter_event_copy (event); - slow_keys_event->emit_event_func = emit_event_func; slow_keys_event->timer = - clutter_threads_add_timeout (get_slow_keys_delay (CLUTTER_INPUT_DEVICE (device)), - trigger_slow_keys, - slow_keys_event); + timeout_source_new (device->seat_impl, + get_slow_keys_delay (CLUTTER_INPUT_DEVICE (device)), + trigger_slow_keys, + slow_keys_event); device->slow_keys_list = g_list_append (device->slow_keys_list, slow_keys_event); - if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS) + if (device->a11y_flags & META_A11Y_SLOW_KEYS_BEEP_PRESS) meta_input_device_native_bell_notify (device); + + return TRUE; } -static void -stop_slow_keys (ClutterEvent *event, - MetaInputDeviceNative *device, - ClutterEmitInputDeviceEvent emit_event_func) +static gboolean +stop_slow_keys (ClutterEvent *event, + MetaInputDeviceNative *device) { GList *item; @@ -321,24 +321,25 @@ stop_slow_keys (ClutterEvent *event, device->slow_keys_list = g_list_delete_link (device->slow_keys_list, item); meta_input_device_native_free_pending_slow_key (slow_keys_event); - if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT) + if (device->a11y_flags & META_A11Y_SLOW_KEYS_BEEP_REJECT) meta_input_device_native_bell_notify (device); - return; + return TRUE; } /* If no key press event was pending, just emit the key release as-is */ - emit_event_func (event, CLUTTER_INPUT_DEVICE (device)); + return FALSE; } static guint get_debounce_delay (ClutterInputDevice *device) { MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device); - ClutterKbdA11ySettings a11y_settings; + MetaKbdA11ySettings a11y_settings; + MetaInputSettings *input_settings; - clutter_seat_get_kbd_a11y_settings (CLUTTER_SEAT (device_native->seat), - &a11y_settings); + input_settings = meta_seat_impl_get_input_settings (device_native->seat_impl); + meta_input_settings_get_kbd_a11y_settings (input_settings, &a11y_settings); /* Settings use int, we use uint, make sure we dont go negative */ return MAX (0, a11y_settings.debounce_delay); } @@ -362,21 +363,22 @@ start_bounce_keys (ClutterEvent *event, device->debounce_key = ((ClutterKeyEvent *) event)->hardware_keycode; device->debounce_timer = - clutter_threads_add_timeout (get_debounce_delay (CLUTTER_INPUT_DEVICE (device)), - clear_bounce_keys, - device); + timeout_source_new (device->seat_impl, + get_debounce_delay (CLUTTER_INPUT_DEVICE (device)), + clear_bounce_keys, + device); } static void stop_bounce_keys (MetaInputDeviceNative *device) { - g_clear_handle_id (&device->debounce_timer, g_source_remove); + g_clear_pointer (&device->debounce_timer, g_source_destroy); } static void notify_bounce_keys_reject (MetaInputDeviceNative *device) { - if (device->a11y_flags & CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT) + if (device->a11y_flags & META_A11Y_BOUNCE_KEYS_BEEP_REJECT) meta_input_device_native_bell_notify (device); } @@ -415,10 +417,9 @@ key_event_is_modifier (ClutterEvent *event) static void notify_stickykeys_mask (MetaInputDeviceNative *device) { - g_signal_emit_by_name (device->seat, - "kbd-a11y-mods-state-changed", - device->stickykeys_latched_mask, - device->stickykeys_locked_mask); + meta_seat_impl_notify_kbd_a11y_mods_state_changed_in_impl (device->seat_impl, + device->stickykeys_latched_mask, + device->stickykeys_locked_mask); } static void @@ -426,15 +427,19 @@ update_internal_xkb_state (MetaInputDeviceNative *device, xkb_mod_mask_t new_latched_mask, xkb_mod_mask_t new_locked_mask) { - MetaSeatNative *seat = device->seat; + MetaSeatImpl *seat_impl = device->seat_impl; xkb_mod_mask_t depressed_mods; xkb_mod_mask_t latched_mods; xkb_mod_mask_t locked_mods; xkb_mod_mask_t group_mods; + struct xkb_state *xkb_state; + + g_rw_lock_writer_lock (&seat_impl->state_lock); - depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED); - latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED); - locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED); + xkb_state = meta_seat_impl_get_xkb_state_in_impl (seat_impl); + depressed_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_DEPRESSED); + latched_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LATCHED); + locked_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LOCKED); latched_mods &= ~device->stickykeys_latched_mask; locked_mods &= ~device->stickykeys_locked_mask; @@ -445,14 +450,16 @@ update_internal_xkb_state (MetaInputDeviceNative *device, latched_mods |= device->stickykeys_latched_mask; locked_mods |= device->stickykeys_locked_mask; - group_mods = xkb_state_serialize_layout (seat->xkb, XKB_STATE_LAYOUT_EFFECTIVE); + group_mods = xkb_state_serialize_layout (xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); - xkb_state_update_mask (seat->xkb, + xkb_state_update_mask (xkb_state, depressed_mods, latched_mods, locked_mods, 0, 0, group_mods); notify_stickykeys_mask (device); + + g_rw_lock_writer_unlock (&seat_impl->state_lock); } static void @@ -461,23 +468,25 @@ update_stickykeys_event (ClutterEvent *event, xkb_mod_mask_t new_latched_mask, xkb_mod_mask_t new_locked_mask) { - MetaSeatNative *seat = device->seat; + MetaSeatImpl *seat_impl = device->seat_impl; xkb_mod_mask_t effective_mods; xkb_mod_mask_t latched_mods; xkb_mod_mask_t locked_mods; + struct xkb_state *xkb_state; update_internal_xkb_state (device, new_latched_mask, new_locked_mask); - effective_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_EFFECTIVE); - latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED); - locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED); + xkb_state = meta_seat_impl_get_xkb_state_in_impl (seat_impl); + effective_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_EFFECTIVE); + latched_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LATCHED); + locked_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LOCKED); _clutter_event_set_state_full (event, - seat->button_state, + seat_impl->button_state, device->stickykeys_depressed_mask, latched_mods, locked_mods, - effective_mods | seat->button_state); + effective_mods | seat_impl->button_state); } static void @@ -487,23 +496,22 @@ notify_stickykeys_change (MetaInputDeviceNative *device) device->stickykeys_depressed_mask = 0; update_internal_xkb_state (device, 0, 0); - g_signal_emit_by_name (CLUTTER_INPUT_DEVICE (device)->seat, - "kbd-a11y-flags-changed", - device->a11y_flags, - CLUTTER_A11Y_STICKY_KEYS_ENABLED); + meta_seat_impl_notify_kbd_a11y_flags_changed_in_impl (device->seat_impl, + device->a11y_flags, + META_A11Y_STICKY_KEYS_ENABLED); } static void set_stickykeys_off (MetaInputDeviceNative *device) { - device->a11y_flags &= ~CLUTTER_A11Y_STICKY_KEYS_ENABLED; + device->a11y_flags &= ~META_A11Y_STICKY_KEYS_ENABLED; notify_stickykeys_change (device); } static void set_stickykeys_on (MetaInputDeviceNative *device) { - device->a11y_flags |= CLUTTER_A11Y_STICKY_KEYS_ENABLED; + device->a11y_flags |= META_A11Y_STICKY_KEYS_ENABLED; notify_stickykeys_change (device); } @@ -518,45 +526,45 @@ clear_stickykeys_event (ClutterEvent *event, static void set_slowkeys_off (MetaInputDeviceNative *device) { - device->a11y_flags &= ~CLUTTER_A11Y_SLOW_KEYS_ENABLED; + device->a11y_flags &= ~META_A11Y_SLOW_KEYS_ENABLED; - g_signal_emit_by_name (CLUTTER_INPUT_DEVICE (device)->seat, - "kbd-a11y-flags-changed", - device->a11y_flags, - CLUTTER_A11Y_SLOW_KEYS_ENABLED); + meta_seat_impl_notify_kbd_a11y_flags_changed_in_impl (device->seat_impl, + device->a11y_flags, + META_A11Y_SLOW_KEYS_ENABLED); } static void set_slowkeys_on (MetaInputDeviceNative *device) { - device->a11y_flags |= CLUTTER_A11Y_SLOW_KEYS_ENABLED; + device->a11y_flags |= META_A11Y_SLOW_KEYS_ENABLED; - g_signal_emit_by_name (CLUTTER_INPUT_DEVICE (device)->seat, - "kbd-a11y-flags-changed", - device->a11y_flags, - CLUTTER_A11Y_SLOW_KEYS_ENABLED); + meta_seat_impl_notify_kbd_a11y_flags_changed_in_impl (device->seat_impl, + device->a11y_flags, + META_A11Y_SLOW_KEYS_ENABLED); } static void handle_stickykeys_press (ClutterEvent *event, MetaInputDeviceNative *device) { - MetaSeatNative *seat = device->seat; + MetaSeatImpl *seat_impl = device->seat_impl; xkb_mod_mask_t depressed_mods; xkb_mod_mask_t new_latched_mask; xkb_mod_mask_t new_locked_mask; + struct xkb_state *xkb_state; if (!key_event_is_modifier (event)) return; if (device->stickykeys_depressed_mask && - (device->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF)) + (device->a11y_flags & META_A11Y_STICKY_KEYS_TWO_KEY_OFF)) { clear_stickykeys_event (event, device); return; } - depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED); + xkb_state = meta_seat_impl_get_xkb_state_in_impl (seat_impl); + depressed_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_DEPRESSED); /* Ignore the lock modifier mask, that one cannot be sticky, yet the * CAPS_LOCK key itself counts as a modifier as it might be remapped * to some other modifier which can be sticky. @@ -589,14 +597,16 @@ static void handle_stickykeys_release (ClutterEvent *event, MetaInputDeviceNative *device) { - MetaSeatNative *seat = device->seat; + MetaSeatImpl *seat_impl = device->seat_impl; + struct xkb_state *xkb_state; + xkb_state = meta_seat_impl_get_xkb_state_in_impl (seat_impl); device->stickykeys_depressed_mask = - xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED); + xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_DEPRESSED); if (key_event_is_modifier (event)) { - if (device->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_BEEP) + if (device->a11y_flags & META_A11Y_STICKY_KEYS_BEEP) meta_input_device_native_bell_notify (device); return; @@ -615,10 +625,10 @@ trigger_toggle_slowkeys (gpointer data) device->toggle_slowkeys_timer = 0; - if (device->a11y_flags & CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP) + if (device->a11y_flags & META_A11Y_FEATURE_STATE_CHANGE_BEEP) meta_input_device_native_bell_notify (device); - if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_ENABLED) + if (device->a11y_flags & META_A11Y_SLOW_KEYS_ENABLED) set_slowkeys_off (device); else set_slowkeys_on (device); @@ -633,15 +643,16 @@ start_toggle_slowkeys (MetaInputDeviceNative *device) return; device->toggle_slowkeys_timer = - clutter_threads_add_timeout (8 * 1000 /* 8 secs */, - trigger_toggle_slowkeys, - device); + timeout_source_new (device->seat_impl, + 8 * 1000 /* 8 secs */, + trigger_toggle_slowkeys, + device); } static void stop_toggle_slowkeys (MetaInputDeviceNative *device) { - g_clear_handle_id (&device->toggle_slowkeys_timer, g_source_remove); + g_clear_pointer (&device->toggle_slowkeys_timer, g_source_destroy); } static void @@ -677,10 +688,10 @@ handle_enablekeys_release (ClutterEvent *event, { device->shift_count = 0; - if (device->a11y_flags & CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP) + if (device->a11y_flags & META_A11Y_FEATURE_STATE_CHANGE_BEEP) meta_input_device_native_bell_notify (device); - if (device->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_ENABLED) + if (device->a11y_flags & META_A11Y_STICKY_KEYS_ENABLED) set_stickykeys_off (device); else set_stickykeys_on (device); @@ -747,8 +758,8 @@ emulate_button_click (MetaInputDeviceNative *device) #define MOUSEKEYS_CURVE (1.0 + (((double) 50.0) * 0.001)) static void -update_mousekeys_params (MetaInputDeviceNative *device, - ClutterKbdA11ySettings *settings) +update_mousekeys_params (MetaInputDeviceNative *device, + MetaKbdA11ySettings *settings) { /* Prevent us from broken settings values */ device->mousekeys_max_speed = MAX (1, settings->mousekeys_max_speed); @@ -830,8 +841,12 @@ emulate_pointer_motion (MetaInputDeviceNative *device_evdev, static gboolean is_numlock_active (MetaInputDeviceNative *device) { - MetaSeatNative *seat = device->seat; - return xkb_state_mod_name_is_active (seat->xkb, + MetaSeatImpl *seat_impl = device->seat_impl; + struct xkb_state *xkb_state; + + xkb_state = meta_seat_impl_get_xkb_state_in_impl (seat_impl); + + return xkb_state_mod_name_is_active (xkb_state, "Mod2", XKB_STATE_MODS_LOCKED); } @@ -851,7 +866,7 @@ enable_mousekeys (MetaInputDeviceNative *device_evdev) return; device->accessibility_virtual_device = - clutter_seat_create_virtual_device (CLUTTER_SEAT (device_evdev->seat), + clutter_seat_create_virtual_device (clutter_input_device_get_seat (device), CLUTTER_POINTER_DEVICE); } @@ -896,18 +911,20 @@ trigger_mousekeys_move (gpointer data) { /* This is the first move, Secdule at mk_init_delay */ device->move_mousekeys_timer = - clutter_threads_add_timeout (device->mousekeys_init_delay, - trigger_mousekeys_move, - device); + timeout_source_new (device->seat_impl, + device->mousekeys_init_delay, + trigger_mousekeys_move, + device); } else { /* More moves, reschedule at mk_interval */ device->move_mousekeys_timer = - clutter_threads_add_timeout (100, /* msec between mousekey events */ - trigger_mousekeys_move, - device); + timeout_source_new (device->seat_impl, + 100, /* msec between mousekey events */ + trigger_mousekeys_move, + device); } /* Pointer motion */ @@ -968,7 +985,7 @@ stop_mousekeys_move (MetaInputDeviceNative *device) device->mousekeys_first_motion_time = 0; device->mousekeys_last_motion_time = 0; - g_clear_handle_id (&device->move_mousekeys_timer, g_source_remove); + g_clear_pointer (&device->move_mousekeys_timer, g_source_destroy); } static void @@ -1106,18 +1123,13 @@ handle_mousekeys_release (ClutterEvent *event, return FALSE; } -static void -meta_input_device_native_process_kbd_a11y_event (ClutterEvent *event, - ClutterInputDevice *device, - ClutterEmitInputDeviceEvent emit_event_func) +gboolean +meta_input_device_native_process_kbd_a11y_event_in_impl (ClutterInputDevice *device, + ClutterEvent *event) { MetaInputDeviceNative *device_evdev = META_INPUT_DEVICE_NATIVE (device); - /* Ignore key events injected from IM */ - if (event->key.flags & CLUTTER_EVENT_FLAG_INPUT_METHOD) - goto emit_event; - - if (device_evdev->a11y_flags & CLUTTER_A11Y_KEYBOARD_ENABLED) + if (device_evdev->a11y_flags & META_A11Y_KEYBOARD_ENABLED) { if (event->type == CLUTTER_KEY_PRESS) handle_enablekeys_press (event, device_evdev); @@ -1125,41 +1137,39 @@ meta_input_device_native_process_kbd_a11y_event (ClutterEvent *eve handle_enablekeys_release (event, device_evdev); } - if (device_evdev->a11y_flags & CLUTTER_A11Y_MOUSE_KEYS_ENABLED) + if (device_evdev->a11y_flags & META_A11Y_MOUSE_KEYS_ENABLED) { if (event->type == CLUTTER_KEY_PRESS && handle_mousekeys_press (event, device_evdev)) - return; /* swallow event */ + return TRUE; /* swallow event */ if (event->type == CLUTTER_KEY_RELEASE && handle_mousekeys_release (event, device_evdev)) - return; /* swallow event */ + return TRUE; /* swallow event */ } - if ((device_evdev->a11y_flags & CLUTTER_A11Y_BOUNCE_KEYS_ENABLED) && + if ((device_evdev->a11y_flags & META_A11Y_BOUNCE_KEYS_ENABLED) && (get_debounce_delay (device) != 0)) { if ((event->type == CLUTTER_KEY_PRESS) && debounce_key (event, device_evdev)) { notify_bounce_keys_reject (device_evdev); - return; + return TRUE; } else if (event->type == CLUTTER_KEY_RELEASE) start_bounce_keys (event, device_evdev); } - if ((device_evdev->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_ENABLED) && + if ((device_evdev->a11y_flags & META_A11Y_SLOW_KEYS_ENABLED) && (get_slow_keys_delay (device) != 0)) { if (event->type == CLUTTER_KEY_PRESS) - start_slow_keys (event, device_evdev, emit_event_func); + return start_slow_keys (event, device_evdev); else if (event->type == CLUTTER_KEY_RELEASE) - stop_slow_keys (event, device_evdev, emit_event_func); - - return; + return stop_slow_keys (event, device_evdev); } - if (device_evdev->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_ENABLED) + if (device_evdev->a11y_flags & META_A11Y_STICKY_KEYS_ENABLED) { if (event->type == CLUTTER_KEY_PRESS) handle_stickykeys_press (event, device_evdev); @@ -1167,39 +1177,38 @@ meta_input_device_native_process_kbd_a11y_event (ClutterEvent *eve handle_stickykeys_release (event, device_evdev); } -emit_event: - emit_event_func (event, device); + return FALSE; } void -meta_input_device_native_apply_kbd_a11y_settings (MetaInputDeviceNative *device, - ClutterKbdA11ySettings *settings) +meta_input_device_native_apply_kbd_a11y_settings_in_impl (MetaInputDeviceNative *device, + MetaKbdA11ySettings *settings) { - ClutterKeyboardA11yFlags changed_flags = (device->a11y_flags ^ settings->controls); + MetaKeyboardA11yFlags changed_flags = (device->a11y_flags ^ settings->controls); - if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_SLOW_KEYS_ENABLED)) + if (changed_flags & (META_A11Y_KEYBOARD_ENABLED | META_A11Y_SLOW_KEYS_ENABLED)) clear_slow_keys (device); - if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_BOUNCE_KEYS_ENABLED)) + if (changed_flags & (META_A11Y_KEYBOARD_ENABLED | META_A11Y_BOUNCE_KEYS_ENABLED)) device->debounce_key = 0; - if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_STICKY_KEYS_ENABLED)) + if (changed_flags & (META_A11Y_KEYBOARD_ENABLED | META_A11Y_STICKY_KEYS_ENABLED)) { device->stickykeys_depressed_mask = 0; update_internal_xkb_state (device, 0, 0); } - if (changed_flags & CLUTTER_A11Y_KEYBOARD_ENABLED) + if (changed_flags & META_A11Y_KEYBOARD_ENABLED) { device->toggle_slowkeys_timer = 0; device->shift_count = 0; device->last_shift_time = 0; } - if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_MOUSE_KEYS_ENABLED)) + if (changed_flags & (META_A11Y_KEYBOARD_ENABLED | META_A11Y_MOUSE_KEYS_ENABLED)) { if (settings->controls & - (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_MOUSE_KEYS_ENABLED)) + (META_A11Y_KEYBOARD_ENABLED | META_A11Y_MOUSE_KEYS_ENABLED)) enable_mousekeys (device); else disable_mousekeys (device); @@ -1211,28 +1220,26 @@ meta_input_device_native_apply_kbd_a11y_settings (MetaInputDeviceNative *device } void -meta_input_device_native_a11y_maybe_notify_toggle_keys (MetaInputDeviceNative *device) +meta_input_device_native_a11y_maybe_notify_toggle_keys_in_impl (MetaInputDeviceNative *device) { - if (device->a11y_flags & CLUTTER_A11Y_TOGGLE_KEYS_ENABLED) + if (device->a11y_flags & META_A11Y_TOGGLE_KEYS_ENABLED) meta_input_device_native_bell_notify (device); } static void meta_input_device_native_class_init (MetaInputDeviceNativeClass *klass) { - ClutterInputDeviceClass *device_manager_class = CLUTTER_INPUT_DEVICE_CLASS (klass); + ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = meta_input_device_native_finalize; object_class->set_property = meta_input_device_native_set_property; object_class->get_property = meta_input_device_native_get_property; - device_manager_class->keycode_to_evdev = meta_input_device_native_keycode_to_evdev; - device_manager_class->update_from_tool = meta_input_device_native_update_from_tool; - device_manager_class->is_mode_switch_button = meta_input_device_native_is_mode_switch_button; - device_manager_class->get_group_n_modes = meta_input_device_native_get_group_n_modes; - device_manager_class->is_grouped = meta_input_device_native_is_grouped; - device_manager_class->process_kbd_a11y_event = meta_input_device_native_process_kbd_a11y_event; + device_class->is_mode_switch_button = meta_input_device_native_is_mode_switch_button; + device_class->get_group_n_modes = meta_input_device_native_get_group_n_modes; + device_class->is_grouped = meta_input_device_native_is_grouped; + device_class->get_pad_feature_group = meta_input_device_native_get_pad_feature_group; obj_props[PROP_DEVICE_MATRIX] = g_param_spec_boxed ("device-matrix", @@ -1258,6 +1265,53 @@ meta_input_device_native_init (MetaInputDeviceNative *self) self->output_ratio = 0; } +static void +update_pad_features (MetaInputDeviceNative *device_native) +{ + ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_native); + struct libinput_device *libinput_device; + struct libinput_tablet_pad_mode_group *mode_group; + int n_groups, n_buttons, n_rings, n_strips, i, j; + + libinput_device = meta_input_device_native_get_libinput_device (device); + n_rings = libinput_device_tablet_pad_get_num_rings (libinput_device); + n_strips = libinput_device_tablet_pad_get_num_strips (libinput_device); + n_groups = libinput_device_tablet_pad_get_num_mode_groups (libinput_device); + n_buttons = libinput_device_tablet_pad_get_num_buttons (libinput_device); + + device_native->pad_features = g_array_new (FALSE, FALSE, sizeof (PadFeature)); + + for (i = 0; i < n_groups; i++) + { + mode_group = + libinput_device_tablet_pad_get_mode_group (libinput_device, i); + + for (j = 0; j < n_buttons; j++) + { + PadFeature feature = { CLUTTER_PAD_FEATURE_BUTTON, j, i }; + + if (libinput_tablet_pad_mode_group_has_button (mode_group, j)) + g_array_append_val (device_native->pad_features, feature); + } + + for (j = 0; j < n_rings; j++) + { + PadFeature feature = { CLUTTER_PAD_FEATURE_RING, j, i }; + + if (libinput_tablet_pad_mode_group_has_ring (mode_group, j)) + g_array_append_val (device_native->pad_features, feature); + } + + for (j = 0; j < n_strips; j++) + { + PadFeature feature = { CLUTTER_PAD_FEATURE_STRIP, j, i }; + + if (libinput_tablet_pad_mode_group_has_strip (mode_group, j)) + g_array_append_val (device_native->pad_features, feature); + } + } +} + /* * meta_input_device_native_new: * @manager: the device manager @@ -1268,17 +1322,17 @@ meta_input_device_native_init (MetaInputDeviceNative *self) * it with the provided seat. */ ClutterInputDevice * -meta_input_device_native_new (MetaSeatNative *seat, - struct libinput_device *libinput_device) +meta_input_device_native_new_in_impl (MetaSeatImpl *seat_impl, + struct libinput_device *libinput_device) { MetaInputDeviceNative *device; ClutterInputDeviceType type; char *vendor, *product; - int n_rings = 0, n_strips = 0, n_groups = 1; + int n_rings = 0, n_strips = 0, n_groups = 1, n_buttons = 0; char *node_path; double width, height; - type = meta_input_device_native_determine_type (libinput_device); + type = meta_input_device_native_determine_type_in_impl (libinput_device); vendor = g_strdup_printf ("%.4x", libinput_device_get_id_vendor (libinput_device)); product = g_strdup_printf ("%.4x", libinput_device_get_id_product (libinput_device)); node_path = g_strdup_printf ("/dev/input/%s", libinput_device_get_sysname (libinput_device)); @@ -1289,23 +1343,24 @@ meta_input_device_native_new (MetaSeatNative *seat, n_rings = libinput_device_tablet_pad_get_num_rings (libinput_device); n_strips = libinput_device_tablet_pad_get_num_strips (libinput_device); n_groups = libinput_device_tablet_pad_get_num_mode_groups (libinput_device); + n_buttons = libinput_device_tablet_pad_get_num_buttons (libinput_device); } device = g_object_new (META_TYPE_INPUT_DEVICE_NATIVE, "name", libinput_device_get_name (libinput_device), "device-type", type, "device-mode", CLUTTER_INPUT_MODE_PHYSICAL, - "enabled", TRUE, "vendor-id", vendor, "product-id", product, "n-rings", n_rings, "n-strips", n_strips, "n-mode-groups", n_groups, + "n-buttons", n_buttons, "device-node", node_path, - "seat", seat, + "seat", seat_impl->seat_native, NULL); - device->seat = seat; + device->seat_impl = seat_impl; device->libinput_device = libinput_device; libinput_device_set_user_data (libinput_device, device); @@ -1314,6 +1369,10 @@ meta_input_device_native_new (MetaSeatNative *seat, g_free (product); g_free (node_path); + if (libinput_device_has_capability (libinput_device, + LIBINPUT_DEVICE_CAP_TABLET_PAD)) + update_pad_features (device); + if (libinput_device_get_size (libinput_device, &width, &height) == 0) device->device_aspect_ratio = width / height; @@ -1328,7 +1387,7 @@ meta_input_device_native_new (MetaSeatNative *seat, * Create a new virtual ClutterInputDevice of the given type. */ ClutterInputDevice * -meta_input_device_native_new_virtual (MetaSeatNative *seat, +meta_input_device_native_new_virtual (MetaSeatImpl *seat_impl, ClutterInputDeviceType type, ClutterInputMode mode) { @@ -1355,24 +1414,23 @@ meta_input_device_native_new_virtual (MetaSeatNative *seat, "name", name, "device-type", type, "device-mode", mode, - "enabled", TRUE, - "seat", seat, + "seat", seat_impl->seat_native, NULL); - device->seat = seat; + device->seat_impl = seat_impl; return CLUTTER_INPUT_DEVICE (device); } -MetaSeatNative * -meta_input_device_native_get_seat (MetaInputDeviceNative *device) +MetaSeatImpl * +meta_input_device_native_get_seat_impl (MetaInputDeviceNative *device) { - return device->seat; + return device->seat_impl; } void -meta_input_device_native_update_leds (MetaInputDeviceNative *device, - enum libinput_led leds) +meta_input_device_native_update_leds_in_impl (MetaInputDeviceNative *device, + enum libinput_led leds) { if (!device->libinput_device) return; @@ -1381,7 +1439,7 @@ meta_input_device_native_update_leds (MetaInputDeviceNative *device, } ClutterInputDeviceType -meta_input_device_native_determine_type (struct libinput_device *ldev) +meta_input_device_native_determine_type_in_impl (struct libinput_device *ldev) { /* This setting is specific to touchpads and alike, only in these * devices there is this additional layer of touch event interpretation. @@ -1426,18 +1484,17 @@ meta_input_device_native_get_libinput_device (ClutterInputDevice *device) } void -meta_input_device_native_translate_coordinates (ClutterInputDevice *device, - ClutterStage *stage, - float *x, - float *y) +meta_input_device_native_translate_coordinates_in_impl (ClutterInputDevice *device, + MetaViewportInfo *viewports, + float *x, + float *y) { MetaInputDeviceNative *device_evdev = META_INPUT_DEVICE_NATIVE (device); double min_x = 0, min_y = 0, max_x = 1, max_y = 1; - double stage_width, stage_height; + float stage_width, stage_height; double x_d, y_d; - stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); - stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); + meta_viewport_info_get_extents (viewports, &stage_width, &stage_height); x_d = *x / stage_width; y_d = *y / stage_height; @@ -1462,7 +1519,7 @@ meta_input_device_native_translate_coordinates (ClutterInputDevice *device, } MetaInputDeviceMapping -meta_input_device_native_get_mapping_mode (ClutterInputDevice *device) +meta_input_device_native_get_mapping_mode_in_impl (ClutterInputDevice *device) { MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device); ClutterInputDeviceType device_type; @@ -1480,8 +1537,8 @@ meta_input_device_native_get_mapping_mode (ClutterInputDevice *device) } void -meta_input_device_native_set_mapping_mode (ClutterInputDevice *device, - MetaInputDeviceMapping mapping) +meta_input_device_native_set_mapping_mode_in_impl (ClutterInputDevice *device, + MetaInputDeviceMapping mapping) { MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device); ClutterInputDeviceType device_type; @@ -1495,3 +1552,23 @@ meta_input_device_native_set_mapping_mode (ClutterInputDevice *device, device_native->mapping_mode = mapping; } + +void +meta_input_device_native_set_coords_in_impl (MetaInputDeviceNative *device_native, + float x, + float y) +{ + device_native->pointer_x = x; + device_native->pointer_y = y; +} + +void +meta_input_device_native_get_coords_in_impl (MetaInputDeviceNative *device_native, + float *x, + float *y) +{ + if (x) + *x = device_native->pointer_x; + if (y) + *y = device_native->pointer_y; +} diff --git a/src/backends/native/meta-input-device-native.h b/src/backends/native/meta-input-device-native.h index cbc33ce0d11a92ab6ad5b6b035eded00ecf55193..2000888dc485040ab67755217e27bb1b5a7457dd 100644 --- a/src/backends/native/meta-input-device-native.h +++ b/src/backends/native/meta-input-device-native.h @@ -26,9 +26,14 @@ #ifndef META_INPUT_DEVICE_NATIVE_H #define META_INPUT_DEVICE_NATIVE_H +#ifndef META_INPUT_THREAD_H_INSIDE +#error "This header cannot be included directly. Use "backends/native/meta-input-thread.h"" +#endif /* META_INPUT_THREAD_H_INSIDE */ + #include #include "backends/meta-input-device-private.h" +#include "backends/meta-input-settings-private.h" #include "backends/native/meta-seat-native.h" #include "clutter/clutter-mutter.h" @@ -68,23 +73,28 @@ struct _MetaInputDeviceNative ClutterInputDevice parent; struct libinput_device *libinput_device; - MetaSeatNative *seat; + MetaSeatImpl *seat_impl; ClutterInputDeviceTool *last_tool; + GArray *pad_features; cairo_matrix_t device_matrix; double device_aspect_ratio; /* w:h */ double output_ratio; /* w:h */ MetaInputDeviceMapping mapping_mode; + /* Pointer position */ + float pointer_x; + float pointer_y; + /* Keyboard a11y */ - ClutterKeyboardA11yFlags a11y_flags; + MetaKeyboardA11yFlags a11y_flags; GList *slow_keys_list; - guint debounce_timer; + GSource *debounce_timer; uint16_t debounce_key; xkb_mod_mask_t stickykeys_depressed_mask; xkb_mod_mask_t stickykeys_latched_mask; xkb_mod_mask_t stickykeys_locked_mask; - guint toggle_slowkeys_timer; + GSource *toggle_slowkeys_timer; uint16_t shift_count; uint32_t last_shift_time; int mousekeys_btn; @@ -95,7 +105,7 @@ struct _MetaInputDeviceNative guint mousekeys_accel_time; guint mousekeys_max_speed; double mousekeys_curve_factor; - guint move_mousekeys_timer; + GSource *move_mousekeys_timer; uint16_t last_mousekeys_key; }; @@ -106,35 +116,44 @@ struct _MetaInputDeviceNativeClass GType meta_input_device_native_get_type (void) G_GNUC_CONST; -ClutterInputDevice * meta_input_device_native_new (MetaSeatNative *seat, +ClutterInputDevice * meta_input_device_native_new_in_impl (MetaSeatImpl *seat_impl, struct libinput_device *libinput_device); -ClutterInputDevice * meta_input_device_native_new_virtual (MetaSeatNative *seat, - ClutterInputDeviceType type, - ClutterInputMode mode); +ClutterInputDevice * meta_input_device_native_new_virtual (MetaSeatImpl *seat_impl, + ClutterInputDeviceType type, + ClutterInputMode mode); -MetaSeatNative * meta_input_device_native_get_seat (MetaInputDeviceNative *device); +MetaSeatImpl * meta_input_device_native_get_seat_impl (MetaInputDeviceNative *device); -void meta_input_device_native_update_leds (MetaInputDeviceNative *device, - enum libinput_led leds); +void meta_input_device_native_update_leds_in_impl (MetaInputDeviceNative *device, + enum libinput_led leds); -ClutterInputDeviceType meta_input_device_native_determine_type (struct libinput_device *libinput_device); +ClutterInputDeviceType meta_input_device_native_determine_type_in_impl (struct libinput_device *libinput_device); -void meta_input_device_native_translate_coordinates (ClutterInputDevice *device, - ClutterStage *stage, - float *x, - float *y); +void meta_input_device_native_translate_coordinates_in_impl (ClutterInputDevice *device, + MetaViewportInfo *viewports, + float *x, + float *y); -MetaInputDeviceMapping meta_input_device_native_get_mapping_mode (ClutterInputDevice *device); -void meta_input_device_native_set_mapping_mode (ClutterInputDevice *device, - MetaInputDeviceMapping mapping); +MetaInputDeviceMapping meta_input_device_native_get_mapping_mode_in_impl (ClutterInputDevice *device); +void meta_input_device_native_set_mapping_mode_in_impl (ClutterInputDevice *device, + MetaInputDeviceMapping mapping); -void meta_input_device_native_apply_kbd_a11y_settings (MetaInputDeviceNative *device, - ClutterKbdA11ySettings *settings); +void meta_input_device_native_apply_kbd_a11y_settings_in_impl (MetaInputDeviceNative *device, + MetaKbdA11ySettings *settings); -void meta_input_device_native_a11y_maybe_notify_toggle_keys (MetaInputDeviceNative *device_evdev); +void meta_input_device_native_a11y_maybe_notify_toggle_keys_in_impl (MetaInputDeviceNative *device_evdev); struct libinput_device * meta_input_device_native_get_libinput_device (ClutterInputDevice *device); +void meta_input_device_native_set_coords_in_impl (MetaInputDeviceNative *device_native, + float x, + float y); +void meta_input_device_native_get_coords_in_impl (MetaInputDeviceNative *device_native, + float *x, + float *y); +gboolean meta_input_device_native_process_kbd_a11y_event_in_impl (ClutterInputDevice *device, + ClutterEvent *event); + #endif /* META_INPUT_DEVICE_NATIVE_H */ diff --git a/src/backends/native/meta-input-device-tool-native.c b/src/backends/native/meta-input-device-tool-native.c index 8b540afbb5ca3198c8a7b80082a1c02f0fd12d1d..e6ec0c758546738ab7a702e20e64c987a552c519 100644 --- a/src/backends/native/meta-input-device-tool-native.c +++ b/src/backends/native/meta-input-device-tool-native.c @@ -19,7 +19,7 @@ #include "config.h" -#include "backends/native/meta-input-device-tool-native.h" +#include "backends/native/meta-input-thread.h" G_DEFINE_TYPE (MetaInputDeviceToolNative, meta_input_device_tool_native, CLUTTER_TYPE_INPUT_DEVICE_TOOL) @@ -49,6 +49,27 @@ meta_input_device_tool_native_init (MetaInputDeviceToolNative *tool) tool->button_map = g_hash_table_new (NULL, NULL); } +static ClutterInputAxisFlags +translate_axes (struct libinput_tablet_tool *tool) +{ + ClutterInputAxisFlags axes = 0; + + if (libinput_tablet_tool_has_pressure (tool)) + axes |= CLUTTER_INPUT_AXIS_FLAG_PRESSURE; + if (libinput_tablet_tool_has_distance (tool)) + axes |= CLUTTER_INPUT_AXIS_FLAG_DISTANCE; + if (libinput_tablet_tool_has_rotation (tool)) + axes |= CLUTTER_INPUT_AXIS_FLAG_ROTATION; + if (libinput_tablet_tool_has_slider (tool)) + axes |= CLUTTER_INPUT_AXIS_FLAG_SLIDER; + if (libinput_tablet_tool_has_wheel (tool)) + axes |= CLUTTER_INPUT_AXIS_FLAG_WHEEL; + if (libinput_tablet_tool_has_tilt (tool)) + axes |= CLUTTER_INPUT_AXIS_FLAG_XTILT | CLUTTER_INPUT_AXIS_FLAG_YTILT; + + return axes; +} + ClutterInputDeviceTool * meta_input_device_tool_native_new (struct libinput_tablet_tool *tool, uint64_t serial, @@ -60,6 +81,7 @@ meta_input_device_tool_native_new (struct libinput_tablet_tool *tool, "type", type, "serial", serial, "id", libinput_tablet_tool_get_tool_id (tool), + "axes", translate_axes (tool), NULL); evdev_tool->tool = libinput_tablet_tool_ref (tool); @@ -68,8 +90,8 @@ meta_input_device_tool_native_new (struct libinput_tablet_tool *tool, } void -meta_input_device_tool_native_set_pressure_curve (ClutterInputDeviceTool *tool, - double curve[4]) +meta_input_device_tool_native_set_pressure_curve_in_impl (ClutterInputDeviceTool *tool, + double curve[4]) { MetaInputDeviceToolNative *evdev_tool; @@ -87,9 +109,9 @@ meta_input_device_tool_native_set_pressure_curve (ClutterInputDeviceTool *tool, } void -meta_input_device_tool_native_set_button_code (ClutterInputDeviceTool *tool, - uint32_t button, - uint32_t evcode) +meta_input_device_tool_native_set_button_code_in_impl (ClutterInputDeviceTool *tool, + uint32_t button, + uint32_t evcode) { MetaInputDeviceToolNative *evdev_tool; @@ -130,8 +152,8 @@ calculate_bezier_position (double pos, } double -meta_input_device_tool_native_translate_pressure (ClutterInputDeviceTool *tool, - double pressure) +meta_input_device_tool_native_translate_pressure_in_impl (ClutterInputDeviceTool *tool, + double pressure) { MetaInputDeviceToolNative *evdev_tool; @@ -147,8 +169,8 @@ meta_input_device_tool_native_translate_pressure (ClutterInputDeviceTool *tool, } uint32_t -meta_input_device_tool_native_get_button_code (ClutterInputDeviceTool *tool, - uint32_t button) +meta_input_device_tool_native_get_button_code_in_impl (ClutterInputDeviceTool *tool, + uint32_t button) { MetaInputDeviceToolNative *evdev_tool; diff --git a/src/backends/native/meta-input-device-tool-native.h b/src/backends/native/meta-input-device-tool-native.h index 83e79930a8c71b85f92b4fad8aa86adc75ade845..fa12358adef7cecc15e7f068b2f228a69cc5b5e6 100644 --- a/src/backends/native/meta-input-device-tool-native.h +++ b/src/backends/native/meta-input-device-tool-native.h @@ -20,6 +20,10 @@ #ifndef META_INPUT_DEVICE_NATIVE_TOOL_H #define META_INPUT_DEVICE_NATIVE_TOOL_H +#ifndef META_INPUT_THREAD_H_INSIDE +#error "This header cannot be included directly. Use "backends/native/meta-input-thread.h"" +#endif /* META_INPUT_THREAD_H_INSIDE */ + #include #include "clutter/clutter.h" @@ -70,16 +74,16 @@ ClutterInputDeviceTool * meta_input_device_tool_native_new (struct libinput uint64_t serial, ClutterInputDeviceToolType type); -gdouble meta_input_device_tool_native_translate_pressure (ClutterInputDeviceTool *tool, - double pressure); -uint32_t meta_input_device_tool_native_get_button_code (ClutterInputDeviceTool *tool, - uint32_t button); +gdouble meta_input_device_tool_native_translate_pressure_in_impl (ClutterInputDeviceTool *tool, + double pressure); +uint32_t meta_input_device_tool_native_get_button_code_in_impl (ClutterInputDeviceTool *tool, + uint32_t button); -void meta_input_device_tool_native_set_pressure_curve (ClutterInputDeviceTool *tool, - double curve[4]); -void meta_input_device_tool_native_set_button_code (ClutterInputDeviceTool *tool, - uint32_t button, - uint32_t evcode); +void meta_input_device_tool_native_set_pressure_curve_in_impl (ClutterInputDeviceTool *tool, + double curve[4]); +void meta_input_device_tool_native_set_button_code_in_impl (ClutterInputDeviceTool *tool, + uint32_t button, + uint32_t evcode); G_END_DECLS diff --git a/src/backends/native/meta-input-settings-native.c b/src/backends/native/meta-input-settings-native.c index 7129eb6560bff5a8b3492d116c6c79cabfb79a9c..3f9f71fe7fc6dfd87637040a42026ff5da2b0f8f 100644 --- a/src/backends/native/meta-input-settings-native.c +++ b/src/backends/native/meta-input-settings-native.c @@ -26,22 +26,72 @@ #include #include -#include "backends/meta-logical-monitor.h" #include "backends/native/meta-backend-native.h" -#include "backends/native/meta-input-device-native.h" -#include "backends/native/meta-input-device-tool-native.h" +#include "backends/native/meta-input-thread.h" #include "backends/native/meta-input-settings-native.h" G_DEFINE_TYPE (MetaInputSettingsNative, meta_input_settings_native, META_TYPE_INPUT_SETTINGS) +enum +{ + PROP_0, + PROP_SEAT_IMPL, + N_PROPS, +}; + +static GParamSpec *props[N_PROPS] = { 0 }; + static void -meta_input_settings_native_set_send_events (MetaInputSettings *settings, - ClutterInputDevice *device, - GDesktopDeviceSendEvents mode) +meta_input_settings_native_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaInputSettingsNative *input_settings_native = + META_INPUT_SETTINGS_NATIVE (object); + + switch (prop_id) + { + case PROP_SEAT_IMPL: + input_settings_native->seat_impl = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +meta_input_settings_native_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaInputSettingsNative *input_settings_native = + META_INPUT_SETTINGS_NATIVE (object); + + switch (prop_id) + { + case PROP_SEAT_IMPL: + g_value_set_object (value, input_settings_native->seat_impl); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +set_send_events (GTask *task) { + GDesktopDeviceSendEvents mode; + ClutterInputDevice *device; enum libinput_config_send_events_mode libinput_mode; struct libinput_device *libinput_device; + device = g_task_get_source_object (task); + mode = GPOINTER_TO_UINT (g_task_get_task_data (task)); + switch (mode) { case G_DESKTOP_DEVICE_SEND_EVENTS_DISABLED: @@ -58,9 +108,39 @@ meta_input_settings_native_set_send_events (MetaInputSettings *settings, } libinput_device = meta_input_device_native_get_libinput_device (device); - if (!libinput_device) - return; libinput_device_config_send_events_set_mode (libinput_device, libinput_mode); + + return G_SOURCE_REMOVE; +} + +static void +meta_input_settings_native_set_send_events (MetaInputSettings *settings, + ClutterInputDevice *device, + GDesktopDeviceSendEvents mode) +{ + MetaInputSettingsNative *input_settings_native; + GTask *task; + + task = g_task_new (device, NULL, NULL, NULL); + g_task_set_task_data (task, GUINT_TO_POINTER (mode), NULL); + + input_settings_native = META_INPUT_SETTINGS_NATIVE (settings); + meta_seat_impl_run_input_task (input_settings_native->seat_impl, + task, (GSourceFunc) set_send_events); + g_object_unref (task); +} + +static gboolean +set_matrix (GTask *task) +{ + ClutterInputDevice *device; + cairo_matrix_t *dev_matrix; + + device = g_task_get_source_object (task); + dev_matrix = g_task_get_task_data (task); + g_object_set (device, "device-matrix", dev_matrix, NULL); + + return G_SOURCE_REMOVE; } static void @@ -68,22 +148,32 @@ meta_input_settings_native_set_matrix (MetaInputSettings *settings, ClutterInputDevice *device, gfloat matrix[6]) { - cairo_matrix_t dev_matrix; + MetaInputSettingsNative *input_settings_native; + cairo_matrix_t *dev_matrix; + GTask *task; + + dev_matrix = g_new0 (cairo_matrix_t, 1); if (clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE || - meta_input_device_native_get_mapping_mode (device) == + meta_input_device_native_get_mapping_mode_in_impl (device) == META_INPUT_DEVICE_MAPPING_ABSOLUTE) { - cairo_matrix_init (&dev_matrix, matrix[0], matrix[3], matrix[1], + cairo_matrix_init (dev_matrix, matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]); } else { - cairo_matrix_init_identity (&dev_matrix); + cairo_matrix_init_identity (dev_matrix); } - g_object_set (device, "device-matrix", &dev_matrix, NULL); + task = g_task_new (device, NULL, NULL, NULL); + g_task_set_task_data (task, dev_matrix, g_free); + + input_settings_native = META_INPUT_SETTINGS_NATIVE (settings); + meta_seat_impl_run_input_task (input_settings_native->seat_impl, + task, (GSourceFunc) set_matrix); + g_object_unref (task); } static void @@ -410,11 +500,11 @@ meta_input_settings_native_set_keyboard_repeat (MetaInputSettings *settings, guint delay, guint interval) { - ClutterSeat *seat; + MetaInputSettingsNative *input_settings_native; - seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); - meta_seat_native_set_keyboard_repeat (META_SEAT_NATIVE (seat), - enabled, delay, interval); + input_settings_native = META_INPUT_SETTINGS_NATIVE (settings); + meta_seat_impl_set_keyboard_repeat_in_impl (input_settings_native->seat_impl, + enabled, delay, interval); } static void @@ -545,46 +635,43 @@ meta_input_settings_native_set_tablet_mapping (MetaInputSettings *settings, else return; - meta_input_device_native_set_mapping_mode (device, dev_mapping); + meta_input_device_native_set_mapping_mode_in_impl (device, dev_mapping); } -static void -meta_input_settings_native_set_tablet_keep_aspect (MetaInputSettings *settings, - ClutterInputDevice *device, - MetaLogicalMonitor *logical_monitor, - gboolean keep_aspect) +static gboolean +set_tablet_aspect_ratio (GTask *task) { - double aspect_ratio = 0; + ClutterInputDevice *device; + double *aspect_ratio; - if (meta_input_device_native_get_mapping_mode (device) == - META_INPUT_DEVICE_MAPPING_RELATIVE) - keep_aspect = FALSE; + device = g_task_get_source_object (task); + aspect_ratio = g_task_get_task_data (task); + g_object_set (device, "output-aspect-ratio", *aspect_ratio, NULL); - if (keep_aspect) - { - int width, height; + return G_SOURCE_REMOVE; +} - if (logical_monitor) - { - width = logical_monitor->rect.width; - height = logical_monitor->rect.height; - } - else - { - MetaMonitorManager *monitor_manager; - MetaBackend *backend; - - backend = meta_get_backend (); - monitor_manager = meta_backend_get_monitor_manager (backend); - meta_monitor_manager_get_screen_size (monitor_manager, - &width, - &height); - } +static void +meta_input_settings_native_set_tablet_aspect_ratio (MetaInputSettings *settings, + ClutterInputDevice *device, + gdouble aspect_ratio) +{ + MetaInputSettingsNative *input_settings_native; + GTask *task; - aspect_ratio = (double) width / height; - } + if (meta_input_device_native_get_mapping_mode_in_impl (device) == + META_INPUT_DEVICE_MAPPING_RELATIVE) + aspect_ratio = 0; + + task = g_task_new (device, NULL, NULL, NULL); + g_task_set_task_data (task, + g_memdup (&aspect_ratio, sizeof (double)), + g_free); - g_object_set (device, "output-aspect-ratio", aspect_ratio, NULL); + input_settings_native = META_INPUT_SETTINGS_NATIVE (settings); + meta_seat_impl_run_input_task (input_settings_native->seat_impl, + task, (GSourceFunc) set_tablet_aspect_ratio); + g_object_unref (task); } static void @@ -630,7 +717,7 @@ meta_input_settings_native_set_stylus_pressure (MetaInputSettings *settings pressure_curve[2] = (gdouble) curve[2] / 100; pressure_curve[3] = (gdouble) curve[3] / 100; - meta_input_device_tool_native_set_pressure_curve (tool, pressure_curve); + meta_input_device_tool_native_set_pressure_curve_in_impl (tool, pressure_curve); } static guint @@ -660,12 +747,12 @@ meta_input_settings_native_set_stylus_button_map (MetaInputSettings *se GDesktopStylusButtonAction secondary, GDesktopStylusButtonAction tertiary) { - meta_input_device_tool_native_set_button_code (tool, CLUTTER_BUTTON_MIDDLE, - action_to_evcode (primary)); - meta_input_device_tool_native_set_button_code (tool, CLUTTER_BUTTON_SECONDARY, - action_to_evcode (secondary)); - meta_input_device_tool_native_set_button_code (tool, 8, /* Back */ - action_to_evcode (tertiary)); + meta_input_device_tool_native_set_button_code_in_impl (tool, CLUTTER_BUTTON_MIDDLE, + action_to_evcode (primary)); + meta_input_device_tool_native_set_button_code_in_impl (tool, CLUTTER_BUTTON_SECONDARY, + action_to_evcode (secondary)); + meta_input_device_tool_native_set_button_code_in_impl (tool, 8, /* Back */ + action_to_evcode (tertiary)); } static void @@ -726,6 +813,10 @@ static void meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass) { MetaInputSettingsClass *input_settings_class = META_INPUT_SETTINGS_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = meta_input_settings_native_set_property; + object_class->get_property = meta_input_settings_native_get_property; input_settings_class->set_send_events = meta_input_settings_native_set_send_events; input_settings_class->set_matrix = meta_input_settings_native_set_matrix; @@ -745,7 +836,7 @@ meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass) input_settings_class->set_disable_while_typing = meta_input_settings_native_set_disable_while_typing; input_settings_class->set_tablet_mapping = meta_input_settings_native_set_tablet_mapping; - input_settings_class->set_tablet_keep_aspect = meta_input_settings_native_set_tablet_keep_aspect; + input_settings_class->set_tablet_aspect_ratio = meta_input_settings_native_set_tablet_aspect_ratio; input_settings_class->set_tablet_area = meta_input_settings_native_set_tablet_area; input_settings_class->set_mouse_accel_profile = meta_input_settings_native_set_mouse_accel_profile; @@ -760,9 +851,28 @@ meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass) input_settings_class->has_two_finger_scroll = meta_input_settings_native_has_two_finger_scroll; input_settings_class->is_trackball_device = meta_input_settings_native_is_trackball_device; + + props[PROP_SEAT_IMPL] = + g_param_spec_object ("seat-impl", + "Seat Impl", + "Seat Impl", + META_TYPE_SEAT_IMPL, + CLUTTER_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, N_PROPS, props); } static void meta_input_settings_native_init (MetaInputSettingsNative *settings) { } + +MetaInputSettings * +meta_input_settings_native_new_in_impl (MetaSeatImpl *seat_impl) +{ + return g_object_new (META_TYPE_INPUT_SETTINGS_NATIVE, + "seat-impl", seat_impl, + "seat", seat_impl->seat_native, + NULL); +} diff --git a/src/backends/native/meta-input-settings-native.h b/src/backends/native/meta-input-settings-native.h index ee600d5d839689c1ecf5f65acf8bab57bd0e34fe..cddd5b15f97f4472a549360dc7c8f8a5d24cd748 100644 --- a/src/backends/native/meta-input-settings-native.h +++ b/src/backends/native/meta-input-settings-native.h @@ -22,6 +22,10 @@ #ifndef META_INPUT_SETTINGS_NATIVE_H #define META_INPUT_SETTINGS_NATIVE_H +#ifndef META_INPUT_THREAD_H_INSIDE +#error "This header cannot be included directly. Use "backends/native/meta-input-thread.h"" +#endif /* META_INPUT_THREAD_H_INSIDE */ + #include "backends/meta-input-settings-private.h" #define META_TYPE_INPUT_SETTINGS_NATIVE (meta_input_settings_native_get_type ()) @@ -37,6 +41,7 @@ typedef struct _MetaInputSettingsNativeClass MetaInputSettingsNativeClass; struct _MetaInputSettingsNative { MetaInputSettings parent_instance; + MetaSeatImpl *seat_impl; }; struct _MetaInputSettingsNativeClass @@ -46,4 +51,6 @@ struct _MetaInputSettingsNativeClass GType meta_input_settings_native_get_type (void) G_GNUC_CONST; +MetaInputSettings * meta_input_settings_native_new_in_impl (MetaSeatImpl *seat_impl); + #endif /* META_INPUT_SETTINGS_NATIVE_H */ diff --git a/src/backends/native/meta-input-thread.h b/src/backends/native/meta-input-thread.h new file mode 100644 index 0000000000000000000000000000000000000000..196adc27bb6d86abcb6eefcf356b0839457e5428 --- /dev/null +++ b/src/backends/native/meta-input-thread.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: Carlos Garnacho + */ + +#ifndef META_INPUT_THREAD_H +#define META_INPUT_THREAD_H + +#define META_INPUT_THREAD_H_INSIDE + +#include "src/backends/native/meta-input-device-native.h" +#include "src/backends/native/meta-input-device-tool-native.h" +#include "src/backends/native/meta-input-settings-native.h" +#include "src/backends/native/meta-keymap-native.h" +#include "src/backends/native/meta-seat-impl.h" + +#undef META_INPUT_THREAD_H_INSIDE + +#endif /* META_INPUT_THREAD_H */ diff --git a/src/backends/native/meta-keymap-native.c b/src/backends/native/meta-keymap-native.c index 3b0da0d1fa274cd936c469efd7dd4484394ee2e9..d3348e8a95acbc25c34805c3115eacca7e17e619 100644 --- a/src/backends/native/meta-keymap-native.c +++ b/src/backends/native/meta-keymap-native.c @@ -22,7 +22,7 @@ #include "config.h" #include "backends/meta-keymap-utils.h" -#include "backends/native/meta-keymap-native.h" +#include "backends/native/meta-input-thread.h" #include "backends/native/meta-seat-native.h" static const char *option_xkb_layout = "us"; @@ -36,6 +36,8 @@ struct _MetaKeymapNative ClutterKeymap parent_instance; struct xkb_keymap *keymap; + gboolean num_lock; + gboolean caps_lock; }; G_DEFINE_TYPE (MetaKeymapNative, meta_keymap_native, @@ -54,31 +56,17 @@ meta_keymap_native_finalize (GObject *object) static gboolean meta_keymap_native_get_num_lock_state (ClutterKeymap *keymap) { - struct xkb_state *xkb_state; - ClutterSeat *seat; - - seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); - xkb_state = meta_seat_native_get_xkb_state (META_SEAT_NATIVE (seat)); + MetaKeymapNative *keymap_native = META_KEYMAP_NATIVE (keymap); - return xkb_state_mod_name_is_active (xkb_state, - XKB_MOD_NAME_NUM, - XKB_STATE_MODS_LATCHED | - XKB_STATE_MODS_LOCKED); + return keymap_native->num_lock; } static gboolean meta_keymap_native_get_caps_lock_state (ClutterKeymap *keymap) { - struct xkb_state *xkb_state; - ClutterSeat *seat; - - seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); - xkb_state = meta_seat_native_get_xkb_state (META_SEAT_NATIVE (seat)); + MetaKeymapNative *keymap_native = META_KEYMAP_NATIVE (keymap); - return xkb_state_mod_name_is_active (xkb_state, - XKB_MOD_NAME_CAPS, - XKB_STATE_MODS_LATCHED | - XKB_STATE_MODS_LOCKED); + return keymap_native->caps_lock; } static PangoDirection @@ -119,8 +107,8 @@ meta_keymap_native_init (MetaKeymapNative *keymap) } void -meta_keymap_native_set_keyboard_map (MetaKeymapNative *keymap, - struct xkb_keymap *xkb_keymap) +meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap, + struct xkb_keymap *xkb_keymap) { g_return_if_fail (xkb_keymap != NULL); @@ -130,7 +118,28 @@ meta_keymap_native_set_keyboard_map (MetaKeymapNative *keymap, } struct xkb_keymap * -meta_keymap_native_get_keyboard_map (MetaKeymapNative *keymap) +meta_keymap_native_get_keyboard_map_in_impl (MetaKeymapNative *keymap) { return keymap->keymap; } + +void +meta_keymap_native_update_in_impl (MetaKeymapNative *keymap) +{ + struct xkb_state *xkb_state; + ClutterSeat *seat; + + seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); + xkb_state = meta_seat_impl_get_xkb_state_in_impl (META_SEAT_NATIVE (seat)->impl); + + keymap->num_lock = + xkb_state_mod_name_is_active (xkb_state, + XKB_MOD_NAME_NUM, + XKB_STATE_MODS_LATCHED | + XKB_STATE_MODS_LOCKED); + keymap->caps_lock = + xkb_state_mod_name_is_active (xkb_state, + XKB_MOD_NAME_CAPS, + XKB_STATE_MODS_LATCHED | + XKB_STATE_MODS_LOCKED); +} diff --git a/src/backends/native/meta-keymap-native.h b/src/backends/native/meta-keymap-native.h index 27364984ce324a7adc08a8d028b3ba71182e0764..6a6b12d9aa327b9d8b0845757b97bbf8743827ff 100644 --- a/src/backends/native/meta-keymap-native.h +++ b/src/backends/native/meta-keymap-native.h @@ -21,6 +21,10 @@ #ifndef META_KEYMAP_NATIVE_H #define META_KEYMAP_NATIVE_H +#ifndef META_INPUT_THREAD_H_INSIDE +#error "This header cannot be included directly. Use "backends/native/meta-input-thread.h"" +#endif /* META_INPUT_THREAD_H_INSIDE */ + #include "backends/native/meta-xkb-utils.h" #include "clutter/clutter.h" @@ -29,8 +33,9 @@ G_DECLARE_FINAL_TYPE (MetaKeymapNative, meta_keymap_native, META, KEYMAP_NATIVE, ClutterKeymap) -void meta_keymap_native_set_keyboard_map (MetaKeymapNative *keymap, - struct xkb_keymap *xkb_keymap); -struct xkb_keymap * meta_keymap_native_get_keyboard_map (MetaKeymapNative *keymap); +void meta_keymap_native_set_keyboard_map_in_impl (MetaKeymapNative *keymap, + struct xkb_keymap *xkb_keymap); +struct xkb_keymap * meta_keymap_native_get_keyboard_map_in_impl (MetaKeymapNative *keymap); +void meta_keymap_native_update_in_impl (MetaKeymapNative *keymap); #endif /* META_KEYMAP_NATIVE_H */ diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c index 61fe19be09daee64dfa20bf8605cd2e02c738e5c..190d0fa887d24c3e14e1ab5c2ccce70218e11152 100644 --- a/src/backends/native/meta-launcher.c +++ b/src/backends/native/meta-launcher.c @@ -39,8 +39,8 @@ #include "backends/native/meta-backend-native.h" #include "backends/native/meta-clutter-backend-native.h" #include "backends/native/meta-cursor-renderer-native.h" +#include "backends/native/meta-input-thread.h" #include "backends/native/meta-renderer-native.h" -#include "backends/native/meta-seat-native.h" #include "clutter/clutter.h" #include "meta-dbus-login1.h" @@ -51,7 +51,9 @@ struct _MetaLauncher Login1Seat *seat_proxy; char *seat_id; - GHashTable *sysfs_fds; + struct { + GHashTable *sysfs_fds; + } impl; gboolean session_active; }; @@ -383,10 +385,10 @@ out: } static int -on_evdev_device_open (const char *path, - int flags, - gpointer user_data, - GError **error) +on_evdev_device_open_in_input_impl (const char *path, + int flags, + gpointer user_data, + GError **error) { MetaLauncher *self = user_data; @@ -410,7 +412,7 @@ on_evdev_device_open (const char *path, return -1; } - g_hash_table_add (self->sysfs_fds, GINT_TO_POINTER (fd)); + g_hash_table_add (self->impl.sysfs_fds, GINT_TO_POINTER (fd)); return fd; } @@ -418,15 +420,15 @@ on_evdev_device_open (const char *path, } static void -on_evdev_device_close (int fd, - gpointer user_data) +on_evdev_device_close_in_input_impl (int fd, + gpointer user_data) { MetaLauncher *self = user_data; - if (g_hash_table_lookup (self->sysfs_fds, GINT_TO_POINTER (fd))) + if (g_hash_table_lookup (self->impl.sysfs_fds, GINT_TO_POINTER (fd))) { /* /sys/ paths just need close() here */ - g_hash_table_remove (self->sysfs_fds, GINT_TO_POINTER (fd)); + g_hash_table_remove (self->impl.sysfs_fds, GINT_TO_POINTER (fd)); close (fd); return; } @@ -523,14 +525,14 @@ meta_launcher_new (GError **error) self->session_proxy = g_object_ref (session_proxy); self->seat_proxy = g_object_ref (seat_proxy); self->seat_id = g_steal_pointer (&seat_id); - self->sysfs_fds = g_hash_table_new (NULL, NULL); + self->impl.sysfs_fds = g_hash_table_new (NULL, NULL); self->session_active = TRUE; meta_clutter_backend_native_set_seat_id (self->seat_id); - meta_seat_native_set_device_callbacks (on_evdev_device_open, - on_evdev_device_close, - self); + meta_seat_impl_set_device_callbacks (on_evdev_device_open_in_input_impl, + on_evdev_device_close_in_input_impl, + self); g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self); @@ -545,10 +547,11 @@ meta_launcher_new (GError **error) void meta_launcher_free (MetaLauncher *self) { + meta_seat_impl_set_device_callbacks (NULL, NULL, NULL); g_free (self->seat_id); g_object_unref (self->seat_proxy); g_object_unref (self->session_proxy); - g_hash_table_destroy (self->sysfs_fds); + g_hash_table_destroy (self->impl.sysfs_fds); g_slice_free (MetaLauncher, self); } diff --git a/src/backends/native/meta-pointer-constraint-native.c b/src/backends/native/meta-pointer-constraint-native.c new file mode 100644 index 0000000000000000000000000000000000000000..6a1c066ade338a8844d001bb66ec17e475c728bb --- /dev/null +++ b/src/backends/native/meta-pointer-constraint-native.c @@ -0,0 +1,694 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2015-2020 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jonas Ã…dahl + */ + +#include "config.h" + +#include +#include + +#include "core/meta-border.h" +#include "meta-pointer-constraint-native.h" + +struct _MetaPointerConstraintImplNative +{ + MetaPointerConstraintImpl parent; + MetaPointerConstraint *constraint; + cairo_region_t *region; +}; + +G_DEFINE_TYPE (MetaPointerConstraintImplNative, + meta_pointer_constraint_impl_native, + META_TYPE_POINTER_CONSTRAINT_IMPL); + +typedef struct _MetaBox +{ + int x1; + int y1; + int x2; + int y2; +} MetaBox; + +static MetaBorder * +add_border (GArray *borders, + float x1, + float y1, + float x2, + float y2, + MetaBorderMotionDirection blocking_directions) +{ + MetaBorder border; + + border = (MetaBorder) { + .line = (MetaLine2) { + .a = (MetaVector2) { + .x = x1, + .y = y1, + }, + .b = (MetaVector2) { + .x = x2, + .y = y2, + }, + }, + .blocking_directions = blocking_directions, + }; + + g_array_append_val (borders, border); + + return &g_array_index (borders, MetaBorder, borders->len - 1); +} + +static gint +compare_lines_x (gconstpointer a, + gconstpointer b) +{ + const MetaBorder *border_a = a; + const MetaBorder *border_b = b; + + if (border_a->line.a.x == border_b->line.a.x) + return border_a->line.b.x < border_b->line.b.x; + else + return border_a->line.a.x > border_b->line.a.x; +} + +static void +add_non_overlapping_edges (MetaBox *boxes, + unsigned int band_above_start, + unsigned int band_below_start, + unsigned int band_below_end, + GArray *borders) +{ + unsigned int i; + GArray *band_merge; + MetaBorder *border; + MetaBorder *prev_border; + MetaBorder *new_border; + + band_merge = g_array_new (FALSE, FALSE, sizeof *border); + + /* Add bottom band of previous row, and top band of current row, and + * sort them so lower left x coordinate comes first. If there are two + * borders with the same left x coordinate, the wider one comes first. + */ + for (i = band_above_start; i < band_below_start; i++) + { + MetaBox *box = &boxes[i]; + add_border (band_merge, box->x1, box->y2, box->x2, box->y2, + META_BORDER_MOTION_DIRECTION_POSITIVE_Y); + } + for (i = band_below_start; i < band_below_end; i++) + { + MetaBox *box= &boxes[i]; + add_border (band_merge, box->x1, box->y1, box->x2, box->y1, + META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); + } + g_array_sort (band_merge, compare_lines_x); + + /* Combine the two combined bands so that any overlapping border is + * eliminated. */ + prev_border = NULL; + for (i = 0; i < band_merge->len; i++) + { + border = &g_array_index (band_merge, MetaBorder, i); + + g_assert (border->line.a.y == border->line.b.y); + g_assert (!prev_border || + prev_border->line.a.y == border->line.a.y); + g_assert (!prev_border || + (prev_border->line.a.x != border->line.a.x || + prev_border->line.b.x != border->line.b.x)); + g_assert (!prev_border || + prev_border->line.a.x <= border->line.a.x); + + if (prev_border && + prev_border->line.a.x == border->line.a.x) + { + /* + * ------------ + + * ------- = + * [ ]----- + */ + prev_border->line.a.x = border->line.b.x; + } + else if (prev_border && + prev_border->line.b.x == border->line.b.x) + { + /* + * ------------ + + * ------ = + * ------[ ] + */ + prev_border->line.b.x = border->line.a.x; + } + else if (prev_border && + prev_border->line.b.x == border->line.a.x) + { + /* + * -------- + + * ------ = + * -------------- + */ + prev_border->line.b.x = border->line.b.x; + } + else if (prev_border && + prev_border->line.b.x >= border->line.a.x) + { + /* + * --------------- + + * ------ = + * -----[ ]---- + */ + new_border = add_border (borders, + border->line.b.x, + border->line.b.y, + prev_border->line.b.x, + prev_border->line.b.y, + prev_border->blocking_directions); + prev_border->line.b.x = border->line.a.x; + prev_border = new_border; + } + else + { + g_assert (!prev_border || + prev_border->line.b.x < border->line.a.x); + /* + * First border or non-overlapping. + * + * ----- + + * ----- = + * ----- ----- + */ + g_array_append_val (borders, *border); + prev_border = &g_array_index (borders, MetaBorder, borders->len - 1); + } + } + + g_array_free (band_merge, FALSE); +} + +static void +add_band_bottom_edges (MetaBox *boxes, + int band_start, + int band_end, + GArray *borders) +{ + int i; + + for (i = band_start; i < band_end; i++) + { + add_border (borders, + boxes[i].x1, boxes[i].y2, + boxes[i].x2, boxes[i].y2, + META_BORDER_MOTION_DIRECTION_POSITIVE_Y); + } +} + +static void +region_to_outline (cairo_region_t *region, + GArray *borders) +{ + MetaBox *boxes; + int num_boxes; + int i; + int top_most, bottom_most; + int current_roof; + int prev_top; + int band_start, prev_band_start; + + /* + * Remove any overlapping lines from the set of rectangles. Note that + * pixman regions are grouped as rows of rectangles, where rectangles + * in one row never touch or overlap and are all of the same height. + * + * -------- --- -------- --- + * | | | | | | | | + * ----------====---- --- ----------- ----- --- + * | | => | | + * ----==========--------- ----- ---------- + * | | | | + * ------------------- ------------------- + * + */ + + num_boxes = cairo_region_num_rectangles (region); + boxes = g_new (MetaBox, num_boxes); + for (i = 0; i < num_boxes; i++) + { + cairo_rectangle_int_t rect; + cairo_region_get_rectangle (region, i, &rect); + boxes[i] = (MetaBox) { + .x1 = rect.x, + .y1 = rect.y, + .x2 = rect.x + rect.width, + .y2 = rect.y + rect.height, + }; + } + prev_top = 0; + top_most = boxes[0].y1; + current_roof = top_most; + bottom_most = boxes[num_boxes - 1].y2; + band_start = 0; + prev_band_start = 0; + for (i = 0; i < num_boxes; i++) + { + /* Detect if there is a vertical empty space, and add the lower + * level of the previous band if so was the case. */ + if (i > 0 && + boxes[i].y1 != prev_top && + boxes[i].y1 != boxes[i - 1].y2) + { + current_roof = boxes[i].y1; + add_band_bottom_edges (boxes, + band_start, + i, + borders); + } + + /* Special case adding the last band, since it won't be handled + * by the band change detection below. */ + if (boxes[i].y1 != current_roof && i == num_boxes - 1) + { + if (boxes[i].y1 != prev_top) + { + /* The last band is a single box, so we don't + * have a prev_band_start to tell us when the + * previous band started. */ + add_non_overlapping_edges (boxes, + band_start, + i, + i + 1, + borders); + } + else + { + add_non_overlapping_edges (boxes, + prev_band_start, + band_start, + i + 1, + borders); + } + } + + /* Detect when passing a band and combine the top border of the + * just passed band with the bottom band of the previous band. + */ + if (boxes[i].y1 != top_most && boxes[i].y1 != prev_top) + { + /* Combine the two passed bands. */ + if (prev_top != current_roof) + { + add_non_overlapping_edges (boxes, + prev_band_start, + band_start, + i, + borders); + } + + prev_band_start = band_start; + band_start = i; + } + + /* Add the top border if the box is part of the current roof. */ + if (boxes[i].y1 == current_roof) + { + add_border (borders, + boxes[i].x1, boxes[i].y1, + boxes[i].x2, boxes[i].y1, + META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); + } + + /* Add the bottom border of the last band. */ + if (boxes[i].y2 == bottom_most) + { + add_border (borders, + boxes[i].x1, boxes[i].y2, + boxes[i].x2, boxes[i].y2, + META_BORDER_MOTION_DIRECTION_POSITIVE_Y); + } + + /* Always add the left border. */ + add_border (borders, + boxes[i].x1, boxes[i].y1, + boxes[i].x1, boxes[i].y2, + META_BORDER_MOTION_DIRECTION_NEGATIVE_X); + + /* Always add the right border. */ + add_border (borders, + boxes[i].x2, boxes[i].y1, + boxes[i].x2, boxes[i].y2, + META_BORDER_MOTION_DIRECTION_POSITIVE_X); + + prev_top = boxes[i].y1; + } + + g_free (boxes); +} + +static MetaBorder * +get_closest_border (GArray *borders, + MetaLine2 *motion, + uint32_t directions) +{ + MetaBorder *border; + MetaVector2 intersection; + MetaVector2 delta; + float distance_2; + MetaBorder *closest_border = NULL; + float closest_distance_2 = DBL_MAX; + unsigned int i; + + for (i = 0; i < borders->len; i++) + { + border = &g_array_index (borders, MetaBorder, i); + + if (!meta_border_is_blocking_directions (border, directions)) + continue; + + if (!meta_line2_intersects_with (&border->line, motion, &intersection)) + continue; + + delta = meta_vector2_subtract (intersection, motion->a); + distance_2 = delta.x*delta.x + delta.y*delta.y; + if (distance_2 < closest_distance_2) + { + closest_border = border; + closest_distance_2 = distance_2; + } + } + + return closest_border; +} + +static void +clamp_to_border (MetaBorder *border, + MetaLine2 *motion, + uint32_t *motion_dir) +{ + /* + * When clamping either rightward or downward motions, the motion needs to be + * clamped so that the destination coordinate does not end up on the border + * (see weston_pointer_clamp_event_to_region). Do this by clamping such + * motions to the border minus the smallest possible wl_fixed_t value. + * + * When clamping in either leftward or upward motion, the resulting coordinate + * needs to be clamped so that it is enough on the inside to avoid the + * inaccuracies of clutter's stage to actor transformation algorithm (the one + * used in clutter_actor_transform_stage_point) to make it end up outside the + * next motion. It also needs to be clamped so that to the wl_fixed_t + * coordinate may still be right on the border (i.e. at .0). Testing shows + * that the smallest wl_fixed_t value divided by 10 is small enough to make + * the wl_fixed_t coordinate .0 and large enough to avoid the inaccuracies of + * clutters transform algorithm. + */ + if (meta_border_is_horizontal (border)) + { + if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_Y) + motion->b.y = border->line.a.y - wl_fixed_to_double (1); + else + motion->b.y = border->line.a.y + wl_fixed_to_double (1) / 10; + *motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_Y | + META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); + } + else + { + if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_X) + motion->b.x = border->line.a.x - wl_fixed_to_double (1); + else + motion->b.x = border->line.a.x + wl_fixed_to_double (1) / 10; + *motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_X | + META_BORDER_MOTION_DIRECTION_NEGATIVE_X); + } +} + +static uint32_t +get_motion_directions (MetaLine2 *motion) +{ + uint32_t directions = 0; + + if (motion->a.x < motion->b.x) + directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_X; + else if (motion->a.x > motion->b.x) + directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_X; + if (motion->a.y < motion->b.y) + directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_Y; + else if (motion->a.y > motion->b.y) + directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_Y; + + return directions; +} + +static void +meta_pointer_constraint_impl_native_constraint (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device, + uint32_t time, + float prev_x, + float prev_y, + float *x_inout, + float *y_inout) +{ + MetaPointerConstraintImplNative *constraint_impl_native; + cairo_region_t *region; + float x, y; + GArray *borders; + MetaLine2 motion; + MetaBorder *closest_border; + uint32_t directions; + + constraint_impl_native = META_POINTER_CONSTRAINT_IMPL_NATIVE (constraint_impl); + + region = cairo_region_reference (constraint_impl_native->region); + x = *x_inout; + y = *y_inout; + + /* For motions in a positive direction on any axis, append the smallest + * possible value representable in a Wayland absolute coordinate. This is + * in order to avoid not clamping motion that as a floating point number + * won't be clamped, but will be rounded up to be outside of the range + * of wl_fixed_t. */ + if (x > prev_x) + x += (float) wl_fixed_to_double(1); + if (y > prev_y) + y += (float) wl_fixed_to_double(1); + + borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder)); + + /* + * Generate borders given the confine region we are to use. The borders + * are defined to be the outer region of the allowed area. This means + * top/left borders are "within" the allowed area, while bottom/right + * borders are outside. This needs to be considered when clamping + * confined motion vectors. + */ + region_to_outline (region, borders); + cairo_region_destroy (region); + + motion = (MetaLine2) { + .a = (MetaVector2) { + .x = prev_x, + .y = prev_y, + }, + .b = (MetaVector2) { + .x = x, + .y = y, + }, + }; + directions = get_motion_directions (&motion); + + while (directions) + { + closest_border = get_closest_border (borders, + &motion, + directions); + if (closest_border) + clamp_to_border (closest_border, &motion, &directions); + else + break; + } + + *x_inout = motion.b.x; + *y_inout = motion.b.y; + g_array_free (borders, FALSE); +} + +static float +point_to_border_distance_2 (MetaBorder *border, + float x, + float y) +{ + float orig_x, orig_y; + float dx, dy; + + if (meta_border_is_horizontal (border)) + { + if (x < border->line.a.x) + orig_x = border->line.a.x; + else if (x > border->line.b.x) + orig_x = border->line.b.x; + else + orig_x = x; + orig_y = border->line.a.y; + } + else + { + if (y < border->line.a.y) + orig_y = border->line.a.y; + else if (y > border->line.b.y) + orig_y = border->line.b.y; + else + orig_y = y; + orig_x = border->line.a.x; + } + + dx = fabsf (orig_x - x); + dy = fabsf (orig_y - y); + return dx*dx + dy*dy; +} + +static void +closest_point_behind_border (MetaBorder *border, + float *sx, + float *sy) +{ + switch (border->blocking_directions) + { + case META_BORDER_MOTION_DIRECTION_POSITIVE_X: + case META_BORDER_MOTION_DIRECTION_NEGATIVE_X: + if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_X) + *sx = border->line.a.x - wl_fixed_to_double (1); + else + *sx = border->line.a.x + wl_fixed_to_double (1); + if (*sy < border->line.a.y) + *sy = border->line.a.y + wl_fixed_to_double (1); + else if (*sy > border->line.b.y) + *sy = border->line.b.y - wl_fixed_to_double (1); + break; + case META_BORDER_MOTION_DIRECTION_POSITIVE_Y: + case META_BORDER_MOTION_DIRECTION_NEGATIVE_Y: + if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_Y) + *sy = border->line.a.y - wl_fixed_to_double (1); + else + *sy = border->line.a.y + wl_fixed_to_double (1); + if (*sx < border->line.a.x) + *sx = border->line.a.x + wl_fixed_to_double (1); + else if (*sx > (border->line.b.x)) + *sx = border->line.b.x - wl_fixed_to_double (1); + break; + } +} + +static void +meta_pointer_constraint_impl_native_ensure_constrained (MetaPointerConstraintImpl *constraint_impl, + ClutterInputDevice *device) +{ + MetaPointerConstraintImplNative *constraint_impl_native; + graphene_point_t point; + cairo_region_t *region; + float x; + float y; + + constraint_impl_native = META_POINTER_CONSTRAINT_IMPL_NATIVE (constraint_impl); + region = cairo_region_reference (constraint_impl_native->region); + + clutter_seat_query_state (clutter_input_device_get_seat (device), + device, NULL, &point, NULL); + x = point.x; + y = point.y; + + if (!cairo_region_contains_point (region, (int) x, (int) y)) + { + GArray *borders; + float closest_distance_2 = FLT_MAX; + MetaBorder *closest_border = NULL; + ClutterSeat *seat; + unsigned int i; + + borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder)); + + region_to_outline (region, borders); + + for (i = 0; i < borders->len; i++) + { + MetaBorder *border = &g_array_index (borders, MetaBorder, i); + float distance_2; + + distance_2 = point_to_border_distance_2 (border, x, y); + if (distance_2 < closest_distance_2) + { + closest_border = border; + closest_distance_2 = distance_2; + } + } + + closest_point_behind_border (closest_border, &x, &y); + + seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); + clutter_seat_warp_pointer (seat, x, y); + } + + cairo_region_destroy (region); +} + +static void +meta_pointer_constraint_impl_native_finalize (GObject *object) +{ + MetaPointerConstraintImplNative *constraint_impl_native; + + constraint_impl_native = META_POINTER_CONSTRAINT_IMPL_NATIVE (object); + g_clear_pointer (&constraint_impl_native->region, cairo_region_destroy); + + G_OBJECT_CLASS (meta_pointer_constraint_impl_native_parent_class)->finalize (object); +} + +static void +meta_pointer_constraint_impl_native_init (MetaPointerConstraintImplNative *constraint_impl_native) +{ +} + +static void +meta_pointer_constraint_impl_native_class_init (MetaPointerConstraintImplNativeClass *klass) +{ + MetaPointerConstraintImplClass *constraint_impl_class; + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_pointer_constraint_impl_native_finalize; + + constraint_impl_class = META_POINTER_CONSTRAINT_IMPL_CLASS (klass); + constraint_impl_class->constrain = meta_pointer_constraint_impl_native_constraint; + constraint_impl_class->ensure_constrained = + meta_pointer_constraint_impl_native_ensure_constrained; +} + + +MetaPointerConstraintImpl * +meta_pointer_constraint_impl_native_new (MetaPointerConstraint *constraint, + const cairo_region_t *region) +{ + MetaPointerConstraintImplNative *constraint_impl; + + constraint_impl = g_object_new (META_TYPE_POINTER_CONSTRAINT_IMPL_NATIVE, + NULL); + constraint_impl->constraint = constraint; + constraint_impl->region = cairo_region_copy (region); + + return META_POINTER_CONSTRAINT_IMPL (constraint_impl); +} diff --git a/src/backends/native/meta-pointer-constraint-native.h b/src/backends/native/meta-pointer-constraint-native.h new file mode 100644 index 0000000000000000000000000000000000000000..83a2e575d5a12f1cc874f143a35bd6583b9c4464 --- /dev/null +++ b/src/backends/native/meta-pointer-constraint-native.h @@ -0,0 +1,46 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2020 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Carlos Garnacho + */ + +#ifndef META_POINTER_CONSTRAINT_NATIVE_H +#define META_POINTER_CONSTRAINT_NATIVE_H + +#include + +#include "clutter/clutter.h" +#include "backends/meta-pointer-constraint.h" + +G_BEGIN_DECLS + +#define META_TYPE_POINTER_CONSTRAINT_IMPL_NATIVE (meta_pointer_constraint_impl_native_get_type ()) +G_DECLARE_FINAL_TYPE (MetaPointerConstraintImplNative, + meta_pointer_constraint_impl_native, + META, POINTER_CONSTRAINT_IMPL_NATIVE, + MetaPointerConstraintImpl) + +MetaPointerConstraintImpl * meta_pointer_constraint_impl_native_new (MetaPointerConstraint *constraint_impl, + const cairo_region_t *region); + +G_END_DECLS + +#endif /* META_POINTER_CONSTRAINT_NATIVE_H */ diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c new file mode 100644 index 0000000000000000000000000000000000000000..f5e45e5d0179a1d304dedd4cead74a7b060ba40b --- /dev/null +++ b/src/backends/native/meta-seat-impl.c @@ -0,0 +1,3431 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corp. + * Copyright (C) 2014 Jonas Ã…dahl + * Copyright (C) 2016 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: Damien Lespiau + * Author: Jonas Ã…dahl + * Author: Carlos Garnacho + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "backends/meta-cursor-tracker-private.h" +#include "backends/native/meta-barrier-native.h" +#include "backends/native/meta-event-native.h" +#include "backends/native/meta-input-thread.h" +#include "backends/native/meta-virtual-input-device-native.h" +#include "clutter/clutter-mutter.h" +#include "core/bell.h" + +/* + * Clutter makes the assumption that two core devices have ID's 2 and 3 (core + * pointer and core keyboard). + * + * Since the two first devices that will ever be created will be the virtual + * pointer and virtual keyboard of the first seat, we fulfill the made + * assumptions by having the first device having ID 2 and following 3. + */ +#define INITIAL_DEVICE_ID 2 + +/* Try to keep the pointer inside the stage. Hopefully no one is using + * this backend with stages smaller than this. */ +#define INITIAL_POINTER_X 16 +#define INITIAL_POINTER_Y 16 + +#define AUTOREPEAT_VALUE 2 + +#define DISCRETE_SCROLL_STEP 10.0 + +#ifndef BTN_STYLUS3 +#define BTN_STYLUS3 0x149 /* Linux 4.15 */ +#endif + +struct _MetaEventSource +{ + GSource source; + + MetaSeatImpl *seat_impl; + GPollFD event_poll_fd; +}; + +static MetaOpenDeviceCallback device_open_callback; +static MetaCloseDeviceCallback device_close_callback; +static gpointer device_callback_data; + +#ifdef CLUTTER_ENABLE_DEBUG +static const char *device_type_str[] = { + "pointer", /* CLUTTER_POINTER_DEVICE */ + "keyboard", /* CLUTTER_KEYBOARD_DEVICE */ + "extension", /* CLUTTER_EXTENSION_DEVICE */ + "joystick", /* CLUTTER_JOYSTICK_DEVICE */ + "tablet", /* CLUTTER_TABLET_DEVICE */ + "touchpad", /* CLUTTER_TOUCHPAD_DEVICE */ + "touchscreen", /* CLUTTER_TOUCHSCREEN_DEVICE */ + "pen", /* CLUTTER_PEN_DEVICE */ + "eraser", /* CLUTTER_ERASER_DEVICE */ + "cursor", /* CLUTTER_CURSOR_DEVICE */ + "pad", /* CLUTTER_PAD_DEVICE */ +}; +#endif /* CLUTTER_ENABLE_DEBUG */ + +enum +{ + PROP_0, + PROP_SEAT, + PROP_SEAT_ID, + N_PROPS, +}; + +static GParamSpec *props[N_PROPS] = { NULL }; + +enum +{ + KBD_A11Y_FLAGS_CHANGED, + KBD_A11Y_MODS_STATE_CHANGED, + TOUCH_MODE, + BELL, + MODS_STATE_CHANGED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0 }; + +static void meta_seat_impl_initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaSeatImpl, meta_seat_impl, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + meta_seat_impl_initable_iface_init)) + +static void process_events (MetaSeatImpl *seat_impl); +void meta_seat_impl_constrain_pointer (MetaSeatImpl *seat_impl, + ClutterInputDevice *core_pointer, + uint64_t time_us, + float x, + float y, + float *new_x, + float *new_y); +void meta_seat_impl_filter_relative_motion (MetaSeatImpl *seat_impl, + ClutterInputDevice *device, + float x, + float y, + float *dx, + float *dy); +void meta_seat_impl_clear_repeat_source (MetaSeatImpl *seat_impl); + +void +meta_seat_impl_run_input_task (MetaSeatImpl *seat_impl, + GTask *task, + GSourceFunc dispatch_func) +{ + GSource *source; + + source = g_idle_source_new (); + g_source_set_priority (source, G_PRIORITY_HIGH); + g_source_set_callback (source, + dispatch_func, + g_object_ref (task), + g_object_unref); + g_source_attach (source, seat_impl->input_context); + g_source_unref (source); +} + +void +meta_seat_impl_sync_leds_in_impl (MetaSeatImpl *seat_impl) +{ + GSList *iter; + MetaInputDeviceNative *device_native; + int caps_lock, num_lock, scroll_lock; + enum libinput_led leds = 0; + + caps_lock = xkb_state_led_index_is_active (seat_impl->xkb, + seat_impl->caps_lock_led); + num_lock = xkb_state_led_index_is_active (seat_impl->xkb, + seat_impl->num_lock_led); + scroll_lock = xkb_state_led_index_is_active (seat_impl->xkb, + seat_impl->scroll_lock_led); + + if (caps_lock) + leds |= LIBINPUT_LED_CAPS_LOCK; + if (num_lock) + leds |= LIBINPUT_LED_NUM_LOCK; + if (scroll_lock) + leds |= LIBINPUT_LED_SCROLL_LOCK; + + for (iter = seat_impl->devices; iter; iter = iter->next) + { + device_native = iter->data; + meta_input_device_native_update_leds_in_impl (device_native, leds); + } +} + +MetaTouchState * +meta_seat_impl_lookup_touch_state_in_impl (MetaSeatImpl *seat_impl, + int seat_slot) +{ + if (!seat_impl->touch_states) + return NULL; + + return g_hash_table_lookup (seat_impl->touch_states, + GINT_TO_POINTER (seat_slot)); +} + +static void +meta_touch_state_free (MetaTouchState *state) +{ + g_slice_free (MetaTouchState, state); +} + +MetaTouchState * +meta_seat_impl_acquire_touch_state_in_impl (MetaSeatImpl *seat_impl, + int seat_slot) +{ + MetaTouchState *touch_state; + + if (!seat_impl->touch_states) + { + seat_impl->touch_states = + g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) meta_touch_state_free); + } + + g_assert (!g_hash_table_contains (seat_impl->touch_states, + GINT_TO_POINTER (seat_slot))); + + touch_state = g_slice_new0 (MetaTouchState); + *touch_state = (MetaTouchState) { + .seat_impl = seat_impl, + .seat_slot = seat_slot, + }; + + g_hash_table_insert (seat_impl->touch_states, GINT_TO_POINTER (seat_slot), + touch_state); + + return touch_state; +} + +void +meta_seat_impl_release_touch_state_in_impl (MetaSeatImpl *seat_impl, + int seat_slot) +{ + if (!seat_impl->touch_states) + return; + g_hash_table_remove (seat_impl->touch_states, GINT_TO_POINTER (seat_slot)); +} + +void +meta_seat_impl_clear_repeat_source (MetaSeatImpl *seat_impl) +{ + if (seat_impl->repeat_source) + { + g_source_destroy (seat_impl->repeat_source); + g_clear_object (&seat_impl->repeat_device); + } +} + +static void +dispatch_libinput (MetaSeatImpl *seat_impl) +{ + libinput_dispatch (seat_impl->libinput); + process_events (seat_impl); +} + +static gboolean +keyboard_repeat (gpointer data) +{ + MetaSeatImpl *seat_impl = data; + + /* There might be events queued in libinput that could cancel the + repeat timer. */ + dispatch_libinput (seat_impl); + if (!seat_impl->repeat_source) + return G_SOURCE_REMOVE; + + g_return_val_if_fail (seat_impl->repeat_device != NULL, G_SOURCE_REMOVE); + + meta_seat_impl_notify_key_in_impl (seat_impl, + seat_impl->repeat_device, + g_source_get_time (seat_impl->repeat_source), + seat_impl->repeat_key, + AUTOREPEAT_VALUE, + FALSE); + + return G_SOURCE_CONTINUE; +} + +static void +queue_event (MetaSeatImpl *seat_impl, + ClutterEvent *event) +{ + _clutter_event_push (event, FALSE); +} + +static int +update_button_count (MetaSeatImpl *seat_impl, + uint32_t button, + uint32_t state) +{ + if (state) + { + return ++seat_impl->button_count[button]; + } + else + { + /* Handle cases where we newer saw the initial pressed event. */ + if (seat_impl->button_count[button] == 0) + { + meta_topic (META_DEBUG_INPUT, + "Counting release of key 0x%x and count is already 0", + button); + return 0; + } + + return --seat_impl->button_count[button]; + } +} + +typedef struct +{ + MetaSeatImpl *seat_impl; + guint signal_id; + GArray *args; +} MetaSeatSignalData; + +static gboolean +emit_signal_in_main (MetaSeatSignalData *data) +{ + g_signal_emitv ((GValue *) data->args->data, + data->signal_id, + 0, NULL); + + return G_SOURCE_REMOVE; +} + +static void +signal_data_free (MetaSeatSignalData *data) +{ + g_array_unref (data->args); + g_free (data); +} + +static void +emit_signal (MetaSeatImpl *seat_impl, + guint signal_id, + GValue *args, + int n_args) +{ + MetaSeatSignalData *emit_signal_data; + GSource *source; + GArray *array; + GValue self = G_VALUE_INIT; + + g_value_init (&self, META_TYPE_SEAT_IMPL); + g_value_set_object (&self, seat_impl); + + array = g_array_new (FALSE, FALSE, sizeof (GValue)); + g_array_append_val (array, self); + if (args && n_args > 0) + g_array_append_vals (array, args, n_args); + + emit_signal_data = g_new0 (MetaSeatSignalData, 1); + emit_signal_data->seat_impl = seat_impl; + emit_signal_data->signal_id = signal_id; + emit_signal_data->args = array; + + source = g_idle_source_new (); + g_source_set_priority (source, G_PRIORITY_HIGH); + g_source_set_callback (source, + (GSourceFunc) emit_signal_in_main, + emit_signal_data, + (GDestroyNotify) signal_data_free); + + g_source_attach (source, seat_impl->main_context); + g_source_unref (source); +} + +void +meta_seat_impl_notify_key_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *device, + uint64_t time_us, + uint32_t key, + uint32_t state, + gboolean update_keys) +{ + ClutterEvent *event = NULL; + enum xkb_state_component changed_state; + uint32_t keycode; + + if (state != AUTOREPEAT_VALUE) + { + /* Drop any repeated button press (for example from virtual devices. */ + int count = update_button_count (seat_impl, key, state); + if ((state && count > 1) || + (!state && count != 0)) + { + meta_topic (META_DEBUG_INPUT, + "Dropping repeated %s of key 0x%x, count %d, state %d", + state ? "press" : "release", key, count, state); + return; + } + } + + event = meta_key_event_new_from_evdev (device, + seat_impl->core_keyboard, + seat_impl->xkb, + seat_impl->button_state, + us2ms (time_us), key, state); + meta_event_native_set_event_code (event, key); + + keycode = meta_xkb_evdev_to_keycode (key); + + /* We must be careful and not pass multiple releases to xkb, otherwise it gets + confused and locks the modifiers */ + if (state != AUTOREPEAT_VALUE) + { + changed_state = xkb_state_update_key (seat_impl->xkb, keycode, + state ? XKB_KEY_DOWN : XKB_KEY_UP); + } + else + { + changed_state = 0; + clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_REPEATED); + } + + if (!meta_input_device_native_process_kbd_a11y_event_in_impl (seat_impl->core_keyboard, + event)) + queue_event (seat_impl, event); + else + clutter_event_free (event); + + if (update_keys && (changed_state & XKB_STATE_LEDS)) + { + MetaInputDeviceNative *keyboard_native; + gboolean numlock_active; + + emit_signal (seat_impl, signals[MODS_STATE_CHANGED], NULL, 0); + meta_seat_impl_sync_leds_in_impl (seat_impl); + + numlock_active = + xkb_state_mod_name_is_active (seat_impl->xkb, XKB_MOD_NAME_NUM, + XKB_STATE_MODS_LATCHED | + XKB_STATE_MODS_LOCKED); + meta_input_settings_maybe_save_numlock_state (seat_impl->input_settings, + numlock_active); + + keyboard_native = META_INPUT_DEVICE_NATIVE (seat_impl->core_keyboard); + meta_input_device_native_a11y_maybe_notify_toggle_keys_in_impl (keyboard_native); + } + + if (state == 0 || /* key release */ + !seat_impl->repeat || + !xkb_keymap_key_repeats (xkb_state_get_keymap (seat_impl->xkb), + keycode)) + { + seat_impl->repeat_count = 0; + meta_seat_impl_clear_repeat_source (seat_impl); + return; + } + + if (state == 1) /* key press */ + seat_impl->repeat_count = 0; + + seat_impl->repeat_count += 1; + seat_impl->repeat_key = key; + + switch (seat_impl->repeat_count) + { + case 1: + case 2: + { + uint32_t interval; + + meta_seat_impl_clear_repeat_source (seat_impl); + seat_impl->repeat_device = g_object_ref (device); + + if (seat_impl->repeat_count == 1) + interval = seat_impl->repeat_delay; + else + interval = seat_impl->repeat_interval; + + seat_impl->repeat_source = g_timeout_source_new (interval); + g_source_set_priority (seat_impl->repeat_source, CLUTTER_PRIORITY_EVENTS); + g_source_set_callback (seat_impl->repeat_source, + keyboard_repeat, seat_impl, NULL); + g_source_attach (seat_impl->repeat_source, seat_impl->input_context); + return; + } + default: + return; + } +} + +static ClutterEvent * +new_absolute_motion_event (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + float x, + float y, + double *axes) +{ + ClutterEvent *event; + + event = clutter_event_new (CLUTTER_MOTION); + + if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE) + { + meta_seat_impl_constrain_pointer (seat_impl, + seat_impl->core_pointer, + time_us, + seat_impl->pointer_x, + seat_impl->pointer_y, + &x, &y); + } + + meta_event_native_set_time_usec (event, time_us); + event->motion.time = us2ms (time_us); + meta_xkb_translate_state (event, seat_impl->xkb, seat_impl->button_state); + event->motion.x = x; + event->motion.y = y; + + /* This may happen early at startup */ + if (seat_impl->viewports) + { + meta_input_device_native_translate_coordinates_in_impl (input_device, + seat_impl->viewports, + &event->motion.x, + &event->motion.y); + } + + event->motion.axes = axes; + clutter_event_set_device (event, seat_impl->core_pointer); + clutter_event_set_source_device (event, input_device); + + g_rw_lock_writer_lock (&seat_impl->state_lock); + + if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) + { + MetaInputDeviceNative *device_native = + META_INPUT_DEVICE_NATIVE (input_device); + + clutter_event_set_device_tool (event, device_native->last_tool); + clutter_event_set_device (event, input_device); + meta_input_device_native_set_coords_in_impl (META_INPUT_DEVICE_NATIVE (input_device), + x, y); + } + else + { + clutter_event_set_device (event, seat_impl->core_pointer); + meta_input_device_native_set_coords_in_impl (META_INPUT_DEVICE_NATIVE (seat_impl->core_pointer), + x, y); + } + + if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE) + { + seat_impl->pointer_x = x; + seat_impl->pointer_y = y; + } + + g_rw_lock_writer_unlock (&seat_impl->state_lock); + + return event; +} + +void +meta_seat_impl_notify_relative_motion_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + float dx, + float dy, + float dx_unaccel, + float dy_unaccel) +{ + float new_x, new_y; + ClutterEvent *event; + + meta_seat_impl_filter_relative_motion (seat_impl, + input_device, + seat_impl->pointer_x, + seat_impl->pointer_y, + &dx, + &dy); + + new_x = seat_impl->pointer_x + dx; + new_y = seat_impl->pointer_y + dy; + event = new_absolute_motion_event (seat_impl, input_device, + time_us, new_x, new_y, NULL); + + meta_event_native_set_relative_motion (event, + dx, dy, + dx_unaccel, dy_unaccel); + + queue_event (seat_impl, event); +} + +void +meta_seat_impl_notify_absolute_motion_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + float x, + float y, + double *axes) +{ + ClutterEvent *event; + + event = new_absolute_motion_event (seat_impl, input_device, time_us, x, y, axes); + + queue_event (seat_impl, event); +} + +void +meta_seat_impl_notify_button_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + uint32_t button, + uint32_t state) +{ + MetaInputDeviceNative *device_native = (MetaInputDeviceNative *) input_device; + ClutterEvent *event = NULL; + int button_nr; + static int maskmap[8] = + { + CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON3_MASK, CLUTTER_BUTTON2_MASK, + CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK, 0, 0, 0 + }; + int button_count; + + /* Drop any repeated button press (for example from virtual devices. */ + button_count = update_button_count (seat_impl, button, state); + if ((state && button_count > 1) || + (!state && button_count != 0)) + { + meta_topic (META_DEBUG_INPUT, + "Dropping repeated %s of button 0x%x, count %d", + state ? "press" : "release", button, button_count); + return; + } + + /* The evdev button numbers don't map sequentially to clutter button + * numbers (the right and middle mouse buttons are in the opposite + * order) so we'll map them directly with a switch statement */ + switch (button) + { + case BTN_LEFT: + case BTN_TOUCH: + button_nr = CLUTTER_BUTTON_PRIMARY; + break; + + case BTN_RIGHT: + case BTN_STYLUS: + button_nr = CLUTTER_BUTTON_SECONDARY; + break; + + case BTN_MIDDLE: + case BTN_STYLUS2: + button_nr = CLUTTER_BUTTON_MIDDLE; + break; + + case 0x149: /* BTN_STYLUS3 */ + button_nr = 8; + break; + + default: + /* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */ + if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) + button_nr = button - BTN_TOOL_PEN + 4; + else + button_nr = button - (BTN_LEFT - 1) + 4; + break; + } + + if (button_nr < 1 || button_nr > 12) + { + g_warning ("Unhandled button event 0x%x", button); + return; + } + + if (state) + event = clutter_event_new (CLUTTER_BUTTON_PRESS); + else + event = clutter_event_new (CLUTTER_BUTTON_RELEASE); + + if (button_nr < G_N_ELEMENTS (maskmap)) + { + /* Update the modifiers */ + if (state) + seat_impl->button_state |= maskmap[button_nr - 1]; + else + seat_impl->button_state &= ~maskmap[button_nr - 1]; + } + + meta_event_native_set_time_usec (event, time_us); + event->button.time = us2ms (time_us); + meta_xkb_translate_state (event, seat_impl->xkb, seat_impl->button_state); + event->button.button = button_nr; + + if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) + { + meta_input_device_native_get_coords_in_impl (device_native, + &event->button.x, + &event->button.y); + } + else + { + meta_input_device_native_get_coords_in_impl (META_INPUT_DEVICE_NATIVE (seat_impl->core_pointer), + &event->button.x, + &event->button.y); + } + + clutter_event_set_device (event, seat_impl->core_pointer); + clutter_event_set_source_device (event, input_device); + + if (device_native->last_tool) + { + /* Apply the button event code as per the tool mapping */ + uint32_t mapped_button; + + mapped_button = meta_input_device_tool_native_get_button_code_in_impl (device_native->last_tool, + button_nr); + if (mapped_button != 0) + button = mapped_button; + } + + meta_event_native_set_event_code (event, button); + + if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) + { + clutter_event_set_device_tool (event, device_native->last_tool); + clutter_event_set_device (event, input_device); + } + else + { + clutter_event_set_device (event, seat_impl->core_pointer); + } + + queue_event (seat_impl, event); +} + +static MetaSeatImpl * +seat_impl_from_device (ClutterInputDevice *device) +{ + MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device); + + return meta_input_device_native_get_seat_impl (device_native); +} + +static void +notify_scroll (ClutterInputDevice *input_device, + uint64_t time_us, + double dx, + double dy, + ClutterScrollSource scroll_source, + ClutterScrollFinishFlags flags, + gboolean emulated) +{ + MetaSeatImpl *seat_impl; + ClutterEvent *event = NULL; + double scroll_factor; + + seat_impl = seat_impl_from_device (input_device); + + event = clutter_event_new (CLUTTER_SCROLL); + + meta_event_native_set_time_usec (event, time_us); + event->scroll.time = us2ms (time_us); + meta_xkb_translate_state (event, seat_impl->xkb, seat_impl->button_state); + + /* libinput pointer axis events are in pointer motion coordinate space. + * To convert to Xi2 discrete step coordinate space, multiply the factor + * 1/10. */ + event->scroll.direction = CLUTTER_SCROLL_SMOOTH; + scroll_factor = 1.0 / DISCRETE_SCROLL_STEP; + clutter_event_set_scroll_delta (event, + scroll_factor * dx, + scroll_factor * dy); + + event->scroll.x = seat_impl->pointer_x; + event->scroll.y = seat_impl->pointer_y; + clutter_event_set_device (event, seat_impl->core_pointer); + clutter_event_set_source_device (event, input_device); + event->scroll.scroll_source = scroll_source; + event->scroll.finish_flags = flags; + + _clutter_event_set_pointer_emulated (event, emulated); + + queue_event (seat_impl, event); +} + +static void +notify_discrete_scroll (ClutterInputDevice *input_device, + uint64_t time_us, + ClutterScrollDirection direction, + ClutterScrollSource scroll_source, + gboolean emulated) +{ + MetaSeatImpl *seat_impl; + ClutterEvent *event = NULL; + + if (direction == CLUTTER_SCROLL_SMOOTH) + return; + + seat_impl = seat_impl_from_device (input_device); + + event = clutter_event_new (CLUTTER_SCROLL); + + meta_event_native_set_time_usec (event, time_us); + event->scroll.time = us2ms (time_us); + meta_xkb_translate_state (event, seat_impl->xkb, seat_impl->button_state); + + event->scroll.direction = direction; + + event->scroll.x = seat_impl->pointer_x; + event->scroll.y = seat_impl->pointer_y; + clutter_event_set_device (event, seat_impl->core_pointer); + clutter_event_set_source_device (event, input_device); + event->scroll.scroll_source = scroll_source; + + _clutter_event_set_pointer_emulated (event, emulated); + + queue_event (seat_impl, event); +} + +static void +check_notify_discrete_scroll (MetaSeatImpl *seat_impl, + ClutterInputDevice *device, + uint64_t time_us, + ClutterScrollSource scroll_source) +{ + int i, n_xscrolls, n_yscrolls; + + n_xscrolls = floor (fabs (seat_impl->accum_scroll_dx) / DISCRETE_SCROLL_STEP); + n_yscrolls = floor (fabs (seat_impl->accum_scroll_dy) / DISCRETE_SCROLL_STEP); + + for (i = 0; i < n_xscrolls; i++) + { + notify_discrete_scroll (device, time_us, + seat_impl->accum_scroll_dx > 0 ? + CLUTTER_SCROLL_RIGHT : CLUTTER_SCROLL_LEFT, + scroll_source, TRUE); + } + + for (i = 0; i < n_yscrolls; i++) + { + notify_discrete_scroll (device, time_us, + seat_impl->accum_scroll_dy > 0 ? + CLUTTER_SCROLL_DOWN : CLUTTER_SCROLL_UP, + scroll_source, TRUE); + } + + seat_impl->accum_scroll_dx = + fmodf (seat_impl->accum_scroll_dx, DISCRETE_SCROLL_STEP); + seat_impl->accum_scroll_dy = + fmodf (seat_impl->accum_scroll_dy, DISCRETE_SCROLL_STEP); +} + +void +meta_seat_impl_notify_scroll_continuous_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + double dx, + double dy, + ClutterScrollSource scroll_source, + ClutterScrollFinishFlags finish_flags) +{ + if (finish_flags & CLUTTER_SCROLL_FINISHED_HORIZONTAL) + seat_impl->accum_scroll_dx = 0; + else + seat_impl->accum_scroll_dx += dx; + + if (finish_flags & CLUTTER_SCROLL_FINISHED_VERTICAL) + seat_impl->accum_scroll_dy = 0; + else + seat_impl->accum_scroll_dy += dy; + + notify_scroll (input_device, time_us, dx, dy, scroll_source, + finish_flags, FALSE); + check_notify_discrete_scroll (seat_impl, input_device, time_us, scroll_source); +} + +static ClutterScrollDirection +discrete_to_direction (double discrete_dx, + double discrete_dy) +{ + if (discrete_dx > 0) + return CLUTTER_SCROLL_RIGHT; + else if (discrete_dx < 0) + return CLUTTER_SCROLL_LEFT; + else if (discrete_dy > 0) + return CLUTTER_SCROLL_DOWN; + else if (discrete_dy < 0) + return CLUTTER_SCROLL_UP; + else + g_assert_not_reached (); + return 0; +} + +void +meta_seat_impl_notify_discrete_scroll_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + double discrete_dx, + double discrete_dy, + ClutterScrollSource scroll_source) +{ + notify_scroll (input_device, time_us, + discrete_dx * DISCRETE_SCROLL_STEP, + discrete_dy * DISCRETE_SCROLL_STEP, + scroll_source, CLUTTER_SCROLL_FINISHED_NONE, + TRUE); + notify_discrete_scroll (input_device, time_us, + discrete_to_direction (discrete_dx, discrete_dy), + scroll_source, FALSE); + +} + +void +meta_seat_impl_notify_touch_event_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + ClutterEventType evtype, + uint64_t time_us, + int slot, + double x, + double y) +{ + ClutterEvent *event = NULL; + + event = clutter_event_new (evtype); + + meta_event_native_set_time_usec (event, time_us); + event->touch.time = us2ms (time_us); + event->touch.x = x; + event->touch.y = y; + meta_input_device_native_translate_coordinates_in_impl (input_device, + seat_impl->viewports, + &event->touch.x, + &event->touch.y); + + /* "NULL" sequences are special cased in clutter */ + event->touch.sequence = GINT_TO_POINTER (MAX (1, slot + 1)); + meta_xkb_translate_state (event, seat_impl->xkb, seat_impl->button_state); + + if (evtype == CLUTTER_TOUCH_BEGIN || + evtype == CLUTTER_TOUCH_UPDATE) + event->touch.modifier_state |= CLUTTER_BUTTON1_MASK; + + clutter_event_set_device (event, seat_impl->core_pointer); + clutter_event_set_source_device (event, input_device); + + queue_event (seat_impl, event); +} + +/* + * MetaEventSource for reading input devices + */ +static gboolean +meta_event_check (GSource *source) +{ + MetaEventSource *event_source = (MetaEventSource *) source; + gboolean retval; + + retval = !!(event_source->event_poll_fd.revents & G_IO_IN); + + return retval; +} + +static void +constrain_to_barriers (MetaSeatImpl *seat_impl, + ClutterInputDevice *device, + uint32_t time, + float *new_x, + float *new_y) +{ + meta_barrier_manager_native_process_in_impl (seat_impl->barrier_manager, + device, + time, + new_x, new_y); +} + +/* + * The pointer constrain code is mostly a rip-off of the XRandR code from Xorg. + * (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder) + * + * Copyright © 2006 Keith Packard + * Copyright 2010 Red Hat, Inc + * + */ + +static void +constrain_all_screen_monitors (ClutterInputDevice *device, + MetaViewportInfo *viewports, + float *x, + float *y) +{ + float cx, cy; + int i, n_views; + + meta_input_device_native_get_coords_in_impl (META_INPUT_DEVICE_NATIVE (device), + &cx, &cy); + + /* if we're trying to escape, clamp to the CRTC we're coming from */ + + n_views = meta_viewport_info_get_num_views (viewports); + + for (i = 0; i < n_views; i++) + { + int left, right, top, bottom; + cairo_rectangle_int_t rect; + + meta_viewport_info_get_view_info (viewports, i, &rect, NULL); + + left = rect.x; + right = left + rect.width; + top = rect.y; + bottom = top + rect.height; + + if ((cx >= left) && (cx < right) && (cy >= top) && (cy < bottom)) + { + if (*x < left) + *x = left; + if (*x >= right) + *x = right - 1; + if (*y < top) + *y = top; + if (*y >= bottom) + *y = bottom - 1; + + return; + } + } +} + +void +meta_seat_impl_constrain_pointer (MetaSeatImpl *seat_impl, + ClutterInputDevice *core_pointer, + uint64_t time_us, + float x, + float y, + float *new_x, + float *new_y) +{ + /* Constrain to barriers */ + constrain_to_barriers (seat_impl, core_pointer, + us2ms (time_us), + new_x, new_y); + + /* Bar to constraints */ + if (seat_impl->pointer_constraint) + { + meta_pointer_constraint_impl_constrain (seat_impl->pointer_constraint, + core_pointer, + us2ms (time_us), + x, y, + new_x, new_y); + } + + if (seat_impl->viewports) + { + /* if we're moving inside a monitor, we're fine */ + if (meta_viewport_info_get_view_at (seat_impl->viewports, + *new_x, *new_y) >= 0) + return; + + /* if we're trying to escape, clamp to the CRTC we're coming from */ + constrain_all_screen_monitors (core_pointer, seat_impl->viewports, + new_x, new_y); + } +} + +static void +relative_motion_across_outputs (MetaViewportInfo *viewports, + int view, + float cur_x, + float cur_y, + float *dx_inout, + float *dy_inout) +{ + int cur_view = view; + float x = cur_x, y = cur_y; + float target_x = cur_x, target_y = cur_y; + float dx = *dx_inout, dy = *dy_inout; + MetaDisplayDirection direction = -1; + + while (cur_view >= 0) + { + MetaLine2 left, right, top, bottom, motion; + MetaVector2 intersection; + cairo_rectangle_int_t rect; + float scale; + + meta_viewport_info_get_view_info (viewports, cur_view, &rect, &scale); + + motion = (MetaLine2) { + .a = { x, y }, + .b = { x + (dx * scale), y + (dy * scale) } + }; + left = (MetaLine2) { + { rect.x, rect.y }, + { rect.x, rect.y + rect.height } + }; + right = (MetaLine2) { + { rect.x + rect.width, rect.y }, + { rect.x + rect.width, rect.y + rect.height } + }; + top = (MetaLine2) { + { rect.x, rect.y }, + { rect.x + rect.width, rect.y } + }; + bottom = (MetaLine2) { + { rect.x, rect.y + rect.height }, + { rect.x + rect.width, rect.y + rect.height } + }; + + target_x = motion.b.x; + target_y = motion.b.y; + + if (direction != META_DISPLAY_RIGHT && + meta_line2_intersects_with (&motion, &left, &intersection)) + direction = META_DISPLAY_LEFT; + else if (direction != META_DISPLAY_LEFT && + meta_line2_intersects_with (&motion, &right, &intersection)) + direction = META_DISPLAY_RIGHT; + else if (direction != META_DISPLAY_DOWN && + meta_line2_intersects_with (&motion, &top, &intersection)) + direction = META_DISPLAY_UP; + else if (direction != META_DISPLAY_UP && + meta_line2_intersects_with (&motion, &bottom, &intersection)) + direction = META_DISPLAY_DOWN; + else + /* We reached the dest logical monitor */ + break; + + x = intersection.x; + y = intersection.y; + dx -= intersection.x - motion.a.x; + dy -= intersection.y - motion.a.y; + + cur_view = meta_viewport_info_get_neighbor (viewports, cur_view, + direction); + } + + *dx_inout = target_x - cur_x; + *dy_inout = target_y - cur_y; +} + +void +meta_seat_impl_filter_relative_motion (MetaSeatImpl *seat_impl, + ClutterInputDevice *device, + float x, + float y, + float *dx, + float *dy) +{ + int view = -1, dest_view; + float new_dx, new_dy, scale; + + if (meta_is_stage_views_scaled ()) + return; + + if (seat_impl->viewports) + view = meta_viewport_info_get_view_at (seat_impl->viewports, x, y); + if (view < 0) + return; + + meta_viewport_info_get_view_info (seat_impl->viewports, view, NULL, &scale); + new_dx = (*dx) * scale; + new_dy = (*dy) * scale; + + dest_view = meta_viewport_info_get_view_at (seat_impl->viewports, + x + new_dx, + y + new_dy); + if (dest_view >= 0 && dest_view != view) + { + /* If we are crossing monitors, attempt to bisect the distance on each + * axis and apply the relative scale for each of them. + */ + new_dx = *dx; + new_dy = *dy; + relative_motion_across_outputs (seat_impl->viewports, view, + x, y, &new_dx, &new_dy); + } + + *dx = new_dx; + *dy = new_dy; +} + +static void +notify_absolute_motion_in_impl (ClutterInputDevice *input_device, + uint64_t time_us, + float x, + float y, + double *axes) +{ + MetaSeatImpl *seat_impl; + ClutterEvent *event; + + seat_impl = seat_impl_from_device (input_device); + event = new_absolute_motion_event (seat_impl, input_device, time_us, x, y, axes); + + queue_event (seat_impl, event); +} + +static void +notify_relative_tool_motion_in_impl (ClutterInputDevice *input_device, + uint64_t time_us, + float dx, + float dy, + double *axes) +{ + MetaInputDeviceNative *device_native; + ClutterEvent *event; + MetaSeatImpl *seat_impl; + float x, y; + + device_native = META_INPUT_DEVICE_NATIVE (input_device); + seat_impl = seat_impl_from_device (input_device); + x = device_native->pointer_x + dx; + y = device_native->pointer_y + dy; + + meta_seat_impl_filter_relative_motion (seat_impl, + input_device, + seat_impl->pointer_x, + seat_impl->pointer_y, + &dx, + &dy); + + event = new_absolute_motion_event (seat_impl, input_device, time_us, + x, y, axes); + meta_event_native_set_relative_motion (event, dx, dy, 0, 0); + + queue_event (seat_impl, event); +} + +static void +notify_pinch_gesture_event (ClutterInputDevice *input_device, + ClutterTouchpadGesturePhase phase, + uint64_t time_us, + double dx, + double dy, + double angle_delta, + double scale, + uint32_t n_fingers) +{ + MetaSeatImpl *seat_impl; + ClutterEvent *event = NULL; + + seat_impl = seat_impl_from_device (input_device); + + event = clutter_event_new (CLUTTER_TOUCHPAD_PINCH); + + meta_input_device_native_get_coords_in_impl (META_INPUT_DEVICE_NATIVE (seat_impl->core_pointer), + &event->touchpad_pinch.x, + &event->touchpad_pinch.y); + + meta_event_native_set_time_usec (event, time_us); + event->touchpad_pinch.phase = phase; + event->touchpad_pinch.time = us2ms (time_us); + event->touchpad_pinch.dx = dx; + event->touchpad_pinch.dy = dy; + event->touchpad_pinch.angle_delta = angle_delta; + event->touchpad_pinch.scale = scale; + event->touchpad_pinch.n_fingers = n_fingers; + + meta_xkb_translate_state (event, seat_impl->xkb, seat_impl->button_state); + + clutter_event_set_device (event, seat_impl->core_pointer); + clutter_event_set_source_device (event, input_device); + + queue_event (seat_impl, event); +} + +static void +notify_swipe_gesture_event (ClutterInputDevice *input_device, + ClutterTouchpadGesturePhase phase, + uint64_t time_us, + uint32_t n_fingers, + double dx, + double dy) +{ + MetaSeatImpl *seat_impl; + ClutterEvent *event = NULL; + + seat_impl = seat_impl_from_device (input_device); + + event = clutter_event_new (CLUTTER_TOUCHPAD_SWIPE); + + meta_event_native_set_time_usec (event, time_us); + event->touchpad_swipe.phase = phase; + event->touchpad_swipe.time = us2ms (time_us); + + meta_input_device_native_get_coords_in_impl (META_INPUT_DEVICE_NATIVE (seat_impl->core_pointer), + &event->touchpad_swipe.x, + &event->touchpad_swipe.y); + event->touchpad_swipe.dx = dx; + event->touchpad_swipe.dy = dy; + event->touchpad_swipe.n_fingers = n_fingers; + + meta_xkb_translate_state (event, seat_impl->xkb, seat_impl->button_state); + + clutter_event_set_device (event, seat_impl->core_pointer); + clutter_event_set_source_device (event, input_device); + + queue_event (seat_impl, event); +} + +static void +notify_proximity (ClutterInputDevice *input_device, + uint64_t time_us, + gboolean in) +{ + MetaInputDeviceNative *device_native; + MetaSeatImpl *seat_impl; + ClutterEvent *event = NULL; + + device_native = META_INPUT_DEVICE_NATIVE (input_device); + seat_impl = seat_impl_from_device (input_device); + + if (in) + event = clutter_event_new (CLUTTER_PROXIMITY_IN); + else + event = clutter_event_new (CLUTTER_PROXIMITY_OUT); + + meta_event_native_set_time_usec (event, time_us); + + event->proximity.time = us2ms (time_us); + clutter_event_set_device_tool (event, device_native->last_tool); + clutter_event_set_device (event, seat_impl->core_pointer); + clutter_event_set_source_device (event, input_device); + + queue_event (seat_impl, event); +} + +static void +notify_pad_button (ClutterInputDevice *input_device, + uint64_t time_us, + uint32_t button, + uint32_t mode_group, + uint32_t mode, + uint32_t pressed) +{ + MetaSeatImpl *seat_impl; + ClutterEvent *event; + + seat_impl = seat_impl_from_device (input_device); + + if (pressed) + event = clutter_event_new (CLUTTER_PAD_BUTTON_PRESS); + else + event = clutter_event_new (CLUTTER_PAD_BUTTON_RELEASE); + + meta_event_native_set_time_usec (event, time_us); + event->pad_button.button = button; + event->pad_button.group = mode_group; + event->pad_button.mode = mode; + clutter_event_set_device (event, input_device); + clutter_event_set_source_device (event, input_device); + clutter_event_set_time (event, us2ms (time_us)); + + queue_event (seat_impl, event); +} + +static void +notify_pad_strip (ClutterInputDevice *input_device, + uint64_t time_us, + uint32_t strip_number, + uint32_t strip_source, + uint32_t mode_group, + uint32_t mode, + double value) +{ + ClutterInputDevicePadSource source; + MetaSeatImpl *seat_impl; + ClutterEvent *event; + + seat_impl = seat_impl_from_device (input_device); + + if (strip_source == LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER) + source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER; + else + source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_UNKNOWN; + + event = clutter_event_new (CLUTTER_PAD_STRIP); + meta_event_native_set_time_usec (event, time_us); + event->pad_strip.strip_source = source; + event->pad_strip.strip_number = strip_number; + event->pad_strip.value = value; + event->pad_strip.group = mode_group; + event->pad_strip.mode = mode; + clutter_event_set_device (event, input_device); + clutter_event_set_source_device (event, input_device); + clutter_event_set_time (event, us2ms (time_us)); + + queue_event (seat_impl, event); +} + +static void +notify_pad_ring (ClutterInputDevice *input_device, + uint64_t time_us, + uint32_t ring_number, + uint32_t ring_source, + uint32_t mode_group, + uint32_t mode, + double angle) +{ + ClutterInputDevicePadSource source; + MetaSeatImpl *seat_impl; + ClutterEvent *event; + + seat_impl = seat_impl_from_device (input_device); + + if (ring_source == LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER) + source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER; + else + source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_UNKNOWN; + + event = clutter_event_new (CLUTTER_PAD_RING); + meta_event_native_set_time_usec (event, time_us); + event->pad_ring.ring_source = source; + event->pad_ring.ring_number = ring_number; + event->pad_ring.angle = angle; + event->pad_ring.group = mode_group; + event->pad_ring.mode = mode; + clutter_event_set_device (event, input_device); + clutter_event_set_source_device (event, input_device); + clutter_event_set_time (event, us2ms (time_us)); + + queue_event (seat_impl, event); +} + +static gboolean +meta_event_dispatch (GSource *g_source, + GSourceFunc callback, + gpointer user_data) +{ + MetaEventSource *source = (MetaEventSource *) g_source; + MetaSeatImpl *seat_impl; + + seat_impl = source->seat_impl; + + dispatch_libinput (seat_impl); + + return TRUE; +} + +static GSourceFuncs event_funcs = { + NULL, + meta_event_check, + meta_event_dispatch, + NULL +}; + +static MetaEventSource * +meta_event_source_new (MetaSeatImpl *seat_impl) +{ + GSource *source; + MetaEventSource *event_source; + int fd; + + source = g_source_new (&event_funcs, sizeof (MetaEventSource)); + event_source = (MetaEventSource *) source; + + /* setup the source */ + event_source->seat_impl = seat_impl; + + fd = libinput_get_fd (seat_impl->libinput); + event_source->event_poll_fd.fd = fd; + event_source->event_poll_fd.events = G_IO_IN; + + /* and finally configure and attach the GSource */ + g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS); + g_source_add_poll (source, &event_source->event_poll_fd); + g_source_set_can_recurse (source, TRUE); + g_source_attach (source, seat_impl->input_context); + + return event_source; +} + +static void +meta_event_source_free (MetaEventSource *source) +{ + GSource *g_source = (GSource *) source; + + /* ignore the return value of close, it's not like we can do something + * about it */ + close (source->event_poll_fd.fd); + + g_source_destroy (g_source); + g_source_unref (g_source); +} + +static gboolean +has_touchscreen (MetaSeatImpl *seat_impl) +{ + GSList *l; + + for (l = seat_impl->devices; l; l = l->next) + { + ClutterInputDeviceType device_type; + + device_type = clutter_input_device_get_device_type (l->data); + + if (device_type == CLUTTER_TOUCHSCREEN_DEVICE) + return TRUE; + } + + return FALSE; +} + +static gboolean +device_is_tablet_switch (MetaInputDeviceNative *device_native) +{ + if (libinput_device_has_capability (device_native->libinput_device, + LIBINPUT_DEVICE_CAP_SWITCH) && + libinput_device_switch_has_switch (device_native->libinput_device, + LIBINPUT_SWITCH_TABLET_MODE)) + return TRUE; + + return FALSE; +} + +static gboolean +has_tablet_switch (MetaSeatImpl *seat_impl) +{ + GSList *l; + + for (l = seat_impl->devices; l; l = l->next) + { + MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (l->data); + + if (device_is_tablet_switch (device_native)) + return TRUE; + } + + return FALSE; +} + +static void +update_touch_mode (MetaSeatImpl *seat_impl) +{ + gboolean touch_mode; + + /* No touch mode if we don't have a touchscreen, easy */ + if (!seat_impl->has_touchscreen) + touch_mode = FALSE; + /* If we have a tablet mode switch, honor it being unset */ + else if (seat_impl->has_tablet_switch && !seat_impl->tablet_mode_switch_state) + touch_mode = FALSE; + /* If tablet mode is enabled, or if there is no tablet mode switch + * (eg. kiosk machines), assume touch-mode. + */ + else + touch_mode = TRUE; + + if (seat_impl->touch_mode != touch_mode) + { + GValue value = G_VALUE_INIT; + + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, touch_mode); + seat_impl->touch_mode = touch_mode; + emit_signal (seat_impl, signals[TOUCH_MODE], &value, 1); + g_value_unset (&value); + } +} + +static ClutterInputDevice * +evdev_add_device (MetaSeatImpl *seat_impl, + struct libinput_device *libinput_device) +{ + ClutterInputDeviceType type; + ClutterInputDevice *device; + gboolean is_touchscreen, is_tablet_switch; + + device = meta_input_device_native_new_in_impl (seat_impl, libinput_device); + + seat_impl->devices = g_slist_prepend (seat_impl->devices, device); + + /* Clutter assumes that device types are exclusive in the + * ClutterInputDevice API */ + type = meta_input_device_native_determine_type_in_impl (libinput_device); + + is_touchscreen = type == CLUTTER_TOUCHSCREEN_DEVICE; + is_tablet_switch = + device_is_tablet_switch (META_INPUT_DEVICE_NATIVE (device)); + + seat_impl->has_touchscreen |= is_touchscreen; + seat_impl->has_tablet_switch |= is_tablet_switch; + + if (is_touchscreen || is_tablet_switch) + update_touch_mode (seat_impl); + + return device; +} + +static void +evdev_remove_device (MetaSeatImpl *seat_impl, + MetaInputDeviceNative *device_native) +{ + ClutterInputDevice *device; + ClutterInputDeviceType device_type; + gboolean is_touchscreen, is_tablet_switch; + + device = CLUTTER_INPUT_DEVICE (device_native); + seat_impl->devices = g_slist_remove (seat_impl->devices, device); + + device_type = clutter_input_device_get_device_type (device); + + is_touchscreen = device_type == CLUTTER_TOUCHSCREEN_DEVICE; + is_tablet_switch = device_is_tablet_switch (device_native); + + if (is_touchscreen) + seat_impl->has_touchscreen = has_touchscreen (seat_impl); + if (is_tablet_switch) + seat_impl->has_tablet_switch = has_tablet_switch (seat_impl); + + if (is_touchscreen || is_tablet_switch) + update_touch_mode (seat_impl); + + if (seat_impl->repeat_source && seat_impl->repeat_device == device) + meta_seat_impl_clear_repeat_source (seat_impl); + + g_object_unref (device); +} + +static gboolean +process_base_event (MetaSeatImpl *seat_impl, + struct libinput_event *event) +{ + ClutterInputDevice *device; + ClutterEvent *device_event = NULL; + struct libinput_device *libinput_device; + MetaInputSettings *input_settings; + + input_settings = seat_impl->input_settings; + + switch (libinput_event_get_type (event)) + { + case LIBINPUT_EVENT_DEVICE_ADDED: + libinput_device = libinput_event_get_device (event); + + device = evdev_add_device (seat_impl, libinput_device); + device_event = clutter_event_new (CLUTTER_DEVICE_ADDED); + clutter_event_set_device (device_event, device); + meta_input_settings_add_device (input_settings, device); + break; + + case LIBINPUT_EVENT_DEVICE_REMOVED: + libinput_device = libinput_event_get_device (event); + + device = libinput_device_get_user_data (libinput_device); + device_event = clutter_event_new (CLUTTER_DEVICE_REMOVED); + clutter_event_set_device (device_event, device); + evdev_remove_device (seat_impl, + META_INPUT_DEVICE_NATIVE (device)); + meta_input_settings_remove_device (input_settings, device); + break; + + default: + break; + } + + if (device_event) + { + queue_event (seat_impl, device_event); + return TRUE; + } + + return FALSE; +} + +static ClutterScrollSource +translate_scroll_source (enum libinput_pointer_axis_source source) +{ + switch (source) + { + case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: + return CLUTTER_SCROLL_SOURCE_WHEEL; + case LIBINPUT_POINTER_AXIS_SOURCE_FINGER: + return CLUTTER_SCROLL_SOURCE_FINGER; + case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: + return CLUTTER_SCROLL_SOURCE_CONTINUOUS; + default: + return CLUTTER_SCROLL_SOURCE_UNKNOWN; + } +} + +static ClutterInputDeviceToolType +translate_tool_type (struct libinput_tablet_tool *libinput_tool) +{ + enum libinput_tablet_tool_type tool; + + tool = libinput_tablet_tool_get_type (libinput_tool); + + switch (tool) + { + case LIBINPUT_TABLET_TOOL_TYPE_PEN: + return CLUTTER_INPUT_DEVICE_TOOL_PEN; + case LIBINPUT_TABLET_TOOL_TYPE_ERASER: + return CLUTTER_INPUT_DEVICE_TOOL_ERASER; + case LIBINPUT_TABLET_TOOL_TYPE_BRUSH: + return CLUTTER_INPUT_DEVICE_TOOL_BRUSH; + case LIBINPUT_TABLET_TOOL_TYPE_PENCIL: + return CLUTTER_INPUT_DEVICE_TOOL_PENCIL; + case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH: + return CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH; + case LIBINPUT_TABLET_TOOL_TYPE_MOUSE: + return CLUTTER_INPUT_DEVICE_TOOL_MOUSE; + case LIBINPUT_TABLET_TOOL_TYPE_LENS: + return CLUTTER_INPUT_DEVICE_TOOL_LENS; + default: + return CLUTTER_INPUT_DEVICE_TOOL_NONE; + } +} + +static void +input_device_update_tool (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + struct libinput_tablet_tool *libinput_tool) +{ + MetaInputDeviceNative *evdev_device = META_INPUT_DEVICE_NATIVE (input_device); + ClutterInputDeviceTool *tool = NULL; + MetaInputSettings *input_settings; + + if (libinput_tool) + { + if (!seat_impl->tools) + { + seat_impl->tools = + g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) g_object_unref); + } + + tool = g_hash_table_lookup (seat_impl->tools, libinput_tool); + + if (!tool) + { + ClutterInputDeviceToolType tool_type; + uint64_t tool_serial; + + tool_serial = libinput_tablet_tool_get_serial (libinput_tool); + tool_type = translate_tool_type (libinput_tool); + tool = meta_input_device_tool_native_new (libinput_tool, + tool_serial, tool_type); + g_hash_table_insert (seat_impl->tools, libinput_tool, tool); + } + } + + if (evdev_device->last_tool != tool) + { + evdev_device->last_tool = tool; + input_settings = seat_impl->input_settings; + meta_input_settings_notify_tool_change (input_settings, input_device, tool); + } +} + +static double * +translate_tablet_axes (struct libinput_event_tablet_tool *tablet_event, + ClutterInputDeviceTool *tool) +{ + double *axes = g_new0 (double, CLUTTER_INPUT_AXIS_LAST); + struct libinput_tablet_tool *libinput_tool; + double value; + + libinput_tool = libinput_event_tablet_tool_get_tool (tablet_event); + + value = libinput_event_tablet_tool_get_x (tablet_event); + axes[CLUTTER_INPUT_AXIS_X] = value; + value = libinput_event_tablet_tool_get_y (tablet_event); + axes[CLUTTER_INPUT_AXIS_Y] = value; + + if (libinput_tablet_tool_has_distance (libinput_tool)) + { + value = libinput_event_tablet_tool_get_distance (tablet_event); + axes[CLUTTER_INPUT_AXIS_DISTANCE] = value; + } + + if (libinput_tablet_tool_has_pressure (libinput_tool)) + { + value = libinput_event_tablet_tool_get_pressure (tablet_event); + value = meta_input_device_tool_native_translate_pressure_in_impl (tool, value); + axes[CLUTTER_INPUT_AXIS_PRESSURE] = value; + } + + if (libinput_tablet_tool_has_tilt (libinput_tool)) + { + value = libinput_event_tablet_tool_get_tilt_x (tablet_event); + axes[CLUTTER_INPUT_AXIS_XTILT] = value; + value = libinput_event_tablet_tool_get_tilt_y (tablet_event); + axes[CLUTTER_INPUT_AXIS_YTILT] = value; + } + + if (libinput_tablet_tool_has_rotation (libinput_tool)) + { + value = libinput_event_tablet_tool_get_rotation (tablet_event); + axes[CLUTTER_INPUT_AXIS_ROTATION] = value; + } + + if (libinput_tablet_tool_has_slider (libinput_tool)) + { + value = libinput_event_tablet_tool_get_slider_position (tablet_event); + axes[CLUTTER_INPUT_AXIS_SLIDER] = value; + } + + if (libinput_tablet_tool_has_wheel (libinput_tool)) + { + value = libinput_event_tablet_tool_get_wheel_delta (tablet_event); + axes[CLUTTER_INPUT_AXIS_WHEEL] = value; + } + + return axes; +} + +static void +notify_continuous_axis (MetaSeatImpl *seat_impl, + ClutterInputDevice *device, + uint64_t time_us, + ClutterScrollSource scroll_source, + struct libinput_event_pointer *axis_event) +{ + double dx = 0.0, dy = 0.0; + ClutterScrollFinishFlags finish_flags = CLUTTER_SCROLL_FINISHED_NONE; + + if (libinput_event_pointer_has_axis (axis_event, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) + { + dx = libinput_event_pointer_get_axis_value ( + axis_event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); + + if (fabs (dx) < DBL_EPSILON) + finish_flags |= CLUTTER_SCROLL_FINISHED_HORIZONTAL; + } + if (libinput_event_pointer_has_axis (axis_event, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) + { + dy = libinput_event_pointer_get_axis_value ( + axis_event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + + if (fabs (dy) < DBL_EPSILON) + finish_flags |= CLUTTER_SCROLL_FINISHED_VERTICAL; + } + + meta_seat_impl_notify_scroll_continuous_in_impl (seat_impl, device, time_us, + dx, dy, + scroll_source, finish_flags); +} + +static void +notify_discrete_axis (MetaSeatImpl *seat_impl, + ClutterInputDevice *device, + uint64_t time_us, + ClutterScrollSource scroll_source, + struct libinput_event_pointer *axis_event) +{ + double discrete_dx = 0.0, discrete_dy = 0.0; + + if (libinput_event_pointer_has_axis (axis_event, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) + { + discrete_dx = libinput_event_pointer_get_axis_value_discrete ( + axis_event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); + } + if (libinput_event_pointer_has_axis (axis_event, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) + { + discrete_dy = libinput_event_pointer_get_axis_value_discrete ( + axis_event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + } + + meta_seat_impl_notify_discrete_scroll_in_impl (seat_impl, device, + time_us, + discrete_dx, discrete_dy, + scroll_source); +} + +static void +process_tablet_axis (MetaSeatImpl *seat_impl, + struct libinput_event *event) +{ + struct libinput_device *libinput_device = libinput_event_get_device (event); + uint64_t time; + double x, y, dx, dy, *axes; + float stage_width, stage_height; + ClutterInputDevice *device; + struct libinput_event_tablet_tool *tablet_event = + libinput_event_get_tablet_tool_event (event); + MetaInputDeviceNative *evdev_device; + + device = libinput_device_get_user_data (libinput_device); + evdev_device = META_INPUT_DEVICE_NATIVE (device); + + axes = translate_tablet_axes (tablet_event, + evdev_device->last_tool); + + meta_viewport_info_get_extents (seat_impl->viewports, + &stage_width, &stage_height); + + time = libinput_event_tablet_tool_get_time_usec (tablet_event); + + if (meta_input_device_native_get_mapping_mode_in_impl (device) == META_INPUT_DEVICE_MAPPING_RELATIVE || + clutter_input_device_tool_get_tool_type (evdev_device->last_tool) == CLUTTER_INPUT_DEVICE_TOOL_MOUSE || + clutter_input_device_tool_get_tool_type (evdev_device->last_tool) == CLUTTER_INPUT_DEVICE_TOOL_LENS) + { + dx = libinput_event_tablet_tool_get_dx (tablet_event); + dy = libinput_event_tablet_tool_get_dy (tablet_event); + notify_relative_tool_motion_in_impl (device, time, dx, dy, axes); + } + else + { + x = libinput_event_tablet_tool_get_x_transformed (tablet_event, stage_width); + y = libinput_event_tablet_tool_get_y_transformed (tablet_event, stage_height); + notify_absolute_motion_in_impl (device, time, x, y, axes); + } +} + +static gboolean +process_device_event (MetaSeatImpl *seat_impl, + struct libinput_event *event) +{ + gboolean handled = TRUE; + struct libinput_device *libinput_device = libinput_event_get_device(event); + ClutterInputDevice *device; + MetaInputDeviceNative *device_native; + + switch (libinput_event_get_type (event)) + { + case LIBINPUT_EVENT_KEYBOARD_KEY: + { + uint32_t key, key_state, seat_key_count; + uint64_t time_us; + struct libinput_event_keyboard *key_event = + libinput_event_get_keyboard_event (event); + + device = libinput_device_get_user_data (libinput_device); + time_us = libinput_event_keyboard_get_time_usec (key_event); + key = libinput_event_keyboard_get_key (key_event); + key_state = libinput_event_keyboard_get_key_state (key_event) == + LIBINPUT_KEY_STATE_PRESSED; + seat_key_count = + libinput_event_keyboard_get_seat_key_count (key_event); + + /* Ignore key events that are not seat wide state changes. */ + if ((key_state == LIBINPUT_KEY_STATE_PRESSED && + seat_key_count != 1) || + (key_state == LIBINPUT_KEY_STATE_RELEASED && + seat_key_count != 0)) + { + meta_topic (META_DEBUG_INPUT, + "Dropping key-%s of key 0x%x because seat-wide " + "key count is %d", + key_state == LIBINPUT_KEY_STATE_PRESSED ? "press" : "release", + key, seat_key_count); + break; + } + + meta_seat_impl_notify_key_in_impl (seat_impl, + device, + time_us, key, key_state, TRUE); + + break; + } + + case LIBINPUT_EVENT_POINTER_MOTION: + { + struct libinput_event_pointer *pointer_event = + libinput_event_get_pointer_event (event); + uint64_t time_us; + double dx; + double dy; + double dx_unaccel; + double dy_unaccel; + + device = libinput_device_get_user_data (libinput_device); + time_us = libinput_event_pointer_get_time_usec (pointer_event); + dx = libinput_event_pointer_get_dx (pointer_event); + dy = libinput_event_pointer_get_dy (pointer_event); + dx_unaccel = libinput_event_pointer_get_dx_unaccelerated (pointer_event); + dy_unaccel = libinput_event_pointer_get_dy_unaccelerated (pointer_event); + + meta_seat_impl_notify_relative_motion_in_impl (seat_impl, + device, + time_us, + dx, dy, + dx_unaccel, dy_unaccel); + + break; + } + + case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: + { + uint64_t time_us; + double x, y; + float stage_width, stage_height; + struct libinput_event_pointer *motion_event = + libinput_event_get_pointer_event (event); + device = libinput_device_get_user_data (libinput_device); + + meta_viewport_info_get_extents (seat_impl->viewports, + &stage_width, &stage_height); + + time_us = libinput_event_pointer_get_time_usec (motion_event); + x = libinput_event_pointer_get_absolute_x_transformed (motion_event, + stage_width); + y = libinput_event_pointer_get_absolute_y_transformed (motion_event, + stage_height); + + meta_seat_impl_notify_absolute_motion_in_impl (seat_impl, + device, + time_us, + x, y, + NULL); + + break; + } + + case LIBINPUT_EVENT_POINTER_BUTTON: + { + uint32_t button, button_state, seat_button_count; + uint64_t time_us; + struct libinput_event_pointer *button_event = + libinput_event_get_pointer_event (event); + device = libinput_device_get_user_data (libinput_device); + + time_us = libinput_event_pointer_get_time_usec (button_event); + button = libinput_event_pointer_get_button (button_event); + button_state = libinput_event_pointer_get_button_state (button_event) == + LIBINPUT_BUTTON_STATE_PRESSED; + seat_button_count = + libinput_event_pointer_get_seat_button_count (button_event); + + /* Ignore button events that are not seat wide state changes. */ + if ((button_state == LIBINPUT_BUTTON_STATE_PRESSED && + seat_button_count != 1) || + (button_state == LIBINPUT_BUTTON_STATE_RELEASED && + seat_button_count != 0)) + { + meta_topic (META_DEBUG_INPUT, + "Dropping button-%s of button 0x%x because seat-wide " + "button count is %d", + button_state == LIBINPUT_BUTTON_STATE_PRESSED ? "press" : "release", + button, seat_button_count); + break; + } + + meta_seat_impl_notify_button_in_impl (seat_impl, device, + time_us, button, button_state); + break; + } + + case LIBINPUT_EVENT_POINTER_AXIS: + { + uint64_t time_us; + enum libinput_pointer_axis_source source; + struct libinput_event_pointer *axis_event = + libinput_event_get_pointer_event (event); + ClutterScrollSource scroll_source; + + device = libinput_device_get_user_data (libinput_device); + + time_us = libinput_event_pointer_get_time_usec (axis_event); + source = libinput_event_pointer_get_axis_source (axis_event); + scroll_source = translate_scroll_source (source); + + /* libinput < 0.8 sent wheel click events with value 10. Since 0.8 + the value is the angle of the click in degrees. To keep + backwards-compat with existing clients, we just send multiples of + the click count. */ + + switch (scroll_source) + { + case CLUTTER_SCROLL_SOURCE_WHEEL: + notify_discrete_axis (seat_impl, device, time_us, scroll_source, + axis_event); + break; + case CLUTTER_SCROLL_SOURCE_FINGER: + case CLUTTER_SCROLL_SOURCE_CONTINUOUS: + case CLUTTER_SCROLL_SOURCE_UNKNOWN: + notify_continuous_axis (seat_impl, device, time_us, scroll_source, + axis_event); + break; + } + break; + } + + case LIBINPUT_EVENT_TOUCH_DOWN: + { + int seat_slot; + uint64_t time_us; + double x, y; + float stage_width, stage_height; + MetaTouchState *touch_state; + struct libinput_event_touch *touch_event = + libinput_event_get_touch_event (event); + + device = libinput_device_get_user_data (libinput_device); + device_native = META_INPUT_DEVICE_NATIVE (device); + + meta_viewport_info_get_extents (seat_impl->viewports, + &stage_width, &stage_height); + + seat_slot = libinput_event_touch_get_seat_slot (touch_event); + time_us = libinput_event_touch_get_time_usec (touch_event); + x = libinput_event_touch_get_x_transformed (touch_event, + stage_width); + y = libinput_event_touch_get_y_transformed (touch_event, + stage_height); + + g_rw_lock_writer_lock (&seat_impl->state_lock); + + touch_state = meta_seat_impl_acquire_touch_state_in_impl (seat_impl, seat_slot); + touch_state->coords.x = x; + touch_state->coords.y = y; + + g_rw_lock_writer_unlock (&seat_impl->state_lock); + + meta_seat_impl_notify_touch_event_in_impl (seat_impl, device, + CLUTTER_TOUCH_BEGIN, + time_us, + touch_state->seat_slot, + touch_state->coords.x, + touch_state->coords.y); + break; + } + + case LIBINPUT_EVENT_TOUCH_UP: + { + int seat_slot; + uint64_t time_us; + MetaTouchState *touch_state; + struct libinput_event_touch *touch_event = + libinput_event_get_touch_event (event); + + device = libinput_device_get_user_data (libinput_device); + device_native = META_INPUT_DEVICE_NATIVE (device); + + seat_slot = libinput_event_touch_get_seat_slot (touch_event); + time_us = libinput_event_touch_get_time_usec (touch_event); + touch_state = meta_seat_impl_lookup_touch_state_in_impl (seat_impl, seat_slot); + if (!touch_state) + break; + + meta_seat_impl_notify_touch_event_in_impl (seat_impl, device, + CLUTTER_TOUCH_END, time_us, + touch_state->seat_slot, + touch_state->coords.x, + touch_state->coords.y); + + g_rw_lock_writer_lock (&seat_impl->state_lock); + meta_seat_impl_release_touch_state_in_impl (seat_impl, seat_slot); + g_rw_lock_writer_unlock (&seat_impl->state_lock); + break; + } + + case LIBINPUT_EVENT_TOUCH_MOTION: + { + int seat_slot; + uint64_t time_us; + double x, y; + float stage_width, stage_height; + MetaTouchState *touch_state; + struct libinput_event_touch *touch_event = + libinput_event_get_touch_event (event); + + device = libinput_device_get_user_data (libinput_device); + device_native = META_INPUT_DEVICE_NATIVE (device); + + meta_viewport_info_get_extents (seat_impl->viewports, + &stage_width, &stage_height); + + seat_slot = libinput_event_touch_get_seat_slot (touch_event); + time_us = libinput_event_touch_get_time_usec (touch_event); + x = libinput_event_touch_get_x_transformed (touch_event, + stage_width); + y = libinput_event_touch_get_y_transformed (touch_event, + stage_height); + + g_rw_lock_writer_lock (&seat_impl->state_lock); + touch_state = meta_seat_impl_lookup_touch_state_in_impl (seat_impl, seat_slot); + if (touch_state) + { + touch_state->coords.x = x; + touch_state->coords.y = y; + } + g_rw_lock_writer_unlock (&seat_impl->state_lock); + + if (!touch_state) + break; + + meta_seat_impl_notify_touch_event_in_impl (seat_impl, device, + CLUTTER_TOUCH_UPDATE, + time_us, + touch_state->seat_slot, + touch_state->coords.x, + touch_state->coords.y); + break; + } + case LIBINPUT_EVENT_TOUCH_CANCEL: + { + int seat_slot; + MetaTouchState *touch_state; + uint64_t time_us; + struct libinput_event_touch *touch_event = + libinput_event_get_touch_event (event); + + device = libinput_device_get_user_data (libinput_device); + device_native = META_INPUT_DEVICE_NATIVE (device); + time_us = libinput_event_touch_get_time_usec (touch_event); + + seat_slot = libinput_event_touch_get_seat_slot (touch_event); + touch_state = meta_seat_impl_lookup_touch_state_in_impl (seat_impl, seat_slot); + if (!touch_state) + break; + + meta_seat_impl_notify_touch_event_in_impl (touch_state->seat_impl, + CLUTTER_INPUT_DEVICE (device_native), + CLUTTER_TOUCH_CANCEL, + time_us, + touch_state->seat_slot, + touch_state->coords.x, + touch_state->coords.y); + + meta_seat_impl_release_touch_state_in_impl (seat_impl, seat_slot); + break; + } + case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: + case LIBINPUT_EVENT_GESTURE_PINCH_END: + { + struct libinput_event_gesture *gesture_event = + libinput_event_get_gesture_event (event); + ClutterTouchpadGesturePhase phase; + uint32_t n_fingers; + uint64_t time_us; + + if (libinput_event_get_type (event) == LIBINPUT_EVENT_GESTURE_PINCH_BEGIN) + phase = CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN; + else + phase = libinput_event_gesture_get_cancelled (gesture_event) ? + CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL : CLUTTER_TOUCHPAD_GESTURE_PHASE_END; + + n_fingers = libinput_event_gesture_get_finger_count (gesture_event); + device = libinput_device_get_user_data (libinput_device); + time_us = libinput_event_gesture_get_time_usec (gesture_event); + notify_pinch_gesture_event (device, phase, time_us, 0, 0, 0, 0, n_fingers); + break; + } + case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: + { + struct libinput_event_gesture *gesture_event = + libinput_event_get_gesture_event (event); + double angle_delta, scale, dx, dy; + uint32_t n_fingers; + uint64_t time_us; + + n_fingers = libinput_event_gesture_get_finger_count (gesture_event); + device = libinput_device_get_user_data (libinput_device); + time_us = libinput_event_gesture_get_time_usec (gesture_event); + angle_delta = libinput_event_gesture_get_angle_delta (gesture_event); + scale = libinput_event_gesture_get_scale (gesture_event); + dx = libinput_event_gesture_get_dx (gesture_event); + dy = libinput_event_gesture_get_dy (gesture_event); + + notify_pinch_gesture_event (device, + CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE, + time_us, dx, dy, angle_delta, scale, n_fingers); + break; + } + case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: + case LIBINPUT_EVENT_GESTURE_SWIPE_END: + { + struct libinput_event_gesture *gesture_event = + libinput_event_get_gesture_event (event); + ClutterTouchpadGesturePhase phase; + uint32_t n_fingers; + uint64_t time_us; + + device = libinput_device_get_user_data (libinput_device); + time_us = libinput_event_gesture_get_time_usec (gesture_event); + n_fingers = libinput_event_gesture_get_finger_count (gesture_event); + + if (libinput_event_get_type (event) == LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN) + phase = CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN; + else + phase = libinput_event_gesture_get_cancelled (gesture_event) ? + CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL : CLUTTER_TOUCHPAD_GESTURE_PHASE_END; + + notify_swipe_gesture_event (device, phase, time_us, n_fingers, 0, 0); + break; + } + case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: + { + struct libinput_event_gesture *gesture_event = + libinput_event_get_gesture_event (event); + uint32_t n_fingers; + uint64_t time_us; + double dx, dy; + + device = libinput_device_get_user_data (libinput_device); + time_us = libinput_event_gesture_get_time_usec (gesture_event); + n_fingers = libinput_event_gesture_get_finger_count (gesture_event); + dx = libinput_event_gesture_get_dx (gesture_event); + dy = libinput_event_gesture_get_dy (gesture_event); + + notify_swipe_gesture_event (device, + CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE, + time_us, n_fingers, dx, dy); + break; + } + case LIBINPUT_EVENT_TABLET_TOOL_AXIS: + { + process_tablet_axis (seat_impl, event); + break; + } + case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: + { + uint64_t time; + struct libinput_event_tablet_tool *tablet_event = + libinput_event_get_tablet_tool_event (event); + struct libinput_tablet_tool *libinput_tool = NULL; + enum libinput_tablet_tool_proximity_state state; + gboolean in; + + state = libinput_event_tablet_tool_get_proximity_state (tablet_event); + time = libinput_event_tablet_tool_get_time_usec (tablet_event); + device = libinput_device_get_user_data (libinput_device); + in = state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN; + + libinput_tool = libinput_event_tablet_tool_get_tool (tablet_event); + + if (in) + input_device_update_tool (seat_impl, device, libinput_tool); + notify_proximity (device, time, in); + if (!in) + input_device_update_tool (seat_impl, device, NULL); + + break; + } + case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: + { + uint64_t time_us; + uint32_t button_state; + struct libinput_event_tablet_tool *tablet_event = + libinput_event_get_tablet_tool_event (event); + uint32_t tablet_button; + + process_tablet_axis (seat_impl, event); + + device = libinput_device_get_user_data (libinput_device); + time_us = libinput_event_tablet_tool_get_time_usec (tablet_event); + tablet_button = libinput_event_tablet_tool_get_button (tablet_event); + + button_state = libinput_event_tablet_tool_get_button_state (tablet_event) == + LIBINPUT_BUTTON_STATE_PRESSED; + + meta_seat_impl_notify_button_in_impl (seat_impl, device, + time_us, tablet_button, button_state); + break; + } + case LIBINPUT_EVENT_TABLET_TOOL_TIP: + { + uint64_t time_us; + uint32_t button_state; + struct libinput_event_tablet_tool *tablet_event = + libinput_event_get_tablet_tool_event (event); + + device = libinput_device_get_user_data (libinput_device); + time_us = libinput_event_tablet_tool_get_time_usec (tablet_event); + + button_state = libinput_event_tablet_tool_get_tip_state (tablet_event) == + LIBINPUT_TABLET_TOOL_TIP_DOWN; + + /* To avoid jumps on tip, notify axes before the tip down event + but after the tip up event */ + if (button_state) + process_tablet_axis (seat_impl, event); + + meta_seat_impl_notify_button_in_impl (seat_impl, device, + time_us, BTN_TOUCH, button_state); + if (!button_state) + process_tablet_axis (seat_impl, event); + break; + } + case LIBINPUT_EVENT_TABLET_PAD_BUTTON: + { + uint64_t time; + uint32_t button_state, button, group, mode; + struct libinput_tablet_pad_mode_group *mode_group; + struct libinput_event_tablet_pad *pad_event = + libinput_event_get_tablet_pad_event (event); + + device = libinput_device_get_user_data (libinput_device); + time = libinput_event_tablet_pad_get_time_usec (pad_event); + + mode_group = libinput_event_tablet_pad_get_mode_group (pad_event); + group = libinput_tablet_pad_mode_group_get_index (mode_group); + mode = libinput_event_tablet_pad_get_mode (pad_event); + + button = libinput_event_tablet_pad_get_button_number (pad_event); + button_state = libinput_event_tablet_pad_get_button_state (pad_event) == + LIBINPUT_BUTTON_STATE_PRESSED; + notify_pad_button (device, time, button, group, mode, button_state); + break; + } + case LIBINPUT_EVENT_TABLET_PAD_STRIP: + { + uint64_t time; + uint32_t number, source, group, mode; + struct libinput_tablet_pad_mode_group *mode_group; + struct libinput_event_tablet_pad *pad_event = + libinput_event_get_tablet_pad_event (event); + double value; + + device = libinput_device_get_user_data (libinput_device); + time = libinput_event_tablet_pad_get_time_usec (pad_event); + number = libinput_event_tablet_pad_get_strip_number (pad_event); + value = libinput_event_tablet_pad_get_strip_position (pad_event); + source = libinput_event_tablet_pad_get_strip_source (pad_event); + + mode_group = libinput_event_tablet_pad_get_mode_group (pad_event); + group = libinput_tablet_pad_mode_group_get_index (mode_group); + mode = libinput_event_tablet_pad_get_mode (pad_event); + + notify_pad_strip (device, time, number, source, group, mode, value); + break; + } + case LIBINPUT_EVENT_TABLET_PAD_RING: + { + uint64_t time; + uint32_t number, source, group, mode; + struct libinput_tablet_pad_mode_group *mode_group; + struct libinput_event_tablet_pad *pad_event = + libinput_event_get_tablet_pad_event (event); + double angle; + + device = libinput_device_get_user_data (libinput_device); + time = libinput_event_tablet_pad_get_time_usec (pad_event); + number = libinput_event_tablet_pad_get_ring_number (pad_event); + angle = libinput_event_tablet_pad_get_ring_position (pad_event); + source = libinput_event_tablet_pad_get_ring_source (pad_event); + + mode_group = libinput_event_tablet_pad_get_mode_group (pad_event); + group = libinput_tablet_pad_mode_group_get_index (mode_group); + mode = libinput_event_tablet_pad_get_mode (pad_event); + + notify_pad_ring (device, time, number, source, group, mode, angle); + break; + } + case LIBINPUT_EVENT_SWITCH_TOGGLE: + { + struct libinput_event_switch *switch_event = + libinput_event_get_switch_event (event); + enum libinput_switch sw = + libinput_event_switch_get_switch (switch_event); + enum libinput_switch_state state = + libinput_event_switch_get_switch_state (switch_event); + + if (sw == LIBINPUT_SWITCH_TABLET_MODE) + { + seat_impl->tablet_mode_switch_state = (state == LIBINPUT_SWITCH_STATE_ON); + update_touch_mode (seat_impl); + } + break; + } + default: + handled = FALSE; + } + + return handled; +} + +static void +process_event (MetaSeatImpl *seat_impl, + struct libinput_event *event) +{ + if (process_base_event (seat_impl, event)) + return; + if (process_device_event (seat_impl, event)) + return; +} + +static void +process_events (MetaSeatImpl *seat_impl) +{ + struct libinput_event *event; + + while ((event = libinput_get_event (seat_impl->libinput))) + { + process_event(seat_impl, event); + libinput_event_destroy(event); + } +} + +static int +open_restricted (const char *path, + int flags, + void *user_data) +{ + int fd; + + if (device_open_callback) + { + GError *error = NULL; + + fd = device_open_callback (path, flags, device_callback_data, &error); + + if (fd < 0) + { + g_warning ("Could not open device %s: %s", path, error->message); + g_error_free (error); + } + } + else + { + fd = open (path, O_RDWR | O_NONBLOCK); + if (fd < 0) + { + g_warning ("Could not open device %s: %s", path, strerror (errno)); + } + } + + return fd; +} + +static void +close_restricted (int fd, + void *user_data) +{ + if (device_close_callback) + device_close_callback (fd, device_callback_data); + else + close (fd); +} + +static const struct libinput_interface libinput_interface = { + open_restricted, + close_restricted +}; + +static void +kbd_a11y_changed_cb (MetaInputSettings *input_settings, + MetaKbdA11ySettings *a11y_settings, + MetaSeatImpl *seat_impl) +{ + MetaInputDeviceNative *keyboard; + + keyboard = META_INPUT_DEVICE_NATIVE (seat_impl->core_keyboard); + meta_input_device_native_apply_kbd_a11y_settings_in_impl (keyboard, a11y_settings); +} + +static void +meta_seat_impl_set_keyboard_numlock_in_impl (MetaSeatImpl *seat_impl, + gboolean numlock_state) +{ + xkb_mod_mask_t depressed_mods; + xkb_mod_mask_t latched_mods; + xkb_mod_mask_t locked_mods; + xkb_mod_mask_t group_mods; + xkb_mod_mask_t numlock; + struct xkb_keymap *xkb_keymap; + MetaKeymapNative *keymap; + + keymap = seat_impl->keymap; + xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (keymap); + + numlock = (1 << xkb_keymap_mod_get_index (xkb_keymap, "Mod2")); + + depressed_mods = + xkb_state_serialize_mods (seat_impl->xkb, XKB_STATE_MODS_DEPRESSED); + latched_mods = + xkb_state_serialize_mods (seat_impl->xkb, XKB_STATE_MODS_LATCHED); + locked_mods = + xkb_state_serialize_mods (seat_impl->xkb, XKB_STATE_MODS_LOCKED); + group_mods = + xkb_state_serialize_layout (seat_impl->xkb, XKB_STATE_LAYOUT_EFFECTIVE); + + if (numlock_state) + locked_mods |= numlock; + else + locked_mods &= ~numlock; + + xkb_state_update_mask (seat_impl->xkb, + depressed_mods, + latched_mods, + locked_mods, + 0, 0, + group_mods); + + meta_seat_impl_sync_leds_in_impl (seat_impl); + meta_keymap_native_update_in_impl (seat_impl->keymap); +} + +static gpointer +input_thread (MetaSeatImpl *seat_impl) +{ + MetaEventSource *source; + struct udev *udev; + struct xkb_keymap *xkb_keymap; + + g_main_context_push_thread_default (seat_impl->input_context); + + udev = udev_new (); + if (G_UNLIKELY (udev == NULL)) + { + g_warning ("Failed to create udev object"); + seat_impl->input_thread_initialized = TRUE; + return NULL; + } + + seat_impl->libinput = libinput_udev_create_context (&libinput_interface, + seat_impl, udev); + if (seat_impl->libinput == NULL) + { + g_critical ("Failed to create the libinput object."); + seat_impl->input_thread_initialized = TRUE; + return NULL; + } + + if (libinput_udev_assign_seat (seat_impl->libinput, seat_impl->seat_id) == -1) + { + g_critical ("Failed to assign a seat to the libinput object."); + libinput_unref (seat_impl->libinput); + seat_impl->libinput = NULL; + seat_impl->input_thread_initialized = TRUE; + return NULL; + } + + udev_unref (udev); + + seat_impl->input_settings = meta_input_settings_native_new_in_impl (seat_impl); + g_signal_connect_object (seat_impl->input_settings, "kbd-a11y-changed", + G_CALLBACK (kbd_a11y_changed_cb), seat_impl, 0); + + source = meta_event_source_new (seat_impl); + seat_impl->event_source = source; + + seat_impl->keymap = g_object_new (META_TYPE_KEYMAP_NATIVE, NULL); + + xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (seat_impl->keymap); + + if (xkb_keymap) + { + seat_impl->xkb = xkb_state_new (xkb_keymap); + + seat_impl->caps_lock_led = + xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_CAPS); + seat_impl->num_lock_led = + xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_NUM); + seat_impl->scroll_lock_led = + xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_SCROLL); + } + + if (meta_input_settings_maybe_restore_numlock_state (seat_impl->input_settings)) + meta_seat_impl_set_keyboard_numlock_in_impl (seat_impl, TRUE); + + seat_impl->has_touchscreen = has_touchscreen (seat_impl); + seat_impl->has_tablet_switch = has_tablet_switch (seat_impl); + update_touch_mode (seat_impl); + + g_mutex_lock (&seat_impl->init_mutex); + seat_impl->input_thread_initialized = TRUE; + g_cond_signal (&seat_impl->init_cond); + g_mutex_unlock (&seat_impl->init_mutex); + + seat_impl->input_loop = g_main_loop_new (seat_impl->input_context, FALSE); + g_main_loop_run (seat_impl->input_loop); + g_main_loop_unref (seat_impl->input_loop); + + g_main_context_pop_thread_default (seat_impl->input_context); + + return NULL; +} + +static gboolean +meta_seat_impl_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + MetaSeatImpl *seat_impl = META_SEAT_IMPL (initable); + + seat_impl->input_context = g_main_context_new (); + seat_impl->main_context = g_main_context_ref_thread_default (); + g_assert (seat_impl->main_context == g_main_context_default ()); + + seat_impl->input_thread = + g_thread_try_new ("Mutter Input Thread", + (GThreadFunc) input_thread, + initable, + error); + if (!seat_impl->input_thread) + return FALSE; + + /* Initialize thread synchronously */ + g_mutex_lock (&seat_impl->init_mutex); + while (!seat_impl->input_thread_initialized) + g_cond_wait (&seat_impl->init_cond, &seat_impl->init_mutex); + g_mutex_unlock (&seat_impl->init_mutex); + + return TRUE; +} + +static void +meta_seat_impl_constructed (GObject *object) +{ + MetaSeatImpl *seat_impl = META_SEAT_IMPL (object); + ClutterInputDevice *device; + + device = meta_input_device_native_new_virtual ( + seat_impl, CLUTTER_POINTER_DEVICE, + CLUTTER_INPUT_MODE_LOGICAL); + seat_impl->pointer_x = INITIAL_POINTER_X; + seat_impl->pointer_y = INITIAL_POINTER_Y; + meta_input_device_native_set_coords_in_impl (META_INPUT_DEVICE_NATIVE (device), + seat_impl->pointer_x, + seat_impl->pointer_y); + seat_impl->core_pointer = device; + + device = meta_input_device_native_new_virtual ( + seat_impl, CLUTTER_KEYBOARD_DEVICE, + CLUTTER_INPUT_MODE_LOGICAL); + seat_impl->core_keyboard = device; + + seat_impl->udev_client = g_udev_client_new ((const char *[]) { "input", NULL }); + + if (G_OBJECT_CLASS (meta_seat_impl_parent_class)->constructed) + G_OBJECT_CLASS (meta_seat_impl_parent_class)->constructed (object); +} + +static void +meta_seat_impl_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaSeatImpl *seat_impl = META_SEAT_IMPL (object); + + switch (prop_id) + { + case PROP_SEAT: + seat_impl->seat_native = g_value_get_object (value); + break; + case PROP_SEAT_ID: + seat_impl->seat_id = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_seat_impl_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaSeatImpl *seat_impl = META_SEAT_IMPL (object); + + switch (prop_id) + { + case PROP_SEAT: + g_value_set_object (value, seat_impl->seat_native); + break; + case PROP_SEAT_ID: + g_value_set_string (value, seat_impl->seat_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_seat_impl_dispose (GObject *object) +{ + MetaSeatImpl *seat_impl = META_SEAT_IMPL (object); + + if (seat_impl->libinput) + { + libinput_unref (seat_impl->libinput); + seat_impl->libinput = NULL; + } + + G_OBJECT_CLASS (meta_seat_impl_parent_class)->dispose (object); +} + +static void +meta_seat_impl_finalize (GObject *object) +{ + MetaSeatImpl *seat_impl = META_SEAT_IMPL (object); + gboolean numlock_active; + GSList *iter; + + g_main_loop_quit (seat_impl->input_loop); + g_thread_join (seat_impl->input_thread); + + for (iter = seat_impl->devices; iter; iter = g_slist_next (iter)) + { + ClutterInputDevice *device = iter->data; + + g_object_unref (device); + } + g_slist_free (seat_impl->devices); + g_clear_pointer (&seat_impl->tools, g_hash_table_unref); + + if (seat_impl->touch_states) + g_hash_table_destroy (seat_impl->touch_states); + + g_object_unref (seat_impl->udev_client); + + meta_event_source_free (seat_impl->event_source); + + numlock_active = + xkb_state_mod_name_is_active (seat_impl->xkb, XKB_MOD_NAME_NUM, + XKB_STATE_MODS_LATCHED | + XKB_STATE_MODS_LOCKED); + meta_input_settings_maybe_save_numlock_state (seat_impl->input_settings, + numlock_active); + + xkb_state_unref (seat_impl->xkb); + + meta_seat_impl_clear_repeat_source (seat_impl); + + g_free (seat_impl->seat_id); + + g_rw_lock_clear (&seat_impl->state_lock); + + G_OBJECT_CLASS (meta_seat_impl_parent_class)->finalize (object); +} + +ClutterInputDevice * +meta_seat_impl_get_pointer (MetaSeatImpl *seat_impl) +{ + return seat_impl->core_pointer; +} + +ClutterInputDevice * +meta_seat_impl_get_keyboard (MetaSeatImpl *seat_impl) +{ + return seat_impl->core_keyboard; +} + +GSList * +meta_seat_impl_get_devices_in_impl (MetaSeatImpl *seat_impl) +{ + return g_slist_copy_deep (seat_impl->devices, + (GCopyFunc) g_object_ref, + NULL); +} + +MetaKeymapNative * +meta_seat_impl_get_keymap (MetaSeatImpl *seat_impl) +{ + return g_object_ref (seat_impl->keymap); +} + +static gboolean +warp_pointer_in_impl (GTask *task) +{ + MetaSeatImpl *seat = g_task_get_source_object (task); + graphene_point_t *point; + + point = g_task_get_task_data (task); + notify_absolute_motion_in_impl (seat->core_pointer, 0, + point->x, point->y, NULL); + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +void +meta_seat_impl_warp_pointer (MetaSeatImpl *seat_impl, + int x, + int y) +{ + graphene_point_t *point; + GTask *task; + + point = graphene_point_alloc (); + point->x = x; + point->y = y; + + task = g_task_new (seat_impl, NULL, NULL, NULL); + g_task_set_task_data (task, point, (GDestroyNotify) graphene_point_free); + meta_seat_impl_run_input_task (seat_impl, task, + (GSourceFunc) warp_pointer_in_impl); + g_object_unref (task); +} + +gboolean +meta_seat_impl_query_state (MetaSeatImpl *seat_impl, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t *coords, + ClutterModifierType *modifiers) +{ + MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device); + gboolean retval = FALSE; + ClutterModifierType mods = 0; + + g_rw_lock_reader_lock (&seat_impl->state_lock); + + if (sequence) + { + MetaTouchState *touch_state; + int slot; + + slot = meta_event_native_sequence_get_slot (sequence); + touch_state = meta_seat_impl_lookup_touch_state_in_impl (seat_impl, slot); + if (!touch_state) + goto out; + + if (coords) + { + coords->x = touch_state->coords.x; + coords->y = touch_state->coords.y; + } + + if (seat_impl->xkb) + mods = meta_xkb_translate_modifiers (seat_impl->xkb, 0); + + retval = TRUE; + } + else + { + if (coords) + { + coords->x = device_native->pointer_x; + coords->y = device_native->pointer_y; + } + + if (seat_impl->xkb) + { + mods = meta_xkb_translate_modifiers (seat_impl->xkb, + seat_impl->button_state); + } + + retval = TRUE; + } + + if (modifiers) + *modifiers = mods; + + out: + g_rw_lock_reader_unlock (&seat_impl->state_lock); + return retval; +} + +static void +meta_seat_impl_initable_iface_init (GInitableIface *iface) +{ + iface->init = meta_seat_impl_initable_init; +} + +static void +meta_seat_impl_class_init (MetaSeatImplClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = meta_seat_impl_constructed; + object_class->set_property = meta_seat_impl_set_property; + object_class->get_property = meta_seat_impl_get_property; + object_class->dispose = meta_seat_impl_dispose; + object_class->finalize = meta_seat_impl_finalize; + + props[PROP_SEAT] = + g_param_spec_object ("seat", + "Seat", + "Seat", + META_TYPE_SEAT_NATIVE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + props[PROP_SEAT_ID] = + g_param_spec_string ("seat-id", + "Seat ID", + "Seat ID", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + + signals[KBD_A11Y_FLAGS_CHANGED] = + g_signal_new ("kbd-a11y-flags-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, + G_TYPE_UINT, G_TYPE_UINT); + signals[KBD_A11Y_MODS_STATE_CHANGED] = + g_signal_new ("kbd-a11y-mods-state-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, + G_TYPE_UINT, G_TYPE_UINT); + signals[TOUCH_MODE] = + g_signal_new ("touch-mode", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + signals[BELL] = + g_signal_new ("bell", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + signals[MODS_STATE_CHANGED] = + g_signal_new ("mods-state-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + + g_object_class_install_properties (object_class, N_PROPS, props); +} + +static void +meta_seat_impl_init (MetaSeatImpl *seat_impl) +{ + g_rw_lock_init (&seat_impl->state_lock); + + seat_impl->repeat = TRUE; + seat_impl->repeat_delay = 250; /* ms */ + seat_impl->repeat_interval = 33; /* ms */ + + g_mutex_init (&seat_impl->init_mutex); + g_cond_init (&seat_impl->init_cond); + + seat_impl->barrier_manager = meta_barrier_manager_native_new (); +} + +/** + * meta_seat_impl_set_device_callbacks: (skip) + * @open_callback: the user replacement for open() + * @close_callback: the user replacement for close() + * @user_data: user data for @callback + * + * Through this function, the application can set a custom callback + * to be invoked when Clutter is about to open an evdev device. It can do + * so if special handling is needed, for example to circumvent permission + * problems. + * + * Setting @callback to %NULL will reset the default behavior. + * + * For reliable effects, this function must be called before clutter_init(). + */ +void +meta_seat_impl_set_device_callbacks (MetaOpenDeviceCallback open_callback, + MetaCloseDeviceCallback close_callback, + gpointer user_data) +{ + device_open_callback = open_callback; + device_close_callback = close_callback; + device_callback_data = user_data; +} + +void +meta_seat_impl_update_xkb_state_in_impl (MetaSeatImpl *seat_impl) +{ + xkb_mod_mask_t latched_mods = 0; + xkb_mod_mask_t locked_mods = 0; + struct xkb_keymap *xkb_keymap; + + g_rw_lock_writer_lock (&seat_impl->state_lock); + + xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (seat_impl->keymap); + + if (seat_impl->xkb) + { + latched_mods = xkb_state_serialize_mods (seat_impl->xkb, + XKB_STATE_MODS_LATCHED); + locked_mods = xkb_state_serialize_mods (seat_impl->xkb, + XKB_STATE_MODS_LOCKED); + xkb_state_unref (seat_impl->xkb); + } + + seat_impl->xkb = xkb_state_new (xkb_keymap); + + xkb_state_update_mask (seat_impl->xkb, + 0, /* depressed */ + latched_mods, + locked_mods, + 0, 0, seat_impl->layout_idx); + + seat_impl->caps_lock_led = + xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_CAPS); + seat_impl->num_lock_led = + xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_NUM); + seat_impl->scroll_lock_led = + xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_SCROLL); + + meta_seat_impl_sync_leds_in_impl (seat_impl); + meta_keymap_native_update_in_impl (seat_impl->keymap); + + g_rw_lock_writer_unlock (&seat_impl->state_lock); +} + +static gboolean +release_devices (GTask *task) +{ + MetaSeatImpl *seat_impl = g_task_get_source_object (task); + + if (seat_impl->released) + { + g_warning ("meta_seat_impl_release_devices() shouldn't be called " + "multiple times without a corresponding call to " + "meta_seat_impl_reclaim_devices() first"); + } + else + { + libinput_suspend (seat_impl->libinput); + process_events (seat_impl); + + seat_impl->released = TRUE; + } + + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +/** + * meta_seat_impl_release_devices: + * + * Releases all the evdev devices that Clutter is currently managing. This api + * is typically used when switching away from the Clutter application when + * switching tty. The devices can be reclaimed later with a call to + * meta_seat_impl_reclaim_devices(). + * + * This function should only be called after clutter has been initialized. + */ +void +meta_seat_impl_release_devices (MetaSeatImpl *seat_impl) +{ + GTask *task; + + g_return_if_fail (META_IS_SEAT_IMPL (seat_impl)); + + task = g_task_new (seat_impl, NULL, NULL, NULL); + meta_seat_impl_run_input_task (seat_impl, task, + (GSourceFunc) release_devices); + g_object_unref (task); +} + +static gboolean +reclaim_devices (GTask *task) +{ + MetaSeatImpl *seat_impl = g_task_get_source_object (task); + + if (seat_impl->released) + { + libinput_resume (seat_impl->libinput); + meta_seat_impl_update_xkb_state_in_impl (seat_impl); + process_events (seat_impl); + + seat_impl->released = FALSE; + } + else + { + g_warning ("Spurious call to meta_seat_impl_reclaim_devices() without " + "previous call to meta_seat_impl_release_devices"); + } + + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +/** + * meta_seat_impl_reclaim_devices: + * + * This causes Clutter to re-probe for evdev devices. This is must only be + * called after a corresponding call to meta_seat_impl_release_devices() + * was previously used to release all evdev devices. This API is typically + * used when a clutter application using evdev has regained focus due to + * switching ttys. + * + * This function should only be called after clutter has been initialized. + */ +void +meta_seat_impl_reclaim_devices (MetaSeatImpl *seat_impl) +{ + GTask *task; + + g_return_if_fail (META_IS_SEAT_IMPL (seat_impl)); + + task = g_task_new (seat_impl, NULL, NULL, NULL); + meta_seat_impl_run_input_task (seat_impl, task, (GSourceFunc) reclaim_devices); + g_object_unref (task); +} + +static gboolean +set_keyboard_map (GTask *task) +{ + MetaSeatImpl *seat_impl = g_task_get_source_object (task); + struct xkb_keymap *xkb_keymap = g_task_get_task_data (task); + MetaKeymapNative *keymap; + + keymap = seat_impl->keymap; + meta_keymap_native_set_keyboard_map_in_impl (keymap, xkb_keymap); + + meta_seat_impl_update_xkb_state_in_impl (seat_impl); + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +/** + * meta_seat_impl_set_keyboard_map: (skip) + * @seat: the #ClutterSeat created by the evdev backend + * @keymap: the new keymap + * + * Instructs @evdev to use the speficied keyboard map. This will cause + * the backend to drop the state and create a new one with the new + * map. To avoid state being lost, callers should ensure that no key + * is pressed when calling this function. + */ +void +meta_seat_impl_set_keyboard_map (MetaSeatImpl *seat_impl, + struct xkb_keymap *xkb_keymap) +{ + GTask *task; + + g_return_if_fail (META_IS_SEAT_IMPL (seat_impl)); + g_return_if_fail (xkb_keymap != NULL); + + task = g_task_new (seat_impl, NULL, NULL, NULL); + g_task_set_task_data (task, + xkb_keymap_ref (xkb_keymap), + (GDestroyNotify) xkb_keymap_unref); + meta_seat_impl_run_input_task (seat_impl, task, (GSourceFunc) set_keyboard_map); + g_object_unref (task); +} + +static gboolean +set_keyboard_layout_index (GTask *task) +{ + MetaSeatImpl *seat_impl = g_task_get_source_object (task); + xkb_layout_index_t idx = GPOINTER_TO_UINT (g_task_get_task_data (task)); + xkb_mod_mask_t depressed_mods; + xkb_mod_mask_t latched_mods; + xkb_mod_mask_t locked_mods; + struct xkb_state *state; + + g_rw_lock_writer_lock (&seat_impl->state_lock); + + state = seat_impl->xkb; + + depressed_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED); + latched_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED); + locked_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED); + + xkb_state_update_mask (state, depressed_mods, latched_mods, locked_mods, 0, 0, idx); + meta_keymap_native_update_in_impl (seat_impl->keymap); + + seat_impl->layout_idx = idx; + + g_rw_lock_writer_unlock (&seat_impl->state_lock); + + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +/** + * meta_seat_impl_set_keyboard_layout_index: (skip) + * @seat: the #ClutterSeat created by the evdev backend + * @idx: the xkb layout index to set + * + * Sets the xkb layout index on the backend's #xkb_state . + */ +void +meta_seat_impl_set_keyboard_layout_index (MetaSeatImpl *seat_impl, + xkb_layout_index_t idx) +{ + GTask *task; + + g_return_if_fail (META_IS_SEAT_IMPL (seat_impl)); + + task = g_task_new (seat_impl, NULL, NULL, NULL); + g_task_set_task_data (task, GUINT_TO_POINTER (idx), NULL); + meta_seat_impl_run_input_task (seat_impl, task, + (GSourceFunc) set_keyboard_layout_index); + g_object_unref (task); +} + +/** + * meta_seat_impl_set_keyboard_repeat_in_impl: + * @seat: the #ClutterSeat created by the evdev backend + * @repeat: whether to enable or disable keyboard repeat events + * @delay: the delay in ms between the hardware key press event and + * the first synthetic event + * @interval: the period in ms between consecutive synthetic key + * press events + * + * Enables or disables sythetic key press events, allowing for initial + * delay and interval period to be specified. + */ +void +meta_seat_impl_set_keyboard_repeat_in_impl (MetaSeatImpl *seat_impl, + gboolean repeat, + uint32_t delay, + uint32_t interval) +{ + g_return_if_fail (META_IS_SEAT_IMPL (seat_impl)); + + seat_impl->repeat = repeat; + seat_impl->repeat_delay = delay; + seat_impl->repeat_interval = interval; +} + +struct xkb_state * +meta_seat_impl_get_xkb_state_in_impl (MetaSeatImpl *seat_impl) +{ + return seat_impl->xkb; +} + +MetaBarrierManagerNative * +meta_seat_impl_get_barrier_manager (MetaSeatImpl *seat_impl) +{ + return seat_impl->barrier_manager; +} + +static gboolean +set_pointer_constraint (GTask *task) +{ + MetaSeatImpl *seat_impl = g_task_get_source_object (task); + MetaPointerConstraintImpl *constraint_impl = g_task_get_task_data (task); + + if (!g_set_object (&seat_impl->pointer_constraint, constraint_impl)) + return G_SOURCE_REMOVE; + + if (constraint_impl) + { + meta_pointer_constraint_impl_ensure_constrained (constraint_impl, + seat_impl->core_pointer); + } + + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +void +meta_seat_impl_set_pointer_constraint (MetaSeatImpl *seat, + MetaPointerConstraintImpl *constraint_impl) +{ + GTask *task; + + g_return_if_fail (META_IS_SEAT_IMPL (seat)); + + task = g_task_new (seat, NULL, NULL, NULL); + g_task_set_task_data (task, g_object_ref (constraint_impl), g_object_unref); + meta_seat_impl_run_input_task (seat, task, + (GSourceFunc) set_pointer_constraint); + g_object_unref (task); +} + +static gboolean +set_viewports (GTask *task) +{ + MetaSeatImpl *seat = g_task_get_source_object (task); + MetaViewportInfo *viewports = g_task_get_task_data (task); + + g_set_object (&seat->viewports, viewports); + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +void +meta_seat_impl_set_viewports (MetaSeatImpl *seat_impl, + MetaViewportInfo *viewports) +{ + GTask *task; + + g_return_if_fail (META_IS_SEAT_IMPL (seat_impl)); + + task = g_task_new (seat_impl, NULL, NULL, NULL); + g_task_set_task_data (task, g_object_ref (viewports), g_object_unref); + meta_seat_impl_run_input_task (seat_impl, task, + (GSourceFunc) set_viewports); + g_object_unref (task); +} + +MetaSeatImpl * +meta_seat_impl_new (MetaSeatNative *seat_native, + const char *seat_id) +{ + return g_initable_new (META_TYPE_SEAT_IMPL, + NULL, NULL, + "seat", seat_native, + "seat-id", seat_id, + NULL); +} + +void +meta_seat_impl_notify_kbd_a11y_flags_changed_in_impl (MetaSeatImpl *seat_impl, + MetaKeyboardA11yFlags new_flags, + MetaKeyboardA11yFlags what_changed) +{ + MetaInputSettings *input_settings; + GValue values[] = { G_VALUE_INIT, G_VALUE_INIT }; + + input_settings = seat_impl->input_settings; + meta_input_settings_notify_kbd_a11y_change (input_settings, + new_flags, what_changed); + g_value_init (&values[0], G_TYPE_UINT); + g_value_set_uint (&values[0], new_flags); + g_value_init (&values[1], G_TYPE_UINT); + g_value_set_uint (&values[1], what_changed); + + emit_signal (seat_impl, signals[KBD_A11Y_FLAGS_CHANGED], + values, G_N_ELEMENTS (values)); +} + +void +meta_seat_impl_notify_kbd_a11y_mods_state_changed_in_impl (MetaSeatImpl *seat_impl, + xkb_mod_mask_t new_latched_mods, + xkb_mod_mask_t new_locked_mods) +{ + GValue values[] = { G_VALUE_INIT, G_VALUE_INIT }; + + g_value_init (&values[0], G_TYPE_UINT); + g_value_set_uint (&values[0], new_latched_mods); + g_value_init (&values[1], G_TYPE_UINT); + g_value_set_uint (&values[1], new_locked_mods); + + emit_signal (seat_impl, signals[KBD_A11Y_MODS_STATE_CHANGED], + values, G_N_ELEMENTS (values)); +} + +void +meta_seat_impl_notify_bell_in_impl (MetaSeatImpl *seat_impl) +{ + emit_signal (seat_impl, signals[BELL], NULL, 0); +} + +MetaInputSettings * +meta_seat_impl_get_input_settings (MetaSeatImpl *seat_impl) +{ + return seat_impl->input_settings; +} diff --git a/src/backends/native/meta-seat-impl.h b/src/backends/native/meta-seat-impl.h new file mode 100644 index 0000000000000000000000000000000000000000..ab0ef75d38a86018770ae9043eeb4ae42eeadc6a --- /dev/null +++ b/src/backends/native/meta-seat-impl.h @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2010 Intel Corp. + * Copyright (C) 2014 Jonas Ã…dahl + * Copyright (C) 2016 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Author: Damien Lespiau + * Author: Jonas Ã…dahl + */ + +#ifndef META_SEAT_IMPL_H +#define META_SEAT_IMPL_H + +#ifndef META_INPUT_THREAD_H_INSIDE +#error "This header cannot be included directly. Use "backends/native/meta-input-thread.h"" +#endif /* META_INPUT_THREAD_H_INSIDE */ + +#include +#include +#include + +#include "backends/meta-input-settings-private.h" +#include "backends/meta-viewport-info.h" +#include "backends/native/meta-backend-native-types.h" +#include "backends/native/meta-barrier-native.h" +#include "backends/native/meta-cursor-renderer-native.h" +#include "backends/native/meta-keymap-native.h" +#include "backends/native/meta-pointer-constraint-native.h" +#include "backends/native/meta-xkb-utils.h" +#include "clutter/clutter.h" + +typedef struct _MetaTouchState MetaTouchState; +typedef struct _MetaSeatImpl MetaSeatImpl; +typedef struct _MetaEventSource MetaEventSource; + +struct _MetaTouchState +{ + MetaSeatImpl *seat_impl; + + int device_slot; + int seat_slot; + graphene_point_t coords; +}; + +struct _MetaSeatImpl +{ + GObject parent_instance; + + GMainContext *main_context; + GMainContext *input_context; + GMainLoop *input_loop; + GThread *input_thread; + GMutex init_mutex; + GCond init_cond; + + MetaSeatNative *seat_native; + char *seat_id; + MetaEventSource *event_source; + struct libinput *libinput; + GRWLock state_lock; + + GSList *devices; + GHashTable *tools; + + ClutterInputDevice *core_pointer; + ClutterInputDevice *core_keyboard; + + GHashTable *touch_states; + GHashTable *cursor_renderers; + + struct xkb_state *xkb; + xkb_led_index_t caps_lock_led; + xkb_led_index_t num_lock_led; + xkb_led_index_t scroll_lock_led; + xkb_layout_index_t layout_idx; + uint32_t button_state; + int button_count[KEY_CNT]; + + MetaBarrierManagerNative *barrier_manager; + MetaPointerConstraintImpl *pointer_constraint; + + MetaKeymapNative *keymap; + MetaInputSettings *input_settings; + + MetaViewportInfo *viewports; + + GUdevClient *udev_client; + gboolean tablet_mode_switch_state; + gboolean has_touchscreen; + gboolean has_tablet_switch; + gboolean touch_mode; + gboolean input_thread_initialized; + + /* keyboard repeat */ + gboolean repeat; + uint32_t repeat_delay; + uint32_t repeat_interval; + uint32_t repeat_key; + uint32_t repeat_count; + ClutterInputDevice *repeat_device; + GSource *repeat_source; + + float pointer_x; + float pointer_y; + + /* Emulation of discrete scroll events out of smooth ones */ + float accum_scroll_dx; + float accum_scroll_dy; + + gboolean released; +}; + +#define META_TYPE_SEAT_IMPL meta_seat_impl_get_type () +G_DECLARE_FINAL_TYPE (MetaSeatImpl, meta_seat_impl, + META, SEAT_IMPL, GObject) + +MetaSeatImpl * meta_seat_impl_new (MetaSeatNative *seat_native, + const char *seat_id); + +void meta_seat_impl_run_input_task (MetaSeatImpl *seat_impl, + GTask *task, + GSourceFunc dispatch_func); + +void meta_seat_impl_notify_key_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *device, + uint64_t time_us, + uint32_t key, + uint32_t state, + gboolean update_keys); + +void meta_seat_impl_notify_relative_motion_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + float dx, + float dy, + float dx_unaccel, + float dy_unaccel); + +void meta_seat_impl_notify_absolute_motion_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + float x, + float y, + double *axes); + +void meta_seat_impl_notify_button_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + uint32_t button, + uint32_t state); + +void meta_seat_impl_notify_scroll_continuous_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + double dx, + double dy, + ClutterScrollSource source, + ClutterScrollFinishFlags flags); + +void meta_seat_impl_notify_discrete_scroll_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + uint64_t time_us, + double discrete_dx, + double discrete_dy, + ClutterScrollSource source); + +void meta_seat_impl_notify_touch_event_in_impl (MetaSeatImpl *seat_impl, + ClutterInputDevice *input_device, + ClutterEventType evtype, + uint64_t time_us, + int slot, + double x, + double y); + +void meta_seat_impl_sync_leds_in_impl (MetaSeatImpl *seat_impl); + +MetaTouchState * meta_seat_impl_acquire_touch_state_in_impl (MetaSeatImpl *seat_impl, + int seat_slot); +MetaTouchState * meta_seat_impl_lookup_touch_state_in_impl (MetaSeatImpl *seat_impl, + int seat_slot); +void meta_seat_impl_release_touch_state_in_impl (MetaSeatImpl *seat_impl, + int seat_slot); + +void meta_seat_impl_update_xkb_state_in_impl (MetaSeatImpl *seat_impl); + +/** + * MetaOpenDeviceCallback: + * @path: the device path + * @flags: flags to be passed to open + * + * This callback will be called when Clutter needs to access an input + * device. It should return an open file descriptor for the file at @path, + * or -1 if opening failed. + */ +typedef int (* MetaOpenDeviceCallback) (const char *path, + int flags, + gpointer user_data, + GError **error); +typedef void (* MetaCloseDeviceCallback) (int fd, + gpointer user_data); + +void meta_seat_impl_set_device_callbacks (MetaOpenDeviceCallback open_callback, + MetaCloseDeviceCallback close_callback, + gpointer user_data); + +void meta_seat_impl_release_devices (MetaSeatImpl *seat_impl); +void meta_seat_impl_reclaim_devices (MetaSeatImpl *seat_impl); + +struct xkb_state * meta_seat_impl_get_xkb_state_in_impl (MetaSeatImpl *seat_impl); + +void meta_seat_impl_set_keyboard_map (MetaSeatImpl *seat_impl, + struct xkb_keymap *keymap); + +void meta_seat_impl_set_keyboard_layout_index (MetaSeatImpl *seat_impl, + xkb_layout_index_t idx); + +void meta_seat_impl_set_keyboard_repeat_in_impl (MetaSeatImpl *seat_impl, + gboolean repeat, + uint32_t delay, + uint32_t interval); + +MetaBarrierManagerNative * meta_seat_impl_get_barrier_manager (MetaSeatImpl *seat_impl); + +void meta_seat_impl_set_pointer_constraint (MetaSeatImpl *seat_impl, + MetaPointerConstraintImpl *constraint_impl); +void meta_seat_impl_set_viewports (MetaSeatImpl *seat_impl, + MetaViewportInfo *viewports); + +void meta_seat_impl_warp_pointer (MetaSeatImpl *seat_impl, + int x, + int y); +gboolean meta_seat_impl_query_state (MetaSeatImpl *seat_impl, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t *coords, + ClutterModifierType *modifiers); +ClutterInputDevice * meta_seat_impl_get_pointer (MetaSeatImpl *seat_impl); +ClutterInputDevice * meta_seat_impl_get_keyboard (MetaSeatImpl *seat_impl); +GSList * meta_seat_impl_get_devices_in_impl (MetaSeatImpl *seat_impl); + +MetaKeymapNative * meta_seat_impl_get_keymap (MetaSeatImpl *seat_impl); + +void meta_seat_impl_notify_kbd_a11y_flags_changed_in_impl (MetaSeatImpl *seat_impl, + MetaKeyboardA11yFlags new_flags, + MetaKeyboardA11yFlags what_changed); +void meta_seat_impl_notify_kbd_a11y_mods_state_changed_in_impl (MetaSeatImpl *seat_impl, + xkb_mod_mask_t new_latched_mods, + xkb_mod_mask_t new_locked_mods); +void meta_seat_impl_notify_bell_in_impl (MetaSeatImpl *seat_impl); + +MetaInputSettings * meta_seat_impl_get_input_settings (MetaSeatImpl *seat_impl); + +#endif /* META_SEAT_IMPL_H */ diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c index e2f62b09b32918abfe389de5ee1f305316b51ce8..73abb9052dd0c307aca1b7f2e078e243791b9c6e 100644 --- a/src/backends/native/meta-seat-native.c +++ b/src/backends/native/meta-seat-native.c @@ -28,2536 +28,149 @@ #include "backends/native/meta-seat-native.h" -#include -#include -#include -#include -#include - #include "backends/meta-cursor-tracker-private.h" +#include "backends/meta-keymap-utils.h" #include "backends/native/meta-barrier-native.h" #include "backends/native/meta-event-native.h" -#include "backends/native/meta-input-device-native.h" -#include "backends/native/meta-input-device-tool-native.h" +#include "backends/native/meta-input-thread.h" #include "backends/native/meta-keymap-native.h" #include "backends/native/meta-virtual-input-device-native.h" #include "clutter/clutter-mutter.h" #include "core/bell.h" -/* - * Clutter makes the assumption that two core devices have ID's 2 and 3 (core - * pointer and core keyboard). - * - * Since the two first devices that will ever be created will be the virtual - * pointer and virtual keyboard of the first seat, we fulfill the made - * assumptions by having the first device having ID 2 and following 3. - */ -#define INITIAL_DEVICE_ID 2 - -/* Try to keep the pointer inside the stage. Hopefully no one is using - * this backend with stages smaller than this. */ -#define INITIAL_POINTER_X 16 -#define INITIAL_POINTER_Y 16 - -#define AUTOREPEAT_VALUE 2 - -#define DISCRETE_SCROLL_STEP 10.0 - -#ifndef BTN_STYLUS3 -#define BTN_STYLUS3 0x149 /* Linux 4.15 */ -#endif - -struct _MetaEventSource -{ - GSource source; - - MetaSeatNative *seat; - GPollFD event_poll_fd; -}; - -static MetaOpenDeviceCallback device_open_callback; -static MetaCloseDeviceCallback device_close_callback; -static gpointer device_callback_data; - -#ifdef CLUTTER_ENABLE_DEBUG -static const char *device_type_str[] = { - "pointer", /* CLUTTER_POINTER_DEVICE */ - "keyboard", /* CLUTTER_KEYBOARD_DEVICE */ - "extension", /* CLUTTER_EXTENSION_DEVICE */ - "joystick", /* CLUTTER_JOYSTICK_DEVICE */ - "tablet", /* CLUTTER_TABLET_DEVICE */ - "touchpad", /* CLUTTER_TOUCHPAD_DEVICE */ - "touchscreen", /* CLUTTER_TOUCHSCREEN_DEVICE */ - "pen", /* CLUTTER_PEN_DEVICE */ - "eraser", /* CLUTTER_ERASER_DEVICE */ - "cursor", /* CLUTTER_CURSOR_DEVICE */ - "pad", /* CLUTTER_PAD_DEVICE */ -}; -#endif /* CLUTTER_ENABLE_DEBUG */ - enum { PROP_0, PROP_SEAT_ID, - N_PROPS, - - /* This property is overridden */ - PROP_TOUCH_MODE, -}; - -GParamSpec *props[N_PROPS] = { NULL }; - -G_DEFINE_TYPE (MetaSeatNative, meta_seat_native, CLUTTER_TYPE_SEAT) - -static void process_events (MetaSeatNative *seat); - -void -meta_seat_native_set_libinput_seat (MetaSeatNative *seat, - struct libinput_seat *libinput_seat) -{ - g_assert (seat->libinput_seat == NULL); - - libinput_seat_ref (libinput_seat); - libinput_seat_set_user_data (libinput_seat, seat); - seat->libinput_seat = libinput_seat; -} - -void -meta_seat_native_sync_leds (MetaSeatNative *seat) -{ - GSList *iter; - MetaInputDeviceNative *device_evdev; - int caps_lock, num_lock, scroll_lock; - enum libinput_led leds = 0; - - caps_lock = xkb_state_led_index_is_active (seat->xkb, seat->caps_lock_led); - num_lock = xkb_state_led_index_is_active (seat->xkb, seat->num_lock_led); - scroll_lock = xkb_state_led_index_is_active (seat->xkb, seat->scroll_lock_led); - - if (caps_lock) - leds |= LIBINPUT_LED_CAPS_LOCK; - if (num_lock) - leds |= LIBINPUT_LED_NUM_LOCK; - if (scroll_lock) - leds |= LIBINPUT_LED_SCROLL_LOCK; - - for (iter = seat->devices; iter; iter = iter->next) - { - device_evdev = iter->data; - meta_input_device_native_update_leds (device_evdev, leds); - } -} - -MetaTouchState * -meta_seat_native_lookup_touch_state (MetaSeatNative *seat, - int seat_slot) -{ - if (!seat->touch_states) - return NULL; - - return g_hash_table_lookup (seat->touch_states, GINT_TO_POINTER (seat_slot)); -} - -static void -meta_touch_state_free (MetaTouchState *state) -{ - g_slice_free (MetaTouchState, state); -} - -MetaTouchState * -meta_seat_native_acquire_touch_state (MetaSeatNative *seat, - int seat_slot) -{ - MetaTouchState *touch_state; - - if (!seat->touch_states) - { - seat->touch_states = - g_hash_table_new_full (NULL, NULL, NULL, - (GDestroyNotify) meta_touch_state_free); - } - - g_assert (!g_hash_table_contains (seat->touch_states, - GINT_TO_POINTER (seat_slot))); - - touch_state = g_slice_new0 (MetaTouchState); - *touch_state = (MetaTouchState) { - .seat = seat, - .seat_slot = seat_slot, - }; - - g_hash_table_insert (seat->touch_states, GINT_TO_POINTER (seat_slot), - touch_state); - - return touch_state; -} - -void -meta_seat_native_release_touch_state (MetaSeatNative *seat, - int seat_slot) -{ - if (!seat->touch_states) - return; - - g_hash_table_remove (seat->touch_states, GINT_TO_POINTER (seat_slot)); -} - -void -meta_seat_native_clear_repeat_timer (MetaSeatNative *seat) -{ - if (seat->repeat_timer) - { - g_clear_handle_id (&seat->repeat_timer, g_source_remove); - g_clear_object (&seat->repeat_device); - } -} - -static void -dispatch_libinput (MetaSeatNative *seat) -{ - libinput_dispatch (seat->libinput); - process_events (seat); -} - -static gboolean -keyboard_repeat (gpointer data) -{ - MetaSeatNative *seat = data; - GSource *source; - - /* There might be events queued in libinput that could cancel the - repeat timer. */ - dispatch_libinput (seat); - if (!seat->repeat_timer) - return G_SOURCE_REMOVE; - - g_return_val_if_fail (seat->repeat_device != NULL, G_SOURCE_REMOVE); - source = g_main_context_find_source_by_id (NULL, seat->repeat_timer); - - meta_seat_native_notify_key (seat, - seat->repeat_device, - g_source_get_time (source), - seat->repeat_key, - AUTOREPEAT_VALUE, - FALSE); - - return G_SOURCE_CONTINUE; -} - -static void -queue_event (MetaSeatNative *seat, - ClutterEvent *event) -{ - ClutterStage *stage = meta_seat_native_get_stage (seat); - - if (!stage) - { - /* No stage yet, drop this event on the floor */ - clutter_event_free (event); - return; - } - - event->any.stage = stage; - _clutter_event_push (event, FALSE); -} - -static int -update_button_count (MetaSeatNative *seat, - uint32_t button, - uint32_t state) -{ - if (state) - { - return ++seat->button_count[button]; - } - else - { - /* Handle cases where we newer saw the initial pressed event. */ - if (seat->button_count[button] == 0) - { - meta_topic (META_DEBUG_INPUT, - "Counting release of key 0x%x and count is already 0", - button); - return 0; - } - - return --seat->button_count[button]; - } -} - -void -meta_seat_native_notify_key (MetaSeatNative *seat, - ClutterInputDevice *device, - uint64_t time_us, - uint32_t key, - uint32_t state, - gboolean update_keys) -{ - ClutterEvent *event = NULL; - enum xkb_state_component changed_state; - - if (state != AUTOREPEAT_VALUE) - { - /* Drop any repeated button press (for example from virtual devices. */ - int count = update_button_count (seat, key, state); - if ((state && count > 1) || - (!state && count != 0)) - { - meta_topic (META_DEBUG_INPUT, - "Dropping repeated %s of key 0x%x, count %d, state %d", - state ? "press" : "release", key, count, state); - return; - } - } - - event = meta_key_event_new_from_evdev (device, - seat->core_keyboard, - seat->xkb, - seat->button_state, - us2ms (time_us), key, state); - meta_event_native_set_event_code (event, key); - - /* We must be careful and not pass multiple releases to xkb, otherwise it gets - confused and locks the modifiers */ - if (state != AUTOREPEAT_VALUE) - { - changed_state = xkb_state_update_key (seat->xkb, - event->key.hardware_keycode, - state ? XKB_KEY_DOWN : XKB_KEY_UP); - } - else - { - changed_state = 0; - clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_REPEATED); - } - - queue_event (seat, event); - - if (update_keys && (changed_state & XKB_STATE_LEDS)) - { - g_signal_emit_by_name (seat->keymap, "state-changed"); - meta_seat_native_sync_leds (seat); - meta_input_device_native_a11y_maybe_notify_toggle_keys (META_INPUT_DEVICE_NATIVE (seat->core_keyboard)); - } - - if (state == 0 || /* key release */ - !seat->repeat || - !xkb_keymap_key_repeats (xkb_state_get_keymap (seat->xkb), - event->key.hardware_keycode)) - { - meta_seat_native_clear_repeat_timer (seat); - return; - } - - if (state == 1) /* key press */ - seat->repeat_count = 0; - - seat->repeat_count += 1; - seat->repeat_key = key; - - switch (seat->repeat_count) - { - case 1: - case 2: - { - uint32_t interval; - - meta_seat_native_clear_repeat_timer (seat); - seat->repeat_device = g_object_ref (device); - - if (seat->repeat_count == 1) - interval = seat->repeat_delay; - else - interval = seat->repeat_interval; - - seat->repeat_timer = - clutter_threads_add_timeout_full (CLUTTER_PRIORITY_EVENTS, - interval, - keyboard_repeat, - seat, - NULL); - return; - } - default: - return; - } -} - -static ClutterEvent * -new_absolute_motion_event (MetaSeatNative *seat, - ClutterInputDevice *input_device, - uint64_t time_us, - float x, - float y, - double *axes) -{ - ClutterStage *stage = meta_seat_native_get_stage (seat); - ClutterEvent *event; - - event = clutter_event_new (CLUTTER_MOTION); - - if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE) - { - meta_seat_native_constrain_pointer (seat, - seat->core_pointer, - time_us, - seat->pointer_x, - seat->pointer_y, - &x, &y); - } - - meta_event_native_set_time_usec (event, time_us); - event->motion.time = us2ms (time_us); - meta_xkb_translate_state (event, seat->xkb, seat->button_state); - event->motion.x = x; - event->motion.y = y; - meta_input_device_native_translate_coordinates (input_device, stage, - &event->motion.x, - &event->motion.y); - event->motion.axes = axes; - clutter_event_set_device (event, seat->core_pointer); - clutter_event_set_source_device (event, input_device); - - if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) - { - MetaInputDeviceNative *device_evdev = - META_INPUT_DEVICE_NATIVE (input_device); - - clutter_event_set_device_tool (event, device_evdev->last_tool); - clutter_event_set_device (event, input_device); - } - else - { - clutter_event_set_device (event, seat->core_pointer); - } - - if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE) - { - seat->pointer_x = x; - seat->pointer_y = y; - } - - return event; -} - -void -meta_seat_native_notify_relative_motion (MetaSeatNative *seat, - ClutterInputDevice *input_device, - uint64_t time_us, - float dx, - float dy, - float dx_unaccel, - float dy_unaccel) -{ - float new_x, new_y; - ClutterEvent *event; - - meta_seat_native_filter_relative_motion (seat, - input_device, - seat->pointer_x, - seat->pointer_y, - &dx, - &dy); - - new_x = seat->pointer_x + dx; - new_y = seat->pointer_y + dy; - event = new_absolute_motion_event (seat, input_device, - time_us, new_x, new_y, NULL); - - meta_event_native_set_relative_motion (event, - dx, dy, - dx_unaccel, dy_unaccel); - - queue_event (seat, event); -} - -void -meta_seat_native_notify_absolute_motion (MetaSeatNative *seat, - ClutterInputDevice *input_device, - uint64_t time_us, - float x, - float y, - double *axes) -{ - ClutterEvent *event; - - event = new_absolute_motion_event (seat, input_device, time_us, x, y, axes); - - queue_event (seat, event); -} - -void -meta_seat_native_notify_button (MetaSeatNative *seat, - ClutterInputDevice *input_device, - uint64_t time_us, - uint32_t button, - uint32_t state) -{ - MetaInputDeviceNative *device_evdev = (MetaInputDeviceNative *) input_device; - ClutterEvent *event = NULL; - int button_nr; - static int maskmap[8] = - { - CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON3_MASK, CLUTTER_BUTTON2_MASK, - CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK, 0, 0, 0 - }; - int button_count; - - /* Drop any repeated button press (for example from virtual devices. */ - button_count = update_button_count (seat, button, state); - if ((state && button_count > 1) || - (!state && button_count != 0)) - { - meta_topic (META_DEBUG_INPUT, - "Dropping repeated %s of button 0x%x, count %d", - state ? "press" : "release", button, button_count); - return; - } - - /* The evdev button numbers don't map sequentially to clutter button - * numbers (the right and middle mouse buttons are in the opposite - * order) so we'll map them directly with a switch statement */ - switch (button) - { - case BTN_LEFT: - case BTN_TOUCH: - button_nr = CLUTTER_BUTTON_PRIMARY; - break; - - case BTN_RIGHT: - case BTN_STYLUS: - button_nr = CLUTTER_BUTTON_SECONDARY; - break; - - case BTN_MIDDLE: - case BTN_STYLUS2: - button_nr = CLUTTER_BUTTON_MIDDLE; - break; - - case 0x149: /* BTN_STYLUS3 */ - button_nr = 8; - break; - - default: - /* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */ - if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) - button_nr = button - BTN_TOOL_PEN + 4; - else - button_nr = button - (BTN_LEFT - 1) + 4; - break; - } - - if (button_nr < 1 || button_nr > 12) - { - g_warning ("Unhandled button event 0x%x", button); - return; - } - - if (state) - event = clutter_event_new (CLUTTER_BUTTON_PRESS); - else - event = clutter_event_new (CLUTTER_BUTTON_RELEASE); - - if (button_nr < G_N_ELEMENTS (maskmap)) - { - /* Update the modifiers */ - if (state) - seat->button_state |= maskmap[button_nr - 1]; - else - seat->button_state &= ~maskmap[button_nr - 1]; - } - - meta_event_native_set_time_usec (event, time_us); - event->button.time = us2ms (time_us); - meta_xkb_translate_state (event, seat->xkb, seat->button_state); - event->button.button = button_nr; - - if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) - { - graphene_point_t point; - - clutter_input_device_get_coords (input_device, NULL, &point); - event->button.x = point.x; - event->button.y = point.y; - } - else - { - event->button.x = seat->pointer_x; - event->button.y = seat->pointer_y; - } - - clutter_event_set_device (event, seat->core_pointer); - clutter_event_set_source_device (event, input_device); - - if (device_evdev->last_tool) - { - /* Apply the button event code as per the tool mapping */ - uint32_t mapped_button; - - mapped_button = meta_input_device_tool_native_get_button_code (device_evdev->last_tool, - button_nr); - if (mapped_button != 0) - button = mapped_button; - } - - meta_event_native_set_event_code (event, button); - - if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE) - { - clutter_event_set_device_tool (event, device_evdev->last_tool); - clutter_event_set_device (event, input_device); - } - else - { - clutter_event_set_device (event, seat->core_pointer); - } - - queue_event (seat, event); -} - -static void -notify_scroll (ClutterInputDevice *input_device, - uint64_t time_us, - double dx, - double dy, - ClutterScrollSource scroll_source, - ClutterScrollFinishFlags flags, - gboolean emulated) -{ - MetaInputDeviceNative *device_evdev; - MetaSeatNative *seat; - ClutterEvent *event = NULL; - double scroll_factor; - - device_evdev = META_INPUT_DEVICE_NATIVE (input_device); - seat = meta_input_device_native_get_seat (device_evdev); - - event = clutter_event_new (CLUTTER_SCROLL); - - meta_event_native_set_time_usec (event, time_us); - event->scroll.time = us2ms (time_us); - meta_xkb_translate_state (event, seat->xkb, seat->button_state); - - /* libinput pointer axis events are in pointer motion coordinate space. - * To convert to Xi2 discrete step coordinate space, multiply the factor - * 1/10. */ - event->scroll.direction = CLUTTER_SCROLL_SMOOTH; - scroll_factor = 1.0 / DISCRETE_SCROLL_STEP; - clutter_event_set_scroll_delta (event, - scroll_factor * dx, - scroll_factor * dy); - - event->scroll.x = seat->pointer_x; - event->scroll.y = seat->pointer_y; - clutter_event_set_device (event, seat->core_pointer); - clutter_event_set_source_device (event, input_device); - event->scroll.scroll_source = scroll_source; - event->scroll.finish_flags = flags; - - _clutter_event_set_pointer_emulated (event, emulated); - - queue_event (seat, event); -} - -static void -notify_discrete_scroll (ClutterInputDevice *input_device, - uint64_t time_us, - ClutterScrollDirection direction, - ClutterScrollSource scroll_source, - gboolean emulated) -{ - MetaInputDeviceNative *device_evdev; - MetaSeatNative *seat; - ClutterEvent *event = NULL; - - if (direction == CLUTTER_SCROLL_SMOOTH) - return; - - device_evdev = META_INPUT_DEVICE_NATIVE (input_device); - seat = meta_input_device_native_get_seat (device_evdev); - - event = clutter_event_new (CLUTTER_SCROLL); - - meta_event_native_set_time_usec (event, time_us); - event->scroll.time = us2ms (time_us); - meta_xkb_translate_state (event, seat->xkb, seat->button_state); - - event->scroll.direction = direction; - - event->scroll.x = seat->pointer_x; - event->scroll.y = seat->pointer_y; - clutter_event_set_device (event, seat->core_pointer); - clutter_event_set_source_device (event, input_device); - event->scroll.scroll_source = scroll_source; - - _clutter_event_set_pointer_emulated (event, emulated); - - queue_event (seat, event); -} - -static void -check_notify_discrete_scroll (MetaSeatNative *seat, - ClutterInputDevice *device, - uint64_t time_us, - ClutterScrollSource scroll_source) -{ - int i, n_xscrolls, n_yscrolls; - - n_xscrolls = floor (fabs (seat->accum_scroll_dx) / DISCRETE_SCROLL_STEP); - n_yscrolls = floor (fabs (seat->accum_scroll_dy) / DISCRETE_SCROLL_STEP); - - for (i = 0; i < n_xscrolls; i++) - { - notify_discrete_scroll (device, time_us, - seat->accum_scroll_dx > 0 ? - CLUTTER_SCROLL_RIGHT : CLUTTER_SCROLL_LEFT, - scroll_source, TRUE); - } - - for (i = 0; i < n_yscrolls; i++) - { - notify_discrete_scroll (device, time_us, - seat->accum_scroll_dy > 0 ? - CLUTTER_SCROLL_DOWN : CLUTTER_SCROLL_UP, - scroll_source, TRUE); - } - - seat->accum_scroll_dx = fmodf (seat->accum_scroll_dx, DISCRETE_SCROLL_STEP); - seat->accum_scroll_dy = fmodf (seat->accum_scroll_dy, DISCRETE_SCROLL_STEP); -} - -void -meta_seat_native_notify_scroll_continuous (MetaSeatNative *seat, - ClutterInputDevice *input_device, - uint64_t time_us, - double dx, - double dy, - ClutterScrollSource scroll_source, - ClutterScrollFinishFlags finish_flags) -{ - if (finish_flags & CLUTTER_SCROLL_FINISHED_HORIZONTAL) - seat->accum_scroll_dx = 0; - else - seat->accum_scroll_dx += dx; - - if (finish_flags & CLUTTER_SCROLL_FINISHED_VERTICAL) - seat->accum_scroll_dy = 0; - else - seat->accum_scroll_dy += dy; - - notify_scroll (input_device, time_us, dx, dy, scroll_source, - finish_flags, FALSE); - check_notify_discrete_scroll (seat, input_device, time_us, scroll_source); -} - -static ClutterScrollDirection -discrete_to_direction (double discrete_dx, - double discrete_dy) -{ - if (discrete_dx > 0) - return CLUTTER_SCROLL_RIGHT; - else if (discrete_dx < 0) - return CLUTTER_SCROLL_LEFT; - else if (discrete_dy > 0) - return CLUTTER_SCROLL_DOWN; - else if (discrete_dy < 0) - return CLUTTER_SCROLL_UP; - else - g_assert_not_reached (); - return 0; -} - -void -meta_seat_native_notify_discrete_scroll (MetaSeatNative *seat, - ClutterInputDevice *input_device, - uint64_t time_us, - double discrete_dx, - double discrete_dy, - ClutterScrollSource scroll_source) -{ - notify_scroll (input_device, time_us, - discrete_dx * DISCRETE_SCROLL_STEP, - discrete_dy * DISCRETE_SCROLL_STEP, - scroll_source, CLUTTER_SCROLL_FINISHED_NONE, - TRUE); - notify_discrete_scroll (input_device, time_us, - discrete_to_direction (discrete_dx, discrete_dy), - scroll_source, FALSE); - -} - -void -meta_seat_native_notify_touch_event (MetaSeatNative *seat, - ClutterInputDevice *input_device, - ClutterEventType evtype, - uint64_t time_us, - int slot, - double x, - double y) -{ - ClutterStage *stage = meta_seat_native_get_stage (seat); - ClutterEvent *event = NULL; - - event = clutter_event_new (evtype); - - meta_event_native_set_time_usec (event, time_us); - event->touch.time = us2ms (time_us); - event->touch.x = x; - event->touch.y = y; - meta_input_device_native_translate_coordinates (input_device, stage, - &event->touch.x, - &event->touch.y); - - /* "NULL" sequences are special cased in clutter */ - event->touch.sequence = GINT_TO_POINTER (MAX (1, slot + 1)); - meta_xkb_translate_state (event, seat->xkb, seat->button_state); - - if (evtype == CLUTTER_TOUCH_BEGIN || - evtype == CLUTTER_TOUCH_UPDATE) - event->touch.modifier_state |= CLUTTER_BUTTON1_MASK; - - clutter_event_set_device (event, seat->core_pointer); - clutter_event_set_source_device (event, input_device); - - queue_event (seat, event); -} - - -/* - * MetaEventSource for reading input devices - */ -static gboolean -meta_event_prepare (GSource *source, - gint *timeout) -{ - gboolean retval; - - *timeout = -1; - retval = clutter_events_pending (); - - return retval; -} - -static gboolean -meta_event_check (GSource *source) -{ - MetaEventSource *event_source = (MetaEventSource *) source; - gboolean retval; - - retval = ((event_source->event_poll_fd.revents & G_IO_IN) || - clutter_events_pending ()); - - return retval; -} - -static void -constrain_to_barriers (MetaSeatNative *seat, - ClutterInputDevice *device, - uint32_t time, - float *new_x, - float *new_y) -{ - meta_barrier_manager_native_process (seat->barrier_manager, - device, - time, - new_x, new_y); -} - -/* - * The pointer constrain code is mostly a rip-off of the XRandR code from Xorg. - * (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder) - * - * Copyright © 2006 Keith Packard - * Copyright 2010 Red Hat, Inc - * - */ - -static void -constrain_all_screen_monitors (ClutterInputDevice *device, - MetaMonitorManager *monitor_manager, - float *x, - float *y) -{ - graphene_point_t current; - float cx, cy; - GList *logical_monitors, *l; - - clutter_input_device_get_coords (device, NULL, ¤t); - - cx = current.x; - cy = current.y; - - /* if we're trying to escape, clamp to the CRTC we're coming from */ - - logical_monitors = - meta_monitor_manager_get_logical_monitors (monitor_manager); - for (l = logical_monitors; l; l = l->next) - { - MetaLogicalMonitor *logical_monitor = l->data; - int left, right, top, bottom; - - left = logical_monitor->rect.x; - right = left + logical_monitor->rect.width; - top = logical_monitor->rect.y; - bottom = top + logical_monitor->rect.height; - - if ((cx >= left) && (cx < right) && (cy >= top) && (cy < bottom)) - { - if (*x < left) - *x = left; - if (*x >= right) - *x = right - 1; - if (*y < top) - *y = top; - if (*y >= bottom) - *y = bottom - 1; - - return; - } - } -} - -void -meta_seat_native_constrain_pointer (MetaSeatNative *seat, - ClutterInputDevice *core_pointer, - uint64_t time_us, - float x, - float y, - float *new_x, - float *new_y) -{ - MetaBackend *backend = meta_get_backend (); - MetaMonitorManager *monitor_manager = - meta_backend_get_monitor_manager (backend); - - constrain_to_barriers (seat, core_pointer, - us2ms (time_us), - new_x, new_y); - - if (seat->constrain_callback) - { - seat->constrain_callback (core_pointer, - us2ms (time_us), - x, y, - new_x, new_y, - seat->constrain_data); - } - - /* if we're moving inside a monitor, we're fine */ - if (meta_monitor_manager_get_logical_monitor_at (monitor_manager, - *new_x, *new_y)) - return; - - /* if we're trying to escape, clamp to the CRTC we're coming from */ - constrain_all_screen_monitors (core_pointer, monitor_manager, new_x, new_y); -} - -static void -relative_motion_across_outputs (MetaMonitorManager *monitor_manager, - MetaLogicalMonitor *current, - float cur_x, - float cur_y, - float *dx_inout, - float *dy_inout) -{ - MetaLogicalMonitor *cur = current; - float x = cur_x, y = cur_y; - float target_x = cur_x, target_y = cur_y; - float dx = *dx_inout, dy = *dy_inout; - MetaDisplayDirection direction = -1; - - while (cur) - { - MetaLine2 left, right, top, bottom, motion; - MetaVector2 intersection; - - motion = (MetaLine2) { - .a = { x, y }, - .b = { x + (dx * cur->scale), y + (dy * cur->scale) } - }; - left = (MetaLine2) { - { cur->rect.x, cur->rect.y }, - { cur->rect.x, cur->rect.y + cur->rect.height } - }; - right = (MetaLine2) { - { cur->rect.x + cur->rect.width, cur->rect.y }, - { cur->rect.x + cur->rect.width, cur->rect.y + cur->rect.height } - }; - top = (MetaLine2) { - { cur->rect.x, cur->rect.y }, - { cur->rect.x + cur->rect.width, cur->rect.y } - }; - bottom = (MetaLine2) { - { cur->rect.x, cur->rect.y + cur->rect.height }, - { cur->rect.x + cur->rect.width, cur->rect.y + cur->rect.height } - }; - - target_x = motion.b.x; - target_y = motion.b.y; - - if (direction != META_DISPLAY_RIGHT && - meta_line2_intersects_with (&motion, &left, &intersection)) - direction = META_DISPLAY_LEFT; - else if (direction != META_DISPLAY_LEFT && - meta_line2_intersects_with (&motion, &right, &intersection)) - direction = META_DISPLAY_RIGHT; - else if (direction != META_DISPLAY_DOWN && - meta_line2_intersects_with (&motion, &top, &intersection)) - direction = META_DISPLAY_UP; - else if (direction != META_DISPLAY_UP && - meta_line2_intersects_with (&motion, &bottom, &intersection)) - direction = META_DISPLAY_DOWN; - else - /* We reached the dest logical monitor */ - break; - - x = intersection.x; - y = intersection.y; - dx -= intersection.x - motion.a.x; - dy -= intersection.y - motion.a.y; - - cur = meta_monitor_manager_get_logical_monitor_neighbor (monitor_manager, - cur, direction); - } - - *dx_inout = target_x - cur_x; - *dy_inout = target_y - cur_y; -} - -void -meta_seat_native_filter_relative_motion (MetaSeatNative *seat, - ClutterInputDevice *device, - float x, - float y, - float *dx, - float *dy) -{ - MetaBackend *backend = meta_get_backend (); - MetaMonitorManager *monitor_manager = - meta_backend_get_monitor_manager (backend); - MetaLogicalMonitor *logical_monitor, *dest_logical_monitor; - float new_dx, new_dy; - - if (meta_is_stage_views_scaled ()) - return; - - logical_monitor = meta_monitor_manager_get_logical_monitor_at (monitor_manager, - x, y); - if (!logical_monitor) - return; - - new_dx = (*dx) * logical_monitor->scale; - new_dy = (*dy) * logical_monitor->scale; - - dest_logical_monitor = meta_monitor_manager_get_logical_monitor_at (monitor_manager, - x + new_dx, - y + new_dy); - if (dest_logical_monitor && - dest_logical_monitor != logical_monitor) - { - /* If we are crossing monitors, attempt to bisect the distance on each - * axis and apply the relative scale for each of them. - */ - new_dx = *dx; - new_dy = *dy; - relative_motion_across_outputs (monitor_manager, logical_monitor, - x, y, &new_dx, &new_dy); - } - - *dx = new_dx; - *dy = new_dy; -} - -static void -notify_absolute_motion (ClutterInputDevice *input_device, - uint64_t time_us, - float x, - float y, - double *axes) -{ - MetaSeatNative *seat; - ClutterEvent *event; - - seat = meta_input_device_native_get_seat (META_INPUT_DEVICE_NATIVE (input_device)); - event = new_absolute_motion_event (seat, input_device, time_us, x, y, axes); - - queue_event (seat, event); -} - -static void -notify_relative_tool_motion (ClutterInputDevice *input_device, - uint64_t time_us, - float dx, - float dy, - double *axes) -{ - MetaInputDeviceNative *device_evdev; - ClutterEvent *event; - MetaSeatNative *seat; - gfloat x, y; - - device_evdev = META_INPUT_DEVICE_NATIVE (input_device); - seat = meta_input_device_native_get_seat (device_evdev); - x = input_device->current_x + dx; - y = input_device->current_y + dy; - - meta_seat_native_filter_relative_motion (seat, - input_device, - seat->pointer_x, - seat->pointer_y, - &dx, - &dy); - - event = new_absolute_motion_event (seat, input_device, time_us, x, y, axes); - meta_event_native_set_relative_motion (event, dx, dy, 0, 0); - - queue_event (seat, event); -} - -static void -notify_pinch_gesture_event (ClutterInputDevice *input_device, - ClutterTouchpadGesturePhase phase, - uint64_t time_us, - double dx, - double dy, - double angle_delta, - double scale, - uint32_t n_fingers) -{ - MetaInputDeviceNative *device_evdev; - MetaSeatNative *seat; - ClutterEvent *event = NULL; - graphene_point_t pos; - - device_evdev = META_INPUT_DEVICE_NATIVE (input_device); - seat = meta_input_device_native_get_seat (device_evdev); - - event = clutter_event_new (CLUTTER_TOUCHPAD_PINCH); - - clutter_input_device_get_coords (seat->core_pointer, NULL, &pos); - - meta_event_native_set_time_usec (event, time_us); - event->touchpad_pinch.phase = phase; - event->touchpad_pinch.time = us2ms (time_us); - event->touchpad_pinch.x = pos.x; - event->touchpad_pinch.y = pos.y; - event->touchpad_pinch.dx = dx; - event->touchpad_pinch.dy = dy; - event->touchpad_pinch.angle_delta = angle_delta; - event->touchpad_pinch.scale = scale; - event->touchpad_pinch.n_fingers = n_fingers; - - meta_xkb_translate_state (event, seat->xkb, seat->button_state); - - clutter_event_set_device (event, seat->core_pointer); - clutter_event_set_source_device (event, input_device); - - queue_event (seat, event); -} - -static void -notify_swipe_gesture_event (ClutterInputDevice *input_device, - ClutterTouchpadGesturePhase phase, - uint64_t time_us, - uint32_t n_fingers, - double dx, - double dy) -{ - MetaInputDeviceNative *device_evdev; - MetaSeatNative *seat; - ClutterEvent *event = NULL; - graphene_point_t pos; - - device_evdev = META_INPUT_DEVICE_NATIVE (input_device); - seat = meta_input_device_native_get_seat (device_evdev); - - event = clutter_event_new (CLUTTER_TOUCHPAD_SWIPE); - - meta_event_native_set_time_usec (event, time_us); - event->touchpad_swipe.phase = phase; - event->touchpad_swipe.time = us2ms (time_us); - - clutter_input_device_get_coords (seat->core_pointer, NULL, &pos); - event->touchpad_swipe.x = pos.x; - event->touchpad_swipe.y = pos.y; - event->touchpad_swipe.dx = dx; - event->touchpad_swipe.dy = dy; - event->touchpad_swipe.n_fingers = n_fingers; - - meta_xkb_translate_state (event, seat->xkb, seat->button_state); - - clutter_event_set_device (event, seat->core_pointer); - clutter_event_set_source_device (event, input_device); - - queue_event (seat, event); -} - -static void -notify_proximity (ClutterInputDevice *input_device, - uint64_t time_us, - gboolean in) -{ - MetaInputDeviceNative *device_evdev; - MetaSeatNative *seat; - ClutterEvent *event = NULL; - - device_evdev = META_INPUT_DEVICE_NATIVE (input_device); - seat = meta_input_device_native_get_seat (device_evdev); - - if (in) - event = clutter_event_new (CLUTTER_PROXIMITY_IN); - else - event = clutter_event_new (CLUTTER_PROXIMITY_OUT); - - meta_event_native_set_time_usec (event, time_us); - - event->proximity.time = us2ms (time_us); - clutter_event_set_device_tool (event, device_evdev->last_tool); - clutter_event_set_device (event, seat->core_pointer); - clutter_event_set_source_device (event, input_device); - - queue_event (seat, event); -} - -static void -notify_pad_button (ClutterInputDevice *input_device, - uint64_t time_us, - uint32_t button, - uint32_t mode_group, - uint32_t mode, - uint32_t pressed) -{ - MetaInputDeviceNative *device_evdev; - MetaSeatNative *seat; - ClutterEvent *event; - - device_evdev = META_INPUT_DEVICE_NATIVE (input_device); - seat = meta_input_device_native_get_seat (device_evdev); - - if (pressed) - event = clutter_event_new (CLUTTER_PAD_BUTTON_PRESS); - else - event = clutter_event_new (CLUTTER_PAD_BUTTON_RELEASE); - - meta_event_native_set_time_usec (event, time_us); - event->pad_button.button = button; - event->pad_button.group = mode_group; - event->pad_button.mode = mode; - clutter_event_set_device (event, input_device); - clutter_event_set_source_device (event, input_device); - clutter_event_set_time (event, us2ms (time_us)); - - queue_event (seat, event); -} - -static void -notify_pad_strip (ClutterInputDevice *input_device, - uint64_t time_us, - uint32_t strip_number, - uint32_t strip_source, - uint32_t mode_group, - uint32_t mode, - double value) -{ - ClutterInputDevicePadSource source; - MetaInputDeviceNative *device_evdev; - MetaSeatNative *seat; - ClutterEvent *event; - - device_evdev = META_INPUT_DEVICE_NATIVE (input_device); - seat = meta_input_device_native_get_seat (device_evdev); - - if (strip_source == LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER) - source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER; - else - source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_UNKNOWN; - - event = clutter_event_new (CLUTTER_PAD_STRIP); - meta_event_native_set_time_usec (event, time_us); - event->pad_strip.strip_source = source; - event->pad_strip.strip_number = strip_number; - event->pad_strip.value = value; - event->pad_strip.group = mode_group; - event->pad_strip.mode = mode; - clutter_event_set_device (event, input_device); - clutter_event_set_source_device (event, input_device); - clutter_event_set_time (event, us2ms (time_us)); - - queue_event (seat, event); -} - -static void -notify_pad_ring (ClutterInputDevice *input_device, - uint64_t time_us, - uint32_t ring_number, - uint32_t ring_source, - uint32_t mode_group, - uint32_t mode, - double angle) -{ - ClutterInputDevicePadSource source; - MetaInputDeviceNative *device_evdev; - MetaSeatNative *seat; - ClutterEvent *event; - - device_evdev = META_INPUT_DEVICE_NATIVE (input_device); - seat = meta_input_device_native_get_seat (device_evdev); - - if (ring_source == LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER) - source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER; - else - source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_UNKNOWN; - - event = clutter_event_new (CLUTTER_PAD_RING); - meta_event_native_set_time_usec (event, time_us); - event->pad_ring.ring_source = source; - event->pad_ring.ring_number = ring_number; - event->pad_ring.angle = angle; - event->pad_ring.group = mode_group; - event->pad_ring.mode = mode; - clutter_event_set_device (event, input_device); - clutter_event_set_source_device (event, input_device); - clutter_event_set_time (event, us2ms (time_us)); - - queue_event (seat, event); -} - -static gboolean -meta_event_dispatch (GSource *g_source, - GSourceFunc callback, - gpointer user_data) -{ - MetaEventSource *source = (MetaEventSource *) g_source; - MetaSeatNative *seat; - ClutterEvent *event; - - seat = source->seat; - - /* Don't queue more events if we haven't finished handling the previous batch - */ - if (clutter_events_pending ()) - goto queue_event; - - dispatch_libinput (seat); - - queue_event: - event = clutter_event_get (); - - if (event) - { - ClutterModifierType event_state; - ClutterInputDevice *input_device = - clutter_event_get_source_device (event); - MetaInputDeviceNative *device_evdev = - META_INPUT_DEVICE_NATIVE (input_device); - MetaSeatNative *seat = - meta_input_device_native_get_seat (device_evdev); - - /* update the device states *before* the event */ - event_state = seat->button_state | - xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_EFFECTIVE); - _clutter_input_device_set_state (seat->core_pointer, event_state); - _clutter_input_device_set_state (seat->core_keyboard, event_state); - - /* forward the event into clutter for emission etc. */ - _clutter_stage_queue_event (event->any.stage, event, FALSE); - } - - return TRUE; -} -static GSourceFuncs event_funcs = { - meta_event_prepare, - meta_event_check, - meta_event_dispatch, - NULL -}; - -static MetaEventSource * -meta_event_source_new (MetaSeatNative *seat) -{ - GSource *source; - MetaEventSource *event_source; - gint fd; - - source = g_source_new (&event_funcs, sizeof (MetaEventSource)); - event_source = (MetaEventSource *) source; - - /* setup the source */ - event_source->seat = seat; - - fd = libinput_get_fd (seat->libinput); - event_source->event_poll_fd.fd = fd; - event_source->event_poll_fd.events = G_IO_IN; - - /* and finally configure and attach the GSource */ - g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS); - g_source_add_poll (source, &event_source->event_poll_fd); - g_source_set_can_recurse (source, TRUE); - g_source_attach (source, NULL); - - return event_source; -} - -static void -meta_event_source_free (MetaEventSource *source) -{ - GSource *g_source = (GSource *) source; - - /* ignore the return value of close, it's not like we can do something - * about it */ - close (source->event_poll_fd.fd); - - g_source_destroy (g_source); - g_source_unref (g_source); -} - -static gboolean -has_touchscreen (MetaSeatNative *seat) -{ - GSList *l; - - for (l = seat->devices; l; l = l->next) - { - ClutterInputDeviceType device_type; - - device_type = clutter_input_device_get_device_type (l->data); - - if (device_type == CLUTTER_TOUCHSCREEN_DEVICE) - return TRUE; - } - - return FALSE; -} - -static gboolean -has_tablet_switch (MetaSeatNative *seat) -{ - GSList *l; - - for (l = seat->devices; l; l = l->next) - { - MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (l->data); - - if (libinput_device_has_capability (device_native->libinput_device, - LIBINPUT_DEVICE_CAP_SWITCH) && - libinput_device_switch_has_switch (device_native->libinput_device, - LIBINPUT_SWITCH_TABLET_MODE)) - return TRUE; - } - - return FALSE; -} - -static void -update_touch_mode (MetaSeatNative *seat) -{ - gboolean touch_mode; - - /* No touch mode if we don't have a touchscreen, easy */ - if (!seat->has_touchscreen) - touch_mode = FALSE; - /* If we have a tablet mode switch, honor it being unset */ - else if (seat->has_tablet_switch && !seat->tablet_mode_switch_state) - touch_mode = FALSE; - /* If tablet mode is enabled, or if there is no tablet mode switch - * (eg. kiosk machines), assume touch-mode. - */ - else - touch_mode = TRUE; - - if (seat->touch_mode != touch_mode) - { - seat->touch_mode = touch_mode; - g_object_notify (G_OBJECT (seat), "touch-mode"); - } -} - -static ClutterInputDevice * -evdev_add_device (MetaSeatNative *seat, - struct libinput_device *libinput_device) -{ - ClutterInputDeviceType type; - ClutterInputDevice *device, *logical = NULL; - - device = meta_input_device_native_new (seat, libinput_device); - - seat->devices = g_slist_prepend (seat->devices, device); - - /* Clutter assumes that device types are exclusive in the - * ClutterInputDevice API */ - type = meta_input_device_native_determine_type (libinput_device); - - if (type == CLUTTER_KEYBOARD_DEVICE) - logical = seat->core_keyboard; - else if (type == CLUTTER_POINTER_DEVICE) - logical = seat->core_pointer; - - if (logical) - { - _clutter_input_device_set_associated_device (device, logical); - _clutter_input_device_add_physical_device (logical, device); - } - - return device; -} - -static void -evdev_remove_device (MetaSeatNative *seat, - MetaInputDeviceNative *device_evdev) -{ - ClutterInputDevice *device; - - device = CLUTTER_INPUT_DEVICE (device_evdev); - seat->devices = g_slist_remove (seat->devices, device); - - g_object_unref (device); -} - -static gboolean -meta_seat_native_handle_device_event (ClutterSeat *seat, - ClutterEvent *event) -{ - MetaSeatNative *seat_native = META_SEAT_NATIVE (seat); - ClutterInputDevice *device = event->device.device; - MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device); - gboolean is_touchscreen, is_tablet_switch; - - is_touchscreen = - clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE; - is_tablet_switch = - libinput_device_has_capability (device_native->libinput_device, - LIBINPUT_DEVICE_CAP_SWITCH) && - libinput_device_switch_has_switch (device_native->libinput_device, - LIBINPUT_SWITCH_TABLET_MODE); - - switch (event->type) - { - case CLUTTER_DEVICE_ADDED: - if (is_touchscreen) - seat_native->has_touchscreen = TRUE; - - if (is_tablet_switch) - seat_native->has_tablet_switch = TRUE; - break; - - case CLUTTER_DEVICE_REMOVED: - if (is_touchscreen) - seat_native->has_touchscreen = has_touchscreen (seat_native); - - if (is_tablet_switch) - seat_native->has_tablet_switch = has_tablet_switch (seat_native); - - if (seat_native->repeat_timer && seat_native->repeat_device == device) - meta_seat_native_clear_repeat_timer (seat_native); - break; - - default: - break; - } - - if (is_touchscreen || is_tablet_switch) - update_touch_mode (seat_native); - - return TRUE; -} - -static gboolean -process_base_event (MetaSeatNative *seat, - struct libinput_event *event) -{ - ClutterInputDevice *device = NULL; - ClutterEvent *device_event = NULL; - struct libinput_device *libinput_device; - ClutterStage *stage; - - stage = meta_seat_native_get_stage (seat); - - switch (libinput_event_get_type (event)) - { - case LIBINPUT_EVENT_DEVICE_ADDED: - libinput_device = libinput_event_get_device (event); - device = evdev_add_device (seat, libinput_device); - - if (stage) - { - device_event = clutter_event_new (CLUTTER_DEVICE_ADDED); - clutter_event_set_device (device_event, device); - } - break; - - case LIBINPUT_EVENT_DEVICE_REMOVED: - libinput_device = libinput_event_get_device (event); - - device = libinput_device_get_user_data (libinput_device); - - if (stage) - { - device_event = clutter_event_new (CLUTTER_DEVICE_REMOVED); - clutter_event_set_device (device_event, device); - } - - evdev_remove_device (seat, - META_INPUT_DEVICE_NATIVE (device)); - break; - - default: - break; - } - - if (device_event) - { - queue_event (seat, device_event); - return TRUE; - } - - return FALSE; -} - -static ClutterScrollSource -translate_scroll_source (enum libinput_pointer_axis_source source) -{ - switch (source) - { - case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: - return CLUTTER_SCROLL_SOURCE_WHEEL; - case LIBINPUT_POINTER_AXIS_SOURCE_FINGER: - return CLUTTER_SCROLL_SOURCE_FINGER; - case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: - return CLUTTER_SCROLL_SOURCE_CONTINUOUS; - default: - return CLUTTER_SCROLL_SOURCE_UNKNOWN; - } -} - -static ClutterInputDeviceToolType -translate_tool_type (struct libinput_tablet_tool *libinput_tool) -{ - enum libinput_tablet_tool_type tool; - - tool = libinput_tablet_tool_get_type (libinput_tool); - - switch (tool) - { - case LIBINPUT_TABLET_TOOL_TYPE_PEN: - return CLUTTER_INPUT_DEVICE_TOOL_PEN; - case LIBINPUT_TABLET_TOOL_TYPE_ERASER: - return CLUTTER_INPUT_DEVICE_TOOL_ERASER; - case LIBINPUT_TABLET_TOOL_TYPE_BRUSH: - return CLUTTER_INPUT_DEVICE_TOOL_BRUSH; - case LIBINPUT_TABLET_TOOL_TYPE_PENCIL: - return CLUTTER_INPUT_DEVICE_TOOL_PENCIL; - case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH: - return CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH; - case LIBINPUT_TABLET_TOOL_TYPE_MOUSE: - return CLUTTER_INPUT_DEVICE_TOOL_MOUSE; - case LIBINPUT_TABLET_TOOL_TYPE_LENS: - return CLUTTER_INPUT_DEVICE_TOOL_LENS; - default: - return CLUTTER_INPUT_DEVICE_TOOL_NONE; - } -} - -static void -input_device_update_tool (ClutterInputDevice *input_device, - struct libinput_tablet_tool *libinput_tool) -{ - MetaInputDeviceNative *evdev_device = META_INPUT_DEVICE_NATIVE (input_device); - MetaSeatNative *seat = meta_input_device_native_get_seat (evdev_device); - ClutterInputDeviceTool *tool = NULL; - ClutterInputDeviceToolType tool_type; - uint64_t tool_serial; - - if (libinput_tool) - { - tool_serial = libinput_tablet_tool_get_serial (libinput_tool); - tool_type = translate_tool_type (libinput_tool); - tool = clutter_input_device_lookup_tool (input_device, - tool_serial, tool_type); - - if (!tool) - { - tool = meta_input_device_tool_native_new (libinput_tool, - tool_serial, tool_type); - clutter_input_device_add_tool (input_device, tool); - } - } - - if (evdev_device->last_tool != tool) - { - evdev_device->last_tool = tool; - g_signal_emit_by_name (seat, "tool-changed", input_device, tool); - } -} - -static gdouble * -translate_tablet_axes (struct libinput_event_tablet_tool *tablet_event, - ClutterInputDeviceTool *tool) -{ - GArray *axes = g_array_new (FALSE, FALSE, sizeof (gdouble)); - struct libinput_tablet_tool *libinput_tool; - gdouble value; - - libinput_tool = libinput_event_tablet_tool_get_tool (tablet_event); + N_PROPS, - value = libinput_event_tablet_tool_get_x (tablet_event); - g_array_append_val (axes, value); - value = libinput_event_tablet_tool_get_y (tablet_event); - g_array_append_val (axes, value); + /* This property is overridden */ + PROP_TOUCH_MODE, +}; - if (libinput_tablet_tool_has_distance (libinput_tool)) - { - value = libinput_event_tablet_tool_get_distance (tablet_event); - g_array_append_val (axes, value); - } +static GParamSpec *props[N_PROPS] = { NULL }; - if (libinput_tablet_tool_has_pressure (libinput_tool)) - { - value = libinput_event_tablet_tool_get_pressure (tablet_event); - value = meta_input_device_tool_native_translate_pressure (tool, value); - g_array_append_val (axes, value); - } +G_DEFINE_TYPE (MetaSeatNative, meta_seat_native, CLUTTER_TYPE_SEAT) - if (libinput_tablet_tool_has_tilt (libinput_tool)) - { - value = libinput_event_tablet_tool_get_tilt_x (tablet_event); - g_array_append_val (axes, value); - value = libinput_event_tablet_tool_get_tilt_y (tablet_event); - g_array_append_val (axes, value); - } +static gboolean +meta_seat_native_handle_event_post (ClutterSeat *seat, + const ClutterEvent *event) +{ + MetaSeatNative *seat_native = META_SEAT_NATIVE (seat); + ClutterInputDevice *device = clutter_event_get_source_device (event); + ClutterEventType event_type = event->type; - if (libinput_tablet_tool_has_rotation (libinput_tool)) + if (event_type == CLUTTER_PROXIMITY_IN) { - value = libinput_event_tablet_tool_get_rotation (tablet_event); - g_array_append_val (axes, value); - } + MetaCursorRendererNative *cursor_renderer_native; - if (libinput_tablet_tool_has_slider (libinput_tool)) - { - value = libinput_event_tablet_tool_get_slider_position (tablet_event); - g_array_append_val (axes, value); - } + if (!seat_native->tablet_cursors) + { + seat_native->tablet_cursors = g_hash_table_new_full (NULL, NULL, NULL, + g_object_unref); + } - if (libinput_tablet_tool_has_wheel (libinput_tool)) - { - value = libinput_event_tablet_tool_get_wheel_delta (tablet_event); - g_array_append_val (axes, value); + cursor_renderer_native = + meta_cursor_renderer_native_new (meta_get_backend (), device); + g_hash_table_insert (seat_native->tablet_cursors, + device, cursor_renderer_native); + return TRUE; } - - if (axes->len == 0) + else if (event_type == CLUTTER_PROXIMITY_OUT) { - g_array_free (axes, TRUE); - return NULL; + if (seat_native->tablet_cursors) + g_hash_table_remove (seat_native->tablet_cursors, device); + return TRUE; } - else - return (gdouble *) g_array_free (axes, FALSE); -} - -static MetaSeatNative * -seat_from_device (ClutterInputDevice *device) -{ - MetaInputDeviceNative *device_evdev = META_INPUT_DEVICE_NATIVE (device); - - return meta_input_device_native_get_seat (device_evdev); -} - -static void -notify_continuous_axis (MetaSeatNative *seat, - ClutterInputDevice *device, - uint64_t time_us, - ClutterScrollSource scroll_source, - struct libinput_event_pointer *axis_event) -{ - gdouble dx = 0.0, dy = 0.0; - ClutterScrollFinishFlags finish_flags = CLUTTER_SCROLL_FINISHED_NONE; - - if (libinput_event_pointer_has_axis (axis_event, - LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) + else if (event_type == CLUTTER_DEVICE_ADDED) { - dx = libinput_event_pointer_get_axis_value ( - axis_event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); - - if (fabs (dx) < DBL_EPSILON) - finish_flags |= CLUTTER_SCROLL_FINISHED_HORIZONTAL; + if (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_LOGICAL) + seat_native->devices = g_list_prepend (seat_native->devices, g_object_ref (device)); } - if (libinput_event_pointer_has_axis (axis_event, - LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) + else if (event_type == CLUTTER_DEVICE_REMOVED) { - dy = libinput_event_pointer_get_axis_value ( - axis_event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + GList *l = g_list_find (seat_native->devices, device); - if (fabs (dy) < DBL_EPSILON) - finish_flags |= CLUTTER_SCROLL_FINISHED_VERTICAL; + if (l) + { + seat_native->devices = g_list_delete_link (seat_native->devices, l); + g_object_unref (device); + } } - meta_seat_native_notify_scroll_continuous (seat, device, time_us, - dx, dy, - scroll_source, finish_flags); + return FALSE; } static void -notify_discrete_axis (MetaSeatNative *seat, - ClutterInputDevice *device, - uint64_t time_us, - ClutterScrollSource scroll_source, - struct libinput_event_pointer *axis_event) +proxy_kbd_a11y_flags_changed (MetaSeatImpl *seat_impl, + MetaKeyboardA11yFlags new_flags, + MetaKeyboardA11yFlags what_changed, + MetaSeatNative *seat_native) { - gdouble discrete_dx = 0.0, discrete_dy = 0.0; - - if (libinput_event_pointer_has_axis (axis_event, - LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) - { - discrete_dx = libinput_event_pointer_get_axis_value_discrete ( - axis_event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); - } - if (libinput_event_pointer_has_axis (axis_event, - LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) - { - discrete_dy = libinput_event_pointer_get_axis_value_discrete ( - axis_event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); - } - - meta_seat_native_notify_discrete_scroll (seat, device, - time_us, - discrete_dx, discrete_dy, - scroll_source); + g_signal_emit_by_name (seat_native, + "kbd-a11y-flags-changed", + new_flags, what_changed); } static void -process_tablet_axis (MetaSeatNative *seat, - struct libinput_event *event) -{ - struct libinput_device *libinput_device = libinput_event_get_device (event); - ClutterStage *stage = meta_seat_native_get_stage (seat); - uint64_t time; - double x, y, dx, dy, *axes; - float stage_width, stage_height; - ClutterInputDevice *device; - struct libinput_event_tablet_tool *tablet_event = - libinput_event_get_tablet_tool_event (event); - MetaInputDeviceNative *evdev_device; - - device = libinput_device_get_user_data (libinput_device); - evdev_device = META_INPUT_DEVICE_NATIVE (device); - - axes = translate_tablet_axes (tablet_event, - evdev_device->last_tool); - if (!axes) - return; - - stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); - stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); - - time = libinput_event_tablet_tool_get_time_usec (tablet_event); - - if (meta_input_device_native_get_mapping_mode (device) == META_INPUT_DEVICE_MAPPING_RELATIVE || - clutter_input_device_tool_get_tool_type (evdev_device->last_tool) == CLUTTER_INPUT_DEVICE_TOOL_MOUSE || - clutter_input_device_tool_get_tool_type (evdev_device->last_tool) == CLUTTER_INPUT_DEVICE_TOOL_LENS) - { - dx = libinput_event_tablet_tool_get_dx (tablet_event); - dy = libinput_event_tablet_tool_get_dy (tablet_event); - notify_relative_tool_motion (device, time, dx, dy, axes); - } - else - { - x = libinput_event_tablet_tool_get_x_transformed (tablet_event, stage_width); - y = libinput_event_tablet_tool_get_y_transformed (tablet_event, stage_height); - notify_absolute_motion (device, time, x, y, axes); - } -} - -static gboolean -process_device_event (MetaSeatNative *seat, - struct libinput_event *event) +proxy_kbd_a11y_mods_state_changed (MetaSeatImpl *seat_impl, + xkb_mod_mask_t new_latched_mods, + xkb_mod_mask_t new_locked_mods, + MetaSeatNative *seat_native) { - gboolean handled = TRUE; - struct libinput_device *libinput_device = libinput_event_get_device(event); - ClutterInputDevice *device; - MetaInputDeviceNative *device_evdev; - - switch (libinput_event_get_type (event)) - { - case LIBINPUT_EVENT_KEYBOARD_KEY: - { - uint32_t key, key_state, seat_key_count; - uint64_t time_us; - struct libinput_event_keyboard *key_event = - libinput_event_get_keyboard_event (event); - - device = libinput_device_get_user_data (libinput_device); - time_us = libinput_event_keyboard_get_time_usec (key_event); - key = libinput_event_keyboard_get_key (key_event); - key_state = libinput_event_keyboard_get_key_state (key_event) == - LIBINPUT_KEY_STATE_PRESSED; - seat_key_count = - libinput_event_keyboard_get_seat_key_count (key_event); - - /* Ignore key events that are not seat wide state changes. */ - if ((key_state == LIBINPUT_KEY_STATE_PRESSED && - seat_key_count != 1) || - (key_state == LIBINPUT_KEY_STATE_RELEASED && - seat_key_count != 0)) - { - meta_topic (META_DEBUG_INPUT, - "Dropping key-%s of key 0x%x because seat-wide " - "key count is %d", - key_state == LIBINPUT_KEY_STATE_PRESSED ? "press" : "release", - key, seat_key_count); - break; - } - - meta_seat_native_notify_key (seat_from_device (device), - device, - time_us, key, key_state, TRUE); - - break; - } - - case LIBINPUT_EVENT_POINTER_MOTION: - { - struct libinput_event_pointer *pointer_event = - libinput_event_get_pointer_event (event); - uint64_t time_us; - double dx; - double dy; - double dx_unaccel; - double dy_unaccel; - - device = libinput_device_get_user_data (libinput_device); - time_us = libinput_event_pointer_get_time_usec (pointer_event); - dx = libinput_event_pointer_get_dx (pointer_event); - dy = libinput_event_pointer_get_dy (pointer_event); - dx_unaccel = libinput_event_pointer_get_dx_unaccelerated (pointer_event); - dy_unaccel = libinput_event_pointer_get_dy_unaccelerated (pointer_event); - - meta_seat_native_notify_relative_motion (seat_from_device (device), - device, - time_us, - dx, dy, - dx_unaccel, dy_unaccel); - - break; - } - - case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: - { - uint64_t time_us; - double x, y; - float stage_width, stage_height; - ClutterStage *stage = meta_seat_native_get_stage (seat); - struct libinput_event_pointer *motion_event = - libinput_event_get_pointer_event (event); - device = libinput_device_get_user_data (libinput_device); - - stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); - stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); - - time_us = libinput_event_pointer_get_time_usec (motion_event); - x = libinput_event_pointer_get_absolute_x_transformed (motion_event, - stage_width); - y = libinput_event_pointer_get_absolute_y_transformed (motion_event, - stage_height); - - meta_seat_native_notify_absolute_motion (seat_from_device (device), - device, - time_us, - x, y, - NULL); - - break; - } - - case LIBINPUT_EVENT_POINTER_BUTTON: - { - uint32_t button, button_state, seat_button_count; - uint64_t time_us; - struct libinput_event_pointer *button_event = - libinput_event_get_pointer_event (event); - device = libinput_device_get_user_data (libinput_device); - - time_us = libinput_event_pointer_get_time_usec (button_event); - button = libinput_event_pointer_get_button (button_event); - button_state = libinput_event_pointer_get_button_state (button_event) == - LIBINPUT_BUTTON_STATE_PRESSED; - seat_button_count = - libinput_event_pointer_get_seat_button_count (button_event); - - /* Ignore button events that are not seat wide state changes. */ - if ((button_state == LIBINPUT_BUTTON_STATE_PRESSED && - seat_button_count != 1) || - (button_state == LIBINPUT_BUTTON_STATE_RELEASED && - seat_button_count != 0)) - { - meta_topic (META_DEBUG_INPUT, - "Dropping button-%s of button 0x%x because seat-wide " - "button count is %d", - button_state == LIBINPUT_BUTTON_STATE_PRESSED ? "press" : "release", - button, seat_button_count); - break; - } - - meta_seat_native_notify_button (seat_from_device (device), device, - time_us, button, button_state); - break; - } - - case LIBINPUT_EVENT_POINTER_AXIS: - { - uint64_t time_us; - enum libinput_pointer_axis_source source; - struct libinput_event_pointer *axis_event = - libinput_event_get_pointer_event (event); - MetaSeatNative *seat; - ClutterScrollSource scroll_source; - - device = libinput_device_get_user_data (libinput_device); - seat = meta_input_device_native_get_seat (META_INPUT_DEVICE_NATIVE (device)); - - time_us = libinput_event_pointer_get_time_usec (axis_event); - source = libinput_event_pointer_get_axis_source (axis_event); - scroll_source = translate_scroll_source (source); - - /* libinput < 0.8 sent wheel click events with value 10. Since 0.8 - the value is the angle of the click in degrees. To keep - backwards-compat with existing clients, we just send multiples of - the click count. */ - - switch (scroll_source) - { - case CLUTTER_SCROLL_SOURCE_WHEEL: - notify_discrete_axis (seat, device, time_us, scroll_source, - axis_event); - break; - case CLUTTER_SCROLL_SOURCE_FINGER: - case CLUTTER_SCROLL_SOURCE_CONTINUOUS: - case CLUTTER_SCROLL_SOURCE_UNKNOWN: - notify_continuous_axis (seat, device, time_us, scroll_source, - axis_event); - break; - } - break; - } - - case LIBINPUT_EVENT_TOUCH_DOWN: - { - int seat_slot; - uint64_t time_us; - double x, y; - float stage_width, stage_height; - MetaSeatNative *seat; - ClutterStage *stage; - MetaTouchState *touch_state; - struct libinput_event_touch *touch_event = - libinput_event_get_touch_event (event); - - device = libinput_device_get_user_data (libinput_device); - device_evdev = META_INPUT_DEVICE_NATIVE (device); - seat = meta_input_device_native_get_seat (device_evdev); - stage = meta_seat_native_get_stage (seat); - - stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); - stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); - - seat_slot = libinput_event_touch_get_seat_slot (touch_event); - time_us = libinput_event_touch_get_time_usec (touch_event); - x = libinput_event_touch_get_x_transformed (touch_event, - stage_width); - y = libinput_event_touch_get_y_transformed (touch_event, - stage_height); - - touch_state = meta_seat_native_acquire_touch_state (seat, seat_slot); - touch_state->coords.x = x; - touch_state->coords.y = y; - - meta_seat_native_notify_touch_event (seat, device, - CLUTTER_TOUCH_BEGIN, - time_us, - touch_state->seat_slot, - touch_state->coords.x, - touch_state->coords.y); - break; - } - - case LIBINPUT_EVENT_TOUCH_UP: - { - int seat_slot; - uint64_t time_us; - MetaSeatNative *seat; - MetaTouchState *touch_state; - struct libinput_event_touch *touch_event = - libinput_event_get_touch_event (event); - - device = libinput_device_get_user_data (libinput_device); - device_evdev = META_INPUT_DEVICE_NATIVE (device); - seat = meta_input_device_native_get_seat (device_evdev); - - seat_slot = libinput_event_touch_get_seat_slot (touch_event); - time_us = libinput_event_touch_get_time_usec (touch_event); - touch_state = meta_seat_native_lookup_touch_state (seat, seat_slot); - if (!touch_state) - break; - - meta_seat_native_notify_touch_event (seat, device, - CLUTTER_TOUCH_END, time_us, - touch_state->seat_slot, - touch_state->coords.x, - touch_state->coords.y); - meta_seat_native_release_touch_state (seat, seat_slot); - break; - } - - case LIBINPUT_EVENT_TOUCH_MOTION: - { - int seat_slot; - uint64_t time_us; - double x, y; - float stage_width, stage_height; - MetaSeatNative *seat; - ClutterStage *stage; - MetaTouchState *touch_state; - struct libinput_event_touch *touch_event = - libinput_event_get_touch_event (event); - - device = libinput_device_get_user_data (libinput_device); - device_evdev = META_INPUT_DEVICE_NATIVE (device); - seat = meta_input_device_native_get_seat (device_evdev); - stage = meta_seat_native_get_stage (seat); - - stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); - stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); - - seat_slot = libinput_event_touch_get_seat_slot (touch_event); - time_us = libinput_event_touch_get_time_usec (touch_event); - x = libinput_event_touch_get_x_transformed (touch_event, - stage_width); - y = libinput_event_touch_get_y_transformed (touch_event, - stage_height); - - touch_state = meta_seat_native_lookup_touch_state (seat, seat_slot); - if (!touch_state) - break; - - touch_state->coords.x = x; - touch_state->coords.y = y; - - meta_seat_native_notify_touch_event (seat, device, - CLUTTER_TOUCH_UPDATE, - time_us, - touch_state->seat_slot, - touch_state->coords.x, - touch_state->coords.y); - break; - } - case LIBINPUT_EVENT_TOUCH_CANCEL: - { - int seat_slot; - MetaTouchState *touch_state; - uint64_t time_us; - MetaSeatNative *seat; - struct libinput_event_touch *touch_event = - libinput_event_get_touch_event (event); - - device = libinput_device_get_user_data (libinput_device); - device_evdev = META_INPUT_DEVICE_NATIVE (device); - seat = meta_input_device_native_get_seat (device_evdev); - time_us = libinput_event_touch_get_time_usec (touch_event); - - seat_slot = libinput_event_touch_get_seat_slot (touch_event); - touch_state = meta_seat_native_lookup_touch_state (seat, seat_slot); - if (!touch_state) - break; - - meta_seat_native_notify_touch_event (touch_state->seat, - device, - CLUTTER_TOUCH_CANCEL, - time_us, - touch_state->seat_slot, - touch_state->coords.x, - touch_state->coords.y); - - meta_seat_native_release_touch_state (seat, seat_slot); - break; - } - case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: - case LIBINPUT_EVENT_GESTURE_PINCH_END: - { - struct libinput_event_gesture *gesture_event = - libinput_event_get_gesture_event (event); - ClutterTouchpadGesturePhase phase; - uint32_t n_fingers; - uint64_t time_us; - - if (libinput_event_get_type (event) == LIBINPUT_EVENT_GESTURE_PINCH_BEGIN) - phase = CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN; - else - phase = libinput_event_gesture_get_cancelled (gesture_event) ? - CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL : CLUTTER_TOUCHPAD_GESTURE_PHASE_END; - - n_fingers = libinput_event_gesture_get_finger_count (gesture_event); - device = libinput_device_get_user_data (libinput_device); - time_us = libinput_event_gesture_get_time_usec (gesture_event); - notify_pinch_gesture_event (device, phase, time_us, 0, 0, 0, 0, n_fingers); - break; - } - case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: - { - struct libinput_event_gesture *gesture_event = - libinput_event_get_gesture_event (event); - gdouble angle_delta, scale, dx, dy; - uint32_t n_fingers; - uint64_t time_us; - - n_fingers = libinput_event_gesture_get_finger_count (gesture_event); - device = libinput_device_get_user_data (libinput_device); - time_us = libinput_event_gesture_get_time_usec (gesture_event); - angle_delta = libinput_event_gesture_get_angle_delta (gesture_event); - scale = libinput_event_gesture_get_scale (gesture_event); - dx = libinput_event_gesture_get_dx (gesture_event); - dy = libinput_event_gesture_get_dy (gesture_event); - - notify_pinch_gesture_event (device, - CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE, - time_us, dx, dy, angle_delta, scale, n_fingers); - break; - } - case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: - case LIBINPUT_EVENT_GESTURE_SWIPE_END: - { - struct libinput_event_gesture *gesture_event = - libinput_event_get_gesture_event (event); - ClutterTouchpadGesturePhase phase; - uint32_t n_fingers; - uint64_t time_us; - - device = libinput_device_get_user_data (libinput_device); - time_us = libinput_event_gesture_get_time_usec (gesture_event); - n_fingers = libinput_event_gesture_get_finger_count (gesture_event); - - if (libinput_event_get_type (event) == LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN) - phase = CLUTTER_TOUCHPAD_GESTURE_PHASE_BEGIN; - else - phase = libinput_event_gesture_get_cancelled (gesture_event) ? - CLUTTER_TOUCHPAD_GESTURE_PHASE_CANCEL : CLUTTER_TOUCHPAD_GESTURE_PHASE_END; - - notify_swipe_gesture_event (device, phase, time_us, n_fingers, 0, 0); - break; - } - case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: - { - struct libinput_event_gesture *gesture_event = - libinput_event_get_gesture_event (event); - uint32_t n_fingers; - uint64_t time_us; - double dx, dy; - - device = libinput_device_get_user_data (libinput_device); - time_us = libinput_event_gesture_get_time_usec (gesture_event); - n_fingers = libinput_event_gesture_get_finger_count (gesture_event); - dx = libinput_event_gesture_get_dx (gesture_event); - dy = libinput_event_gesture_get_dy (gesture_event); - - notify_swipe_gesture_event (device, - CLUTTER_TOUCHPAD_GESTURE_PHASE_UPDATE, - time_us, n_fingers, dx, dy); - break; - } - case LIBINPUT_EVENT_TABLET_TOOL_AXIS: - { - process_tablet_axis (seat, event); - break; - } - case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: - { - uint64_t time; - struct libinput_event_tablet_tool *tablet_event = - libinput_event_get_tablet_tool_event (event); - struct libinput_tablet_tool *libinput_tool = NULL; - enum libinput_tablet_tool_proximity_state state; - - state = libinput_event_tablet_tool_get_proximity_state (tablet_event); - time = libinput_event_tablet_tool_get_time_usec (tablet_event); - device = libinput_device_get_user_data (libinput_device); - - libinput_tool = libinput_event_tablet_tool_get_tool (tablet_event); - - if (state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN) - input_device_update_tool (device, libinput_tool); - notify_proximity (device, time, state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN); - if (state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) - input_device_update_tool (device, NULL); - break; - } - case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: - { - uint64_t time_us; - uint32_t button_state; - struct libinput_event_tablet_tool *tablet_event = - libinput_event_get_tablet_tool_event (event); - uint32_t tablet_button; - - process_tablet_axis (seat, event); - - device = libinput_device_get_user_data (libinput_device); - time_us = libinput_event_tablet_tool_get_time_usec (tablet_event); - tablet_button = libinput_event_tablet_tool_get_button (tablet_event); - - button_state = libinput_event_tablet_tool_get_button_state (tablet_event) == - LIBINPUT_BUTTON_STATE_PRESSED; - - meta_seat_native_notify_button (seat_from_device (device), device, - time_us, tablet_button, button_state); - break; - } - case LIBINPUT_EVENT_TABLET_TOOL_TIP: - { - uint64_t time_us; - uint32_t button_state; - struct libinput_event_tablet_tool *tablet_event = - libinput_event_get_tablet_tool_event (event); - - device = libinput_device_get_user_data (libinput_device); - time_us = libinput_event_tablet_tool_get_time_usec (tablet_event); - - button_state = libinput_event_tablet_tool_get_tip_state (tablet_event) == - LIBINPUT_TABLET_TOOL_TIP_DOWN; - - /* To avoid jumps on tip, notify axes before the tip down event - but after the tip up event */ - if (button_state) - process_tablet_axis (seat, event); - - meta_seat_native_notify_button (seat_from_device (device), device, - time_us, BTN_TOUCH, button_state); - if (!button_state) - process_tablet_axis (seat, event); - break; - } - case LIBINPUT_EVENT_TABLET_PAD_BUTTON: - { - uint64_t time; - uint32_t button_state, button, group, mode; - struct libinput_tablet_pad_mode_group *mode_group; - struct libinput_event_tablet_pad *pad_event = - libinput_event_get_tablet_pad_event (event); - - device = libinput_device_get_user_data (libinput_device); - time = libinput_event_tablet_pad_get_time_usec (pad_event); - - mode_group = libinput_event_tablet_pad_get_mode_group (pad_event); - group = libinput_tablet_pad_mode_group_get_index (mode_group); - mode = libinput_event_tablet_pad_get_mode (pad_event); - - button = libinput_event_tablet_pad_get_button_number (pad_event); - button_state = libinput_event_tablet_pad_get_button_state (pad_event) == - LIBINPUT_BUTTON_STATE_PRESSED; - notify_pad_button (device, time, button, group, mode, button_state); - break; - } - case LIBINPUT_EVENT_TABLET_PAD_STRIP: - { - uint64_t time; - uint32_t number, source, group, mode; - struct libinput_tablet_pad_mode_group *mode_group; - struct libinput_event_tablet_pad *pad_event = - libinput_event_get_tablet_pad_event (event); - double value; - - device = libinput_device_get_user_data (libinput_device); - time = libinput_event_tablet_pad_get_time_usec (pad_event); - number = libinput_event_tablet_pad_get_strip_number (pad_event); - value = libinput_event_tablet_pad_get_strip_position (pad_event); - source = libinput_event_tablet_pad_get_strip_source (pad_event); - - mode_group = libinput_event_tablet_pad_get_mode_group (pad_event); - group = libinput_tablet_pad_mode_group_get_index (mode_group); - mode = libinput_event_tablet_pad_get_mode (pad_event); - - notify_pad_strip (device, time, number, source, group, mode, value); - break; - } - case LIBINPUT_EVENT_TABLET_PAD_RING: - { - uint64_t time; - uint32_t number, source, group, mode; - struct libinput_tablet_pad_mode_group *mode_group; - struct libinput_event_tablet_pad *pad_event = - libinput_event_get_tablet_pad_event (event); - double angle; - - device = libinput_device_get_user_data (libinput_device); - time = libinput_event_tablet_pad_get_time_usec (pad_event); - number = libinput_event_tablet_pad_get_ring_number (pad_event); - angle = libinput_event_tablet_pad_get_ring_position (pad_event); - source = libinput_event_tablet_pad_get_ring_source (pad_event); - - mode_group = libinput_event_tablet_pad_get_mode_group (pad_event); - group = libinput_tablet_pad_mode_group_get_index (mode_group); - mode = libinput_event_tablet_pad_get_mode (pad_event); - - notify_pad_ring (device, time, number, source, group, mode, angle); - break; - } - case LIBINPUT_EVENT_SWITCH_TOGGLE: - { - struct libinput_event_switch *switch_event = - libinput_event_get_switch_event (event); - enum libinput_switch sw = - libinput_event_switch_get_switch (switch_event); - enum libinput_switch_state state = - libinput_event_switch_get_switch_state (switch_event); - - if (sw == LIBINPUT_SWITCH_TABLET_MODE) - { - seat->tablet_mode_switch_state = (state == LIBINPUT_SWITCH_STATE_ON); - update_touch_mode (seat); - } - break; - } - default: - handled = FALSE; - } - - return handled; + g_signal_emit_by_name (seat_native, + "kbd-a11y-mods-state-changed", + new_latched_mods, + new_locked_mods); } static void -process_event (MetaSeatNative *seat, - struct libinput_event *event) +proxy_touch_mode_changed (MetaSeatImpl *seat_impl, + gboolean enabled, + MetaSeatNative *seat_native) { - if (process_base_event (seat, event)) - return; - if (process_device_event (seat, event)) - return; + seat_native->touch_mode = enabled; + g_object_notify (G_OBJECT (seat_native), "touch-mode"); } static void -process_events (MetaSeatNative *seat) -{ - struct libinput_event *event; - - while ((event = libinput_get_event (seat->libinput))) - { - process_event(seat, event); - libinput_event_destroy(event); - } -} - -static int -open_restricted (const char *path, - int flags, - void *user_data) +proxy_bell (MetaSeatImpl *seat_impl, + MetaSeatNative *seat_native) { - gint fd; - - if (device_open_callback) - { - GError *error = NULL; - - fd = device_open_callback (path, flags, device_callback_data, &error); - - if (fd < 0) - { - g_warning ("Could not open device %s: %s", path, error->message); - g_error_free (error); - } - } - else - { - fd = open (path, O_RDWR | O_NONBLOCK); - if (fd < 0) - { - g_warning ("Could not open device %s: %s", path, strerror (errno)); - } - } - - return fd; + clutter_seat_bell_notify (CLUTTER_SEAT (seat_native)); } static void -close_restricted (int fd, - void *user_data) +proxy_mods_state_changed (MetaSeatImpl *seat_impl, + ClutterSeat *seat) { - if (device_close_callback) - device_close_callback (fd, device_callback_data); - else - close (fd); -} + ClutterKeymap *keymap; -static const struct libinput_interface libinput_interface = { - open_restricted, - close_restricted -}; + keymap = clutter_seat_get_keymap (seat); + g_signal_emit_by_name (keymap, "state-changed"); +} static void meta_seat_native_constructed (GObject *object) { MetaSeatNative *seat = META_SEAT_NATIVE (object); - ClutterInputDevice *device; - MetaEventSource *source; - struct udev *udev; - struct xkb_keymap *xkb_keymap; - - device = meta_input_device_native_new_virtual ( - seat, CLUTTER_POINTER_DEVICE, - CLUTTER_INPUT_MODE_LOGICAL); - seat->pointer_x = INITIAL_POINTER_X; - seat->pointer_y = INITIAL_POINTER_Y; - _clutter_input_device_set_coords (device, NULL, - seat->pointer_x, seat->pointer_y); - seat->core_pointer = device; - - device = meta_input_device_native_new_virtual ( - seat, CLUTTER_KEYBOARD_DEVICE, - CLUTTER_INPUT_MODE_LOGICAL); - seat->core_keyboard = device; - - udev = udev_new (); - if (G_UNLIKELY (udev == NULL)) - { - g_warning ("Failed to create udev object"); - return; - } - - seat->libinput = libinput_udev_create_context (&libinput_interface, - seat, udev); - if (seat->libinput == NULL) - { - g_critical ("Failed to create the libinput object."); - return; - } - - if (libinput_udev_assign_seat (seat->libinput, seat->seat_id) == -1) - { - g_critical ("Failed to assign a seat to the libinput object."); - libinput_unref (seat->libinput); - seat->libinput = NULL; - return; - } - - udev_unref (udev); - - seat->udev_client = g_udev_client_new ((const gchar *[]) { "input", NULL }); - source = meta_event_source_new (seat); - seat->event_source = source; + seat->impl = meta_seat_impl_new (seat, seat->seat_id); + g_signal_connect (seat->impl, "kbd-a11y-flags-changed", + G_CALLBACK (proxy_kbd_a11y_flags_changed), seat); + g_signal_connect (seat->impl, "kbd-a11y-mods-state-changed", + G_CALLBACK (proxy_kbd_a11y_mods_state_changed), seat); + g_signal_connect (seat->impl, "touch-mode", + G_CALLBACK (proxy_touch_mode_changed), seat); + g_signal_connect (seat->impl, "bell", + G_CALLBACK (proxy_bell), seat); + g_signal_connect (seat->impl, "mods-state-changed", + G_CALLBACK (proxy_mods_state_changed), seat); - seat->keymap = g_object_new (META_TYPE_KEYMAP_NATIVE, NULL); - xkb_keymap = meta_keymap_native_get_keyboard_map (seat->keymap); + seat->core_pointer = meta_seat_impl_get_pointer (seat->impl); + seat->core_keyboard = meta_seat_impl_get_keyboard (seat->impl); - if (xkb_keymap) - { - seat->xkb = xkb_state_new (xkb_keymap); - - seat->caps_lock_led = - xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_CAPS); - seat->num_lock_led = - xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_NUM); - seat->scroll_lock_led = - xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_SCROLL); - } - - seat->has_touchscreen = has_touchscreen (seat); - seat->has_tablet_switch = has_tablet_switch (seat); - update_touch_mode (seat); + meta_seat_native_set_keyboard_map (seat, "us", "", ""); if (G_OBJECT_CLASS (meta_seat_native_parent_class)->constructed) G_OBJECT_CLASS (meta_seat_native_parent_class)->constructed (object); @@ -2603,63 +216,30 @@ meta_seat_native_get_property (GObject *object, } } -static void -meta_seat_native_dispose (GObject *object) -{ - MetaSeatNative *seat = META_SEAT_NATIVE (object); - - g_clear_signal_handler (&seat->stage_added_handler, seat->stage_manager); - g_clear_signal_handler (&seat->stage_removed_handler, seat->stage_manager); - - if (seat->stage_manager) - { - g_object_unref (seat->stage_manager); - seat->stage_manager = NULL; - } - - if (seat->libinput) - { - libinput_unref (seat->libinput); - seat->libinput = NULL; - } - - G_OBJECT_CLASS (meta_seat_native_parent_class)->dispose (object); -} - static void meta_seat_native_finalize (GObject *object) { MetaSeatNative *seat = META_SEAT_NATIVE (object); - GSList *iter; + GList *iter; - for (iter = seat->devices; iter; iter = g_slist_next (iter)) + if (seat->xkb_keymap) + xkb_keymap_unref (seat->xkb_keymap); + g_clear_object (&seat->core_pointer); + g_clear_object (&seat->core_keyboard); + g_clear_object (&seat->impl); + + for (iter = seat->devices; iter; iter = g_list_next (iter)) { ClutterInputDevice *device = iter->data; g_object_unref (device); } - g_slist_free (seat->devices); - - if (seat->touch_states) - g_hash_table_destroy (seat->touch_states); + g_list_free (seat->devices); g_hash_table_destroy (seat->reserved_virtual_slots); - g_object_unref (seat->udev_client); - - meta_event_source_free (seat->event_source); - - xkb_state_unref (seat->xkb); - - meta_seat_native_clear_repeat_timer (seat); - - if (seat->libinput_seat) - libinput_seat_unref (seat->libinput_seat); - - g_list_free (seat->free_device_ids); - - if (seat->constrain_data_notify != NULL) - seat->constrain_data_notify (seat->constrain_data); + g_clear_pointer (&seat->tablet_cursors, g_hash_table_unref); + g_object_unref (seat->cursor_renderer); g_free (seat->seat_id); @@ -2703,6 +283,9 @@ meta_seat_native_get_keymap (ClutterSeat *seat) { MetaSeatNative *seat_native = META_SEAT_NATIVE (seat); + if (!seat_native->keymap) + seat_native->keymap = meta_seat_impl_get_keymap (seat_native->impl); + return CLUTTER_KEYMAP (seat_native->keymap); } @@ -2729,18 +312,6 @@ meta_seat_native_free_event_data (ClutterSeat *seat, meta_event_native_free (event_evdev); } -static void -meta_seat_native_apply_kbd_a11y_settings (ClutterSeat *seat, - ClutterKbdA11ySettings *settings) -{ - ClutterInputDevice *device; - - device = clutter_seat_get_keyboard (seat); - if (device) - meta_input_device_native_apply_kbd_a11y_settings (META_INPUT_DEVICE_NATIVE (device), - settings); -} - static guint bump_virtual_touch_slot_base (MetaSeatNative *seat_native) { @@ -2825,12 +396,21 @@ meta_seat_native_warp_pointer (ClutterSeat *seat, int y) { MetaSeatNative *seat_native = META_SEAT_NATIVE (seat); - MetaBackend *backend = meta_get_backend (); - MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); - notify_absolute_motion (seat_native->core_pointer, 0, x, y, NULL); + meta_seat_impl_warp_pointer (seat_native->impl, x, y); +} + +static gboolean +meta_seat_native_query_state (ClutterSeat *seat, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t *coords, + ClutterModifierType *modifiers) +{ + MetaSeatNative *seat_native = META_SEAT_NATIVE (seat); - meta_cursor_tracker_update_position (cursor_tracker, x, y); + return meta_seat_impl_query_state (seat_native->impl, device, sequence, + coords, modifiers); } static void @@ -2842,7 +422,6 @@ meta_seat_native_class_init (MetaSeatNativeClass *klass) object_class->constructed = meta_seat_native_constructed; object_class->set_property = meta_seat_native_set_property; object_class->get_property = meta_seat_native_get_property; - object_class->dispose = meta_seat_native_dispose; object_class->finalize = meta_seat_native_finalize; seat_class->get_pointer = meta_seat_native_get_pointer; @@ -2852,12 +431,12 @@ meta_seat_native_class_init (MetaSeatNativeClass *klass) seat_class->get_keymap = meta_seat_native_get_keymap; seat_class->copy_event_data = meta_seat_native_copy_event_data; seat_class->free_event_data = meta_seat_native_free_event_data; - seat_class->apply_kbd_a11y_settings = meta_seat_native_apply_kbd_a11y_settings; seat_class->create_virtual_device = meta_seat_native_create_virtual_device; seat_class->get_supported_virtual_device_types = meta_seat_native_get_supported_virtual_device_types; seat_class->compress_motion = meta_seat_native_compress_motion; seat_class->warp_pointer = meta_seat_native_warp_pointer; - seat_class->handle_device_event = meta_seat_native_handle_device_event; + seat_class->handle_event_post = meta_seat_native_handle_event_post; + seat_class->query_state = meta_seat_native_query_state; props[PROP_SEAT_ID] = g_param_spec_string ("seat-id", @@ -2873,183 +452,12 @@ meta_seat_native_class_init (MetaSeatNativeClass *klass) "touch-mode"); } -static void -meta_seat_native_stage_added_cb (ClutterStageManager *manager, - ClutterStage *stage, - MetaSeatNative *seat) -{ - /* NB: Currently we can only associate a single stage with all evdev - * devices. - * - * We save a pointer to the stage so if we release/reclaim input - * devices due to switching virtual terminals then we know what - * stage to re associate the devices with. - */ - meta_seat_native_set_stage (seat, stage); - - /* We only want to do this once so we can catch the default - stage. If the application has multiple stages then it will need - to manage the stage of the input devices itself */ - g_clear_signal_handler (&seat->stage_added_handler, seat->stage_manager); -} - -static void -meta_seat_native_stage_removed_cb (ClutterStageManager *manager, - ClutterStage *stage, - MetaSeatNative *seat) -{ - meta_seat_native_set_stage (seat, NULL); -} - static void meta_seat_native_init (MetaSeatNative *seat) { - seat->stage_manager = clutter_stage_manager_get_default (); - g_object_ref (seat->stage_manager); - - /* evdev doesn't have any way to link an event to a particular stage - so we'll have to leave it up to applications to set the - corresponding stage for an input device. However to make it - easier for applications that are only using one fullscreen stage - (which is probably the most frequent use-case for the evdev - backend) we'll associate any input devices that don't have a - stage with the first stage created. */ - seat->stage_added_handler = - g_signal_connect (seat->stage_manager, - "stage-added", - G_CALLBACK (meta_seat_native_stage_added_cb), - seat); - seat->stage_removed_handler = - g_signal_connect (seat->stage_manager, - "stage-removed", - G_CALLBACK (meta_seat_native_stage_removed_cb), - seat); - - seat->device_id_next = INITIAL_DEVICE_ID; - - seat->repeat = TRUE; - seat->repeat_delay = 250; /* ms */ - seat->repeat_interval = 33; /* ms */ - - seat->barrier_manager = meta_barrier_manager_native_new (); - seat->reserved_virtual_slots = g_hash_table_new (NULL, NULL); } -void -meta_seat_native_set_stage (MetaSeatNative *seat, - ClutterStage *stage) -{ - GSList *l; - - if (seat->stage == stage) - return; - - seat->stage = stage; - - for (l = seat->devices; l; l = l->next) - { - ClutterInputDevice *device = l->data; - - if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_PHYSICAL) - { - ClutterEvent *device_event; - - device_event = clutter_event_new (CLUTTER_DEVICE_ADDED); - clutter_event_set_device (device_event, device); - device_event->device.stage = stage; - queue_event (seat, device_event); - } - } -} - -ClutterStage * -meta_seat_native_get_stage (MetaSeatNative *seat) -{ - return seat->stage; -} - -/** - * meta_seat_native_set_device_callbacks: (skip) - * @open_callback: the user replacement for open() - * @close_callback: the user replacement for close() - * @user_data: user data for @callback - * - * Through this function, the application can set a custom callback - * to be invoked when Clutter is about to open an evdev device. It can do - * so if special handling is needed, for example to circumvent permission - * problems. - * - * Setting @callback to %NULL will reset the default behavior. - * - * For reliable effects, this function must be called before clutter_init(). - */ -void -meta_seat_native_set_device_callbacks (MetaOpenDeviceCallback open_callback, - MetaCloseDeviceCallback close_callback, - gpointer user_data) -{ - device_open_callback = open_callback; - device_close_callback = close_callback; - device_callback_data = user_data; -} - -/** - * meta_seat_native_set_pointer_constrain_callback: - * @seat: the #ClutterSeat created by the evdev backend - * @callback: the callback - * @user_data: data to pass to the callback - * @user_data_notify: function to be called when removing the callback - * - * Sets a callback to be invoked for every pointer motion. The callback - * can then modify the new pointer coordinates to constrain movement within - * a specific region. - */ -void -meta_seat_native_set_pointer_constrain_callback (MetaSeatNative *seat, - MetaPointerConstrainCallback callback, - gpointer user_data, - GDestroyNotify user_data_notify) -{ - g_return_if_fail (META_IS_SEAT_NATIVE (seat)); - - if (seat->constrain_data_notify) - seat->constrain_data_notify (seat->constrain_data); - - seat->constrain_callback = callback; - seat->constrain_data = user_data; - seat->constrain_data_notify = user_data_notify; -} - -void -meta_seat_native_update_xkb_state (MetaSeatNative *seat) -{ - xkb_mod_mask_t latched_mods; - xkb_mod_mask_t locked_mods; - struct xkb_keymap *xkb_keymap; - - xkb_keymap = meta_keymap_native_get_keyboard_map (seat->keymap); - - latched_mods = xkb_state_serialize_mods (seat->xkb, - XKB_STATE_MODS_LATCHED); - locked_mods = xkb_state_serialize_mods (seat->xkb, - XKB_STATE_MODS_LOCKED); - xkb_state_unref (seat->xkb); - seat->xkb = xkb_state_new (xkb_keymap); - - xkb_state_update_mask (seat->xkb, - 0, /* depressed */ - latched_mods, - locked_mods, - 0, 0, seat->layout_idx); - - seat->caps_lock_led = xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_CAPS); - seat->num_lock_led = xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_NUM); - seat->scroll_lock_led = xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_SCROLL); - - meta_seat_native_sync_leds (seat); -} - /** * meta_seat_native_release_devices: * @@ -3073,9 +481,7 @@ meta_seat_native_release_devices (MetaSeatNative *seat) return; } - libinput_suspend (seat->libinput); - process_events (seat); - + meta_seat_impl_release_devices (seat->impl); seat->released = TRUE; } @@ -3100,13 +506,32 @@ meta_seat_native_reclaim_devices (MetaSeatNative *seat) return; } - libinput_resume (seat->libinput); - meta_seat_native_update_xkb_state (seat); - process_events (seat); - + meta_seat_impl_reclaim_devices (seat->impl); seat->released = FALSE; } +static struct xkb_keymap * +create_keymap (const char *layouts, + const char *variants, + const char *options) +{ + struct xkb_rule_names names; + struct xkb_keymap *keymap; + struct xkb_context *context; + + names.rules = DEFAULT_XKB_RULES_FILE; + names.model = DEFAULT_XKB_MODEL; + names.layout = layouts; + names.variant = variants; + names.options = options; + + context = meta_create_xkb_context (); + keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS); + xkb_context_unref (context); + + return keymap; +} + /** * meta_seat_native_set_keyboard_map: (skip) * @seat: the #ClutterSeat created by the evdev backend @@ -3118,19 +543,30 @@ meta_seat_native_reclaim_devices (MetaSeatNative *seat) * is pressed when calling this function. */ void -meta_seat_native_set_keyboard_map (MetaSeatNative *seat, - struct xkb_keymap *xkb_keymap) +meta_seat_native_set_keyboard_map (MetaSeatNative *seat, + const char *layouts, + const char *variants, + const char *options) { - ClutterKeymap *keymap; + struct xkb_keymap *keymap, *impl_keymap; - g_return_if_fail (META_IS_SEAT_NATIVE (seat)); - g_return_if_fail (xkb_keymap != NULL); + keymap = create_keymap (layouts, variants, options); + impl_keymap = create_keymap (layouts, variants, options); + + if (keymap == NULL) + { + g_warning ("Unable to load configured keymap: rules=%s, model=%s, layout=%s, variant=%s, options=%s", + DEFAULT_XKB_RULES_FILE, DEFAULT_XKB_MODEL, layouts, + variants, options); + return; + } - keymap = clutter_seat_get_keymap (CLUTTER_SEAT (seat)); - meta_keymap_native_set_keyboard_map (META_KEYMAP_NATIVE (keymap), - xkb_keymap); + if (seat->xkb_keymap) + xkb_keymap_unref (seat->xkb_keymap); + seat->xkb_keymap = keymap; - meta_seat_native_update_xkb_state (seat); + meta_seat_impl_set_keyboard_map (seat->impl, impl_keymap); + xkb_keymap_unref (impl_keymap); } /** @@ -3146,7 +582,7 @@ meta_seat_native_get_keyboard_map (MetaSeatNative *seat) { g_return_val_if_fail (META_IS_SEAT_NATIVE (seat), NULL); - return xkb_state_get_keymap (seat->xkb); + return seat->xkb_keymap; } /** @@ -3160,22 +596,10 @@ void meta_seat_native_set_keyboard_layout_index (MetaSeatNative *seat, xkb_layout_index_t idx) { - xkb_mod_mask_t depressed_mods; - xkb_mod_mask_t latched_mods; - xkb_mod_mask_t locked_mods; - struct xkb_state *state; - g_return_if_fail (META_IS_SEAT_NATIVE (seat)); - state = seat->xkb; - - depressed_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED); - latched_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED); - locked_mods = xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED); - - xkb_state_update_mask (state, depressed_mods, latched_mods, locked_mods, 0, 0, idx); - - seat->layout_idx = idx; + seat->xkb_layout_index = idx; + meta_seat_impl_set_keyboard_layout_index (seat->impl, idx); } /** @@ -3184,88 +608,52 @@ meta_seat_native_set_keyboard_layout_index (MetaSeatNative *seat, xkb_layout_index_t meta_seat_native_get_keyboard_layout_index (MetaSeatNative *seat) { - return seat->layout_idx; + return seat->xkb_layout_index; } -/** - * meta_seat_native_set_keyboard_numlock: (skip) - * @seat: the #ClutterSeat created by the evdev backend - * @numlock_set: TRUE to set NumLock ON, FALSE otherwise. - * - * Sets the NumLock state on the backend's #xkb_state . - */ -void -meta_seat_native_set_keyboard_numlock (MetaSeatNative *seat, - gboolean numlock_state) +MetaBarrierManagerNative * +meta_seat_native_get_barrier_manager (MetaSeatNative *seat) { - xkb_mod_mask_t depressed_mods; - xkb_mod_mask_t latched_mods; - xkb_mod_mask_t locked_mods; - xkb_mod_mask_t group_mods; - xkb_mod_mask_t numlock; - struct xkb_keymap *xkb_keymap; - ClutterKeymap *keymap; - - g_return_if_fail (META_IS_SEAT_NATIVE (seat)); - - keymap = clutter_seat_get_keymap (CLUTTER_SEAT (seat)); - xkb_keymap = meta_keymap_native_get_keyboard_map (META_KEYMAP_NATIVE (keymap)); - - numlock = (1 << xkb_keymap_mod_get_index (xkb_keymap, "Mod2")); - - depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED); - latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED); - locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED); - group_mods = xkb_state_serialize_layout (seat->xkb, XKB_STATE_LAYOUT_EFFECTIVE); - - if (numlock_state) - locked_mods |= numlock; - else - locked_mods &= ~numlock; - - xkb_state_update_mask (seat->xkb, - depressed_mods, - latched_mods, - locked_mods, - 0, 0, - group_mods); - - meta_seat_native_sync_leds (seat); + return meta_seat_impl_get_barrier_manager (seat->impl); } -/** - * meta_seat_native_set_keyboard_repeat: - * @seat: the #ClutterSeat created by the evdev backend - * @repeat: whether to enable or disable keyboard repeat events - * @delay: the delay in ms between the hardware key press event and - * the first synthetic event - * @interval: the period in ms between consecutive synthetic key - * press events - * - * Enables or disables sythetic key press events, allowing for initial - * delay and interval period to be specified. - */ void -meta_seat_native_set_keyboard_repeat (MetaSeatNative *seat, - gboolean repeat, - uint32_t delay, - uint32_t interval) +meta_seat_native_set_pointer_constraint (MetaSeatNative *seat, + MetaPointerConstraintImpl *constraint_impl) { - g_return_if_fail (META_IS_SEAT_NATIVE (seat)); - - seat->repeat = repeat; - seat->repeat_delay = delay; - seat->repeat_interval = interval; + meta_seat_impl_set_pointer_constraint (seat->impl, constraint_impl); } -struct xkb_state * -meta_seat_native_get_xkb_state (MetaSeatNative *seat) +MetaCursorRenderer * +meta_seat_native_maybe_ensure_cursor_renderer (MetaSeatNative *seat_native, + ClutterInputDevice *device) { - return seat->xkb; + if (device == seat_native->core_pointer) + { + if (!seat_native->cursor_renderer) + { + MetaCursorRendererNative *cursor_renderer_native; + + cursor_renderer_native = + meta_cursor_renderer_native_new (meta_get_backend (), + seat_native->core_pointer); + seat_native->cursor_renderer = + META_CURSOR_RENDERER (cursor_renderer_native); + } + + return seat_native->cursor_renderer; + } + + if (seat_native->tablet_cursors && + clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE) + return g_hash_table_lookup (seat_native->tablet_cursors, device); + + return NULL; } -MetaBarrierManagerNative * -meta_seat_native_get_barrier_manager (MetaSeatNative *seat) +void +meta_seat_native_set_viewports (MetaSeatNative *seat, + MetaViewportInfo *viewports) { - return seat->barrier_manager; + meta_seat_impl_set_viewports (seat->impl, viewports); } diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h index 0cc353e7d86a6e59f98576325c149596245a6a74..7f94828d0e069ddf59d5f1d70554c8fca4f3b297 100644 --- a/src/backends/native/meta-seat-native.h +++ b/src/backends/native/meta-seat-native.h @@ -27,212 +27,51 @@ #include #include +#include "backends/meta-input-settings-private.h" +#include "backends/meta-viewport-info.h" +#include "backends/native/meta-backend-native-types.h" #include "backends/native/meta-barrier-native.h" -#include "backends/native/meta-keymap-native.h" +#include "backends/native/meta-cursor-renderer-native.h" +#include "backends/native/meta-pointer-constraint-native.h" #include "backends/native/meta-xkb-utils.h" #include "clutter/clutter.h" -typedef struct _MetaTouchState MetaTouchState; typedef struct _MetaSeatNative MetaSeatNative; -typedef struct _MetaEventSource MetaEventSource; - -/** - * MetaPointerConstrainCallback: - * @device: the core pointer device - * @time: the event time in milliseconds - * @x: (inout): the new X coordinate - * @y: (inout): the new Y coordinate - * @user_data: user data passed to this function - * - * This callback will be called for all pointer motion events, and should - * update (@x, @y) to constrain the pointer position appropriately. - * The subsequent motion event will use the updated values as the new coordinates. - * Note that the coordinates are not clamped to the stage size, and the callback - * must make sure that this happens before it returns. - * Also note that the event will be emitted even if the pointer is constrained - * to be in the same position. - */ -typedef void (* MetaPointerConstrainCallback) (ClutterInputDevice *device, - uint32_t time, - float prev_x, - float prev_y, - float *x, - float *y, - gpointer user_data); - -struct _MetaTouchState -{ - MetaSeatNative *seat; - - int device_slot; - int seat_slot; - graphene_point_t coords; -}; struct _MetaSeatNative { ClutterSeat parent_instance; + MetaSeatImpl *impl; char *seat_id; - MetaEventSource *event_source; - struct libinput *libinput; - struct libinput_seat *libinput_seat; - GSList *devices; + GList *devices; + struct xkb_keymap *xkb_keymap; + xkb_layout_index_t xkb_layout_index; ClutterInputDevice *core_pointer; ClutterInputDevice *core_keyboard; - GHashTable *touch_states; guint virtual_touch_slot_base; GHashTable *reserved_virtual_slots; - struct xkb_state *xkb; - xkb_led_index_t caps_lock_led; - xkb_led_index_t num_lock_led; - xkb_led_index_t scroll_lock_led; - xkb_layout_index_t layout_idx; - uint32_t button_state; - int button_count[KEY_CNT]; - - ClutterStage *stage; - ClutterStageManager *stage_manager; - gulong stage_added_handler; - gulong stage_removed_handler; - - int device_id_next; - GList *free_device_ids; - - MetaBarrierManagerNative *barrier_manager; - - MetaPointerConstrainCallback constrain_callback; - gpointer constrain_data; - GDestroyNotify constrain_data_notify; - MetaKeymapNative *keymap; - - GUdevClient *udev_client; - guint tablet_mode_switch_state : 1; - guint has_touchscreen : 1; - guint has_tablet_switch : 1; - guint touch_mode : 1; - - /* keyboard repeat */ - gboolean repeat; - uint32_t repeat_delay; - uint32_t repeat_interval; - uint32_t repeat_key; - uint32_t repeat_count; - uint32_t repeat_timer; - ClutterInputDevice *repeat_device; - - float pointer_x; - float pointer_y; - - /* Emulation of discrete scroll events out of smooth ones */ - float accum_scroll_dx; - float accum_scroll_dy; + MetaCursorRenderer *cursor_renderer; + GHashTable *tablet_cursors; gboolean released; + gboolean touch_mode; }; #define META_TYPE_SEAT_NATIVE meta_seat_native_get_type () G_DECLARE_FINAL_TYPE (MetaSeatNative, meta_seat_native, META, SEAT_NATIVE, ClutterSeat) -void meta_seat_native_notify_key (MetaSeatNative *seat, - ClutterInputDevice *device, - uint64_t time_us, - uint32_t key, - uint32_t state, - gboolean update_keys); - -void meta_seat_native_notify_relative_motion (MetaSeatNative *seat_evdev, - ClutterInputDevice *input_device, - uint64_t time_us, - float dx, - float dy, - float dx_unaccel, - float dy_unaccel); - -void meta_seat_native_notify_absolute_motion (MetaSeatNative *seat_evdev, - ClutterInputDevice *input_device, - uint64_t time_us, - float x, - float y, - double *axes); - -void meta_seat_native_notify_button (MetaSeatNative *seat, - ClutterInputDevice *input_device, - uint64_t time_us, - uint32_t button, - uint32_t state); - -void meta_seat_native_notify_scroll_continuous (MetaSeatNative *seat, - ClutterInputDevice *input_device, - uint64_t time_us, - double dx, - double dy, - ClutterScrollSource source, - ClutterScrollFinishFlags flags); - -void meta_seat_native_notify_discrete_scroll (MetaSeatNative *seat, - ClutterInputDevice *input_device, - uint64_t time_us, - double discrete_dx, - double discrete_dy, - ClutterScrollSource source); - -void meta_seat_native_notify_touch_event (MetaSeatNative *seat, - ClutterInputDevice *input_device, - ClutterEventType evtype, - uint64_t time_us, - int slot, - double x, - double y); - void meta_seat_native_set_libinput_seat (MetaSeatNative *seat, struct libinput_seat *libinput_seat); void meta_seat_native_sync_leds (MetaSeatNative *seat); -MetaTouchState * meta_seat_native_acquire_touch_state (MetaSeatNative *seat, - int seat_slot); -MetaTouchState * meta_seat_native_lookup_touch_state (MetaSeatNative *seat, - int seat_slot); - -void meta_seat_native_release_touch_state (MetaSeatNative *seat, - int seat_slot); - -void meta_seat_native_set_stage (MetaSeatNative *seat, - ClutterStage *stage); -ClutterStage * meta_seat_native_get_stage (MetaSeatNative *seat); - -void meta_seat_native_clear_repeat_timer (MetaSeatNative *seat); - -gint meta_seat_native_acquire_device_id (MetaSeatNative *seat); -void meta_seat_native_release_device_id (MetaSeatNative *seat, - ClutterInputDevice *device); - -void meta_seat_native_update_xkb_state (MetaSeatNative *seat); - -void meta_seat_native_constrain_pointer (MetaSeatNative *seat, - ClutterInputDevice *core_pointer, - uint64_t time_us, - float x, - float y, - float *new_x, - float *new_y); - -void meta_seat_native_filter_relative_motion (MetaSeatNative *seat, - ClutterInputDevice *device, - float x, - float y, - float *dx, - float *dy); - -void meta_seat_native_dispatch (MetaSeatNative *seat); - /** * MetaOpenDeviceCallback: * @path: the device path @@ -256,15 +95,10 @@ void meta_seat_native_set_device_callbacks (MetaOpenDeviceCallback open_callba void meta_seat_native_release_devices (MetaSeatNative *seat); void meta_seat_native_reclaim_devices (MetaSeatNative *seat); -void meta_seat_native_set_pointer_constrain_callback (MetaSeatNative *seat, - MetaPointerConstrainCallback callback, - gpointer user_data, - GDestroyNotify user_data_notify); - -struct xkb_state * meta_seat_native_get_xkb_state (MetaSeatNative *seat); - -void meta_seat_native_set_keyboard_map (MetaSeatNative *seat, - struct xkb_keymap *keymap); +void meta_seat_native_set_keyboard_map (MetaSeatNative *seat, + const char *layouts, + const char *variants, + const char *options); struct xkb_keymap * meta_seat_native_get_keyboard_map (MetaSeatNative *seat); @@ -273,9 +107,6 @@ void meta_seat_native_set_keyboard_layout_index (MetaSeatNative *seat, xkb_layout_index_t meta_seat_native_get_keyboard_layout_index (MetaSeatNative *seat); -void meta_seat_native_set_keyboard_numlock (MetaSeatNative *seat, - gboolean numlock_state); - void meta_seat_native_set_keyboard_repeat (MetaSeatNative *seat, gboolean repeat, uint32_t delay, @@ -286,4 +117,15 @@ void meta_seat_native_release_touch_slots (MetaSeatNative *seat, MetaBarrierManagerNative * meta_seat_native_get_barrier_manager (MetaSeatNative *seat); +void meta_seat_native_set_pointer_constraint (MetaSeatNative *seat, + MetaPointerConstraintImpl *constraint_impl); +MetaCursorRenderer * meta_seat_native_maybe_ensure_cursor_renderer (MetaSeatNative *seat, + ClutterInputDevice *device); + +void meta_seat_native_set_viewports (MetaSeatNative *seat, + MetaViewportInfo *viewports); +void meta_seat_native_notify_kbd_a11y_change (MetaSeatNative *seat, + MetaKeyboardA11yFlags new_flags, + MetaKeyboardA11yFlags what_changed); + #endif /* META_SEAT_NATIVE_H */ diff --git a/src/backends/native/meta-virtual-input-device-native.c b/src/backends/native/meta-virtual-input-device-native.c index 42fba7dbe6682fe855d4defd2cdfa476793c750b..9291d3f3d361524e5e8dbd0c60584c4d99130023 100644 --- a/src/backends/native/meta-virtual-input-device-native.c +++ b/src/backends/native/meta-virtual-input-device-native.c @@ -22,8 +22,7 @@ #include #include -#include "backends/native/meta-input-device-native.h" -#include "backends/native/meta-keymap-native.h" +#include "backends/native/meta-input-thread.h" #include "backends/native/meta-seat-native.h" #include "backends/native/meta-virtual-input-device-native.h" #include "clutter/clutter-mutter.h" @@ -41,16 +40,62 @@ enum static GParamSpec *obj_props[PROP_LAST]; +typedef struct _ImplState ImplState; + +struct _ImplState +{ + ClutterInputDevice *device; + int button_count[KEY_CNT]; +}; + struct _MetaVirtualInputDeviceNative { ClutterVirtualInputDevice parent; - ClutterInputDevice *device; MetaSeatNative *seat; guint slot_base; - int button_count[KEY_CNT]; + ImplState *impl_state; }; +typedef struct +{ + uint64_t time_us; + double x; + double y; +} MetaVirtualEventMotion; + +typedef struct +{ + uint64_t time_us; + uint32_t button; + ClutterButtonState button_state; +} MetaVirtualEventButton; + +typedef struct +{ + uint64_t time_us; + double dx; + double dy; + ClutterScrollDirection direction; + ClutterScrollSource scroll_source; + ClutterScrollFinishFlags finish_flags; +} MetaVirtualEventScroll; + +typedef struct +{ + uint64_t time_us; + uint32_t key; + ClutterKeyState key_state; +} MetaVirtualEventKey; + +typedef struct +{ + uint64_t time_us; + int device_slot; + double x; + double y; +} MetaVirtualEventTouch; + G_DEFINE_TYPE (MetaVirtualInputDeviceNative, meta_virtual_input_device_native, CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE) @@ -63,14 +108,14 @@ typedef enum _EvdevButtonType } EvdevButtonType; static int -update_button_count (MetaVirtualInputDeviceNative *virtual_evdev, - uint32_t button, - uint32_t state) +update_button_count_in_impl (MetaVirtualInputDeviceNative *virtual_evdev, + uint32_t button, + uint32_t state) { if (state) - return ++virtual_evdev->button_count[button]; + return ++virtual_evdev->impl_state->button_count[button]; else - return --virtual_evdev->button_count[button]; + return --virtual_evdev->impl_state->button_count[button]; } static EvdevButtonType @@ -109,48 +154,74 @@ get_button_type (uint16_t code) return EVDEV_BUTTON_TYPE_NONE; } -static void -release_pressed_buttons (ClutterVirtualInputDevice *virtual_device) +static gboolean +release_device_in_impl (GTask *task) { - MetaVirtualInputDeviceNative *virtual_evdev = - META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); + ImplState *impl_state = g_task_get_task_data (task); + MetaInputDeviceNative *device_native; + MetaSeatImpl *seat_impl; int code; uint64_t time_us; + device_native = META_INPUT_DEVICE_NATIVE (impl_state->device); + seat_impl = meta_input_device_native_get_seat_impl (device_native); time_us = g_get_monotonic_time (); meta_topic (META_DEBUG_INPUT, "Releasing pressed buttons while destroying virtual input device " - "(device %p)", virtual_device); + "(device %p)", device_native); - for (code = 0; code < G_N_ELEMENTS (virtual_evdev->button_count); code++) + for (code = 0; code < G_N_ELEMENTS (impl_state->button_count); code++) { - if (virtual_evdev->button_count[code] == 0) + if (impl_state->button_count[code] == 0) continue; switch (get_button_type (code)) { case EVDEV_BUTTON_TYPE_KEY: - meta_seat_native_notify_key (virtual_evdev->seat, - virtual_evdev->device, - time_us, - code, - CLUTTER_KEY_STATE_RELEASED, - TRUE); + meta_seat_impl_notify_key_in_impl (seat_impl, + impl_state->device, + time_us, + code, + CLUTTER_KEY_STATE_RELEASED, + TRUE); break; case EVDEV_BUTTON_TYPE_BUTTON: - meta_seat_native_notify_button (virtual_evdev->seat, - virtual_evdev->device, - time_us, - code, - CLUTTER_BUTTON_STATE_RELEASED); + meta_seat_impl_notify_button_in_impl (seat_impl, + impl_state->device, + time_us, + code, + CLUTTER_BUTTON_STATE_RELEASED); break; case EVDEV_BUTTON_TYPE_NONE: g_assert_not_reached (); } - - update_button_count (virtual_evdev, code, 0); } + + g_clear_object (&impl_state->device); + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +static gboolean +notify_relative_motion_in_impl (GTask *task) +{ + MetaVirtualInputDeviceNative *virtual_evdev = + g_task_get_source_object (task); + MetaSeatImpl *seat = virtual_evdev->seat->impl; + MetaVirtualEventMotion *event = g_task_get_task_data (task); + + if (event->time_us == CLUTTER_CURRENT_TIME) + event->time_us = g_get_monotonic_time (); + + meta_seat_impl_notify_relative_motion_in_impl (seat, + virtual_evdev->impl_state->device, + event->time_us, + event->x, event->y, + event->x, event->y); + g_task_return_boolean (task, TRUE); + return G_SOURCE_REMOVE; } static void @@ -159,19 +230,43 @@ meta_virtual_input_device_native_notify_relative_motion (ClutterVirtualInputDevi double dx, double dy) { + MetaVirtualEventMotion *event; MetaVirtualInputDeviceNative *virtual_evdev = META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); + GTask *task; - g_return_if_fail (virtual_evdev->device != NULL); + g_return_if_fail (virtual_evdev->impl_state->device != NULL); - if (time_us == CLUTTER_CURRENT_TIME) - time_us = g_get_monotonic_time (); + event = g_new0 (MetaVirtualEventMotion, 1); + event->time_us = time_us; + event->x = dx; + event->y = dy; + + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, event, g_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) notify_relative_motion_in_impl); + g_object_unref (task); +} - meta_seat_native_notify_relative_motion (virtual_evdev->seat, - virtual_evdev->device, - time_us, - dx, dy, - dx, dy); +static gboolean +notify_absolute_motion_in_impl (GTask *task) +{ + MetaVirtualInputDeviceNative *virtual_evdev = + g_task_get_source_object (task); + MetaSeatImpl *seat = virtual_evdev->seat->impl; + MetaVirtualEventMotion *event = g_task_get_task_data (task); + + if (event->time_us == CLUTTER_CURRENT_TIME) + event->time_us = g_get_monotonic_time (); + + meta_seat_impl_notify_absolute_motion_in_impl (seat, + virtual_evdev->impl_state->device, + event->time_us, + event->x, event->y, + NULL); + g_task_return_boolean (task, TRUE); + return G_SOURCE_REMOVE; } static void @@ -180,19 +275,23 @@ meta_virtual_input_device_native_notify_absolute_motion (ClutterVirtualInputDevi double x, double y) { + MetaVirtualEventMotion *event; MetaVirtualInputDeviceNative *virtual_evdev = META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); + GTask *task; - g_return_if_fail (virtual_evdev->device != NULL); + g_return_if_fail (virtual_evdev->impl_state->device != NULL); - if (time_us == CLUTTER_CURRENT_TIME) - time_us = g_get_monotonic_time (); + event = g_new0 (MetaVirtualEventMotion, 1); + event->time_us = time_us; + event->x = x; + event->y = y; - meta_seat_native_notify_absolute_motion (virtual_evdev->seat, - virtual_evdev->device, - time_us, - x, y, - NULL); + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, event, g_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) notify_absolute_motion_in_impl); + g_object_unref (task); } static int @@ -215,100 +314,155 @@ translate_to_evdev_button (int clutter_button) } } -static void -meta_virtual_input_device_native_notify_button (ClutterVirtualInputDevice *virtual_device, - uint64_t time_us, - uint32_t button, - ClutterButtonState button_state) +static gboolean +notify_button_in_impl (GTask *task) { MetaVirtualInputDeviceNative *virtual_evdev = - META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); + g_task_get_source_object (task); + MetaSeatImpl *seat = virtual_evdev->seat->impl; + MetaVirtualEventButton *event = g_task_get_task_data (task); int button_count; int evdev_button; - g_return_if_fail (virtual_evdev->device != NULL); - - if (time_us == CLUTTER_CURRENT_TIME) - time_us = g_get_monotonic_time (); + if (event->time_us == CLUTTER_CURRENT_TIME) + event->time_us = g_get_monotonic_time (); - evdev_button = translate_to_evdev_button (button); + evdev_button = translate_to_evdev_button (event->button); if (get_button_type (evdev_button) != EVDEV_BUTTON_TYPE_BUTTON) { g_warning ("Unknown/invalid virtual device button 0x%x pressed", evdev_button); - return; + goto out; } - button_count = update_button_count (virtual_evdev, evdev_button, button_state); + button_count = update_button_count_in_impl (virtual_evdev, evdev_button, + event->button_state); if (button_count < 0 || button_count > 1) { g_warning ("Received multiple virtual 0x%x button %s (ignoring)", evdev_button, - button_state == CLUTTER_BUTTON_STATE_PRESSED ? "presses" : "releases"); - update_button_count (virtual_evdev, evdev_button, 1 - button_state); - return; + event->button_state == CLUTTER_BUTTON_STATE_PRESSED ? + "presses" : "releases"); + update_button_count_in_impl (virtual_evdev, evdev_button, 1 - event->button_state); + goto out; } meta_topic (META_DEBUG_INPUT, "Emitting virtual button-%s of button 0x%x (device %p)", - button_state == CLUTTER_BUTTON_STATE_PRESSED ? "press" : "release", - evdev_button, virtual_device); - - meta_seat_native_notify_button (virtual_evdev->seat, - virtual_evdev->device, - time_us, - evdev_button, - button_state); + event->button_state == CLUTTER_BUTTON_STATE_PRESSED ? + "press" : "release", + evdev_button, virtual_evdev); + + meta_seat_impl_notify_button_in_impl (seat, + virtual_evdev->impl_state->device, + event->time_us, + evdev_button, + event->button_state); + out: + g_task_return_boolean (task, TRUE); + return G_SOURCE_REMOVE; } static void -meta_virtual_input_device_native_notify_key (ClutterVirtualInputDevice *virtual_device, - uint64_t time_us, - uint32_t key, - ClutterKeyState key_state) +meta_virtual_input_device_native_notify_button (ClutterVirtualInputDevice *virtual_device, + uint64_t time_us, + uint32_t button, + ClutterButtonState button_state) { + MetaVirtualEventButton *event; MetaVirtualInputDeviceNative *virtual_evdev = META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); - int key_count; + GTask *task; - g_return_if_fail (virtual_evdev->device != NULL); + g_return_if_fail (virtual_evdev->impl_state->device != NULL); - if (time_us == CLUTTER_CURRENT_TIME) - time_us = g_get_monotonic_time (); + event = g_new0 (MetaVirtualEventButton, 1); + event->time_us = time_us; + event->button = button; + event->button_state = button_state; - if (get_button_type (key) != EVDEV_BUTTON_TYPE_KEY) + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, event, g_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) notify_button_in_impl); + g_object_unref (task); +} + +static gboolean +notify_key_in_impl (GTask *task) +{ + MetaVirtualInputDeviceNative *virtual_evdev = + g_task_get_source_object (task); + MetaSeatImpl *seat = virtual_evdev->seat->impl; + MetaVirtualEventKey *event = g_task_get_task_data (task); + int key_count; + + if (event->time_us == CLUTTER_CURRENT_TIME) + event->time_us = g_get_monotonic_time (); + + if (get_button_type (event->key) != EVDEV_BUTTON_TYPE_KEY) { - g_warning ("Unknown/invalid virtual device key 0x%x pressed", key); - return; + g_warning ("Unknown/invalid virtual device key 0x%x pressed", event->key); + goto out; } - key_count = update_button_count (virtual_evdev, key, key_state); + key_count = update_button_count_in_impl (virtual_evdev, event->key, event->key_state); if (key_count < 0 || key_count > 1) { - g_warning ("Received multiple virtual 0x%x key %s (ignoring)", key, - key_state == CLUTTER_KEY_STATE_PRESSED ? "presses" : "releases"); - update_button_count (virtual_evdev, key, 1 - key_state); - return; + g_warning ("Received multiple virtual 0x%x key %s (ignoring)", event->key, + event->key_state == CLUTTER_KEY_STATE_PRESSED ? + "presses" : "releases"); + update_button_count_in_impl (virtual_evdev, event->key, 1 - event->key_state); + goto out; } meta_topic (META_DEBUG_INPUT, "Emitting virtual key-%s of key 0x%x (device %p)", - key_state == CLUTTER_KEY_STATE_PRESSED ? "press" : "release", - key, virtual_device); + event->key_state == CLUTTER_KEY_STATE_PRESSED ? "press" : "release", + event->key, virtual_evdev); + + meta_seat_impl_notify_key_in_impl (seat, + virtual_evdev->impl_state->device, + event->time_us, + event->key, + event->key_state, + TRUE); + + out: + g_task_return_boolean (task, TRUE); + return G_SOURCE_REMOVE; +} + +static void +meta_virtual_input_device_native_notify_key (ClutterVirtualInputDevice *virtual_device, + uint64_t time_us, + uint32_t key, + ClutterKeyState key_state) +{ + MetaVirtualEventKey *event; + MetaVirtualInputDeviceNative *virtual_evdev = + META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); + GTask *task; + + g_return_if_fail (virtual_evdev->impl_state->device != NULL); + + event = g_new0 (MetaVirtualEventKey, 1); + event->time_us = time_us; + event->key = key; + event->key_state = key_state; - meta_seat_native_notify_key (virtual_evdev->seat, - virtual_evdev->device, - time_us, - key, - key_state, - TRUE); + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, event, g_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) notify_key_in_impl); + g_object_unref (task); } static gboolean -pick_keycode_for_keyval_in_current_group (ClutterVirtualInputDevice *virtual_device, - guint keyval, - guint *keycode_out, - guint *level_out) +pick_keycode_for_keyval_in_current_group_in_impl (ClutterVirtualInputDevice *virtual_device, + guint keyval, + guint *keycode_out, + guint *level_out) { MetaVirtualInputDeviceNative *virtual_evdev = META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); @@ -321,8 +475,8 @@ pick_keycode_for_keyval_in_current_group (ClutterVirtualInputDevice *virtual_dev backend = clutter_get_default_backend (); keymap = clutter_seat_get_keymap (clutter_backend_get_default_seat (backend)); - xkb_keymap = meta_keymap_native_get_keyboard_map (META_KEYMAP_NATIVE (keymap)); - state = virtual_evdev->seat->xkb; + xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (META_KEYMAP_NATIVE (keymap)); + state = meta_seat_impl_get_xkb_state_in_impl (virtual_evdev->seat->impl); layout = xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE); min_keycode = xkb_keymap_min_keycode (xkb_keymap); @@ -353,10 +507,10 @@ pick_keycode_for_keyval_in_current_group (ClutterVirtualInputDevice *virtual_dev } static void -apply_level_modifiers (ClutterVirtualInputDevice *virtual_device, - uint64_t time_us, - uint32_t level, - uint32_t key_state) +apply_level_modifiers_in_impl (ClutterVirtualInputDevice *virtual_device, + uint64_t time_us, + uint32_t level, + uint32_t key_state) { MetaVirtualInputDeviceNative *virtual_evdev = META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); @@ -379,85 +533,119 @@ apply_level_modifiers (ClutterVirtualInputDevice *virtual_device, return; } - if (!pick_keycode_for_keyval_in_current_group (virtual_device, keysym, - &keycode, NULL)) + if (!pick_keycode_for_keyval_in_current_group_in_impl (virtual_device, keysym, + &keycode, NULL)) return; - clutter_input_device_keycode_to_evdev (virtual_evdev->device, - keycode, &evcode); + evcode = meta_xkb_keycode_to_evdev (keycode); meta_topic (META_DEBUG_INPUT, "Emitting virtual key-%s of modifier key 0x%x (device %p)", key_state == CLUTTER_KEY_STATE_PRESSED ? "press" : "release", evcode, virtual_device); - meta_seat_native_notify_key (virtual_evdev->seat, - virtual_evdev->device, - time_us, - evcode, - key_state, - TRUE); + meta_seat_impl_notify_key_in_impl (virtual_evdev->seat->impl, + virtual_evdev->impl_state->device, + time_us, + evcode, + key_state, + TRUE); } -static void -meta_virtual_input_device_native_notify_keyval (ClutterVirtualInputDevice *virtual_device, - uint64_t time_us, - uint32_t keyval, - ClutterKeyState key_state) +static gboolean +notify_keyval_in_impl (GTask *task) { MetaVirtualInputDeviceNative *virtual_evdev = - META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); + g_task_get_source_object (task); + ClutterVirtualInputDevice *virtual_device = + CLUTTER_VIRTUAL_INPUT_DEVICE (virtual_evdev); + MetaSeatImpl *seat = virtual_evdev->seat->impl; + MetaVirtualEventKey *event = g_task_get_task_data (task); int key_count; guint keycode = 0, level = 0, evcode = 0; - g_return_if_fail (virtual_evdev->device != NULL); - - if (time_us == CLUTTER_CURRENT_TIME) - time_us = g_get_monotonic_time (); + if (event->time_us == CLUTTER_CURRENT_TIME) + event->time_us = g_get_monotonic_time (); - if (!pick_keycode_for_keyval_in_current_group (virtual_device, - keyval, &keycode, &level)) + if (!pick_keycode_for_keyval_in_current_group_in_impl (virtual_device, + event->key, + &keycode, &level)) { - g_warning ("No keycode found for keyval %x in current group", keyval); - return; + g_warning ("No keycode found for keyval %x in current group", event->key); + goto out; } - clutter_input_device_keycode_to_evdev (virtual_evdev->device, - keycode, &evcode); + evcode = meta_xkb_keycode_to_evdev (keycode); if (get_button_type (evcode) != EVDEV_BUTTON_TYPE_KEY) { g_warning ("Unknown/invalid virtual device key 0x%x pressed", evcode); - return; + goto out; } - key_count = update_button_count (virtual_evdev, evcode, key_state); + key_count = update_button_count_in_impl (virtual_evdev, evcode, event->key_state); if (key_count < 0 || key_count > 1) { g_warning ("Received multiple virtual 0x%x key %s (ignoring)", evcode, - key_state == CLUTTER_KEY_STATE_PRESSED ? "presses" : "releases"); - update_button_count (virtual_evdev, evcode, 1 - key_state); - return; + event->key_state == CLUTTER_KEY_STATE_PRESSED ? + "presses" : "releases"); + update_button_count_in_impl (virtual_evdev, evcode, 1 - event->key_state); + goto out; } meta_topic (META_DEBUG_INPUT, "Emitting virtual key-%s of key 0x%x with modifier level %d, " "press count %d (device %p)", - key_state == CLUTTER_KEY_STATE_PRESSED ? "press" : "release", - evcode, level, key_count, virtual_device); + event->key_state == CLUTTER_KEY_STATE_PRESSED ? "press" : "release", + evcode, level, key_count, virtual_evdev); + + if (event->key_state) + { + apply_level_modifiers_in_impl (virtual_device, event->time_us, + level, event->key_state); + } - if (key_state) - apply_level_modifiers (virtual_device, time_us, level, key_state); + meta_seat_impl_notify_key_in_impl (seat, + virtual_evdev->impl_state->device, + event->time_us, + evcode, + event->key_state, + TRUE); - meta_seat_native_notify_key (virtual_evdev->seat, - virtual_evdev->device, - time_us, - evcode, - key_state, - TRUE); + if (!event->key_state) + { + apply_level_modifiers_in_impl (virtual_device, event->time_us, + level, event->key_state); + } - if (!key_state) - apply_level_modifiers (virtual_device, time_us, level, key_state); + out: + g_task_return_boolean (task, TRUE); + return G_SOURCE_REMOVE; +} + +static void +meta_virtual_input_device_native_notify_keyval (ClutterVirtualInputDevice *virtual_device, + uint64_t time_us, + uint32_t keyval, + ClutterKeyState key_state) +{ + MetaVirtualEventKey *event; + MetaVirtualInputDeviceNative *virtual_evdev = + META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); + GTask *task; + + g_return_if_fail (virtual_evdev->impl_state->device != NULL); + + event = g_new0 (MetaVirtualEventKey, 1); + event->time_us = time_us; + event->key = keyval; + event->key_state = key_state; + + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, event, g_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) notify_keyval_in_impl); + g_object_unref (task); } static void @@ -489,28 +677,74 @@ direction_to_discrete (ClutterScrollDirection direction, } } +static gboolean +notify_discrete_scroll_in_impl (GTask *task) +{ + MetaVirtualInputDeviceNative *virtual_evdev = + g_task_get_source_object (task); + MetaSeatImpl *seat = virtual_evdev->seat->impl; + MetaVirtualEventScroll *event = g_task_get_task_data (task); + double discrete_dx = 0.0, discrete_dy = 0.0; + + if (event->time_us == CLUTTER_CURRENT_TIME) + event->time_us = g_get_monotonic_time (); + + direction_to_discrete (event->direction, &discrete_dx, &discrete_dy); + + meta_seat_impl_notify_discrete_scroll_in_impl (seat, + virtual_evdev->impl_state->device, + event->time_us, + discrete_dx, discrete_dy, + event->scroll_source); + + g_task_return_boolean (task, TRUE); + return G_SOURCE_REMOVE; +} + static void meta_virtual_input_device_native_notify_discrete_scroll (ClutterVirtualInputDevice *virtual_device, uint64_t time_us, ClutterScrollDirection direction, ClutterScrollSource scroll_source) { + MetaVirtualEventScroll *event; MetaVirtualInputDeviceNative *virtual_evdev = META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); - double discrete_dx = 0.0, discrete_dy = 0.0; + GTask *task; - g_return_if_fail (virtual_evdev->device != NULL); + g_return_if_fail (virtual_evdev->impl_state->device != NULL); - if (time_us == CLUTTER_CURRENT_TIME) - time_us = g_get_monotonic_time (); + event = g_new0 (MetaVirtualEventScroll, 1); + event->time_us = time_us; + event->direction = direction; + event->scroll_source = scroll_source; - direction_to_discrete (direction, &discrete_dx, &discrete_dy); + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, event, g_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) notify_discrete_scroll_in_impl); + g_object_unref (task); +} - meta_seat_native_notify_discrete_scroll (virtual_evdev->seat, - virtual_evdev->device, - time_us, - discrete_dx, discrete_dy, - scroll_source); +static gboolean +notify_scroll_continuous_in_impl (GTask *task) +{ + MetaVirtualInputDeviceNative *virtual_evdev = + g_task_get_source_object (task); + MetaSeatImpl *seat = virtual_evdev->seat->impl; + MetaVirtualEventScroll *event = g_task_get_task_data (task); + + if (event->time_us == CLUTTER_CURRENT_TIME) + event->time_us = g_get_monotonic_time (); + + meta_seat_impl_notify_scroll_continuous_in_impl (seat, + virtual_evdev->impl_state->device, + event->time_us, + event->dx, event->dy, + event->scroll_source, + CLUTTER_SCROLL_FINISHED_NONE); + g_task_return_boolean (task, TRUE); + return G_SOURCE_REMOVE; } static void @@ -521,20 +755,58 @@ meta_virtual_input_device_native_notify_scroll_continuous (ClutterVirtualInputDe ClutterScrollSource scroll_source, ClutterScrollFinishFlags finish_flags) { + MetaVirtualEventScroll *event; MetaVirtualInputDeviceNative *virtual_evdev = META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); + GTask *task; + + g_return_if_fail (virtual_evdev->impl_state->device != NULL); + + event = g_new0 (MetaVirtualEventScroll, 1); + event->time_us = time_us; + event->dx = dx; + event->dy = dy; + event->scroll_source = scroll_source; + event->finish_flags = finish_flags; + + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, event, g_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) notify_scroll_continuous_in_impl); + g_object_unref (task); +} - g_return_if_fail (virtual_evdev->device != NULL); +static gboolean +notify_touch_down_in_impl (GTask *task) +{ + MetaVirtualInputDeviceNative *virtual_evdev = + g_task_get_source_object (task); + MetaSeatImpl *seat = virtual_evdev->seat->impl; + MetaVirtualEventTouch *event = g_task_get_task_data (task); + MetaTouchState *touch_state; - if (time_us == CLUTTER_CURRENT_TIME) - time_us = g_get_monotonic_time (); + if (event->time_us == CLUTTER_CURRENT_TIME) + event->time_us = g_get_monotonic_time (); - meta_seat_native_notify_scroll_continuous (virtual_evdev->seat, - virtual_evdev->device, - time_us, - dx, dy, - scroll_source, - CLUTTER_SCROLL_FINISHED_NONE); + touch_state = meta_seat_impl_acquire_touch_state_in_impl (seat, + event->device_slot); + if (!touch_state) + goto out; + + touch_state->coords.x = event->x; + touch_state->coords.y = event->y; + + meta_seat_impl_notify_touch_event_in_impl (seat, + virtual_evdev->impl_state->device, + CLUTTER_TOUCH_BEGIN, + event->time_us, + touch_state->seat_slot, + touch_state->coords.x, + touch_state->coords.y); + + out: + g_task_return_boolean (task, TRUE); + return G_SOURCE_REMOVE; } static void @@ -544,32 +816,57 @@ meta_virtual_input_device_native_notify_touch_down (ClutterVirtualInputDevice *v double x, double y) { + MetaVirtualEventTouch *event; MetaVirtualInputDeviceNative *virtual_evdev = META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); - MetaTouchState *touch_state; - guint seat_slot; + GTask *task; - g_return_if_fail (virtual_evdev->device != NULL); + g_return_if_fail (virtual_evdev->impl_state->device != NULL); - if (time_us == CLUTTER_CURRENT_TIME) - time_us = g_get_monotonic_time (); + event = g_new0 (MetaVirtualEventTouch, 1); + event->time_us = time_us; + event->device_slot = virtual_evdev->slot_base + (guint) device_slot; + event->x = x; + event->y = y; - seat_slot = virtual_evdev->slot_base + (guint) device_slot; - touch_state = meta_seat_native_acquire_touch_state (virtual_evdev->seat, - seat_slot); - if (!touch_state) - return; + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, event, g_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) notify_touch_down_in_impl); + g_object_unref (task); +} + +static gboolean +notify_touch_motion_in_impl (GTask *task) +{ + MetaVirtualInputDeviceNative *virtual_evdev = + g_task_get_source_object (task); + MetaSeatImpl *seat = virtual_evdev->seat->impl; + MetaVirtualEventTouch *event = g_task_get_task_data (task); + MetaTouchState *touch_state; - touch_state->coords.x = x; - touch_state->coords.y = y; + if (event->time_us == CLUTTER_CURRENT_TIME) + event->time_us = g_get_monotonic_time (); - meta_seat_native_notify_touch_event (virtual_evdev->seat, - virtual_evdev->device, - CLUTTER_TOUCH_BEGIN, - time_us, - touch_state->seat_slot, - touch_state->coords.x, - touch_state->coords.y); + touch_state = meta_seat_impl_lookup_touch_state_in_impl (seat, + event->device_slot); + if (!touch_state) + goto out; + + touch_state->coords.x = event->x; + touch_state->coords.y = event->y; + + meta_seat_impl_notify_touch_event_in_impl (seat, + virtual_evdev->impl_state->device, + CLUTTER_TOUCH_UPDATE, + event->time_us, + touch_state->seat_slot, + touch_state->coords.x, + touch_state->coords.y); + + out: + g_task_return_boolean (task, TRUE); + return G_SOURCE_REMOVE; } static void @@ -579,32 +876,57 @@ meta_virtual_input_device_native_notify_touch_motion (ClutterVirtualInputDevice double x, double y) { + MetaVirtualEventTouch *event; MetaVirtualInputDeviceNative *virtual_evdev = META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); - MetaTouchState *touch_state; - guint seat_slot; + GTask *task; - g_return_if_fail (virtual_evdev->device != NULL); + g_return_if_fail (virtual_evdev->impl_state->device != NULL); - if (time_us == CLUTTER_CURRENT_TIME) - time_us = g_get_monotonic_time (); + event = g_new0 (MetaVirtualEventTouch, 1); + event->time_us = time_us; + event->device_slot = virtual_evdev->slot_base + (guint) device_slot; + event->x = x; + event->y = y; - seat_slot = virtual_evdev->slot_base + (guint) device_slot; - touch_state = meta_seat_native_lookup_touch_state (virtual_evdev->seat, - seat_slot); - if (!touch_state) - return; + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, event, g_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) notify_touch_motion_in_impl); + g_object_unref (task); +} + +static gboolean +notify_touch_up_in_impl (GTask *task) +{ + MetaVirtualInputDeviceNative *virtual_evdev = + g_task_get_source_object (task); + MetaSeatImpl *seat = virtual_evdev->seat->impl; + MetaVirtualEventTouch *event = g_task_get_task_data (task); + MetaTouchState *touch_state; - touch_state->coords.x = x; - touch_state->coords.y = y; + if (event->time_us == CLUTTER_CURRENT_TIME) + event->time_us = g_get_monotonic_time (); - meta_seat_native_notify_touch_event (virtual_evdev->seat, - virtual_evdev->device, - CLUTTER_TOUCH_BEGIN, - time_us, - touch_state->seat_slot, - touch_state->coords.x, - touch_state->coords.y); + touch_state = meta_seat_impl_lookup_touch_state_in_impl (seat, + event->device_slot); + if (!touch_state) + goto out; + + meta_seat_impl_notify_touch_event_in_impl (seat, + virtual_evdev->impl_state->device, + CLUTTER_TOUCH_END, + event->time_us, + touch_state->seat_slot, + touch_state->coords.x, + touch_state->coords.y); + + meta_seat_impl_release_touch_state_in_impl (virtual_evdev->seat->impl, + touch_state->seat_slot); + + out: + g_task_return_boolean (task, TRUE); + return G_SOURCE_REMOVE; } static void @@ -612,32 +934,22 @@ meta_virtual_input_device_native_notify_touch_up (ClutterVirtualInputDevice *vir uint64_t time_us, int device_slot) { + MetaVirtualEventTouch *event; MetaVirtualInputDeviceNative *virtual_evdev = META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device); - MetaTouchState *touch_state; - guint seat_slot; - - g_return_if_fail (virtual_evdev->device != NULL); + GTask *task; - if (time_us == CLUTTER_CURRENT_TIME) - time_us = g_get_monotonic_time (); - - seat_slot = virtual_evdev->slot_base + (guint) device_slot; - touch_state = meta_seat_native_lookup_touch_state (virtual_evdev->seat, - seat_slot); - if (!touch_state) - return; + g_return_if_fail (virtual_evdev->impl_state->device != NULL); - meta_seat_native_notify_touch_event (virtual_evdev->seat, - virtual_evdev->device, - CLUTTER_TOUCH_BEGIN, - time_us, - touch_state->seat_slot, - touch_state->coords.x, - touch_state->coords.y); + event = g_new0 (MetaVirtualEventTouch, 1); + event->time_us = time_us; + event->device_slot = virtual_evdev->slot_base + (guint) device_slot; - meta_seat_native_release_touch_state (virtual_evdev->seat, - touch_state->seat_slot); + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, event, g_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) notify_touch_up_in_impl); + g_object_unref (task); } static void @@ -701,14 +1013,18 @@ meta_virtual_input_device_native_constructed (GObject *object) "Creating new virtual input device of type %d (%p)", device_type, virtual_device); - virtual_evdev->device = - meta_input_device_native_new_virtual (virtual_evdev->seat, + virtual_evdev->impl_state = g_new0 (ImplState, 1); + virtual_evdev->impl_state->device = + meta_input_device_native_new_virtual (virtual_evdev->seat->impl, device_type, CLUTTER_INPUT_MODE_PHYSICAL); +} - g_signal_emit_by_name (virtual_evdev->seat, - "device-added", - virtual_evdev->device); +static void +impl_state_free (ImplState *impl_state) +{ + g_clear_object (&impl_state->device); + g_free (impl_state); } static void @@ -721,14 +1037,18 @@ meta_virtual_input_device_native_dispose (GObject *object) GObjectClass *object_class = G_OBJECT_CLASS (meta_virtual_input_device_native_parent_class); - if (virtual_evdev->device) + if (virtual_evdev->impl_state) { - release_pressed_buttons (virtual_device); - g_signal_emit_by_name (virtual_evdev->seat, - "device-removed", - virtual_evdev->device); + GTask *task; + + task = g_task_new (virtual_device, NULL, NULL, NULL); + g_task_set_task_data (task, virtual_evdev->impl_state, + (GDestroyNotify) impl_state_free); + meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task, + (GSourceFunc) release_device_in_impl); + g_object_unref (task); - g_clear_object (&virtual_evdev->device); + virtual_evdev->impl_state = NULL; } meta_seat_native_release_touch_slots (virtual_evdev->seat, diff --git a/src/backends/native/meta-xkb-utils.c b/src/backends/native/meta-xkb-utils.c index 6470e520e95a1c7fa801afc7aa6c85e3f148d2f6..45f89bec7ff04a612c620142ac5d09b524a479b0 100644 --- a/src/backends/native/meta-xkb-utils.c +++ b/src/backends/native/meta-xkb-utils.c @@ -62,7 +62,7 @@ meta_key_event_new_from_evdev (ClutterInputDevice *device, * 0, whereas X11's minimum keycode, for really stupid reasons, is 8. * So the evdev XKB rules are based on the keycodes all being shifted * upwards by 8. */ - key += 8; + key = meta_xkb_evdev_to_keycode (key); n = xkb_key_get_syms (xkb_state, key, &syms); if (n == 1) @@ -106,3 +106,32 @@ meta_xkb_translate_state (ClutterEvent *event, xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED), xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE) | button_state); } + +ClutterModifierType +meta_xkb_translate_modifiers (struct xkb_state *state, + ClutterModifierType button_state) +{ + ClutterModifierType modifiers; + + modifiers = xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE); + modifiers |= button_state; + + return modifiers; +} + +uint32_t +meta_xkb_keycode_to_evdev (uint32_t xkb_keycode) +{ + /* The keycodes from the evdev backend are almost evdev + * keycodes: we use the evdev keycode file, but xkb rules have an + * offset by 8. See the comment in _clutter_key_event_new_from_evdev() + */ + return xkb_keycode - 8; +} + +uint32_t +meta_xkb_evdev_to_keycode (uint32_t evcode) +{ + /* The inverse of meta_xkb_keycode_to_evdev */ + return evcode + 8; +} diff --git a/src/backends/native/meta-xkb-utils.h b/src/backends/native/meta-xkb-utils.h index 5121d08d6ed37ef487c32e75d0cadb116242dfe0..d605813e6dc1f0fd0c2ab6ce40bf664e20604a62 100644 --- a/src/backends/native/meta-xkb-utils.h +++ b/src/backends/native/meta-xkb-utils.h @@ -35,5 +35,9 @@ ClutterEvent * meta_key_event_new_from_evdev (ClutterInputDevice *device, void meta_xkb_translate_state (ClutterEvent *event, struct xkb_state *xkb_state, uint32_t button_state); +ClutterModifierType meta_xkb_translate_modifiers (struct xkb_state *state, + ClutterModifierType button_state); +uint32_t meta_xkb_keycode_to_evdev (uint32_t hardware_keycode); +uint32_t meta_xkb_evdev_to_keycode (uint32_t evcode); #endif /* META_XKB_UTILS_H */ diff --git a/src/backends/x11/cm/meta-backend-x11-cm.c b/src/backends/x11/cm/meta-backend-x11-cm.c index 28726f7d7da9d39e037e13e4199ebfab83a3154d..3b39178e0dbcabca5a851d80506c9d52346bf690 100644 --- a/src/backends/x11/cm/meta-backend-x11-cm.c +++ b/src/backends/x11/cm/meta-backend-x11-cm.c @@ -41,10 +41,13 @@ struct _MetaBackendX11Cm { MetaBackendX11 parent; + MetaCursorRenderer *cursor_renderer; char *keymap_layouts; char *keymap_variants; char *keymap_options; int locked_group; + + MetaInputSettings *input_settings; }; G_DEFINE_TYPE (MetaBackendX11Cm, meta_backend_x11_cm, META_TYPE_BACKEND_X11) @@ -86,8 +89,11 @@ meta_backend_x11_cm_post_init (MetaBackend *backend) { MetaBackendClass *parent_backend_class = META_BACKEND_CLASS (meta_backend_x11_cm_parent_class); + MetaBackendX11Cm *x11_cm = META_BACKEND_X11_CM (backend); ClutterSeat *seat; + x11_cm->input_settings = g_object_new (META_TYPE_INPUT_SETTINGS_X11, NULL); + parent_backend_class->post_init (backend); seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); @@ -116,11 +122,21 @@ meta_backend_x11_cm_create_monitor_manager (MetaBackend *backend, } static MetaCursorRenderer * -meta_backend_x11_cm_create_cursor_renderer (MetaBackend *backend) +meta_backend_x11_cm_get_cursor_renderer (MetaBackend *backend, + ClutterInputDevice *device) { - return g_object_new (META_TYPE_CURSOR_RENDERER_X11, - "backend", backend, - NULL); + MetaBackendX11Cm *x11_cm = META_BACKEND_X11_CM (backend); + + if (!x11_cm->cursor_renderer) + { + x11_cm->cursor_renderer = + g_object_new (META_TYPE_CURSOR_RENDERER_X11, + "backend", backend, + "device", device, + NULL); + } + + return x11_cm->cursor_renderer; } static MetaCursorTracker * @@ -132,9 +148,11 @@ meta_backend_x11_cm_create_cursor_tracker (MetaBackend *backend) } static MetaInputSettings * -meta_backend_x11_cm_create_input_settings (MetaBackend *backend) +meta_backend_x11_cm_get_input_settings (MetaBackend *backend) { - return g_object_new (META_TYPE_INPUT_SETTINGS_X11, NULL); + MetaBackendX11Cm *x11_cm = META_BACKEND_X11_CM (backend); + + return x11_cm->input_settings; } static void @@ -444,9 +462,9 @@ meta_backend_x11_cm_class_init (MetaBackendX11CmClass *klass) backend_class->post_init = meta_backend_x11_cm_post_init; backend_class->create_renderer = meta_backend_x11_cm_create_renderer; backend_class->create_monitor_manager = meta_backend_x11_cm_create_monitor_manager; - backend_class->create_cursor_renderer = meta_backend_x11_cm_create_cursor_renderer; + backend_class->get_cursor_renderer = meta_backend_x11_cm_get_cursor_renderer; backend_class->create_cursor_tracker = meta_backend_x11_cm_create_cursor_tracker; - backend_class->create_input_settings = meta_backend_x11_cm_create_input_settings; + backend_class->get_input_settings = meta_backend_x11_cm_get_input_settings; backend_class->update_screen_size = meta_backend_x11_cm_update_screen_size; backend_class->select_stage_events = meta_backend_x11_cm_select_stage_events; backend_class->lock_layout_group = meta_backend_x11_cm_lock_layout_group; diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c index d53deb3861593de1d86fdcf328d344b5ed356ebc..94a13e7cdb64bb4e80a0717e27e72bbaf65d9849 100644 --- a/src/backends/x11/meta-backend-x11.c +++ b/src/backends/x11/meta-backend-x11.c @@ -50,6 +50,7 @@ #include "backends/x11/meta-seat-x11.h" #include "backends/x11/meta-stage-x11.h" #include "backends/x11/meta-renderer-x11.h" +#include "backends/x11/meta-xkb-a11y-x11.h" #include "clutter/clutter.h" #include "clutter/x11/clutter-x11.h" #include "compositor/compositor-private.h" @@ -81,6 +82,8 @@ struct _MetaBackendX11Private uint8_t xkb_event_base; uint8_t xkb_error_base; + gulong keymap_state_changed_id; + struct xkb_keymap *keymap; xkb_layout_index_t keymap_layout_group; @@ -519,6 +522,17 @@ on_monitors_changed (MetaMonitorManager *manager, priv->cached_current_logical_monitor = NULL; } +static void +on_kbd_a11y_changed (MetaInputSettings *input_settings, + MetaKbdA11ySettings *a11y_settings, + MetaBackend *backend) +{ + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); + + meta_seat_x11_apply_kbd_a11y_settings (seat, a11y_settings); +} + static void meta_backend_x11_post_init (MetaBackend *backend) { @@ -527,6 +541,7 @@ meta_backend_x11_post_init (MetaBackend *backend) MetaMonitorManager *monitor_manager; ClutterBackend *clutter_backend; ClutterSeat *seat; + MetaInputSettings *input_settings; int major, minor; gboolean has_xi = FALSE; @@ -584,6 +599,23 @@ meta_backend_x11_post_init (MetaBackend *backend) seat = clutter_backend_get_default_seat (clutter_backend); meta_seat_x11_notify_devices (META_SEAT_X11 (seat), CLUTTER_STAGE (meta_backend_get_stage (backend))); + + input_settings = meta_backend_get_input_settings (backend); + + if (input_settings) + { + g_signal_connect_object (meta_backend_get_input_settings (backend), + "kbd-a11y-changed", + G_CALLBACK (on_kbd_a11y_changed), backend, 0); + + if (meta_input_settings_maybe_restore_numlock_state (input_settings)) + { + unsigned int num_mask; + + num_mask = XkbKeysymToModifiers (priv->xdisplay, XK_Num_Lock); + XkbLockModifiers (priv->xdisplay, XkbUseCoreKbd, num_mask, num_mask); + } + } } static ClutterBackend * @@ -736,19 +768,6 @@ meta_backend_x11_get_keymap_layout_group (MetaBackend *backend) return priv->keymap_layout_group; } -static void -meta_backend_x11_set_numlock (MetaBackend *backend, - gboolean numlock_state) -{ - MetaBackendX11 *x11 = META_BACKEND_X11 (backend); - MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); - unsigned int num_mask; - - num_mask = XkbKeysymToModifiers (priv->xdisplay, XK_Num_Lock); - XkbLockModifiers (priv->xdisplay, XkbUseCoreKbd, num_mask, - numlock_state ? num_mask : 0); -} - void meta_backend_x11_handle_event (MetaBackendX11 *x11, XEvent *xevent) @@ -831,9 +850,21 @@ initable_iface_init (GInitableIface *initable_iface) static void meta_backend_x11_finalize (GObject *object) { + MetaBackend *backend = META_BACKEND (object); MetaBackendX11 *x11 = META_BACKEND_X11 (object); MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); + if (priv->keymap_state_changed_id) + { + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); + ClutterKeymap *keymap; + + seat = clutter_backend_get_default_seat (clutter_backend); + keymap = clutter_seat_get_keymap (seat); + g_clear_signal_handler (&priv->keymap_state_changed_id, keymap); + } + if (priv->user_active_alarm != None) { XSyncDestroyAlarm (priv->xdisplay, priv->user_active_alarm); @@ -858,7 +889,6 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass) backend_class->get_current_logical_monitor = meta_backend_x11_get_current_logical_monitor; backend_class->get_keymap = meta_backend_x11_get_keymap; backend_class->get_keymap_layout_group = meta_backend_x11_get_keymap_layout_group; - backend_class->set_numlock = meta_backend_x11_set_numlock; } static void diff --git a/src/backends/x11/meta-cursor-tracker-x11.c b/src/backends/x11/meta-cursor-tracker-x11.c index 1e6c39e71de4996dacd6eb55404c7772df5725cd..7355f828ea0040ea9588f7e8d6565dc4f1f36201 100644 --- a/src/backends/x11/meta-cursor-tracker-x11.c +++ b/src/backends/x11/meta-cursor-tracker-x11.c @@ -69,10 +69,8 @@ static void update_position (MetaCursorTrackerX11 *tracker_x11) { MetaCursorTracker *tracker = META_CURSOR_TRACKER (tracker_x11); - graphene_point_t point; - meta_cursor_tracker_get_pointer (tracker, &point, NULL); - meta_cursor_tracker_update_position (tracker, point.x, point.y); + meta_cursor_tracker_invalidate_position (tracker); } static gboolean diff --git a/src/backends/x11/meta-input-device-tool-x11.c b/src/backends/x11/meta-input-device-tool-x11.c index 0632fea5a24b3f9b6b300d034dd83460a7926500..bec4d1fadf38534fb92685a40f16dd3159045696 100644 --- a/src/backends/x11/meta-input-device-tool-x11.c +++ b/src/backends/x11/meta-input-device-tool-x11.c @@ -38,8 +38,19 @@ ClutterInputDeviceTool * meta_input_device_tool_x11_new (guint serial, ClutterInputDeviceToolType type) { + ClutterInputAxisFlags axes = + CLUTTER_INPUT_AXIS_FLAG_PRESSURE | + CLUTTER_INPUT_AXIS_FLAG_DISTANCE | + CLUTTER_INPUT_AXIS_FLAG_XTILT | + CLUTTER_INPUT_AXIS_FLAG_YTILT | + CLUTTER_INPUT_AXIS_FLAG_WHEEL | + CLUTTER_INPUT_AXIS_FLAG_DISTANCE | + CLUTTER_INPUT_AXIS_FLAG_ROTATION | + CLUTTER_INPUT_AXIS_FLAG_SLIDER; + return g_object_new (META_TYPE_INPUT_DEVICE_TOOL_X11, "type", type, "serial", serial, + "axes", axes, NULL); } diff --git a/src/backends/x11/meta-input-device-x11.c b/src/backends/x11/meta-input-device-x11.c index 7d518076678bf50eafc9d5319fb21fc56a281ab0..0c4e023d1d13231610fda61f724090755d8424d6 100644 --- a/src/backends/x11/meta-input-device-x11.c +++ b/src/backends/x11/meta-input-device-x11.c @@ -37,11 +37,37 @@ struct _MetaInputDeviceX11 float current_x; float current_y; + GArray *axes; + GArray *scroll_info; + #ifdef HAVE_LIBWACOM GArray *group_modes; #endif }; +typedef struct _MetaX11AxisInfo +{ + ClutterInputAxis axis; + + double min_axis; + double max_axis; + + double min_value; + double max_value; + + double resolution; +} MetaX11AxisInfo; + +typedef struct _MetaX11ScrollInfo +{ + guint axis_id; + ClutterScrollDirection direction; + double increment; + + double last_value; + guint last_value_valid : 1; +} MetaX11ScrollInfo; + struct _MetaInputDeviceX11Class { ClutterInputDeviceClass device_class; @@ -80,20 +106,6 @@ meta_input_device_x11_constructed (GObject *object) #endif } -static gboolean -meta_input_device_x11_keycode_to_evdev (ClutterInputDevice *device, - uint32_t hardware_keycode, - uint32_t *evdev_keycode) -{ - /* When using evdev under X11 the hardware keycodes are the evdev - keycodes plus 8. I haven't been able to find any documentation to - know what the +8 is for. FIXME: This should probably verify that - X server is using evdev. */ - *evdev_keycode = hardware_keycode - 8; - - return TRUE; -} - static gboolean meta_input_device_x11_is_grouped (ClutterInputDevice *device, ClutterInputDevice *other_device) @@ -133,6 +145,9 @@ meta_input_device_x11_finalize (GObject *object) { MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (object); + g_clear_pointer (&device_xi2->axes, g_array_unref); + g_clear_pointer (&device_xi2->scroll_info, g_array_unref); + #ifdef HAVE_LIBWACOM if (device_xi2->group_modes) g_array_unref (device_xi2->group_modes); @@ -267,7 +282,6 @@ meta_input_device_x11_class_init (MetaInputDeviceX11Class *klass) gobject_class->set_property = meta_input_device_x11_set_property; gobject_class->get_property = meta_input_device_x11_get_property; - device_class->keycode_to_evdev = meta_input_device_x11_keycode_to_evdev; device_class->is_grouped = meta_input_device_x11_is_grouped; device_class->get_group_n_modes = meta_input_device_x11_get_group_n_modes; device_class->is_mode_switch_button = meta_input_device_x11_is_mode_switch_button; @@ -433,7 +447,8 @@ meta_input_device_x11_get_pointer_location (ClutterInputDevice *device, MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (device); g_return_val_if_fail (META_IS_INPUT_DEVICE_X11 (device), FALSE); - g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, FALSE); + g_return_val_if_fail (clutter_input_device_get_device_type (device) == + CLUTTER_POINTER_DEVICE, FALSE); /* Throttle XServer queries and roundtrips using an idle timeout */ if (device_xi2->inhibit_pointer_query_timer == 0) @@ -460,6 +475,218 @@ meta_input_device_x11_get_device_id (ClutterInputDevice *device) return device_xi2->device_id; } +void +meta_input_device_x11_reset_axes (ClutterInputDevice *device) +{ + MetaInputDeviceX11 *device_x11 = META_INPUT_DEVICE_X11 (device); + + g_clear_pointer (&device_x11->axes, g_array_unref); +} + +int +meta_input_device_x11_add_axis (ClutterInputDevice *device, + ClutterInputAxis axis, + double minimum, + double maximum, + double resolution) +{ + MetaInputDeviceX11 *device_x11 = META_INPUT_DEVICE_X11 (device); + MetaX11AxisInfo info; + guint pos; + + if (device_x11->axes == NULL) + device_x11->axes = g_array_new (FALSE, TRUE, sizeof (MetaX11AxisInfo)); + + info.axis = axis; + info.min_value = minimum; + info.max_value = maximum; + info.resolution = resolution; + + switch (axis) + { + case CLUTTER_INPUT_AXIS_X: + case CLUTTER_INPUT_AXIS_Y: + info.min_axis = 0; + info.max_axis = 0; + break; + + case CLUTTER_INPUT_AXIS_XTILT: + case CLUTTER_INPUT_AXIS_YTILT: + info.min_axis = -1; + info.max_axis = 1; + break; + + default: + info.min_axis = 0; + info.max_axis = 1; + break; + } + + g_array_append_val (device_x11->axes, info); + pos = device_x11->axes->len - 1; + + return pos; +} + +gboolean +meta_input_device_x11_get_axis (ClutterInputDevice *device, + int idx, + ClutterInputAxis *use) +{ + MetaInputDeviceX11 *device_x11 = META_INPUT_DEVICE_X11 (device); + MetaX11AxisInfo *info; + + if (device_x11->axes == NULL) + return FALSE; + + if (idx < 0 || idx >= device_x11->axes->len) + return FALSE; + + info = &g_array_index (device_x11->axes, MetaX11AxisInfo, idx); + + if (use) + *use = info->axis; + + return TRUE; +} + +gboolean +meta_input_device_x11_translate_axis (ClutterInputDevice *device, + int idx, + double value, + double *axis_value) +{ + MetaInputDeviceX11 *device_x11 = META_INPUT_DEVICE_X11 (device); + MetaX11AxisInfo *info; + double width; + double real_value; + + if (device_x11->axes == NULL || idx < 0 || idx >= device_x11->axes->len) + return FALSE; + + info = &g_array_index (device_x11->axes, MetaX11AxisInfo, idx); + + if (info->axis == CLUTTER_INPUT_AXIS_X || + info->axis == CLUTTER_INPUT_AXIS_Y) + return FALSE; + + if (fabs (info->max_value - info->min_value) < 0.0000001) + return FALSE; + + width = info->max_value - info->min_value; + real_value = (info->max_axis * (value - info->min_value) + + info->min_axis * (info->max_value - value)) + / width; + + if (axis_value) + *axis_value = real_value; + + return TRUE; +} + +int +meta_input_device_x11_get_n_axes (ClutterInputDevice *device) +{ + MetaInputDeviceX11 *device_x11 = META_INPUT_DEVICE_X11 (device); + + return device_x11->axes->len; +} + +void +meta_input_device_x11_add_scroll_info (ClutterInputDevice *device, + int idx, + ClutterScrollDirection direction, + double increment) +{ + MetaInputDeviceX11 *device_x11 = META_INPUT_DEVICE_X11 (device); + MetaX11ScrollInfo info; + + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); + + info.axis_id = idx; + info.direction = direction; + info.increment = increment; + info.last_value_valid = FALSE; + + if (device_x11->scroll_info == NULL) + { + device_x11->scroll_info = g_array_new (FALSE, + FALSE, + sizeof (MetaX11ScrollInfo)); + } + + g_array_append_val (device_x11->scroll_info, info); +} + +gboolean +meta_input_device_x11_get_scroll_delta (ClutterInputDevice *device, + int idx, + double value, + ClutterScrollDirection *direction_p, + double *delta_p) +{ + MetaInputDeviceX11 *device_x11 = META_INPUT_DEVICE_X11 (device); + int i; + + if (device_x11->scroll_info == NULL) + return FALSE; + + for (i = 0; i < device_x11->scroll_info->len; i++) + { + MetaX11ScrollInfo *info = &g_array_index (device_x11->scroll_info, + MetaX11ScrollInfo, + i); + + if (info->axis_id == idx) + { + if (direction_p != NULL) + *direction_p = info->direction; + + if (delta_p != NULL) + *delta_p = 0.0; + + if (info->last_value_valid) + { + if (delta_p != NULL) + { + *delta_p = (value - info->last_value) + / info->increment; + } + + info->last_value = value; + } + else + { + info->last_value = value; + info->last_value_valid = TRUE; + } + + return TRUE; + } + } + + return FALSE; +} + +void +meta_input_device_x11_reset_scroll_info (ClutterInputDevice *device) +{ + MetaInputDeviceX11 *device_x11 = META_INPUT_DEVICE_X11 (device); + int i; + + if (device_x11->scroll_info == NULL) + return; + + for (i = 0; i < device_x11->scroll_info->len; i++) + { + MetaX11ScrollInfo *info = &g_array_index (device_x11->scroll_info, + MetaX11ScrollInfo, + i); + + info->last_value_valid = FALSE; + } +} + #ifdef HAVE_LIBWACOM uint32_t meta_input_device_x11_get_pad_group_mode (ClutterInputDevice *device, diff --git a/src/backends/x11/meta-input-device-x11.h b/src/backends/x11/meta-input-device-x11.h index f74c4a2a42347364dc02e36b15fa63e7897a5f9d..66e03f5814ce399fda2efe3ba3b37a2acf53be12 100644 --- a/src/backends/x11/meta-input-device-x11.h +++ b/src/backends/x11/meta-input-device-x11.h @@ -71,6 +71,32 @@ gboolean meta_input_device_x11_get_pointer_location (ClutterInputDevice *device, float *y); int meta_input_device_x11_get_device_id (ClutterInputDevice *device); +int meta_input_device_x11_get_n_axes (ClutterInputDevice *device); +void meta_input_device_x11_reset_axes (ClutterInputDevice *device); +int meta_input_device_x11_add_axis (ClutterInputDevice *device, + ClutterInputAxis axis, + double minimum, + double maximum, + double resolution); +gboolean meta_input_device_x11_get_axis (ClutterInputDevice *device, + int idx, + ClutterInputAxis *use); +gboolean meta_input_device_x11_translate_axis (ClutterInputDevice *device, + int idx, + double value, + double *axis_value); + +void meta_input_device_x11_add_scroll_info (ClutterInputDevice *device, + int idx, + ClutterScrollDirection direction, + double increment); +gboolean meta_input_device_x11_get_scroll_delta (ClutterInputDevice *device, + int idx, + gdouble value, + ClutterScrollDirection *direction_p, + double *delta_p); +void meta_input_device_x11_reset_scroll_info (ClutterInputDevice *device); + G_END_DECLS #endif /* META_INPUT_DEVICE_X11_H */ diff --git a/src/backends/x11/meta-input-settings-x11.c b/src/backends/x11/meta-input-settings-x11.c index 36ae21e9fed445e78a1203615e30758d1d0083e8..a8b366315d3fede64bd7d5f5d8f6ea59123c4941 100644 --- a/src/backends/x11/meta-input-settings-x11.c +++ b/src/backends/x11/meta-input-settings-x11.c @@ -35,7 +35,6 @@ #include #endif -#include "backends/meta-logical-monitor.h" #include "backends/x11/meta-backend-x11.h" #include "backends/x11/meta-input-device-x11.h" #include "core/display-private.h" @@ -735,37 +734,19 @@ meta_input_settings_x11_set_tablet_area (MetaInputSettings *settings, } static void -meta_input_settings_x11_set_tablet_keep_aspect (MetaInputSettings *settings, - ClutterInputDevice *device, - MetaLogicalMonitor *logical_monitor, - gboolean keep_aspect) +meta_input_settings_x11_set_tablet_aspect_ratio (MetaInputSettings *settings, + ClutterInputDevice *device, + gdouble aspect_ratio) { - gint32 width, height, dev_x, dev_y, dev_width, dev_height, area[4] = { 0 }; + int32_t dev_x, dev_y, dev_width, dev_height, area[4] = { 0 }; if (!device_query_area (device, &dev_x, &dev_y, &dev_width, &dev_height)) return; - if (keep_aspect) + if (aspect_ratio > 0) { - double aspect_ratio, dev_aspect; + double dev_aspect; - if (logical_monitor) - { - width = logical_monitor->rect.width; - height = logical_monitor->rect.height; - } - else - { - MetaMonitorManager *monitor_manager; - MetaBackend *backend; - - backend = meta_get_backend (); - monitor_manager = meta_backend_get_monitor_manager (backend); - meta_monitor_manager_get_screen_size (monitor_manager, - &width, &height); - } - - aspect_ratio = (double) width / height; dev_aspect = (double) dev_width / dev_height; if (dev_aspect > aspect_ratio) @@ -937,7 +918,7 @@ meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass) input_settings_class->set_keyboard_repeat = meta_input_settings_x11_set_keyboard_repeat; input_settings_class->set_tablet_mapping = meta_input_settings_x11_set_tablet_mapping; - input_settings_class->set_tablet_keep_aspect = meta_input_settings_x11_set_tablet_keep_aspect; + input_settings_class->set_tablet_aspect_ratio = meta_input_settings_x11_set_tablet_aspect_ratio; input_settings_class->set_tablet_area = meta_input_settings_x11_set_tablet_area; input_settings_class->set_mouse_accel_profile = meta_input_settings_x11_set_mouse_accel_profile; diff --git a/src/backends/x11/meta-keymap-x11.c b/src/backends/x11/meta-keymap-x11.c index ac2b1d7878fe0c48df08bf3573e51fd8bfc9f5b4..d30b46e985b722a8c2cf59a137bc7fb866a60f7f 100644 --- a/src/backends/x11/meta-keymap-x11.c +++ b/src/backends/x11/meta-keymap-x11.c @@ -26,6 +26,8 @@ #include #include +#include "backends/meta-backend-private.h" +#include "backends/meta-input-settings-private.h" #include "backends/x11/meta-keymap-x11.h" #include "clutter/clutter.h" #include "clutter/clutter-mutter.h" @@ -218,6 +220,21 @@ update_locked_mods (MetaKeymapX11 *keymap_x11, if ((keymap_x11->caps_lock_state != old_caps_lock_state) || (keymap_x11->num_lock_state != old_num_lock_state)) g_signal_emit_by_name (keymap_x11, "state-changed"); + + if (keymap_x11->num_lock_state != old_num_lock_state) + { + MetaBackend *backend; + MetaInputSettings *input_settings; + + backend = meta_get_backend (); + input_settings = meta_backend_get_input_settings (backend); + + if (input_settings) + { + meta_input_settings_maybe_save_numlock_state (input_settings, + keymap_x11->num_lock_state); + } + } } /* the code to retrieve the keymap direction and cache it diff --git a/src/backends/x11/meta-seat-x11.c b/src/backends/x11/meta-seat-x11.c index 841eb9e27e43cd7153ecd4022a4554febfe5a430..ce1fae3c002c1f577c5a98074bdfccfd0c2a686b 100644 --- a/src/backends/x11/meta-seat-x11.c +++ b/src/backends/x11/meta-seat-x11.c @@ -19,7 +19,10 @@ #include "config.h" #include +#include +#include "backends/meta-input-settings-private.h" +#include "backends/x11/meta-backend-x11.h" #include "backends/x11/meta-event-x11.h" #include "backends/x11/meta-input-device-tool-x11.h" #include "backends/x11/meta-input-device-x11.h" @@ -44,6 +47,15 @@ enum PROP_TOUCH_MODE, }; +typedef struct _MetaTouchInfo MetaTouchInfo; + +struct _MetaTouchInfo +{ + ClutterEventSequence *sequence; + double x; + double y; +}; + struct _MetaSeatX11 { ClutterSeat parent_instance; @@ -52,6 +64,7 @@ struct _MetaSeatX11 GList *devices; GHashTable *devices_by_id; GHashTable *tools_by_serial; + GHashTable *touch_coords; MetaKeymapX11 *keymap; int pointer_id; @@ -135,7 +148,7 @@ translate_valuator_class (Display *xdisplay, } } - _clutter_input_device_add_axis (device, axis, + meta_input_device_x11_add_axis (device, axis, class->min, class->max, class->resolution); @@ -162,23 +175,6 @@ translate_device_classes (Display *xdisplay, switch (class_info->type) { - case XIKeyClass: - { - XIKeyClassInfo *key_info = (XIKeyClassInfo *) class_info; - int j; - - _clutter_input_device_set_n_keys (device, - key_info->num_keycodes); - - for (j = 0; j < key_info->num_keycodes; j++) - { - clutter_input_device_set_key (device, j, - key_info->keycodes[i], - 0); - } - } - break; - case XIValuatorClass: translate_valuator_class (xdisplay, device, (XIValuatorClassInfo *) class_info); @@ -201,7 +197,7 @@ translate_device_classes (Display *xdisplay, : "horizontal", scroll_info->increment); - _clutter_input_device_add_scroll_info (device, + meta_input_device_x11_add_scroll_info (device, scroll_info->number, direction, scroll_info->increment); @@ -462,7 +458,6 @@ create_device (MetaSeatX11 *seat_x11, ClutterInputDeviceType source, touch_source; ClutterInputDevice *retval; ClutterInputMode mode; - gboolean is_enabled; uint32_t num_touches = 0, num_rings = 0, num_strips = 0; char *vendor_id = NULL, *product_id = NULL, *node_path = NULL; @@ -508,19 +503,16 @@ create_device (MetaSeatX11 *seat_x11, case XIMasterKeyboard: case XIMasterPointer: mode = CLUTTER_INPUT_MODE_LOGICAL; - is_enabled = TRUE; break; case XISlaveKeyboard: case XISlavePointer: mode = CLUTTER_INPUT_MODE_PHYSICAL; - is_enabled = FALSE; break; case XIFloatingSlave: default: mode = CLUTTER_INPUT_MODE_FLOATING; - is_enabled = FALSE; break; } @@ -532,10 +524,7 @@ create_device (MetaSeatX11 *seat_x11, } if (source == CLUTTER_PAD_DEVICE) - { - is_enabled = TRUE; - get_pad_features (info, &num_rings, &num_strips); - } + get_pad_features (info, &num_rings, &num_strips); retval = g_object_new (META_TYPE_INPUT_DEVICE_X11, "name", info->name, @@ -544,7 +533,6 @@ create_device (MetaSeatX11 *seat_x11, "device-type", source, "device-mode", mode, "backend", backend, - "enabled", is_enabled, "vendor-id", vendor_id, "product-id", product_id, "device-node", node_path, @@ -627,8 +615,7 @@ update_touch_mode (MetaSeatX11 *seat_x11) static ClutterInputDevice * add_device (MetaSeatX11 *seat_x11, ClutterBackend *backend, - XIDeviceInfo *info, - gboolean in_construction) + XIDeviceInfo *info) { ClutterInputDevice *device; @@ -664,22 +651,6 @@ add_device (MetaSeatX11 *seat_x11, if (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE) pad_passive_button_grab (device); - /* relationships between devices and signal emissions are not - * necessary while we're constructing the device manager instance - */ - if (!in_construction) - { - if (info->use == XISlavePointer || info->use == XISlaveKeyboard) - { - ClutterInputDevice *logical; - - logical = g_hash_table_lookup (seat_x11->devices_by_id, - GINT_TO_POINTER (info->attachment)); - _clutter_input_device_set_associated_device (device, logical); - _clutter_input_device_add_physical_device (logical, device); - } - } - return device; } @@ -716,24 +687,33 @@ remove_device (MetaSeatX11 *seat_x11, } static gboolean -meta_seat_x11_handle_device_event (ClutterSeat *seat, - ClutterEvent *event) +meta_seat_x11_handle_event_post (ClutterSeat *seat, + const ClutterEvent *event) { MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat); - ClutterInputDevice *device = event->device.device; + ClutterInputDevice *device; + MetaInputSettings *input_settings; gboolean is_touch; + if (event->type != CLUTTER_DEVICE_ADDED && + event->type != CLUTTER_DEVICE_REMOVED) + return TRUE; + + device = clutter_event_get_device (event); is_touch = clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE; + input_settings = meta_backend_get_input_settings (meta_get_backend ()); switch (event->type) { case CLUTTER_DEVICE_ADDED: + meta_input_settings_add_device (input_settings, device); seat_x11->has_touchscreens |= is_touch; break; case CLUTTER_DEVICE_REMOVED: if (is_touch) seat_x11->has_touchscreens = has_touchscreens (seat_x11); + meta_input_settings_remove_device (input_settings, device); break; default: break; @@ -745,36 +725,6 @@ meta_seat_x11_handle_device_event (ClutterSeat *seat, return TRUE; } -static void -relate_logical_devices (gpointer key, - gpointer value, - gpointer data) -{ - MetaSeatX11 *seat_x11 = data; - ClutterInputDevice *device, *relative; - - device = g_hash_table_lookup (seat_x11->devices_by_id, key); - relative = g_hash_table_lookup (seat_x11->devices_by_id, value); - - _clutter_input_device_set_associated_device (device, relative); - _clutter_input_device_set_associated_device (relative, device); -} - -static void -relate_physical_devices (gpointer key, - gpointer value, - gpointer data) -{ - MetaSeatX11 *seat_x11 = data; - ClutterInputDevice *logical, *physical; - - physical = g_hash_table_lookup (seat_x11->devices_by_id, key); - logical = g_hash_table_lookup (seat_x11->devices_by_id, value); - - _clutter_input_device_set_associated_device (physical, logical); - _clutter_input_device_add_physical_device (logical, physical); -} - static uint device_get_tool_serial (ClutterInputDevice *device) { @@ -833,7 +783,7 @@ translate_hierarchy_event (ClutterBackend *backend, { ClutterInputDevice *device; - device = add_device (seat_x11, backend, &info[0], FALSE); + device = add_device (seat_x11, backend, &info[0]); event->any.type = CLUTTER_DEVICE_ADDED; event->any.time = ev->time; @@ -867,46 +817,10 @@ translate_hierarchy_event (ClutterBackend *backend, else if ((ev->info[i].flags & XISlaveAttached) || (ev->info[i].flags & XISlaveDetached)) { - ClutterInputDevice *logical, *physical; - XIDeviceInfo *info; - int n_devices; - g_debug ("Hierarchy event: physical device %s", (ev->info[i].flags & XISlaveAttached) ? "attached" : "detached"); - - physical = g_hash_table_lookup (seat_x11->devices_by_id, - GINT_TO_POINTER (ev->info[i].deviceid)); - logical = clutter_input_device_get_associated_device (physical); - - /* detach the physical device in both cases */ - if (logical != NULL) - { - _clutter_input_device_remove_physical_device (logical, physical); - _clutter_input_device_set_associated_device (physical, NULL); - } - - /* and attach the physical device to the new logical device if needed */ - if (ev->info[i].flags & XISlaveAttached) - { - clutter_x11_trap_x_errors (); - info = XIQueryDevice (clutter_x11_get_default_display (), - ev->info[i].deviceid, - &n_devices); - clutter_x11_untrap_x_errors (); - if (info != NULL) - { - logical = g_hash_table_lookup (seat_x11->devices_by_id, - GINT_TO_POINTER (info->attachment)); - if (logical != NULL) - { - _clutter_input_device_set_associated_device (physical, logical); - _clutter_input_device_add_physical_device (logical, physical); - } - XIFreeDeviceInfo (info); - } - } } } @@ -930,6 +844,7 @@ translate_property_event (MetaSeatX11 *seat_x11, { ClutterInputDeviceTool *tool = NULL; ClutterInputDeviceToolType type; + MetaInputSettings *input_settings; int serial_id; serial_id = device_get_tool_serial (device); @@ -950,7 +865,8 @@ translate_property_event (MetaSeatX11 *seat_x11, } meta_input_device_x11_update_tool (device, tool); - g_signal_emit_by_name (seat_x11, "tool-changed", device, tool); + input_settings = meta_backend_get_input_settings (meta_get_backend ()); + meta_input_settings_notify_tool_change (input_settings, device, tool); } } @@ -981,7 +897,7 @@ translate_raw_event (MetaSeatX11 *seat_x11, case XI_RawMotion: g_debug ("raw motion: device:%d '%s'", meta_input_device_x11_get_device_id (device), - device->device_name); + clutter_input_device_get_device_name (device)); /* We don't get actual pointer location with raw events, and we cannot * rely on `clutter_input_device_get_coords()` either because of @@ -998,7 +914,7 @@ translate_raw_event (MetaSeatX11 *seat_x11, ? "press " : "release", meta_input_device_x11_get_device_id (device), - device->device_name, + clutter_input_device_get_device_name (device), xev->detail); _clutter_input_pointer_a11y_on_button_event (device, xev->detail, @@ -1031,7 +947,7 @@ translate_pad_axis (ClutterInputDevice *device, if (val <= 0) continue; - _clutter_input_device_translate_axis (device, i, val, value); + meta_input_device_x11_translate_axis (device, i, val, value); if (i == PAD_AXIS_RING1 || i == PAD_AXIS_RING2) { @@ -1103,7 +1019,7 @@ translate_pad_event (ClutterEvent *event, : "pad strip", (unsigned int) xev->event, meta_input_device_x11_get_device_id (device), - device->device_name, + clutter_input_device_get_device_name (device), event->any.time, value); return TRUE; @@ -1216,12 +1132,11 @@ translate_axes (ClutterInputDevice *device, double y, XIValuatorState *valuators) { - uint32_t n_axes = clutter_input_device_get_n_axes (device); uint32_t i; double *retval; double *values; - retval = g_new0 (double, n_axes); + retval = g_new0 (double, CLUTTER_INPUT_AXIS_LAST); values = valuators->values; for (i = 0; i < valuators->mask_len * 8; i++) @@ -1231,22 +1146,23 @@ translate_axes (ClutterInputDevice *device, if (!XIMaskIsSet (valuators->mask, i)) continue; + if (!meta_input_device_x11_get_axis (device, i, &axis)) + continue; - axis = clutter_input_device_get_axis (device, i); val = *values++; switch (axis) { case CLUTTER_INPUT_AXIS_X: - retval[i] = x; + retval[axis] = x; break; case CLUTTER_INPUT_AXIS_Y: - retval[i] = y; + retval[axis] = y; break; default: - _clutter_input_device_translate_axis (device, i, val, &retval[i]); + meta_input_device_x11_translate_axis (device, i, val, &retval[axis]); break; } } @@ -1264,7 +1180,7 @@ scroll_valuators_changed (ClutterInputDevice *device, uint32_t n_axes, n_val, i; double *values; - n_axes = clutter_input_device_get_n_axes (device); + n_axes = meta_input_device_x11_get_n_axes (device); values = valuators->values; *dx_p = *dy_p = 0.0; @@ -1279,7 +1195,7 @@ scroll_valuators_changed (ClutterInputDevice *device, if (!XIMaskIsSet (valuators->mask, i)) continue; - if (_clutter_input_device_get_scroll_delta (device, i, + if (meta_input_device_x11_get_scroll_delta (device, i, values[n_val], &direction, &delta)) @@ -1321,13 +1237,15 @@ static void on_keymap_state_change (MetaKeymapX11 *keymap_x11, gpointer data) { - ClutterSeat *seat = CLUTTER_SEAT (data); - ClutterKbdA11ySettings kbd_a11y_settings; + ClutterSeat *seat = data; + MetaInputSettings *input_settings; + MetaKbdA11ySettings kbd_a11y_settings; /* On keymaps state change, just reapply the current settings, it'll * take care of enabling/disabling mousekeys based on NumLock state. */ - clutter_seat_get_kbd_a11y_settings (seat, &kbd_a11y_settings); + input_settings = meta_backend_get_input_settings (meta_get_backend ()); + meta_input_settings_get_kbd_a11y_settings (input_settings, &kbd_a11y_settings); meta_seat_x11_apply_kbd_a11y_settings (seat, &kbd_a11y_settings); } @@ -1407,7 +1325,6 @@ meta_seat_x11_constructed (GObject *object) { MetaSeatX11 *seat_x11 = META_SEAT_X11 (object); ClutterBackend *backend = clutter_get_default_backend (); - GHashTable *logical_devices, *physical_devices; XIDeviceInfo *info; XIEventMask event_mask; unsigned char mask[XIMaskLen(XI_LASTEVENT)] = { 0, }; @@ -1415,8 +1332,6 @@ meta_seat_x11_constructed (GObject *object) Display *xdisplay; xdisplay = clutter_x11_get_default_display (); - logical_devices = g_hash_table_new (NULL, NULL); - physical_devices = g_hash_table_new (NULL, NULL); info = XIQueryDevice (clutter_x11_get_default_display (), XIAllDevices, &n_devices); @@ -1428,32 +1343,11 @@ meta_seat_x11_constructed (GObject *object) if (!xi_device->enabled) continue; - add_device (seat_x11, backend, xi_device, TRUE); - - if (xi_device->use == XIMasterPointer || - xi_device->use == XIMasterKeyboard) - { - g_hash_table_insert (logical_devices, - GINT_TO_POINTER (xi_device->deviceid), - GINT_TO_POINTER (xi_device->attachment)); - } - else if (xi_device->use == XISlavePointer || - xi_device->use == XISlaveKeyboard) - { - g_hash_table_insert (physical_devices, - GINT_TO_POINTER (xi_device->deviceid), - GINT_TO_POINTER (xi_device->attachment)); - } + add_device (seat_x11, backend, xi_device); } XIFreeDeviceInfo (info); - g_hash_table_foreach (logical_devices, relate_logical_devices, seat_x11); - g_hash_table_destroy (logical_devices); - - g_hash_table_foreach (physical_devices, relate_physical_devices, seat_x11); - g_hash_table_destroy (physical_devices); - XISetMask (mask, XI_HierarchyChanged); XISetMask (mask, XI_DeviceChanged); XISetMask (mask, XI_PropertyEvent); @@ -1500,6 +1394,7 @@ meta_seat_x11_finalize (GObject *object) g_hash_table_unref (seat_x11->devices_by_id); g_hash_table_unref (seat_x11->tools_by_serial); + g_hash_table_unref (seat_x11->touch_coords); g_list_free (seat_x11->devices); G_OBJECT_CLASS (meta_seat_x11_parent_class)->finalize (object); @@ -1598,6 +1493,140 @@ meta_seat_x11_warp_pointer (ClutterSeat *seat, x, y); } +static uint32_t +translate_state (XIButtonState *button_state, + XIModifierState *modifier_state, + XIGroupState *group_state) +{ + uint32_t state = 0; + int i; + + if (modifier_state) + state |= modifier_state->effective; + + if (button_state) + { + for (i = 1; i < XIMaskLen (button_state->mask_len); i++) + { + if (!XIMaskIsSet (button_state->mask, i)) + continue; + + switch (i) + { + case 1: + state |= CLUTTER_BUTTON1_MASK; + break; + case 2: + state |= CLUTTER_BUTTON2_MASK; + break; + case 3: + state |= CLUTTER_BUTTON3_MASK; + break; + case 8: + state |= CLUTTER_BUTTON4_MASK; + break; + case 9: + state |= CLUTTER_BUTTON5_MASK; + break; + default: + break; + } + } + } + + if (group_state) + state = XkbBuildCoreState (group_state->effective, state); + + return state; +} + +static gboolean +meta_seat_x11_query_state (ClutterSeat *seat, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t *coords, + ClutterModifierType *modifiers) +{ + MetaBackendX11 *backend_x11 = META_BACKEND_X11 (meta_get_backend ()); + MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat); + Window root_ret, child_ret; + double root_x, root_y, win_x, win_y; + XIButtonState button_state; + XIModifierState modifier_state; + XIGroupState group_state; + + clutter_x11_trap_x_errors (); + XIQueryPointer (clutter_x11_get_default_display (), + seat_x11->pointer_id, + meta_backend_x11_get_xwindow (backend_x11), + &root_ret, &child_ret, + &root_x, &root_y, &win_x, &win_y, + &button_state, &modifier_state, &group_state); + if (clutter_x11_untrap_x_errors ()) + return FALSE; + + if (sequence) + { + MetaTouchInfo *touch_info; + + touch_info = g_hash_table_lookup (seat_x11->touch_coords, sequence); + if (!touch_info) + return FALSE; + + if (coords) + { + coords->x = touch_info->x; + coords->y = touch_info->y; + } + } + else + { + if (coords) + { + coords->x = win_x; + coords->y = win_y; + } + } + + if (modifiers) + *modifiers = translate_state (&button_state, &modifier_state, &group_state); + + return TRUE; +} + +static void +meta_seat_x11_update_touchpoint (MetaSeatX11 *seat, + ClutterEventSequence *sequence, + double x, + double y) +{ + MetaTouchInfo *touch_info; + + touch_info = g_hash_table_lookup (seat->touch_coords, sequence); + if (!touch_info) + { + touch_info = g_new0 (MetaTouchInfo, 1); + touch_info->sequence = sequence; + g_hash_table_insert (seat->touch_coords, sequence, touch_info); + } + + touch_info->x = x; + touch_info->y = y; +} + +static void +meta_seat_x11_remove_touchpoint (MetaSeatX11 *seat, + ClutterEventSequence *sequence) +{ + g_hash_table_remove (seat->touch_coords, sequence); +} + +static void +meta_touch_info_free (MetaTouchInfo *touch_info) +{ + g_free (touch_info); +} + static void meta_seat_x11_class_init (MetaSeatX11Class *klass) { @@ -1616,11 +1645,11 @@ meta_seat_x11_class_init (MetaSeatX11Class *klass) seat_class->get_keymap = meta_seat_x11_get_keymap; seat_class->copy_event_data = meta_seat_x11_copy_event_data; seat_class->free_event_data = meta_seat_x11_free_event_data; - seat_class->apply_kbd_a11y_settings = meta_seat_x11_apply_kbd_a11y_settings; seat_class->create_virtual_device = meta_seat_x11_create_virtual_device; seat_class->get_supported_virtual_device_types = meta_seat_x11_get_supported_virtual_device_types; seat_class->warp_pointer = meta_seat_x11_warp_pointer; - seat_class->handle_device_event = meta_seat_x11_handle_device_event; + seat_class->handle_event_post = meta_seat_x11_handle_event_post; + seat_class->query_state = meta_seat_x11_query_state; props[PROP_OPCODE] = g_param_spec_int ("opcode", @@ -1658,6 +1687,8 @@ meta_seat_x11_init (MetaSeatX11 *seat) (GDestroyNotify) g_object_unref); seat->tools_by_serial = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref); + seat->touch_coords = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) meta_touch_info_free); } MetaSeatX11 * @@ -1755,7 +1786,7 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, GINT_TO_POINTER (xev->sourceid)); if (device) { - _clutter_input_device_reset_axes (device); + meta_input_device_x11_reset_axes (device); translate_device_classes (clutter_x11_get_default_display (), device, xev->classes, @@ -1763,7 +1794,7 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, } if (source_device) - _clutter_input_device_reset_scroll_info (source_device); + meta_input_device_x11_reset_scroll_info (source_device); } retval = FALSE; break; @@ -1915,7 +1946,7 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, : "pad button release", (unsigned int) stage_x11->xwin, meta_input_device_x11_get_device_id (device), - device->device_name, + clutter_input_device_get_device_name (device), event->any.time, event->pad_button.button); retval = TRUE; @@ -1965,7 +1996,7 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, "emulated:%s)", (unsigned int) stage_x11->xwin, meta_input_device_x11_get_device_id (device), - device->device_name, + clutter_input_device_get_device_name (device), event->any.time, event->scroll.direction == CLUTTER_SCROLL_UP ? "up" : event->scroll.direction == CLUTTER_SCROLL_DOWN ? "down" : @@ -2011,7 +2042,7 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, : "button release", (unsigned int) stage_x11->xwin, meta_input_device_x11_get_device_id (device), - device->device_name, + clutter_input_device_get_device_name (device), event->any.time, event->button.button, event->button.x, @@ -2074,7 +2105,7 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, g_debug ("smooth scroll: win:0x%x device:%d '%s' (x:%.2f, y:%.2f, delta:%f, %f)", (unsigned int) stage_x11->xwin, meta_input_device_x11_get_device_id (event->scroll.device), - event->scroll.device->device_name, + clutter_input_device_get_device_name (event->scroll.device), event->scroll.x, event->scroll.y, delta_x, delta_y); @@ -2110,7 +2141,7 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, g_debug ("motion: win:0x%x device:%d '%s' (x:%.2f, y:%.2f, axes:%s)", (unsigned int) stage_x11->xwin, meta_input_device_x11_get_device_id (event->motion.device), - event->motion.device->device_name, + clutter_input_device_get_device_name (event->motion.device), event->motion.x, event->motion.y, event->motion.axes != NULL ? "yes" : "no"); @@ -2162,6 +2193,15 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, event->touch.modifier_state |= CLUTTER_BUTTON1_MASK; meta_stage_x11_set_user_time (stage_x11, event->touch.time); + meta_seat_x11_update_touchpoint (seat, + GUINT_TO_POINTER (xev->detail), + xev->root_x, + xev->root_y); + } + else if (xi_event->evtype == XI_TouchEnd) + { + meta_seat_x11_remove_touchpoint (seat, + GUINT_TO_POINTER (xev->detail)); } event->touch.sequence = GUINT_TO_POINTER (xev->detail); @@ -2173,7 +2213,7 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, event->type == CLUTTER_TOUCH_BEGIN ? "begin" : "end", (unsigned int) stage_x11->xwin, meta_input_device_x11_get_device_id (event->touch.device), - event->touch.device->device_name, + clutter_input_device_get_device_name (event->touch.device), GPOINTER_TO_UINT (event->touch.sequence), event->touch.x, event->touch.y, @@ -2216,10 +2256,15 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, if (xev->flags & XITouchEmulatingPointer) _clutter_event_set_pointer_emulated (event, TRUE); + meta_seat_x11_update_touchpoint (seat, + event->touch.sequence, + xev->root_x, + xev->root_y); + g_debug ("touch update: win:0x%x device:%d '%s' (seq:%d, x:%.2f, y:%.2f, axes:%s)", (unsigned int) stage_x11->xwin, meta_input_device_x11_get_device_id (event->touch.device), - event->touch.device->device_name, + clutter_input_device_get_device_name (event->touch.device), GPOINTER_TO_UINT (event->touch.sequence), event->touch.x, event->touch.y, @@ -2263,7 +2308,7 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat, translate_coords (stage_x11, xev->event_x, xev->event_y, &event->crossing.x, &event->crossing.y); } - _clutter_input_device_reset_scroll_info (source_device); + meta_input_device_x11_reset_scroll_info (source_device); clutter_event_set_device (event, device); clutter_event_set_source_device (event, source_device); diff --git a/src/backends/x11/meta-xkb-a11y-x11.c b/src/backends/x11/meta-xkb-a11y-x11.c index 5deb6f3ff893d70764f583598f27d1445f10c2bb..d2e76b3f75bce827be1addd632f620617c7e99d4 100644 --- a/src/backends/x11/meta-xkb-a11y-x11.c +++ b/src/backends/x11/meta-xkb-a11y-x11.c @@ -78,47 +78,55 @@ static void check_settings_changed (ClutterSeat *seat) { Display *xdisplay = clutter_x11_get_default_display (); - ClutterKbdA11ySettings kbd_a11y_settings; - ClutterKeyboardA11yFlags what_changed = 0; + MetaKbdA11ySettings kbd_a11y_settings; + MetaKeyboardA11yFlags what_changed = 0; + MetaInputSettings *input_settings; XkbDescRec *desc; desc = get_xkb_desc_rec (xdisplay); if (!desc) return; - clutter_seat_get_kbd_a11y_settings (seat, &kbd_a11y_settings); + input_settings = meta_backend_get_input_settings (meta_get_backend ()); + meta_input_settings_get_kbd_a11y_settings (input_settings, + &kbd_a11y_settings); if (desc->ctrls->enabled_ctrls & XkbSlowKeysMask && - !(kbd_a11y_settings.controls & CLUTTER_A11Y_SLOW_KEYS_ENABLED)) + !(kbd_a11y_settings.controls & META_A11Y_SLOW_KEYS_ENABLED)) { - what_changed |= CLUTTER_A11Y_SLOW_KEYS_ENABLED; - kbd_a11y_settings.controls |= CLUTTER_A11Y_SLOW_KEYS_ENABLED; + what_changed |= META_A11Y_SLOW_KEYS_ENABLED; + kbd_a11y_settings.controls |= META_A11Y_SLOW_KEYS_ENABLED; } else if (!(desc->ctrls->enabled_ctrls & XkbSlowKeysMask) && - kbd_a11y_settings.controls & CLUTTER_A11Y_SLOW_KEYS_ENABLED) + kbd_a11y_settings.controls & META_A11Y_SLOW_KEYS_ENABLED) { - what_changed |= CLUTTER_A11Y_SLOW_KEYS_ENABLED; - kbd_a11y_settings.controls &= ~CLUTTER_A11Y_SLOW_KEYS_ENABLED; + what_changed |= META_A11Y_SLOW_KEYS_ENABLED; + kbd_a11y_settings.controls &= ~META_A11Y_SLOW_KEYS_ENABLED; } if (desc->ctrls->enabled_ctrls & XkbStickyKeysMask && - !(kbd_a11y_settings.controls & CLUTTER_A11Y_STICKY_KEYS_ENABLED)) + !(kbd_a11y_settings.controls & META_A11Y_STICKY_KEYS_ENABLED)) { - what_changed |= CLUTTER_A11Y_STICKY_KEYS_ENABLED; - kbd_a11y_settings.controls |= CLUTTER_A11Y_STICKY_KEYS_ENABLED; + what_changed |= META_A11Y_STICKY_KEYS_ENABLED; + kbd_a11y_settings.controls |= META_A11Y_STICKY_KEYS_ENABLED; } else if (!(desc->ctrls->enabled_ctrls & XkbStickyKeysMask) && - kbd_a11y_settings.controls & CLUTTER_A11Y_STICKY_KEYS_ENABLED) + kbd_a11y_settings.controls & META_A11Y_STICKY_KEYS_ENABLED) { - what_changed |= CLUTTER_A11Y_STICKY_KEYS_ENABLED; - kbd_a11y_settings.controls &= ~CLUTTER_A11Y_STICKY_KEYS_ENABLED; + what_changed |= META_A11Y_STICKY_KEYS_ENABLED; + kbd_a11y_settings.controls &= ~META_A11Y_STICKY_KEYS_ENABLED; } if (what_changed) - g_signal_emit_by_name (seat, - "kbd-a11y-flags-changed", - kbd_a11y_settings.controls, - what_changed); + { + meta_input_settings_notify_kbd_a11y_change (input_settings, + kbd_a11y_settings.controls, + what_changed); + g_signal_emit_by_name (seat, + "kbd-a11y-flags-changed", + kbd_a11y_settings.controls, + what_changed); + } XkbFreeKeyboard (desc, XkbAllComponentsMask, TRUE); } @@ -182,10 +190,10 @@ set_value_mask (gboolean flag, } static gboolean -set_xkb_ctrl (XkbDescRec *desc, - ClutterKeyboardA11yFlags settings, - ClutterKeyboardA11yFlags flag, - unsigned long mask) +set_xkb_ctrl (XkbDescRec *desc, + MetaKeyboardA11yFlags settings, + MetaKeyboardA11yFlags flag, + unsigned long mask) { gboolean result = (settings & flag) == flag; desc->ctrls->enabled_ctrls = set_value_mask (result, desc->ctrls->enabled_ctrls, mask); @@ -194,8 +202,8 @@ set_xkb_ctrl (XkbDescRec *desc, } void -meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat, - ClutterKbdA11ySettings *kbd_a11y_settings) +meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat, + MetaKbdA11ySettings *kbd_a11y_settings) { Display *xdisplay = clutter_x11_get_default_display (); XkbDescRec *desc; @@ -206,13 +214,13 @@ meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat, return; /* general */ - enable_accessX = kbd_a11y_settings->controls & CLUTTER_A11Y_KEYBOARD_ENABLED; + enable_accessX = kbd_a11y_settings->controls & META_A11Y_KEYBOARD_ENABLED; desc->ctrls->enabled_ctrls = set_value_mask (enable_accessX, desc->ctrls->enabled_ctrls, XkbAccessXKeysMask); - if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, CLUTTER_A11Y_TIMEOUT_ENABLED, + if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, META_A11Y_TIMEOUT_ENABLED, XkbAccessXTimeoutMask)) { desc->ctrls->ax_timeout = kbd_a11y_settings->timeout_delay; @@ -226,17 +234,17 @@ meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat, } desc->ctrls->ax_options = - set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP, + set_value_mask (kbd_a11y_settings->controls & META_A11Y_FEATURE_STATE_CHANGE_BEEP, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask); /* bounce keys */ if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, - CLUTTER_A11Y_BOUNCE_KEYS_ENABLED, XkbBounceKeysMask)) + META_A11Y_BOUNCE_KEYS_ENABLED, XkbBounceKeysMask)) { desc->ctrls->debounce_delay = kbd_a11y_settings->debounce_delay; desc->ctrls->ax_options = - set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT, + set_value_mask (kbd_a11y_settings->controls & META_A11Y_BOUNCE_KEYS_BEEP_REJECT, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_BKRejectFBMask); } @@ -248,7 +256,7 @@ meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat, desc->ctrls->enabled_ctrls &= ~(XkbMouseKeysMask | XkbMouseKeysAccelMask); } else if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, - CLUTTER_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask)) + META_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask)) { int mk_max_speed; int mk_accel_time; @@ -273,16 +281,16 @@ meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat, /* slow keys */ if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, - CLUTTER_A11Y_SLOW_KEYS_ENABLED, XkbSlowKeysMask)) + META_A11Y_SLOW_KEYS_ENABLED, XkbSlowKeysMask)) { desc->ctrls->ax_options = - set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS, + set_value_mask (kbd_a11y_settings->controls & META_A11Y_SLOW_KEYS_BEEP_PRESS, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKPressFBMask); desc->ctrls->ax_options = - set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT, + set_value_mask (kbd_a11y_settings->controls & META_A11Y_SLOW_KEYS_BEEP_ACCEPT, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKAcceptFBMask); desc->ctrls->ax_options = - set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT, + set_value_mask (kbd_a11y_settings->controls & META_A11Y_SLOW_KEYS_BEEP_REJECT, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKRejectFBMask); desc->ctrls->slow_keys_delay = kbd_a11y_settings->slowkeys_delay; /* anything larger than 500 seems to loose all keyboard input */ @@ -292,20 +300,20 @@ meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat, /* sticky keys */ if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, - CLUTTER_A11Y_STICKY_KEYS_ENABLED, XkbStickyKeysMask)) + META_A11Y_STICKY_KEYS_ENABLED, XkbStickyKeysMask)) { desc->ctrls->ax_options |= XkbAX_LatchToLockMask; desc->ctrls->ax_options = - set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF, + set_value_mask (kbd_a11y_settings->controls & META_A11Y_STICKY_KEYS_TWO_KEY_OFF, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_TwoKeysMask); desc->ctrls->ax_options = - set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_STICKY_KEYS_BEEP, + set_value_mask (kbd_a11y_settings->controls & META_A11Y_STICKY_KEYS_BEEP, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_StickyKeysFBMask); } /* toggle keys */ desc->ctrls->ax_options = - set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_TOGGLE_KEYS_ENABLED, + set_value_mask (kbd_a11y_settings->controls & META_A11Y_TOGGLE_KEYS_ENABLED, desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_IndicatorFBMask); set_xkb_desc_rec (xdisplay, desc); diff --git a/src/backends/x11/meta-xkb-a11y-x11.h b/src/backends/x11/meta-xkb-a11y-x11.h index 7f11bf7b0a53723847e6861a80cc24e1908a9143..58a4e176611d6cfd32bb74f7ea88de68b7645e33 100644 --- a/src/backends/x11/meta-xkb-a11y-x11.h +++ b/src/backends/x11/meta-xkb-a11y-x11.h @@ -26,11 +26,12 @@ #include +#include "backends/meta-input-settings-private.h" #include "clutter/clutter.h" void -meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat, - ClutterKbdA11ySettings *kbd_a11y_settings); +meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat, + MetaKbdA11ySettings *kbd_a11y_settings); gboolean meta_seat_x11_a11y_init (ClutterSeat *seat); diff --git a/src/backends/x11/nested/meta-backend-x11-nested.c b/src/backends/x11/nested/meta-backend-x11-nested.c index 009a809787c70bb43077b11725d932a243146b0c..425ddcb1a174c8564d532846bd2fdf5cc0400648 100644 --- a/src/backends/x11/nested/meta-backend-x11-nested.c +++ b/src/backends/x11/nested/meta-backend-x11-nested.c @@ -31,6 +31,7 @@ typedef struct _MetaBackendX11NestedPrivate { MetaGpu *gpu; + MetaCursorRenderer *cursor_renderer; } MetaBackendX11NestedPrivate; static GInitableIface *initable_parent_iface; @@ -63,15 +64,27 @@ meta_backend_x11_nested_create_monitor_manager (MetaBackend *backend, } static MetaCursorRenderer * -meta_backend_x11_nested_create_cursor_renderer (MetaBackend *backend) +meta_backend_x11_nested_get_cursor_renderer (MetaBackend *backend, + ClutterInputDevice *device) { - return g_object_new (META_TYPE_CURSOR_RENDERER_X11_NESTED, - "backend", backend, - NULL); + MetaBackendX11Nested *backend_x11_nested = META_BACKEND_X11_NESTED (backend); + MetaBackendX11NestedPrivate *priv = + meta_backend_x11_nested_get_instance_private (backend_x11_nested); + + if (!priv->cursor_renderer) + { + priv->cursor_renderer = + g_object_new (META_TYPE_CURSOR_RENDERER_X11_NESTED, + "backend", backend, + "device", device, + NULL); + } + + return priv->cursor_renderer; } static MetaInputSettings * -meta_backend_x11_nested_create_input_settings (MetaBackend *backend) +meta_backend_x11_nested_get_input_settings (MetaBackend *backend) { return NULL; } @@ -275,8 +288,8 @@ meta_backend_x11_nested_class_init (MetaBackendX11NestedClass *klass) backend_class->post_init = meta_backend_x11_nested_post_init; backend_class->create_renderer = meta_backend_x11_nested_create_renderer; backend_class->create_monitor_manager = meta_backend_x11_nested_create_monitor_manager; - backend_class->create_cursor_renderer = meta_backend_x11_nested_create_cursor_renderer; - backend_class->create_input_settings = meta_backend_x11_nested_create_input_settings; + backend_class->get_cursor_renderer = meta_backend_x11_nested_get_cursor_renderer; + backend_class->get_input_settings = meta_backend_x11_nested_get_input_settings; backend_class->update_screen_size = meta_backend_x11_nested_update_screen_size; backend_class->select_stage_events = meta_backend_x11_nested_select_stage_events; backend_class->lock_layout_group = meta_backend_x11_nested_lock_layout_group; diff --git a/src/core/display-private.h b/src/core/display-private.h index 78f25fdb6c780a38161d0c13dd3af929c7e3ed7a..3d690fcb66bee2333fce63563dd87d751b095134 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -38,6 +38,7 @@ #include "clutter/clutter.h" #include "core/keybindings-private.h" #include "core/meta-gesture-tracker-private.h" +#include "core/meta-pad-action-mapper.h" #include "core/stack-tracker.h" #include "core/startup-notification-private.h" #include "meta/barrier.h" @@ -211,6 +212,7 @@ struct _MetaDisplay ClutterEventSequence *pointer_emulating_sequence; ClutterActor *current_pad_osd; + MetaPadActionMapper *pad_action_mapper; MetaStartupNotification *startup_notification; diff --git a/src/core/display.c b/src/core/display.c index 35ba540b6aec712b6e5492bdb64fc24657c42c7e..2d256623f1f16be5cc9e592c5e0f2c83338ea7b8 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -45,8 +45,7 @@ #include "backends/meta-cursor-tracker-private.h" #include "backends/meta-idle-monitor-dbus.h" #include "backends/meta-input-device-private.h" -#include "backends/meta-input-settings-private.h" -#include "backends/meta-logical-monitor.h" +#include "backends/meta-input-mapper-private.h" #include "backends/meta-stage-private.h" #include "backends/x11/meta-backend-x11.h" #include "backends/x11/meta-event-x11.h" @@ -855,6 +854,8 @@ meta_display_open (void) g_signal_connect (monitor_manager, "monitors-changed-internal", G_CALLBACK (on_monitors_changed_internal), display); + display->pad_action_mapper = meta_pad_action_mapper_new (monitor_manager); + settings = meta_backend_get_settings (backend); g_signal_connect (settings, "ui-scaling-factor-changed", G_CALLBACK (on_ui_scaling_factor_changed), display); @@ -1120,6 +1121,7 @@ meta_display_close (MetaDisplay *display, meta_clipboard_manager_shutdown (display); g_clear_object (&display->selection); + g_clear_object (&display->pad_action_mapper); g_object_unref (display); the_display = NULL; @@ -1629,43 +1631,9 @@ meta_cursor_for_grab_op (MetaGrabOp op) return META_CURSOR_DEFAULT; } -static float -find_highest_logical_monitor_scale (MetaBackend *backend, - MetaCursorSprite *cursor_sprite) -{ - MetaMonitorManager *monitor_manager = - meta_backend_get_monitor_manager (backend); - MetaCursorRenderer *cursor_renderer = - meta_backend_get_cursor_renderer (backend); - graphene_rect_t cursor_rect; - GList *logical_monitors; - GList *l; - float highest_scale = 0.0; - - cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer, - cursor_sprite); - - logical_monitors = - meta_monitor_manager_get_logical_monitors (monitor_manager); - for (l = logical_monitors; l; l = l->next) - { - MetaLogicalMonitor *logical_monitor = l->data; - graphene_rect_t logical_monitor_rect = - meta_rectangle_to_graphene_rect (&logical_monitor->rect); - - if (!graphene_rect_intersection (&cursor_rect, - &logical_monitor_rect, - NULL)) - continue; - - highest_scale = MAX (highest_scale, logical_monitor->scale); - } - - return highest_scale; -} - static void root_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor, + float best_scale, int x, int y, MetaDisplay *display) @@ -1675,14 +1643,11 @@ root_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor, if (meta_is_stage_views_scaled ()) { - float scale; - - scale = find_highest_logical_monitor_scale (backend, cursor_sprite); - if (scale != 0.0) + if (best_scale != 0.0f) { float ceiled_scale; - ceiled_scale = ceilf (scale); + ceiled_scale = ceilf (best_scale); meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor, (int) ceiled_scale); meta_cursor_sprite_set_texture_scale (cursor_sprite, @@ -2944,7 +2909,7 @@ meta_display_request_pad_osd (MetaDisplay *display, gboolean edition_mode) { MetaBackend *backend = meta_get_backend (); - MetaInputSettings *input_settings; + MetaInputMapper *input_mapper; const gchar *layout_path = NULL; ClutterActor *osd; MetaLogicalMonitor *logical_monitor; @@ -2960,13 +2925,13 @@ meta_display_request_pad_osd (MetaDisplay *display, if (display->current_pad_osd) return; - input_settings = meta_backend_get_input_settings (meta_get_backend ()); + input_mapper = meta_backend_get_input_mapper (meta_get_backend ()); - if (input_settings) + if (input_mapper) { - settings = meta_input_settings_get_tablet_settings (input_settings, pad); + settings = meta_input_mapper_get_tablet_settings (input_mapper, pad); logical_monitor = - meta_input_settings_get_tablet_logical_monitor (input_settings, pad); + meta_input_mapper_get_device_logical_monitor (input_mapper, pad); #ifdef HAVE_LIBWACOM wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (pad)); layout_path = libwacom_get_layout_filename (wacom_device); @@ -2989,8 +2954,6 @@ meta_display_request_pad_osd (MetaDisplay *display, g_object_add_weak_pointer (G_OBJECT (display->current_pad_osd), (gpointer *) &display->current_pad_osd); } - - g_object_unref (settings); } gchar * @@ -2999,12 +2962,12 @@ meta_display_get_pad_action_label (MetaDisplay *display, MetaPadActionType action_type, guint action_number) { - MetaInputSettings *settings; gchar *label; /* First, lookup the action, as imposed by settings */ - settings = meta_backend_get_input_settings (meta_get_backend ()); - label = meta_input_settings_get_pad_action_label (settings, pad, action_type, action_number); + label = meta_pad_action_mapper_get_action_label (display->pad_action_mapper, + pad, action_type, + action_number); if (label) return label; @@ -3050,15 +3013,15 @@ static gint lookup_tablet_monitor (MetaDisplay *display, ClutterInputDevice *device) { - MetaInputSettings *input_settings; + MetaInputMapper *input_mapper; MetaLogicalMonitor *monitor; gint monitor_idx = -1; - input_settings = meta_backend_get_input_settings (meta_get_backend ()); - if (!input_settings) + input_mapper = meta_backend_get_input_mapper (meta_get_backend ()); + if (!input_mapper) return -1; - monitor = meta_input_settings_get_tablet_logical_monitor (input_settings, device); + monitor = meta_input_mapper_get_device_logical_monitor (input_mapper, device); if (monitor) { diff --git a/src/core/events.c b/src/core/events.c index 17dcaa0fe6829fbbbf453768d60d55044e6b8037..fdc0bd8b5166334a2b3782b6ccb93e96cc6a77ff 100644 --- a/src/core/events.c +++ b/src/core/events.c @@ -265,8 +265,7 @@ meta_display_handle_event (MetaDisplay *display, handle_pad_event = !display->current_pad_osd || is_mode_switch; if (handle_pad_event && - meta_input_settings_handle_pad_event (meta_backend_get_input_settings (backend), - event)) + meta_pad_action_mapper_handle_event (display->pad_action_mapper, event)) { bypass_wayland = bypass_clutter = TRUE; goto out; @@ -288,22 +287,21 @@ meta_display_handle_event (MetaDisplay *display, #ifdef HAVE_WAYLAND if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION) { - MetaWaylandCompositor *compositor; + MetaCursorRenderer *cursor_renderer; + ClutterInputDevice *device; - compositor = meta_wayland_compositor_get_default (); + device = clutter_event_get_device (event); + cursor_renderer = meta_backend_get_cursor_renderer_for_device (backend, + device); + if (cursor_renderer) + meta_cursor_renderer_update_position (cursor_renderer); - if (meta_wayland_tablet_manager_consumes_event (compositor->tablet_manager, event)) - { - meta_wayland_tablet_manager_update_cursor_position (compositor->tablet_manager, event); - } - else + if (device == clutter_seat_get_pointer (clutter_input_device_get_seat (device))) { MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); - meta_cursor_tracker_update_position (cursor_tracker, - event->motion.x, - event->motion.y); + meta_cursor_tracker_invalidate_position (cursor_tracker); } } #endif diff --git a/src/core/meta-pad-action-mapper.c b/src/core/meta-pad-action-mapper.c new file mode 100644 index 0000000000000000000000000000000000000000..e5331e1dd2364f7abf6d6cc87dd0a4d45ed71322 --- /dev/null +++ b/src/core/meta-pad-action-mapper.c @@ -0,0 +1,858 @@ +/* + * Copyright (C) 2014-2020 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Carlos Garnacho + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_LIBWACOM +#include +#endif + +#include "core/meta-pad-action-mapper.h" +#include "backends/meta-input-device-private.h" +#include "backends/meta-logical-monitor.h" +#include "backends/meta-monitor.h" +#include "core/display-private.h" + +typedef struct _PadMappingInfo PadMappingInfo; + +struct _PadMappingInfo +{ + ClutterInputDevice *device; + GSettings *settings; + guint *group_modes; +}; + +typedef enum +{ + META_PAD_DIRECTION_NONE = -1, + META_PAD_DIRECTION_UP = 0, + META_PAD_DIRECTION_DOWN, + META_PAD_DIRECTION_CW, + META_PAD_DIRECTION_CCW, +} MetaPadDirection; + +struct _MetaPadActionMapper +{ + GObject parent_class; + + GHashTable *pads; + ClutterSeat *seat; + ClutterVirtualInputDevice *virtual_pad_keyboard; + MetaMonitorManager *monitor_manager; + + /* Pad ring/strip emission */ + struct { + ClutterInputDevice *pad; + MetaPadActionType action; + guint number; + double value; + } last_pad_action_info; +}; + +G_DEFINE_TYPE (MetaPadActionMapper, meta_pad_action_mapper, G_TYPE_OBJECT) + +static void +meta_pad_action_mapper_finalize (GObject *object) +{ + MetaPadActionMapper *mapper = META_PAD_ACTION_MAPPER (object); + + g_hash_table_unref (mapper->pads); + g_object_unref (mapper->monitor_manager); + g_clear_object (&mapper->virtual_pad_keyboard); + + G_OBJECT_CLASS (meta_pad_action_mapper_parent_class)->finalize (object); +} + +static void +meta_pad_action_mapper_class_init (MetaPadActionMapperClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_pad_action_mapper_finalize; +} + +static GSettings * +lookup_device_settings (ClutterInputDevice *device) +{ + const char *vendor, *product; + GSettings *settings; + char *path; + + vendor = clutter_input_device_get_vendor_id (device); + product = clutter_input_device_get_product_id (device); + path = g_strdup_printf ("/org/gnome/desktop/peripherals/tablets/%s:%s/", + vendor, product); + + settings = g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet", + path); + g_free (path); + + return settings; +} + +static PadMappingInfo * +pad_mapping_info_new (ClutterInputDevice *pad) +{ + PadMappingInfo *info; + + info = g_new0 (PadMappingInfo, 1); + info->device = pad; + info->settings = lookup_device_settings (pad); + info->group_modes = + g_new0 (guint, clutter_input_device_get_n_mode_groups (pad)); + + return info; +} + +static void +pad_mapping_info_free (PadMappingInfo *info) +{ + g_object_unref (info->settings); + g_free (info->group_modes); + g_free (info); +} + +static void +device_added (ClutterSeat *seat, + ClutterInputDevice *device, + MetaPadActionMapper *mapper) +{ + PadMappingInfo *info; + + if (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE) + { + info = pad_mapping_info_new (device); + g_hash_table_insert (mapper->pads, device, info); + } +} + +static void +device_removed (ClutterSeat *seat, + ClutterInputDevice *device, + MetaPadActionMapper *mapper) +{ + g_hash_table_remove (mapper->pads, device); +} + +static void +meta_pad_action_mapper_init (MetaPadActionMapper *mapper) +{ + mapper->pads = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) pad_mapping_info_free); + + mapper->seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); + g_signal_connect (mapper->seat, "device-added", + G_CALLBACK (device_added), mapper); + g_signal_connect (mapper->seat, "device-removed", + G_CALLBACK (device_removed), mapper); +} + +MetaPadActionMapper * +meta_pad_action_mapper_new (MetaMonitorManager *monitor_manager) +{ + MetaPadActionMapper *action_mapper; + + action_mapper = g_object_new (META_TYPE_PAD_ACTION_MAPPER, NULL); + g_set_object (&action_mapper->monitor_manager, monitor_manager); + + return action_mapper; +} + +static GSettings * +lookup_pad_action_settings (ClutterInputDevice *device, + MetaPadActionType action, + guint number, + MetaPadDirection direction, + int mode) +{ + const char *vendor, *product, *action_type, *detail_type = NULL; + GSettings *settings; + GString *path; + char action_label; + + vendor = clutter_input_device_get_vendor_id (device); + product = clutter_input_device_get_product_id (device); + + action_label = 'A' + number; + + switch (action) + { + case META_PAD_ACTION_BUTTON: + action_type = "button"; + break; + case META_PAD_ACTION_RING: + g_assert (direction == META_PAD_DIRECTION_CW || + direction == META_PAD_DIRECTION_CCW); + action_type = "ring"; + detail_type = (direction == META_PAD_DIRECTION_CW) ? "cw" : "ccw"; + break; + case META_PAD_ACTION_STRIP: + g_assert (direction == META_PAD_DIRECTION_UP || + direction == META_PAD_DIRECTION_DOWN); + action_type = "strip"; + detail_type = (direction == META_PAD_DIRECTION_UP) ? "up" : "down"; + break; + default: + return NULL; + } + + path = g_string_new (NULL); + g_string_append_printf (path, "/org/gnome/desktop/peripherals/tablets/%s:%s/%s%c", + vendor, product, action_type, action_label); + + if (detail_type) + g_string_append_printf (path, "-%s", detail_type); + + if (mode >= 0) + g_string_append_printf (path, "-mode-%d", mode); + + g_string_append_c (path, '/'); + + settings = g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet.pad-button", + path->str); + g_string_free (path, TRUE); + + return settings; +} + +static GDesktopPadButtonAction +meta_pad_action_mapper_get_button_action (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + guint button) +{ + GDesktopPadButtonAction action; + GSettings *settings; + + g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), + G_DESKTOP_PAD_BUTTON_ACTION_NONE); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), + G_DESKTOP_PAD_BUTTON_ACTION_NONE); + + settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON, + button, META_PAD_DIRECTION_NONE, -1); + action = g_settings_get_enum (settings, "action"); + g_object_unref (settings); + + return action; +} + +static gboolean +cycle_logical_monitors (MetaPadActionMapper *mapper, + gboolean skip_all_monitors, + MetaLogicalMonitor *current_logical_monitor, + MetaLogicalMonitor **next_logical_monitor) +{ + MetaMonitorManager *monitor_manager = mapper->monitor_manager; + GList *logical_monitors; + + /* We cycle between: + * - the span of all monitors (current_output = NULL), only for + * non-integrated devices. + * - each monitor individually. + */ + + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + + if (!current_logical_monitor) + { + *next_logical_monitor = logical_monitors->data; + } + else + { + GList *l; + + l = g_list_find (logical_monitors, current_logical_monitor); + if (l->next) + *next_logical_monitor = l->next->data; + else if (skip_all_monitors) + *next_logical_monitor = logical_monitors->data; + else + *next_logical_monitor = NULL; + } + + return TRUE; +} + +static MetaMonitor * +logical_monitor_find_monitor (MetaLogicalMonitor *logical_monitor, + const char *vendor, + const char *product, + const char *serial) +{ + GList *monitors; + GList *l; + + monitors = meta_logical_monitor_get_monitors (logical_monitor); + for (l = monitors; l; l = l->next) + { + MetaMonitor *monitor = l->data; + + if (g_strcmp0 (meta_monitor_get_vendor (monitor), vendor) == 0 && + g_strcmp0 (meta_monitor_get_product (monitor), product) == 0 && + g_strcmp0 (meta_monitor_get_serial (monitor), serial) == 0) + return monitor; + } + + return NULL; +} + +static void +meta_pad_action_mapper_find_monitor (MetaPadActionMapper *mapper, + GSettings *settings, + ClutterInputDevice *device, + MetaMonitor **out_monitor, + MetaLogicalMonitor **out_logical_monitor) +{ + MetaMonitorManager *monitor_manager; + MetaMonitor *monitor; + guint n_values; + GList *logical_monitors; + GList *l; + char **edid; + + edid = g_settings_get_strv (settings, "output"); + 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)); + goto out; + } + + if (!*edid[0] && !*edid[1] && !*edid[2]) + goto out; + + monitor_manager = mapper->monitor_manager; + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + for (l = logical_monitors; l; l = l->next) + { + MetaLogicalMonitor *logical_monitor = l->data; + + monitor = logical_monitor_find_monitor (logical_monitor, + edid[0], edid[1], edid[2]); + if (monitor) + { + if (out_monitor) + *out_monitor = monitor; + if (out_logical_monitor) + *out_logical_monitor = logical_monitor; + break; + } + } + +out: + g_strfreev (edid); +} + +static void +meta_pad_action_mapper_cycle_tablet_output (MetaPadActionMapper *mapper, + ClutterInputDevice *device) +{ + PadMappingInfo *info; + MetaLogicalMonitor *logical_monitor = NULL; + const char *edid[4] = { 0 }, *pretty_name = NULL; + gboolean is_integrated_device = FALSE; +#ifdef HAVE_LIBWACOM + WacomDevice *wacom_device; +#endif + + g_return_if_fail (META_IS_PAD_ACTION_MAPPER (mapper)); + g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device)); + g_return_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE || + clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE); + + info = g_hash_table_lookup (mapper->pads, device); + g_return_if_fail (info != NULL); + +#ifdef HAVE_LIBWACOM + wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (device)); + + if (wacom_device) + { + pretty_name = libwacom_get_name (wacom_device); + is_integrated_device = + libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE; + } +#endif + + meta_pad_action_mapper_find_monitor (mapper, info->settings, device, + NULL, &logical_monitor); + + if (!cycle_logical_monitors (mapper, + is_integrated_device, + logical_monitor, + &logical_monitor)) + return; + + if (logical_monitor) + { + MetaMonitor *monitor; + + /* Pick an arbitrary monitor in the logical monitor to represent it. */ + monitor = meta_logical_monitor_get_monitors (logical_monitor)->data; + edid[0] = meta_monitor_get_vendor (monitor); + edid[1] = meta_monitor_get_product (monitor); + edid[2] = meta_monitor_get_serial (monitor); + } + else + { + edid[0] = ""; + edid[1] = ""; + edid[2] = ""; + } + + g_settings_set_strv (info->settings, "output", edid); + meta_display_show_tablet_mapping_notification (meta_get_display (), + device, pretty_name); +} + +gboolean +meta_pad_action_mapper_is_button_grabbed (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + guint button) +{ + g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), FALSE); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), FALSE); + g_return_val_if_fail (clutter_input_device_get_device_type (pad) == + CLUTTER_PAD_DEVICE, FALSE); + + return (meta_pad_action_mapper_get_button_action (mapper, pad, button) != + G_DESKTOP_PAD_BUTTON_ACTION_NONE); +} + +static void +emulate_modifiers (ClutterVirtualInputDevice *device, + ClutterModifierType mods, + ClutterKeyState state) +{ + guint i; + struct { + ClutterModifierType mod; + guint keyval; + } mod_map[] = { + { CLUTTER_SHIFT_MASK, CLUTTER_KEY_Shift_L }, + { CLUTTER_CONTROL_MASK, CLUTTER_KEY_Control_L }, + { CLUTTER_MOD1_MASK, CLUTTER_KEY_Meta_L } + }; + + for (i = 0; i < G_N_ELEMENTS (mod_map); i++) + { + if ((mods & mod_map[i].mod) == 0) + continue; + + clutter_virtual_input_device_notify_keyval (device, + clutter_get_current_event_time (), + mod_map[i].keyval, state); + } +} + +static void +meta_pad_action_mapper_emulate_keybinding (MetaPadActionMapper *mapper, + const char *accel, + gboolean is_press) +{ + ClutterKeyState state; + guint key, mods; + + if (!accel || !*accel) + return; + + /* FIXME: This is appalling */ + gtk_accelerator_parse (accel, &key, &mods); + + if (!mapper->virtual_pad_keyboard) + { + ClutterBackend *backend; + ClutterSeat *seat; + + backend = clutter_get_default_backend (); + seat = clutter_backend_get_default_seat (backend); + + mapper->virtual_pad_keyboard = + clutter_seat_create_virtual_device (seat, + CLUTTER_KEYBOARD_DEVICE); + } + + state = is_press ? CLUTTER_KEY_STATE_PRESSED : CLUTTER_KEY_STATE_RELEASED; + + if (is_press) + emulate_modifiers (mapper->virtual_pad_keyboard, mods, state); + + clutter_virtual_input_device_notify_keyval (mapper->virtual_pad_keyboard, + clutter_get_current_event_time (), + key, state); + if (!is_press) + emulate_modifiers (mapper->virtual_pad_keyboard, mods, state); +} + +static gboolean +meta_pad_action_mapper_handle_button (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + const ClutterPadButtonEvent *event) +{ + GDesktopPadButtonAction action; + int button, group, mode; + gboolean is_press; + GSettings *settings; + char *accel; + + g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), FALSE); + g_return_val_if_fail (event->type == CLUTTER_PAD_BUTTON_PRESS || + event->type == CLUTTER_PAD_BUTTON_RELEASE, FALSE); + + button = event->button; + mode = event->mode; + group = clutter_input_device_get_mode_switch_button_group (pad, button); + is_press = event->type == CLUTTER_PAD_BUTTON_PRESS; + + if (is_press && group >= 0) + { + guint n_modes = clutter_input_device_get_group_n_modes (pad, group); + const char *pretty_name = NULL; + PadMappingInfo *info; +#ifdef HAVE_LIBWACOM + WacomDevice *wacom_device; +#endif + + info = g_hash_table_lookup (mapper->pads, pad); + +#ifdef HAVE_LIBWACOM + wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (pad)); + + if (wacom_device) + pretty_name = libwacom_get_name (wacom_device); +#endif + meta_display_notify_pad_group_switch (meta_get_display (), pad, + pretty_name, group, mode, n_modes); + info->group_modes[group] = mode; + } + + action = meta_pad_action_mapper_get_button_action (mapper, pad, button); + + switch (action) + { + case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR: + if (is_press) + meta_pad_action_mapper_cycle_tablet_output (mapper, pad); + return TRUE; + case G_DESKTOP_PAD_BUTTON_ACTION_HELP: + if (is_press) + meta_display_request_pad_osd (meta_get_display (), pad, FALSE); + return TRUE; + case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING: + settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON, + button, META_PAD_DIRECTION_NONE, -1); + accel = g_settings_get_string (settings, "keybinding"); + meta_pad_action_mapper_emulate_keybinding (mapper, accel, is_press); + g_object_unref (settings); + g_free (accel); + return TRUE; + case G_DESKTOP_PAD_BUTTON_ACTION_NONE: + default: + return FALSE; + } +} + +static gboolean +meta_pad_action_mapper_handle_action (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + MetaPadActionType action, + guint number, + MetaPadDirection direction, + guint mode) +{ + GSettings *settings; + gboolean handled = FALSE; + char *accel; + + settings = lookup_pad_action_settings (pad, action, number, direction, mode); + accel = g_settings_get_string (settings, "keybinding"); + + if (accel && *accel) + { + meta_pad_action_mapper_emulate_keybinding (mapper, accel, TRUE); + meta_pad_action_mapper_emulate_keybinding (mapper, accel, FALSE); + handled = TRUE; + } + + g_object_unref (settings); + g_free (accel); + + return handled; +} + +static gboolean +meta_pad_action_mapper_get_action_direction (MetaPadActionMapper *mapper, + const ClutterEvent *event, + MetaPadDirection *direction) +{ + ClutterInputDevice *pad = clutter_event_get_device (event); + MetaPadActionType pad_action; + gboolean has_direction = FALSE; + MetaPadDirection inc_dir, dec_dir; + guint number; + double value; + + *direction = META_PAD_DIRECTION_NONE; + + switch (event->type) + { + case CLUTTER_PAD_RING: + pad_action = META_PAD_ACTION_RING; + number = event->pad_ring.ring_number; + value = event->pad_ring.angle; + inc_dir = META_PAD_DIRECTION_CW; + dec_dir = META_PAD_DIRECTION_CCW; + break; + case CLUTTER_PAD_STRIP: + pad_action = META_PAD_ACTION_STRIP; + number = event->pad_strip.strip_number; + value = event->pad_strip.value; + inc_dir = META_PAD_DIRECTION_DOWN; + dec_dir = META_PAD_DIRECTION_UP; + break; + default: + return FALSE; + } + + if (mapper->last_pad_action_info.pad == pad && + mapper->last_pad_action_info.action == pad_action && + mapper->last_pad_action_info.number == number && + value >= 0 && mapper->last_pad_action_info.value >= 0) + { + *direction = (value - mapper->last_pad_action_info.value) > 0 ? + inc_dir : dec_dir; + has_direction = TRUE; + } + + mapper->last_pad_action_info.pad = pad; + mapper->last_pad_action_info.action = pad_action; + mapper->last_pad_action_info.number = number; + mapper->last_pad_action_info.value = value; + return has_direction; +} + +gboolean +meta_pad_action_mapper_handle_event (MetaPadActionMapper *mapper, + const ClutterEvent *event) +{ + ClutterInputDevice *pad; + MetaPadDirection direction = META_PAD_DIRECTION_NONE; + + pad = clutter_event_get_source_device ((ClutterEvent *) event); + + switch (event->type) + { + case CLUTTER_PAD_BUTTON_PRESS: + case CLUTTER_PAD_BUTTON_RELEASE: + return meta_pad_action_mapper_handle_button (mapper, pad, + &event->pad_button); + case CLUTTER_PAD_RING: + if (!meta_pad_action_mapper_get_action_direction (mapper, + event, &direction)) + return FALSE; + return meta_pad_action_mapper_handle_action (mapper, pad, + META_PAD_ACTION_RING, + event->pad_ring.ring_number, + direction, + event->pad_ring.mode); + case CLUTTER_PAD_STRIP: + if (!meta_pad_action_mapper_get_action_direction (mapper, + event, &direction)) + return FALSE; + return meta_pad_action_mapper_handle_action (mapper, pad, + META_PAD_ACTION_STRIP, + event->pad_strip.strip_number, + direction, + event->pad_strip.mode); + default: + return FALSE; + } +} + + +static char * +compose_directional_action_label (GSettings *direction1, + GSettings *direction2) +{ + char *accel1, *accel2, *str = NULL; + + accel1 = g_settings_get_string (direction1, "keybinding"); + accel2 = g_settings_get_string (direction2, "keybinding"); + + if (accel1 && *accel1 && accel2 && *accel2) + str = g_strdup_printf ("%s / %s", accel1, accel2); + + g_free (accel1); + g_free (accel2); + + return str; +} + +static char * +meta_pad_action_mapper_get_ring_label (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + guint number, + guint mode) +{ + GSettings *settings1, *settings2; + char *label; + + /* We only allow keybinding actions with those */ + settings1 = lookup_pad_action_settings (pad, META_PAD_ACTION_RING, number, + META_PAD_DIRECTION_CW, mode); + settings2 = lookup_pad_action_settings (pad, META_PAD_ACTION_RING, number, + META_PAD_DIRECTION_CCW, mode); + label = compose_directional_action_label (settings1, settings2); + g_object_unref (settings1); + g_object_unref (settings2); + + return label; +} + +static char * +meta_pad_action_mapper_get_strip_label (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + guint number, + guint mode) +{ + GSettings *settings1, *settings2; + char *label; + + /* We only allow keybinding actions with those */ + settings1 = lookup_pad_action_settings (pad, META_PAD_ACTION_STRIP, number, + META_PAD_DIRECTION_UP, mode); + settings2 = lookup_pad_action_settings (pad, META_PAD_ACTION_STRIP, number, + META_PAD_DIRECTION_DOWN, mode); + label = compose_directional_action_label (settings1, settings2); + g_object_unref (settings1); + g_object_unref (settings2); + + return label; +} + +static char * +meta_pad_action_mapper_get_button_label (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + guint button) +{ + GDesktopPadButtonAction action; + int group; + + g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), NULL); + g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), NULL); + g_return_val_if_fail (clutter_input_device_get_device_type (pad) == + CLUTTER_PAD_DEVICE, NULL); + + group = clutter_input_device_get_mode_switch_button_group (pad, button); + + if (group >= 0) + { + /* TRANSLATORS: This string refers to a button that switches between + * different modes. + */ + return g_strdup_printf (_("Mode Switch (Group %d)"), group); + } + + action = meta_pad_action_mapper_get_button_action (mapper, pad, button); + + switch (action) + { + case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING: + { + GSettings *settings; + char *accel; + + settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON, + button, META_PAD_DIRECTION_NONE, -1); + accel = g_settings_get_string (settings, "keybinding"); + g_object_unref (settings); + + return accel; + } + case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR: + /* TRANSLATORS: This string refers to an action, cycles drawing tablets' + * mapping through the available outputs. + */ + return g_strdup (_("Switch monitor")); + case G_DESKTOP_PAD_BUTTON_ACTION_HELP: + return g_strdup (_("Show on-screen help")); + case G_DESKTOP_PAD_BUTTON_ACTION_NONE: + default: + return NULL; + } +} + +static guint +get_current_pad_mode (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + MetaPadActionType action_type, + guint number) +{ + PadMappingInfo *info; + guint group = 0, n_groups; + + info = g_hash_table_lookup (mapper->pads, pad); + n_groups = clutter_input_device_get_n_mode_groups (pad); + + if (!info->group_modes || n_groups == 0) + return 0; + + if (action_type == META_PAD_ACTION_RING || + action_type == META_PAD_ACTION_STRIP) + { + /* Assume features are evenly distributed in groups */ + group = number % n_groups; + } + + return info->group_modes[group]; +} + +char * +meta_pad_action_mapper_get_action_label (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + MetaPadActionType action_type, + guint number) +{ + guint mode; + + switch (action_type) + { + case META_PAD_ACTION_BUTTON: + return meta_pad_action_mapper_get_button_label (mapper, pad, number); + case META_PAD_ACTION_RING: + mode = get_current_pad_mode (mapper, pad, action_type, number); + return meta_pad_action_mapper_get_ring_label (mapper, pad, number, mode); + case META_PAD_ACTION_STRIP: + mode = get_current_pad_mode (mapper, pad, action_type, number); + return meta_pad_action_mapper_get_strip_label (mapper, pad, number, mode); + } + + return NULL; +} diff --git a/src/core/meta-pad-action-mapper.h b/src/core/meta-pad-action-mapper.h new file mode 100644 index 0000000000000000000000000000000000000000..63fc2261b5137ee76b05793a265ec3893fcf107c --- /dev/null +++ b/src/core/meta-pad-action-mapper.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Carlos Garnacho + */ + +#ifndef META_PAD_ACTION_MAPPER_H +#define META_PAD_ACTION_MAPPER_H + +#include "clutter/clutter.h" +#include "meta/display.h" +#include "meta/meta-monitor-manager.h" + +#define META_TYPE_PAD_ACTION_MAPPER (meta_pad_action_mapper_get_type ()) +G_DECLARE_FINAL_TYPE (MetaPadActionMapper, meta_pad_action_mapper, + META, PAD_ACTION_MAPPER, GObject) + +MetaPadActionMapper * meta_pad_action_mapper_new (MetaMonitorManager *monitor_manager); + +gboolean meta_pad_action_mapper_is_button_grabbed (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + guint button); +gboolean meta_pad_action_mapper_handle_event (MetaPadActionMapper *mapper, + const ClutterEvent *event); +gchar * meta_pad_action_mapper_get_action_label (MetaPadActionMapper *mapper, + ClutterInputDevice *pad, + MetaPadActionType action, + guint number); + +#endif /* META_PAD_ACTION_MAPPER_H */ diff --git a/src/meson.build b/src/meson.build index cc8527beaba738b7f370ef21f6c10bd049e77789..6db0462fe774d32bd2f036fb56fe70b754800951 100644 --- a/src/meson.build +++ b/src/meson.build @@ -233,6 +233,8 @@ mutter_sources = [ 'backends/meta-settings-private.h', 'backends/meta-stage.c', 'backends/meta-stage-private.h', + 'backends/meta-viewport-info.c', + 'backends/meta-viewport-info.h', 'backends/x11/cm/meta-backend-x11-cm.c', 'backends/x11/cm/meta-backend-x11-cm.h', 'backends/x11/cm/meta-cursor-sprite-xfixes.c', @@ -374,6 +376,7 @@ mutter_sources = [ 'core/meta-inhibit-shortcuts-dialog-default.c', 'core/meta-inhibit-shortcuts-dialog-default-private.h', 'core/meta-launch-context.c', + 'core/meta-pad-action-mapper.c', 'core/meta-selection.c', 'core/meta-selection-source.c', 'core/meta-selection-source-memory.c', @@ -697,9 +700,13 @@ if have_native_backend 'backends/native/meta-kms-utils.h', 'backends/native/meta-kms.c', 'backends/native/meta-kms.h', + 'backends/native/meta-pointer-constraint-native.c', + 'backends/native/meta-pointer-constraint-native.h', 'backends/native/meta-renderer-native-gles3.c', 'backends/native/meta-renderer-native-gles3.h', 'backends/native/meta-renderer-native.h', + 'backends/native/meta-seat-impl.c', + 'backends/native/meta-seat-impl.h', 'backends/native/meta-seat-native.c', 'backends/native/meta-seat-native.h', 'backends/native/meta-stage-native.c', @@ -751,14 +758,6 @@ dbus_idle_monitor_built_sources = gnome.gdbus_codegen('meta-dbus-idle-monitor', ) mutter_built_sources += dbus_idle_monitor_built_sources -mutter_marshal = gnome.genmarshal('meta-marshal', - sources: ['meta-marshal.list'], - prefix: 'meta_marshal', - internal: true, - valist_marshallers: true, - ) -mutter_built_sources += mutter_marshal - if have_profiler mutter_sources += [ 'backends/meta-profiler.c', diff --git a/src/meta-marshal.list b/src/meta-marshal.list deleted file mode 100644 index e26b60a8ec8371db51dd14c1862e49f788f8dcb5..0000000000000000000000000000000000000000 --- a/src/meta-marshal.list +++ /dev/null @@ -1 +0,0 @@ -VOID:FLOAT,FLOAT diff --git a/src/tests/clutter/interactive/test-devices.c b/src/tests/clutter/interactive/test-devices.c index 9a63f731e991905fd1416324445a204dc68615cf..b8d1f0fe7fa93c184bb4d092b544846a23a87e20 100644 --- a/src/tests/clutter/interactive/test-devices.c +++ b/src/tests/clutter/interactive/test-devices.c @@ -49,34 +49,6 @@ device_type_name (ClutterInputDevice *device) } } -static const gchar * -axis_type_name (ClutterInputAxis axis) -{ - switch (axis) - { - case CLUTTER_INPUT_AXIS_X: - return "Absolute X"; - - case CLUTTER_INPUT_AXIS_Y: - return "Absolute Y"; - - case CLUTTER_INPUT_AXIS_PRESSURE: - return "Pressure"; - - case CLUTTER_INPUT_AXIS_XTILT: - return "X Tilt"; - - case CLUTTER_INPUT_AXIS_YTILT: - return "Y Tilt"; - - case CLUTTER_INPUT_AXIS_WHEEL: - return "Wheel"; - - default: - return "Unknown"; - } -} - static gboolean stage_button_event_cb (ClutterActor *actor, ClutterEvent *event, @@ -85,21 +57,18 @@ stage_button_event_cb (ClutterActor *actor, ClutterInputDevice *device; ClutterInputDevice *source_device; ClutterActor *hand = NULL; - gdouble *axes; - guint n_axes, i; device = clutter_event_get_device (event); source_device = clutter_event_get_source_device (event); hand = g_hash_table_lookup (app->devices, device); - g_print ("Device: '%s' (type: %s, source: '%s', axes: %d)\n", + g_print ("Device: '%s' (type: %s, source: '%s')\n", clutter_input_device_get_device_name (device), device_type_name (device), source_device != device ? clutter_input_device_get_device_name (source_device) - : "", - clutter_input_device_get_n_axes (device)); + : ""); if (hand != NULL) { @@ -109,21 +78,6 @@ stage_button_event_cb (ClutterActor *actor, clutter_actor_set_position (hand, event_x, event_y); } - axes = clutter_event_get_axes (event, &n_axes); - for (i = 0; i < n_axes; i++) - { - ClutterInputAxis axis; - - axis = clutter_input_device_get_axis (device, i); - if (axis == CLUTTER_INPUT_AXIS_IGNORE) - continue; - - g_print ("\tAxis[%2d][%s].value: %.2f\n", - i, - axis_type_name (axis), - axes[i]); - } - return FALSE; } @@ -171,8 +125,6 @@ seat_device_added_cb (ClutterSeat *seat, g_print ("*** enabling device '%s' ***\n", clutter_input_device_get_device_name (device)); - clutter_input_device_set_enabled (device, TRUE); - hand = clutter_test_utils_create_texture_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", @@ -268,8 +220,6 @@ test_devices_main (int argc, char **argv) g_print ("*** enabling device '%s' ***\n", clutter_input_device_get_device_name (device)); - clutter_input_device_set_enabled (device, TRUE); - hand = clutter_test_utils_create_texture_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", diff --git a/src/tests/clutter/performance/test-common.h b/src/tests/clutter/performance/test-common.h index ef90ce10996cd05408ad385bf95858e2b2da38b0..ea4210ddcc74dc56181bbb6c13f7227864105d02 100644 --- a/src/tests/clutter/performance/test-common.h +++ b/src/tests/clutter/performance/test-common.h @@ -110,7 +110,6 @@ static gboolean perf_fake_mouse_cb (gpointer stage) event2->crossing.related = NULL; clutter_event_set_device (event2, device); - clutter_input_device_update_from_event (device, event2); clutter_event_put (event2); clutter_event_free (event2); diff --git a/src/wayland/meta-pointer-confinement-wayland.c b/src/wayland/meta-pointer-confinement-wayland.c index 7f980054c7b71e6ce3db3a03e59a0b7c8dbc0574..3df6ed0ab35f2cce5fb26461cd2743882657bba5 100644 --- a/src/wayland/meta-pointer-confinement-wayland.c +++ b/src/wayland/meta-pointer-confinement-wayland.c @@ -41,698 +41,227 @@ #include "backends/meta-backend-private.h" #include "backends/meta-pointer-constraint.h" -#include "compositor/meta-surface-actor-wayland.h" -#include "core/meta-border.h" #include "wayland/meta-wayland-pointer-constraints.h" #include "wayland/meta-wayland-pointer.h" #include "wayland/meta-wayland-seat.h" #include "wayland/meta-wayland-surface.h" -struct _MetaPointerConfinementWayland -{ - MetaPointerConstraint parent; +typedef struct _MetaPointerConfinementWaylandPrivate MetaPointerConfinementWaylandPrivate; +struct _MetaPointerConfinementWaylandPrivate +{ MetaWaylandPointerConstraint *constraint; + gboolean enabled; }; -typedef struct _MetaBox -{ - int x1; - int y1; - int x2; - int y2; -} MetaBox; - -G_DEFINE_TYPE (MetaPointerConfinementWayland, meta_pointer_confinement_wayland, - META_TYPE_POINTER_CONSTRAINT); - -static MetaBorder * -add_border (GArray *borders, - float x1, float y1, - float x2, float y2, - MetaBorderMotionDirection blocking_directions) +enum { - MetaBorder border; - - border = (MetaBorder) { - .line = (MetaLine2) { - .a = (MetaVector2) { - .x = x1, - .y = y1, - }, - .b = (MetaVector2) { - .x = x2, - .y = y2, - }, - }, - .blocking_directions = blocking_directions, - }; - - g_array_append_val (borders, border); - - return &g_array_index (borders, MetaBorder, borders->len - 1); -} + PROP_0, + PROP_WAYLAND_POINTER_CONSTRAINT, + N_PROPS, +}; -static gint -compare_lines_x (gconstpointer a, gconstpointer b) -{ - const MetaBorder *border_a = a; - const MetaBorder *border_b = b; +static GParamSpec *props[N_PROPS] = { 0 }; - if (border_a->line.a.x == border_b->line.a.x) - return border_a->line.b.x < border_b->line.b.x; - else - return border_a->line.a.x > border_b->line.a.x; -} +G_DEFINE_TYPE_WITH_PRIVATE (MetaPointerConfinementWayland, + meta_pointer_confinement_wayland, + G_TYPE_OBJECT) static void -add_non_overlapping_edges (MetaBox *boxes, - unsigned int band_above_start, - unsigned int band_below_start, - unsigned int band_below_end, - GArray *borders) +meta_pointer_confinement_wayland_update (MetaPointerConfinementWayland *self) { - unsigned int i; - GArray *band_merge; - MetaBorder *border; - MetaBorder *prev_border; - MetaBorder *new_border; - - band_merge = g_array_new (FALSE, FALSE, sizeof *border); - - /* Add bottom band of previous row, and top band of current row, and - * sort them so lower left x coordinate comes first. If there are two - * borders with the same left x coordinate, the wider one comes first. - */ - for (i = band_above_start; i < band_below_start; i++) - { - MetaBox *box = &boxes[i]; - add_border (band_merge, box->x1, box->y2, box->x2, box->y2, - META_BORDER_MOTION_DIRECTION_POSITIVE_Y); - } - for (i = band_below_start; i < band_below_end; i++) - { - MetaBox *box= &boxes[i]; - add_border (band_merge, box->x1, box->y1, box->x2, box->y1, - META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); - } - g_array_sort (band_merge, compare_lines_x); - - /* Combine the two combined bands so that any overlapping border is - * eliminated. */ - prev_border = NULL; - for (i = 0; i < band_merge->len; i++) - { - border = &g_array_index (band_merge, MetaBorder, i); - - g_assert (border->line.a.y == border->line.b.y); - g_assert (!prev_border || - prev_border->line.a.y == border->line.a.y); - g_assert (!prev_border || - (prev_border->line.a.x != border->line.a.x || - prev_border->line.b.x != border->line.b.x)); - g_assert (!prev_border || - prev_border->line.a.x <= border->line.a.x); - - if (prev_border && - prev_border->line.a.x == border->line.a.x) - { - /* - * ------------ + - * ------- = - * [ ]----- - */ - prev_border->line.a.x = border->line.b.x; - } - else if (prev_border && - prev_border->line.b.x == border->line.b.x) - { - /* - * ------------ + - * ------ = - * ------[ ] - */ - prev_border->line.b.x = border->line.a.x; - } - else if (prev_border && - prev_border->line.b.x == border->line.a.x) - { - /* - * -------- + - * ------ = - * -------------- - */ - prev_border->line.b.x = border->line.b.x; - } - else if (prev_border && - prev_border->line.b.x >= border->line.a.x) - { - /* - * --------------- + - * ------ = - * -----[ ]---- - */ - new_border = add_border (borders, - border->line.b.x, - border->line.b.y, - prev_border->line.b.x, - prev_border->line.b.y, - prev_border->blocking_directions); - prev_border->line.b.x = border->line.a.x; - prev_border = new_border; - } - else - { - g_assert (!prev_border || - prev_border->line.b.x < border->line.a.x); - /* - * First border or non-overlapping. - * - * ----- + - * ----- = - * ----- ----- - */ - g_array_append_val (borders, *border); - prev_border = &g_array_index (borders, MetaBorder, borders->len - 1); - } - } + MetaPointerConstraint *constraint; - g_array_free (band_merge, FALSE); + constraint = + META_POINTER_CONFINEMENT_WAYLAND_GET_CLASS (self)->create_constraint (self); + meta_backend_set_client_pointer_constraint (meta_get_backend (), constraint); + g_object_unref (constraint); } static void -add_band_bottom_edges (MetaBox *boxes, - int band_start, - int band_end, - GArray *borders) +surface_geometry_changed (MetaWaylandSurface *surface, + MetaPointerConfinementWayland *self) { - int i; - - for (i = band_start; i < band_end; i++) - { - add_border (borders, - boxes[i].x1, boxes[i].y2, - boxes[i].x2, boxes[i].y2, - META_BORDER_MOTION_DIRECTION_POSITIVE_Y); - } + meta_pointer_confinement_wayland_update (self); } static void -region_to_outline (cairo_region_t *region, - GArray *borders) +window_position_changed (MetaWindow *window, + MetaPointerConfinementWayland *self) { - MetaBox *boxes; - int num_boxes; - int i; - int top_most, bottom_most; - int current_roof; - int prev_top; - int band_start, prev_band_start; - - /* - * Remove any overlapping lines from the set of rectangles. Note that - * pixman regions are grouped as rows of rectangles, where rectangles - * in one row never touch or overlap and are all of the same height. - * - * -------- --- -------- --- - * | | | | | | | | - * ----------====---- --- ----------- ----- --- - * | | => | | - * ----==========--------- ----- ---------- - * | | | | - * ------------------- ------------------- - * - */ - - num_boxes = cairo_region_num_rectangles (region); - boxes = g_new (MetaBox, num_boxes); - for (i = 0; i < num_boxes; i++) - { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (region, i, &rect); - boxes[i] = (MetaBox) { - .x1 = rect.x, - .y1 = rect.y, - .x2 = rect.x + rect.width, - .y2 = rect.y + rect.height, - }; - } - prev_top = 0; - top_most = boxes[0].y1; - current_roof = top_most; - bottom_most = boxes[num_boxes - 1].y2; - band_start = 0; - prev_band_start = 0; - for (i = 0; i < num_boxes; i++) - { - /* Detect if there is a vertical empty space, and add the lower - * level of the previous band if so was the case. */ - if (i > 0 && - boxes[i].y1 != prev_top && - boxes[i].y1 != boxes[i - 1].y2) - { - current_roof = boxes[i].y1; - add_band_bottom_edges (boxes, - band_start, - i, - borders); - } - - /* Special case adding the last band, since it won't be handled - * by the band change detection below. */ - if (boxes[i].y1 != current_roof && i == num_boxes - 1) - { - if (boxes[i].y1 != prev_top) - { - /* The last band is a single box, so we don't - * have a prev_band_start to tell us when the - * previous band started. */ - add_non_overlapping_edges (boxes, - band_start, - i, - i + 1, - borders); - } - else - { - add_non_overlapping_edges (boxes, - prev_band_start, - band_start, - i + 1, - borders); - } - } - - /* Detect when passing a band and combine the top border of the - * just passed band with the bottom band of the previous band. - */ - if (boxes[i].y1 != top_most && boxes[i].y1 != prev_top) - { - /* Combine the two passed bands. */ - if (prev_top != current_roof) - { - add_non_overlapping_edges (boxes, - prev_band_start, - band_start, - i, - borders); - } - - prev_band_start = band_start; - band_start = i; - } - - /* Add the top border if the box is part of the current roof. */ - if (boxes[i].y1 == current_roof) - { - add_border (borders, - boxes[i].x1, boxes[i].y1, - boxes[i].x2, boxes[i].y1, - META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); - } - - /* Add the bottom border of the last band. */ - if (boxes[i].y2 == bottom_most) - { - add_border (borders, - boxes[i].x1, boxes[i].y2, - boxes[i].x2, boxes[i].y2, - META_BORDER_MOTION_DIRECTION_POSITIVE_Y); - } - - /* Always add the left border. */ - add_border (borders, - boxes[i].x1, boxes[i].y1, - boxes[i].x1, boxes[i].y2, - META_BORDER_MOTION_DIRECTION_NEGATIVE_X); - - /* Always add the right border. */ - add_border (borders, - boxes[i].x2, boxes[i].y1, - boxes[i].x2, boxes[i].y2, - META_BORDER_MOTION_DIRECTION_POSITIVE_X); - - prev_top = boxes[i].y1; - } - - g_free (boxes); + meta_pointer_confinement_wayland_update (self); } -static MetaBorder * -get_closest_border (GArray *borders, - MetaLine2 *motion, - uint32_t directions) +void +meta_pointer_confinement_wayland_enable (MetaPointerConfinementWayland *confinement) { - MetaBorder *border; - MetaVector2 intersection; - MetaVector2 delta; - float distance_2; - MetaBorder *closest_border = NULL; - float closest_distance_2 = DBL_MAX; - unsigned int i; - - for (i = 0; i < borders->len; i++) - { - border = &g_array_index (borders, MetaBorder, i); - - if (!meta_border_is_blocking_directions (border, directions)) - continue; + MetaPointerConfinementWaylandPrivate *priv; + MetaWaylandPointerConstraint *constraint; + MetaWaylandSurface *surface; + MetaWindow *window; - if (!meta_line2_intersects_with (&border->line, motion, &intersection)) - continue; + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + g_assert (!priv->enabled); - delta = meta_vector2_subtract (intersection, motion->a); - distance_2 = delta.x*delta.x + delta.y*delta.y; - if (distance_2 < closest_distance_2) - { - closest_border = border; - closest_distance_2 = distance_2; - } - } + priv->enabled = TRUE; + constraint = priv->constraint; - return closest_border; -} + surface = meta_wayland_pointer_constraint_get_surface (constraint); + g_signal_connect_object (surface, + "geometry-changed", + G_CALLBACK (surface_geometry_changed), + confinement, + 0); -static void -clamp_to_border (MetaBorder *border, - MetaLine2 *motion, - uint32_t *motion_dir) -{ - /* - * When clamping either rightward or downward motions, the motion needs to be - * clamped so that the destination coordinate does not end up on the border - * (see weston_pointer_clamp_event_to_region). Do this by clamping such - * motions to the border minus the smallest possible wl_fixed_t value. - * - * When clamping in either leftward or upward motion, the resulting coordinate - * needs to be clamped so that it is enough on the inside to avoid the - * inaccuracies of clutter's stage to actor transformation algorithm (the one - * used in clutter_actor_transform_stage_point) to make it end up outside the - * next motion. It also needs to be clamped so that to the wl_fixed_t - * coordinate may still be right on the border (i.e. at .0). Testing shows - * that the smallest wl_fixed_t value divided by 10 is small enough to make - * the wl_fixed_t coordinate .0 and large enough to avoid the inaccuracies of - * clutters transform algorithm. - */ - if (meta_border_is_horizontal (border)) - { - if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_Y) - motion->b.y = border->line.a.y - wl_fixed_to_double (1); - else - motion->b.y = border->line.a.y + wl_fixed_to_double (1) / 10; - *motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_Y | - META_BORDER_MOTION_DIRECTION_NEGATIVE_Y); - } - else + window = meta_wayland_surface_get_window (surface); + if (window) { - if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_X) - motion->b.x = border->line.a.x - wl_fixed_to_double (1); - else - motion->b.x = border->line.a.x + wl_fixed_to_double (1) / 10; - *motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_X | - META_BORDER_MOTION_DIRECTION_NEGATIVE_X); + g_signal_connect_object (window, + "position-changed", + G_CALLBACK (window_position_changed), + confinement, + 0); } -} -static uint32_t -get_motion_directions (MetaLine2 *motion) -{ - uint32_t directions = 0; - - if (motion->a.x < motion->b.x) - directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_X; - else if (motion->a.x > motion->b.x) - directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_X; - if (motion->a.y < motion->b.y) - directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_Y; - else if (motion->a.y > motion->b.y) - directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_Y; - - return directions; + meta_pointer_confinement_wayland_update (confinement); } -static void -meta_pointer_confinement_wayland_constrain (MetaPointerConstraint *constraint, - ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y) +void +meta_pointer_confinement_wayland_disable (MetaPointerConfinementWayland *confinement) { - MetaPointerConfinementWayland *self = - META_POINTER_CONFINEMENT_WAYLAND (constraint); + MetaPointerConfinementWaylandPrivate *priv; + MetaWaylandPointerConstraint *constraint; MetaWaylandSurface *surface; - cairo_region_t *region; - float sx, sy; - float prev_sx, prev_sy; - GArray *borders; - MetaLine2 motion; - MetaBorder *closest_border; - uint32_t directions; - - surface = meta_wayland_pointer_constraint_get_surface (self->constraint); - - meta_wayland_surface_get_relative_coordinates (surface, *x, *y, &sx, &sy); - meta_wayland_surface_get_relative_coordinates (surface, prev_x, prev_y, - &prev_sx, &prev_sy); - - /* For motions in a positive direction on any axis, append the smallest - * possible value representable in a Wayland absolute coordinate. This is - * in order to avoid not clamping motion that as a floating point number - * won't be clamped, but will be rounded up to be outside of the range - * of wl_fixed_t. */ - if (sx > prev_sx) - sx += (float)wl_fixed_to_double(1); - if (sy > prev_sy) - sy += (float)wl_fixed_to_double(1); - - borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder)); - - /* - * Generate borders given the confine region we are to use. The borders - * are defined to be the outer region of the allowed area. This means - * top/left borders are "within" the allowed area, while bottom/right - * borders are outside. This needs to be considered when clamping - * confined motion vectors. - */ - region = - meta_wayland_pointer_constraint_calculate_effective_region (self->constraint); - region_to_outline (region, borders); - cairo_region_destroy (region); + MetaWindow *window; - motion = (MetaLine2) { - .a = (MetaVector2) { - .x = prev_sx, - .y = prev_sy, - }, - .b = (MetaVector2) { - .x = sx, - .y = sy, - }, - }; - directions = get_motion_directions (&motion); - - while (directions) + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + constraint = priv->constraint; + g_assert (priv->enabled); + + priv->enabled = FALSE; + surface = meta_wayland_pointer_constraint_get_surface (constraint); + g_signal_handlers_disconnect_by_func (surface, surface_geometry_changed, + confinement); + + window = meta_wayland_surface_get_window (surface); + if (window) { - closest_border = get_closest_border (borders, - &motion, - directions); - if (closest_border) - clamp_to_border (closest_border, &motion, &directions); - else - break; + g_signal_handlers_disconnect_by_func (window, window_position_changed, + confinement); } - meta_wayland_surface_get_absolute_coordinates (surface, - motion.b.x, motion.b.y, - x, y); + meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL); +} - g_array_free (borders, FALSE); +static void +meta_pointer_confinement_wayland_init (MetaPointerConfinementWayland *confinement_wayland) +{ } -static float -point_to_border_distance_2 (MetaBorder *border, - float x, - float y) +static void +meta_pointer_confinement_wayland_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - float orig_x, orig_y; - float dx, dy; + MetaPointerConfinementWayland *confinement; + MetaPointerConfinementWaylandPrivate *priv; - if (meta_border_is_horizontal (border)) - { - if (x < border->line.a.x) - orig_x = border->line.a.x; - else if (x > border->line.b.x) - orig_x = border->line.b.x; - else - orig_x = x; - orig_y = border->line.a.y; - } - else + confinement = META_POINTER_CONFINEMENT_WAYLAND (object); + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + + switch (prop_id) { - if (y < border->line.a.y) - orig_y = border->line.a.y; - else if (y > border->line.b.y) - orig_y = border->line.b.y; - else - orig_y = y; - orig_x = border->line.a.x; + case PROP_WAYLAND_POINTER_CONSTRAINT: + g_value_set_object (value, priv->constraint); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } - - dx = fabsf (orig_x - x); - dy = fabsf (orig_y - y); - return dx*dx + dy*dy; } static void -warp_to_behind_border (MetaBorder *border, - float *sx, - float *sy) +meta_pointer_confinement_wayland_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - switch (border->blocking_directions) + MetaPointerConfinementWayland *confinement; + MetaPointerConfinementWaylandPrivate *priv; + + confinement = META_POINTER_CONFINEMENT_WAYLAND (object); + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + + switch (prop_id) { - case META_BORDER_MOTION_DIRECTION_POSITIVE_X: - case META_BORDER_MOTION_DIRECTION_NEGATIVE_X: - if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_X) - *sx = border->line.a.x - wl_fixed_to_double (1); - else - *sx = border->line.a.x + wl_fixed_to_double (1); - if (*sy < border->line.a.y) - *sy = border->line.a.y + wl_fixed_to_double (1); - else if (*sy > border->line.b.y) - *sy = border->line.b.y - wl_fixed_to_double (1); + case PROP_WAYLAND_POINTER_CONSTRAINT: + priv->constraint = g_value_get_object (value); break; - case META_BORDER_MOTION_DIRECTION_POSITIVE_Y: - case META_BORDER_MOTION_DIRECTION_NEGATIVE_Y: - if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_Y) - *sy = border->line.a.y - wl_fixed_to_double (1); - else - *sy = border->line.a.y + wl_fixed_to_double (1); - if (*sx < border->line.a.x) - *sx = border->line.a.x + wl_fixed_to_double (1); - else if (*sx > (border->line.b.x)) - *sx = border->line.b.x - wl_fixed_to_double (1); + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } -static void -meta_pointer_confinement_wayland_maybe_warp (MetaPointerConfinementWayland *self) +static MetaPointerConstraint * +meta_pointer_confinement_wayland_create_constraint (MetaPointerConfinementWayland *confinement) { - MetaWaylandSeat *seat; + MetaPointerConfinementWaylandPrivate *priv; + MetaPointerConstraint *constraint; MetaWaylandSurface *surface; - graphene_point_t point; - float sx; - float sy; cairo_region_t *region; + float dx, dy; - seat = meta_wayland_pointer_constraint_get_seat (self->constraint); - surface = meta_wayland_pointer_constraint_get_surface (self->constraint); - - clutter_input_device_get_coords (seat->pointer->device, NULL, &point); - meta_wayland_surface_get_relative_coordinates (surface, - point.x, point.y, - &sx, &sy); + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + surface = meta_wayland_pointer_constraint_get_surface (priv->constraint); region = - meta_wayland_pointer_constraint_calculate_effective_region (self->constraint); - - if (!cairo_region_contains_point (region, (int)sx, (int)sy)) - { - GArray *borders; - float closest_distance_2 = FLT_MAX; - MetaBorder *closest_border = NULL; - ClutterSeat *seat; - unsigned int i; - float x; - float y; - - borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder)); - - region_to_outline (region, borders); - - for (i = 0; i < borders->len; i++) - { - MetaBorder *border = &g_array_index (borders, MetaBorder, i); - float distance_2; - - distance_2 = point_to_border_distance_2 (border, sx, sy); - if (distance_2 < closest_distance_2) - { - closest_border = border; - closest_distance_2 = distance_2; - } - } - - warp_to_behind_border (closest_border, &sx, &sy); + meta_wayland_pointer_constraint_calculate_effective_region (priv->constraint); - meta_wayland_surface_get_absolute_coordinates (surface, sx, sy, &x, &y); - - seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); - clutter_seat_warp_pointer (seat, (int)x, (int)y); - } + meta_wayland_surface_get_absolute_coordinates (surface, 0, 0, &dx, &dy); + cairo_region_translate (region, dx, dy); + constraint = meta_pointer_constraint_new (region); cairo_region_destroy (region); -} -static void -surface_geometry_changed (MetaWaylandSurface *surface, - MetaPointerConfinementWayland *self) -{ - meta_pointer_confinement_wayland_maybe_warp (self); + return constraint; } static void -window_position_changed (MetaWindow *window, - MetaPointerConfinementWayland *self) +meta_pointer_confinement_wayland_class_init (MetaPointerConfinementWaylandClass *klass) { - meta_pointer_confinement_wayland_maybe_warp (self); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = meta_pointer_confinement_wayland_set_property; + object_class->get_property = meta_pointer_confinement_wayland_get_property; + + klass->create_constraint = meta_pointer_confinement_wayland_create_constraint; + + props[PROP_WAYLAND_POINTER_CONSTRAINT] = + g_param_spec_object ("wayland-pointer-constraint", + "Wayland pointer constraint", + "Wayland pointer constraint", + META_TYPE_WAYLAND_POINTER_CONSTRAINT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPS, props); } -MetaPointerConstraint * +MetaPointerConfinementWayland * meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint) { - GObject *object; - MetaPointerConfinementWayland *confinement; - MetaWaylandSurface *surface; - MetaWindow *window; - - object = g_object_new (META_TYPE_POINTER_CONFINEMENT_WAYLAND, NULL); - confinement = META_POINTER_CONFINEMENT_WAYLAND (object); - - confinement->constraint = constraint; - - surface = meta_wayland_pointer_constraint_get_surface (constraint); - g_signal_connect_object (surface, - "geometry-changed", - G_CALLBACK (surface_geometry_changed), - confinement, - 0); - - window = meta_wayland_surface_get_window (surface); - if (window) - { - g_signal_connect_object (window, - "position-changed", - G_CALLBACK (window_position_changed), - confinement, - 0); - } - - return META_POINTER_CONSTRAINT (confinement); -} - -static void -meta_pointer_confinement_wayland_init (MetaPointerConfinementWayland *confinement_wayland) -{ + return g_object_new (META_TYPE_POINTER_CONFINEMENT_WAYLAND, + "wayland-pointer-constraint", constraint, + NULL); } -static void -meta_pointer_confinement_wayland_class_init (MetaPointerConfinementWaylandClass *klass) +MetaWaylandPointerConstraint * +meta_pointer_confinement_wayland_get_wayland_pointer_constraint (MetaPointerConfinementWayland *confinement) { - MetaPointerConstraintClass *pointer_constraint_class = - META_POINTER_CONSTRAINT_CLASS (klass); + MetaPointerConfinementWaylandPrivate *priv; - pointer_constraint_class->constrain = meta_pointer_confinement_wayland_constrain; + priv = meta_pointer_confinement_wayland_get_instance_private (confinement); + return priv->constraint; } diff --git a/src/wayland/meta-pointer-confinement-wayland.h b/src/wayland/meta-pointer-confinement-wayland.h index 482a25a9ae25e7390e31beef65efd2ef493870d1..4f265779c46b855675bcda28cdad7d75af925201 100644 --- a/src/wayland/meta-pointer-confinement-wayland.h +++ b/src/wayland/meta-pointer-confinement-wayland.h @@ -33,12 +33,23 @@ G_BEGIN_DECLS #define META_TYPE_POINTER_CONFINEMENT_WAYLAND (meta_pointer_confinement_wayland_get_type ()) -G_DECLARE_FINAL_TYPE (MetaPointerConfinementWayland, - meta_pointer_confinement_wayland, - META, POINTER_CONFINEMENT_WAYLAND, - MetaPointerConstraint); - -MetaPointerConstraint *meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint); +G_DECLARE_DERIVABLE_TYPE (MetaPointerConfinementWayland, + meta_pointer_confinement_wayland, + META, POINTER_CONFINEMENT_WAYLAND, + GObject) + +struct _MetaPointerConfinementWaylandClass +{ + GObjectClass parent_class; + + MetaPointerConstraint * (*create_constraint) (MetaPointerConfinementWayland *confinement); +}; + +MetaPointerConfinementWayland *meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint); +MetaWaylandPointerConstraint * + meta_pointer_confinement_wayland_get_wayland_pointer_constraint (MetaPointerConfinementWayland *confinement); +void meta_pointer_confinement_wayland_enable (MetaPointerConfinementWayland *confinement); +void meta_pointer_confinement_wayland_disable (MetaPointerConfinementWayland *confinement); G_END_DECLS diff --git a/src/wayland/meta-pointer-lock-wayland.c b/src/wayland/meta-pointer-lock-wayland.c index 08c2789bc43ec7e601d7496943901f3df0e87cbe..9e0e8bcb8c075baf43751666d58701e26b6737a0 100644 --- a/src/wayland/meta-pointer-lock-wayland.c +++ b/src/wayland/meta-pointer-lock-wayland.c @@ -37,33 +37,55 @@ #include -#include "backends/meta-pointer-constraint.h" +#include "backends/meta-backend-private.h" +#include "compositor/meta-surface-actor-wayland.h" struct _MetaPointerLockWayland { - MetaPointerConstraint parent; + GObject parent; + MetaWaylandPointerConstraint *constraint; }; G_DEFINE_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland, - META_TYPE_POINTER_CONSTRAINT); + META_TYPE_POINTER_CONFINEMENT_WAYLAND) -static void -meta_pointer_lock_wayland_constrain (MetaPointerConstraint *constraint, - ClutterInputDevice *device, - guint32 time, - float prev_x, - float prev_y, - float *x, - float *y) +static MetaPointerConstraint * +meta_pointer_lock_wayland_create_constraint (MetaPointerConfinementWayland *confinement) { - *x = prev_x; - *y = prev_y; + MetaBackend *backend = meta_get_backend (); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); + ClutterInputDevice *pointer = clutter_seat_get_pointer (seat); + MetaWaylandPointerConstraint *wayland_constraint; + MetaPointerConstraint *constraint; + MetaWaylandSurface *surface; + graphene_point_t point; + cairo_region_t *region; + float sx, sy, x, y; + + clutter_seat_query_state (seat, pointer, NULL, &point, NULL); + wayland_constraint = + meta_pointer_confinement_wayland_get_wayland_pointer_constraint (confinement); + surface = meta_wayland_pointer_constraint_get_surface (wayland_constraint); + meta_wayland_surface_get_relative_coordinates (surface, + point.x, point.y, + &sx, &sy); + + meta_wayland_surface_get_absolute_coordinates (surface, sx, sy, &x, &y); + region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) { (int) x, (int) y, 1 , 1 }); + + constraint = meta_pointer_constraint_new (region); + cairo_region_destroy (region); + + return constraint; } -MetaPointerConstraint * -meta_pointer_lock_wayland_new (void) +MetaPointerConfinementWayland * +meta_pointer_lock_wayland_new (MetaWaylandPointerConstraint *constraint) { - return g_object_new (META_TYPE_POINTER_LOCK_WAYLAND, NULL); + return g_object_new (META_TYPE_POINTER_LOCK_WAYLAND, + "wayland-pointer-constraint", constraint, + NULL); } static void @@ -74,8 +96,9 @@ meta_pointer_lock_wayland_init (MetaPointerLockWayland *lock_wayland) static void meta_pointer_lock_wayland_class_init (MetaPointerLockWaylandClass *klass) { - MetaPointerConstraintClass *pointer_constraint_class = - META_POINTER_CONSTRAINT_CLASS (klass); + MetaPointerConfinementWaylandClass *confinement_class = + META_POINTER_CONFINEMENT_WAYLAND_CLASS (klass); - pointer_constraint_class->constrain = meta_pointer_lock_wayland_constrain; + confinement_class->create_constraint = + meta_pointer_lock_wayland_create_constraint; } diff --git a/src/wayland/meta-pointer-lock-wayland.h b/src/wayland/meta-pointer-lock-wayland.h index 787b43269d67bd04aeb6bbf021c8a34a38f0c2eb..d52aaa30dd7274b6b0558afcf34db11d8e653795 100644 --- a/src/wayland/meta-pointer-lock-wayland.h +++ b/src/wayland/meta-pointer-lock-wayland.h @@ -27,15 +27,15 @@ #include -#include "backends/meta-pointer-constraint.h" +#include "wayland/meta-pointer-confinement-wayland.h" G_BEGIN_DECLS #define META_TYPE_POINTER_LOCK_WAYLAND (meta_pointer_lock_wayland_get_type ()) G_DECLARE_FINAL_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland, - META, POINTER_LOCK_WAYLAND, MetaPointerConstraint); + META, POINTER_LOCK_WAYLAND, MetaPointerConfinementWayland) -MetaPointerConstraint *meta_pointer_lock_wayland_new (void); +MetaPointerConfinementWayland *meta_pointer_lock_wayland_new (MetaWaylandPointerConstraint *constraint); G_END_DECLS diff --git a/src/wayland/meta-wayland-cursor-surface.c b/src/wayland/meta-wayland-cursor-surface.c index 95f8186df874544cbc6f8189d2963771d5ec101b..60c5d6c3dbc88cfcf8d9510e1a98966263a75a04 100644 --- a/src/wayland/meta-wayland-cursor-surface.c +++ b/src/wayland/meta-wayland-cursor-surface.c @@ -81,6 +81,7 @@ update_cursor_sprite_texture (MetaWaylandCursorSurface *cursor_surface) static void cursor_sprite_prepare_at (MetaCursorSprite *cursor_sprite, + float best_scale, int x, int y, MetaWaylandCursorSurface *cursor_surface) @@ -186,6 +187,7 @@ meta_wayland_cursor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *role, META_WAYLAND_CURSOR_SURFACE (surface->role); MetaWaylandCursorSurfacePrivate *priv = meta_wayland_cursor_surface_get_instance_private (cursor_surface); + ClutterInputDevice *device; graphene_point_t point; graphene_rect_t logical_monitor_rect; @@ -195,7 +197,9 @@ meta_wayland_cursor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *role, logical_monitor_rect = meta_rectangle_to_graphene_rect (&logical_monitor->rect); - point = meta_cursor_renderer_get_position (priv->cursor_renderer); + device = meta_cursor_renderer_get_input_device (priv->cursor_renderer); + clutter_seat_query_state (clutter_input_device_get_seat (device), + device, NULL, &point, NULL); return graphene_rect_contains_point (&logical_monitor_rect, &point); } diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c index 9231ac594270a8ac734d1f2e5a9b04eec65a1039..b5f9a0c37f1f3c383238d59bdf16fdba15d97d76 100644 --- a/src/wayland/meta-wayland-data-device.c +++ b/src/wayland/meta-wayland-data-device.c @@ -612,7 +612,8 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data drag_grab->need_initial_focus = TRUE; - modifiers = clutter_input_device_get_modifier_state (seat->pointer->device); + clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), + seat->pointer->device, NULL, NULL, &modifiers); drag_grab->buttons = modifiers & (CLUTTER_BUTTON1_MASK | CLUTTER_BUTTON2_MASK | CLUTTER_BUTTON3_MASK | CLUTTER_BUTTON4_MASK | CLUTTER_BUTTON5_MASK); @@ -641,7 +642,8 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data 0, 0); clutter_actor_add_child (drag_grab->feedback_actor, drag_surface_actor); - clutter_input_device_get_coords (seat->pointer->device, NULL, &pos); + clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), + seat->pointer->device, NULL, &pos, NULL); meta_feedback_actor_set_position (META_FEEDBACK_ACTOR (drag_grab->feedback_actor), pos.x, pos.y); } diff --git a/src/wayland/meta-wayland-dnd-surface.c b/src/wayland/meta-wayland-dnd-surface.c index c3b0f7557b150c2a06aebec3d089b849d1bc56d5..bdd80f53a28b213747dd4aa93c73320d601cce42 100644 --- a/src/wayland/meta-wayland-dnd-surface.c +++ b/src/wayland/meta-wayland-dnd-surface.c @@ -74,16 +74,15 @@ static MetaLogicalMonitor * dnd_surface_find_logical_monitor (MetaWaylandActorSurface *actor_surface) { MetaBackend *backend = meta_get_backend (); - MetaCursorRenderer *cursor_renderer = - meta_backend_get_cursor_renderer (backend); + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); - graphene_point_t pointer_pos; + graphene_point_t point; - pointer_pos = meta_cursor_renderer_get_position (cursor_renderer); + meta_cursor_tracker_get_pointer (cursor_tracker, &point, NULL); return meta_monitor_manager_get_logical_monitor_at (monitor_manager, - pointer_pos.x, - pointer_pos.y); + point.x, point.y); } static double diff --git a/src/wayland/meta-wayland-pointer-constraints.c b/src/wayland/meta-wayland-pointer-constraints.c index 7547d7e13f10c02539bcb0d0f443d166c77befa6..3a8b8e095dfd61f95d9b9a281b9e23395dfa3820 100644 --- a/src/wayland/meta-wayland-pointer-constraints.c +++ b/src/wayland/meta-wayland-pointer-constraints.c @@ -68,7 +68,7 @@ struct _MetaWaylandPointerConstraint wl_fixed_t x_hint; wl_fixed_t y_hint; - MetaPointerConstraint *constraint; + MetaPointerConfinementWayland *confinement; }; typedef struct _MetaWaylandSurfacePointerConstraintsData @@ -375,7 +375,7 @@ meta_wayland_pointer_constraint_notify_deactivated (MetaWaylandPointerConstraint zwp_confined_pointer_v1_send_unconfined (resource); } -static MetaPointerConstraint * +static MetaPointerConfinementWayland * meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerConstraint *constraint) { struct wl_resource *resource = constraint->resource; @@ -384,7 +384,7 @@ meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerCon &zwp_locked_pointer_v1_interface, &locked_pointer_interface)) { - return meta_pointer_lock_wayland_new (); + return meta_pointer_lock_wayland_new (constraint); } else if (wl_resource_instance_of (resource, &zwp_confined_pointer_v1_interface, @@ -399,8 +399,6 @@ meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerCon static void meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint) { - MetaBackend *backend = meta_get_backend (); - g_assert (!constraint->is_enabled); constraint->is_enabled = TRUE; @@ -408,20 +406,25 @@ meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint meta_wayland_pointer_start_grab (constraint->seat->pointer, &constraint->grab); - constraint->constraint = + constraint->confinement = meta_wayland_pointer_constraint_create_pointer_constraint (constraint); - meta_backend_set_client_pointer_constraint (backend, constraint->constraint); - g_object_add_weak_pointer (G_OBJECT (constraint->constraint), - (gpointer *) &constraint->constraint); - g_object_unref (constraint->constraint); + meta_pointer_confinement_wayland_enable (constraint->confinement); + g_object_add_weak_pointer (G_OBJECT (constraint->confinement), + (gpointer *) &constraint->confinement); } static void meta_wayland_pointer_constraint_disable (MetaWaylandPointerConstraint *constraint) { constraint->is_enabled = FALSE; + + if (constraint->confinement) + { + meta_pointer_confinement_wayland_disable (constraint->confinement); + g_object_unref (constraint->confinement); + } + meta_wayland_pointer_constraint_notify_deactivated (constraint); - meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL); meta_wayland_pointer_end_grab (constraint->grab.pointer); } diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index eb46ecc1d233190c026267438174c35692ff307a..df7d6a442d71f42d3ae5656cb2b88425af19b081 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -949,7 +949,8 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, G_CALLBACK (focus_surface_destroyed), pointer); - clutter_input_device_get_coords (pointer->device, NULL, &pos); + clutter_seat_query_state (clutter_input_device_get_seat (pointer->device), + pointer->device, NULL, &pos, NULL); focus_window = meta_wayland_surface_get_window (pointer->focus_surface); if (focus_window) @@ -1061,7 +1062,8 @@ meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer, float xf = 0.0f, yf = 0.0f; graphene_point_t pos; - clutter_input_device_get_coords (pointer->device, NULL, &pos); + clutter_seat_query_state (clutter_input_device_get_seat (pointer->device), + pointer->device, NULL, &pos, NULL); meta_wayland_surface_get_relative_coordinates (surface, pos.x, pos.y, &xf, &yf); *sx = wl_fixed_from_double (xf); @@ -1168,8 +1170,13 @@ pointer_set_cursor (struct wl_client *client, if (surface) { + ClutterBackend *clutter_backend = clutter_get_default_backend (); + ClutterSeat *clutter_seat = + clutter_backend_get_default_seat (clutter_backend); + ClutterInputDevice *device = clutter_seat_get_pointer (clutter_seat); MetaCursorRenderer *cursor_renderer = - meta_backend_get_cursor_renderer (meta_get_backend ()); + meta_backend_get_cursor_renderer_for_device (meta_get_backend (), + device); MetaWaylandCursorSurface *cursor_surface; cursor_surface = META_WAYLAND_CURSOR_SURFACE (surface->role); diff --git a/src/wayland/meta-wayland-tablet-manager.c b/src/wayland/meta-wayland-tablet-manager.c index 38cec064e94a7428424d9a06277fc3d1c08ddbc4..9c81d5afc2eb7f7b2c9baa4f9ce7778086f1b45f 100644 --- a/src/wayland/meta-wayland-tablet-manager.c +++ b/src/wayland/meta-wayland-tablet-manager.c @@ -242,30 +242,3 @@ meta_wayland_tablet_manager_ensure_seat (MetaWaylandTabletManager *manager, return tablet_seat; } - -void -meta_wayland_tablet_manager_update_cursor_position (MetaWaylandTabletManager *manager, - const ClutterEvent *event) -{ - MetaWaylandTabletSeat *tablet_seat = NULL; - MetaWaylandTabletTool *tool = NULL; - ClutterInputDeviceTool *device_tool; - ClutterInputDevice *device; - - device = clutter_event_get_source_device (event); - device_tool = clutter_event_get_device_tool (event); - - if (device) - tablet_seat = meta_wayland_tablet_manager_lookup_seat (manager, device); - - if (tablet_seat && device_tool) - tool = meta_wayland_tablet_seat_lookup_tool (tablet_seat, device_tool); - - if (tool) - { - gfloat new_x, new_y; - - clutter_event_get_coords (event, &new_x, &new_y); - meta_wayland_tablet_tool_set_cursor_position (tool, new_x, new_y); - } -} diff --git a/src/wayland/meta-wayland-tablet-manager.h b/src/wayland/meta-wayland-tablet-manager.h index 5d4b28c2d615ba55f06b4fee93b62eb4d870f92b..83f9d3d0f416561921a4146e8d67bc99cb585654 100644 --- a/src/wayland/meta-wayland-tablet-manager.h +++ b/src/wayland/meta-wayland-tablet-manager.h @@ -50,7 +50,4 @@ MetaWaylandTabletSeat * meta_wayland_tablet_manager_ensure_seat (MetaWaylandTabletManager *manager, MetaWaylandSeat *seat); -void meta_wayland_tablet_manager_update_cursor_position (MetaWaylandTabletManager *manager, - const ClutterEvent *event); - #endif /* META_WAYLAND_TABLET_MANAGER_H */ diff --git a/src/wayland/meta-wayland-tablet-pad-group.c b/src/wayland/meta-wayland-tablet-pad-group.c index 4229f834a72cce5ce8d8f9255b1326795196313a..46d3d21fc5f713e7a73d463713c2271b19ce4b3e 100644 --- a/src/wayland/meta-wayland-tablet-pad-group.c +++ b/src/wayland/meta-wayland-tablet-pad-group.c @@ -32,12 +32,6 @@ #include "wayland/meta-wayland-tablet-pad.h" #include "wayland/meta-wayland-tablet-seat.h" -#ifdef HAVE_NATIVE_BACKEND -#include "backends/native/meta-backend-native.h" -#include "backends/native/meta-event-native.h" -#include "backends/native/meta-input-device-native.h" -#endif - #include "tablet-unstable-v2-server-protocol.h" static void @@ -123,26 +117,14 @@ gboolean meta_wayland_tablet_pad_group_has_button (MetaWaylandTabletPadGroup *group, guint button) { -#ifdef HAVE_NATIVE_BACKEND - MetaBackend *backend = meta_get_backend (); - - if (META_IS_BACKEND_NATIVE (backend)) - { - struct libinput_device *libinput_device; - struct libinput_tablet_pad_mode_group *mode_group; - guint n_group; + int n_group = g_list_index (group->pad->groups, group); - libinput_device = meta_input_device_native_get_libinput_device (group->pad->device); - n_group = g_list_index (group->pad->groups, group); - mode_group = libinput_device_tablet_pad_get_mode_group (libinput_device, n_group); + if (clutter_input_device_get_pad_feature_group (group->pad->device, + CLUTTER_PAD_FEATURE_BUTTON, + button) == n_group) + return TRUE; - return libinput_tablet_pad_mode_group_has_button (mode_group, button); - } - else -#endif - { - return g_list_length (group->pad->groups) == 1; - } + return FALSE; } static void diff --git a/src/wayland/meta-wayland-tablet-pad.c b/src/wayland/meta-wayland-tablet-pad.c index 167d45948f63768af74d695825ce1b6e2c43df60..22704aee73de1c3cc47117ba9b49d4223cc95a0e 100644 --- a/src/wayland/meta-wayland-tablet-pad.c +++ b/src/wayland/meta-wayland-tablet-pad.c @@ -28,6 +28,7 @@ #include #include "backends/meta-input-settings-private.h" +#include "core/display-private.h" #include "compositor/meta-surface-actor-wayland.h" #include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-tablet-pad-group.h" @@ -37,12 +38,6 @@ #include "wayland/meta-wayland-tablet-seat.h" #include "wayland/meta-wayland-tablet.h" -#ifdef HAVE_NATIVE_BACKEND -#include -#include "backends/native/meta-backend-native.h" -#include "backends/native/meta-input-device-native.h" -#endif - #include "tablet-unstable-v2-server-protocol.h" static void @@ -65,41 +60,20 @@ group_rings_strips (MetaWaylandTabletPad *pad) { gint n_group, n_elem; GList *g, *l; -#ifdef HAVE_NATIVE_BACKEND - MetaBackend *backend = meta_get_backend (); - struct libinput_device *libinput_device = NULL; - - if (META_IS_BACKEND_NATIVE (backend)) - libinput_device = meta_input_device_native_get_libinput_device (pad->device); -#endif for (n_group = 0, g = pad->groups; g; g = g->next) { MetaWaylandTabletPadGroup *group = g->data; -#ifdef HAVE_NATIVE_BACKEND - struct libinput_tablet_pad_mode_group *mode_group = NULL; - - if (libinput_device) - mode_group = libinput_device_tablet_pad_get_mode_group (libinput_device, n_group); -#endif for (n_elem = 0, l = pad->rings; l; l = l->next) { MetaWaylandTabletPadRing *ring = l->data; -#ifdef HAVE_NATIVE_BACKEND - if (mode_group) - { - if (libinput_tablet_pad_mode_group_has_ring (mode_group, n_elem)) - meta_wayland_tablet_pad_ring_set_group (ring, group); - } - else -#endif - { - /* Assign everything to the first group */ - if (n_group == 0) - meta_wayland_tablet_pad_ring_set_group (ring, group); - } + if (clutter_input_device_get_pad_feature_group (pad->device, + CLUTTER_PAD_FEATURE_RING, + n_elem) == n_group) + meta_wayland_tablet_pad_ring_set_group (ring, group); + n_elem++; } @@ -107,19 +81,10 @@ group_rings_strips (MetaWaylandTabletPad *pad) { MetaWaylandTabletPadStrip *strip = l->data; -#ifdef HAVE_NATIVE_BACKEND - if (mode_group) - { - if (libinput_tablet_pad_mode_group_has_strip (mode_group, n_elem)) - meta_wayland_tablet_pad_strip_set_group (strip, group); - } - else -#endif - { - /* Assign everything to the first group */ - if (n_group == 0) - meta_wayland_tablet_pad_strip_set_group (strip, group); - } + if (clutter_input_device_get_pad_feature_group (pad->device, + CLUTTER_PAD_FEATURE_STRIP, + n_elem) == n_group) + meta_wayland_tablet_pad_strip_set_group (strip, group); n_elem++; } @@ -132,9 +97,6 @@ MetaWaylandTabletPad * meta_wayland_tablet_pad_new (ClutterInputDevice *device, MetaWaylandTabletSeat *tablet_seat) { -#ifdef HAVE_NATIVE_BACKEND - MetaBackend *backend = meta_get_backend (); -#endif MetaWaylandTabletPad *pad; guint n_elems, i; @@ -148,16 +110,7 @@ meta_wayland_tablet_pad_new (ClutterInputDevice *device, pad->feedback = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_free); -#ifdef HAVE_NATIVE_BACKEND - /* Buttons, only can be honored this with the native backend */ - if (META_IS_BACKEND_NATIVE (backend)) - { - struct libinput_device *libinput_device; - - libinput_device = meta_input_device_native_get_libinput_device (device); - pad->n_buttons = libinput_device_tablet_pad_get_num_buttons (libinput_device); - } -#endif + pad->n_buttons = clutter_input_device_get_n_buttons (device); n_elems = clutter_input_device_get_n_mode_groups (pad->device); @@ -244,15 +197,14 @@ tablet_pad_set_feedback (struct wl_client *client, { MetaWaylandTabletPad *pad = wl_resource_get_user_data (resource); MetaWaylandTabletPadGroup *group = tablet_pad_lookup_button_group (pad, button); - MetaInputSettings *input_settings; + MetaPadActionMapper *mapper; if (!group || group->mode_switch_serial != serial) return; - input_settings = meta_backend_get_input_settings (meta_get_backend ()); + mapper = meta_get_display ()->pad_action_mapper; - if (input_settings && - meta_input_settings_is_pad_button_grabbed (input_settings, pad->device, button)) + if (meta_pad_action_mapper_is_button_grabbed (mapper, pad->device, button)) return; if (meta_wayland_tablet_pad_group_is_mode_switch_button (group, button)) @@ -367,15 +319,14 @@ static gboolean meta_wayland_tablet_pad_handle_event_action (MetaWaylandTabletPad *pad, const ClutterEvent *event) { - MetaInputSettings *input_settings; + MetaPadActionMapper *mapper; ClutterInputDevice *device; device = clutter_event_get_source_device (event); - input_settings = meta_backend_get_input_settings (meta_get_backend ()); + mapper = meta_get_display ()->pad_action_mapper; - if (input_settings && - meta_input_settings_is_pad_button_grabbed (input_settings, device, - event->pad_button.button)) + if (meta_pad_action_mapper_is_button_grabbed (mapper, device, + event->pad_button.button)) return TRUE; return FALSE; diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c index b26ad401643c790464bfb8a246feabe30734b695..efcb53bca1cbfd0ac83f45987e18270b9ce44e1d 100644 --- a/src/wayland/meta-wayland-tablet-tool.c +++ b/src/wayland/meta-wayland-tablet-tool.c @@ -137,45 +137,6 @@ meta_wayland_tablet_tool_set_cursor_surface (MetaWaylandTabletTool *tool, meta_wayland_tablet_tool_update_cursor_surface (tool); } -static uint32_t -input_device_get_capabilities (ClutterInputDevice *device) -{ - ClutterInputAxis axis; - guint32 capabilities = 0, i; - - for (i = 0; i < clutter_input_device_get_n_axes (device); i++) - { - axis = clutter_input_device_get_axis (device, i); - - switch (axis) - { - case CLUTTER_INPUT_AXIS_PRESSURE: - capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE; - break; - case CLUTTER_INPUT_AXIS_DISTANCE: - capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE; - break; - case CLUTTER_INPUT_AXIS_XTILT: - case CLUTTER_INPUT_AXIS_YTILT: - capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_TILT; - break; - case CLUTTER_INPUT_AXIS_ROTATION: - capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION; - break; - case CLUTTER_INPUT_AXIS_WHEEL: - capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL; - break; - case CLUTTER_INPUT_AXIS_SLIDER: - capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER; - break; - default: - break; - } - } - - return capabilities; -} - static enum zwp_tablet_tool_v2_type input_device_tool_get_type (ClutterInputDeviceTool *device_tool) { @@ -210,26 +171,26 @@ static void meta_wayland_tablet_tool_notify_capabilities (MetaWaylandTabletTool *tool, struct wl_resource *resource) { - uint32_t capabilities; + ClutterInputAxisFlags axes; - capabilities = input_device_get_capabilities (tool->device); + axes = clutter_input_device_tool_get_axes (tool->device_tool); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE)) + if (axes & CLUTTER_INPUT_AXIS_FLAG_PRESSURE) zwp_tablet_tool_v2_send_capability (resource, ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE)) + if (axes & CLUTTER_INPUT_AXIS_FLAG_DISTANCE) zwp_tablet_tool_v2_send_capability (resource, ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_TILT)) + if (axes & (CLUTTER_INPUT_AXIS_FLAG_XTILT | CLUTTER_INPUT_AXIS_FLAG_YTILT)) zwp_tablet_tool_v2_send_capability (resource, ZWP_TABLET_TOOL_V2_CAPABILITY_TILT); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION)) + if (axes & CLUTTER_INPUT_AXIS_FLAG_ROTATION) zwp_tablet_tool_v2_send_capability (resource, ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER)) + if (axes & CLUTTER_INPUT_AXIS_FLAG_SLIDER) zwp_tablet_tool_v2_send_capability (resource, ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL)) + if (axes & CLUTTER_INPUT_AXIS_FLAG_WHEEL) zwp_tablet_tool_v2_send_capability (resource, ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL); } @@ -395,6 +356,7 @@ tablet_tool_handle_cursor_surface_destroy (struct wl_listener *listener, static void tool_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor, + float best_scale, int x, int y, MetaWaylandTabletTool *tool) @@ -729,15 +691,10 @@ broadcast_axis (MetaWaylandTabletTool *tool, ClutterInputAxis axis) { struct wl_resource *resource; - ClutterInputDevice *source; uint32_t value; - gdouble val; - - source = clutter_event_get_source_device (event); - - if (!clutter_input_device_get_axis_value (source, event->motion.axes, axis, &val)) - return; + double val; + val = event->motion.axes[axis]; value = val * TABLET_AXIS_MAX; wl_resource_for_each (resource, &tool->focus_resource_list) @@ -764,16 +721,10 @@ broadcast_tilt (MetaWaylandTabletTool *tool, const ClutterEvent *event) { struct wl_resource *resource; - ClutterInputDevice *source; gdouble xtilt, ytilt; - source = clutter_event_get_source_device (event); - - if (!clutter_input_device_get_axis_value (source, event->motion.axes, - CLUTTER_INPUT_AXIS_XTILT, &xtilt) || - !clutter_input_device_get_axis_value (source, event->motion.axes, - CLUTTER_INPUT_AXIS_YTILT, &ytilt)) - return; + xtilt = event->motion.axes[CLUTTER_INPUT_AXIS_FLAG_XTILT]; + ytilt = event->motion.axes[CLUTTER_INPUT_AXIS_FLAG_YTILT]; wl_resource_for_each (resource, &tool->focus_resource_list) { @@ -788,15 +739,9 @@ broadcast_rotation (MetaWaylandTabletTool *tool, const ClutterEvent *event) { struct wl_resource *resource; - ClutterInputDevice *source; gdouble rotation; - source = clutter_event_get_source_device (event); - - if (!clutter_input_device_get_axis_value (source, event->motion.axes, - CLUTTER_INPUT_AXIS_ROTATION, - &rotation)) - return; + rotation = event->motion.axes[CLUTTER_INPUT_AXIS_FLAG_ROTATION]; wl_resource_for_each (resource, &tool->focus_resource_list) { @@ -810,16 +755,10 @@ broadcast_wheel (MetaWaylandTabletTool *tool, const ClutterEvent *event) { struct wl_resource *resource; - ClutterInputDevice *source; gdouble angle; gint32 clicks = 0; - source = clutter_event_get_source_device (event); - - if (!clutter_input_device_get_axis_value (source, event->motion.axes, - CLUTTER_INPUT_AXIS_WHEEL, - &angle)) - return; + angle = event->motion.axes[CLUTTER_INPUT_AXIS_FLAG_WHEEL]; /* FIXME: Perform proper angle-to-clicks accumulation elsewhere */ if (angle > 0.01) @@ -841,26 +780,21 @@ static void broadcast_axes (MetaWaylandTabletTool *tool, const ClutterEvent *event) { - ClutterInputDevice *device; - guint32 capabilities; - - if (!event->motion.axes) - return; + ClutterInputAxisFlags axes; - device = clutter_event_get_source_device (event); - capabilities = input_device_get_capabilities (device); + axes = clutter_input_device_tool_get_axes (tool->device_tool); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE)) + if (axes & CLUTTER_INPUT_AXIS_FLAG_PRESSURE) broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_PRESSURE); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE)) + if (axes & CLUTTER_INPUT_AXIS_FLAG_DISTANCE) broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_DISTANCE); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_TILT)) + if (axes & (CLUTTER_INPUT_AXIS_FLAG_XTILT | CLUTTER_INPUT_AXIS_FLAG_YTILT)) broadcast_tilt (tool, event); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION)) + if (axes & CLUTTER_INPUT_AXIS_FLAG_ROTATION) broadcast_rotation (tool, event); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER)) + if (axes & CLUTTER_INPUT_AXIS_FLAG_SLIDER) broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_SLIDER); - if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL)) + if (axes & CLUTTER_INPUT_AXIS_FLAG_WHEEL) broadcast_wheel (tool, event); } @@ -912,7 +846,14 @@ meta_wayland_tablet_tool_update (MetaWaylandTabletTool *tool, break; case CLUTTER_PROXIMITY_IN: if (!tool->cursor_renderer) - tool->cursor_renderer = meta_cursor_renderer_new (meta_get_backend ()); + { + MetaCursorRenderer *renderer; + + renderer = + meta_backend_get_cursor_renderer_for_device (meta_get_backend (), + clutter_event_get_source_device (event)); + g_set_object (&tool->cursor_renderer, renderer); + } tool->current_tablet = meta_wayland_tablet_seat_lookup_tablet (tool->seat, clutter_event_get_source_device (event)); @@ -957,15 +898,6 @@ meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool, return CLUTTER_EVENT_STOP; } -void -meta_wayland_tablet_tool_set_cursor_position (MetaWaylandTabletTool *tool, - float new_x, - float new_y) -{ - if (tool->cursor_renderer) - meta_cursor_renderer_set_position (tool->cursor_renderer, new_x, new_y); -} - static gboolean tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool, MetaWaylandSurface *surface) diff --git a/src/wayland/meta-wayland-tablet-tool.h b/src/wayland/meta-wayland-tablet-tool.h index 7cf1d907700442b281863fe0c83ad1b4c65cf8b9..e9ad7db40c3948710677e3cff5ccf2c24c365aeb 100644 --- a/src/wayland/meta-wayland-tablet-tool.h +++ b/src/wayland/meta-wayland-tablet-tool.h @@ -78,10 +78,6 @@ void meta_wayland_tablet_tool_update (MetaWaylandTabletTool *t gboolean meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool, const ClutterEvent *event); -void meta_wayland_tablet_tool_set_cursor_position (MetaWaylandTabletTool *tool, - float new_x, - float new_y); - gboolean meta_wayland_tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool, MetaWaylandSurface *surface, uint32_t serial); diff --git a/src/wayland/meta-xwayland-dnd.c b/src/wayland/meta-xwayland-dnd.c index 60f416821f0745da0d1f20a06589b85fa95e10ab..7f19be24cf8b9a2d2aa525d694acd2924d855851 100644 --- a/src/wayland/meta-xwayland-dnd.c +++ b/src/wayland/meta-xwayland-dnd.c @@ -546,7 +546,8 @@ meta_x11_drag_dest_update (MetaWaylandDataDevice *data_device, MetaWaylandSeat *seat = compositor->seat; graphene_point_t pos; - clutter_input_device_get_coords (seat->pointer->device, NULL, &pos); + clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), + seat->pointer->device, NULL, &pos, NULL); xdnd_send_position (dnd, dnd->dnd_dest, clutter_get_current_event_time (), pos.x, pos.y); @@ -834,7 +835,8 @@ meta_xwayland_dnd_handle_client_message (MetaWaylandCompositor *compositor, dnd->client_message_timestamp = event->data.l[3]; motion = clutter_event_new (CLUTTER_MOTION); - clutter_input_device_get_coords (seat->pointer->device, NULL, &pos); + clutter_seat_query_state (clutter_input_device_get_seat (seat->pointer->device), + seat->pointer->device, NULL, &pos, NULL); clutter_event_set_coords (motion, pos.x, pos.y); clutter_event_set_device (motion, seat->pointer->device); clutter_event_set_source_device (motion, seat->pointer->device);