From 2a2e870c139e2130b00d582546616269bca27458 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 4 Sep 2020 17:11:36 +0200 Subject: [PATCH] clutter: Backport of ::touch-mode In upstream/master this is a ClutterSeat readonly property. Add it to ClutterDeviceManager here, the mechanism and triggering is the same though. --- clutter/clutter/clutter-device-manager.c | 24 +++ clutter/clutter/clutter-device-manager.h | 2 + .../evdev/clutter-device-manager-evdev.c | 179 ++++++++++++++++++ 3 files changed, 205 insertions(+) diff --git a/clutter/clutter/clutter-device-manager.c b/clutter/clutter/clutter-device-manager.c index c676384..e1cc455 100644 --- a/clutter/clutter/clutter-device-manager.c +++ b/clutter/clutter/clutter-device-manager.c @@ -62,6 +62,7 @@ enum PROP_0, PROP_BACKEND, + PROP_TOUCH_MODE, PROP_LAST }; @@ -108,6 +109,7 @@ clutter_device_manager_set_property (GObject *gobject, priv->backend = g_value_get_object (value); break; + case PROP_TOUCH_MODE: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } @@ -127,6 +129,10 @@ clutter_device_manager_get_property (GObject *gobject, g_value_set_object (value, priv->backend); break; + case PROP_TOUCH_MODE: + g_value_set_boolean (value, FALSE); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } @@ -143,6 +149,12 @@ clutter_device_manager_class_init (ClutterDeviceManagerClass *klass) P_("The ClutterBackend of the device manager"), CLUTTER_TYPE_BACKEND, CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + obj_props[PROP_TOUCH_MODE] = + g_param_spec_boolean ("touch-mode", + P_("Touch mode"), + P_("Touch mode"), + FALSE, + CLUTTER_PARAM_READABLE); gobject_class->set_property = clutter_device_manager_set_property; gobject_class->get_property = clutter_device_manager_get_property; @@ -579,3 +591,15 @@ clutter_device_manager_get_kbd_a11y_settings (ClutterDeviceManager *device_man *settings = device_manager->priv->kbd_a11y_settings; } + +gboolean +clutter_device_manager_get_touch_mode (ClutterDeviceManager *device_manager) +{ + gboolean touch_mode; + + g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), FALSE); + + g_object_get (G_OBJECT (device_manager), "touch-mode", &touch_mode, NULL); + + return touch_mode; +} diff --git a/clutter/clutter/clutter-device-manager.h b/clutter/clutter/clutter-device-manager.h index 1cbf030..a4a6271 100644 --- a/clutter/clutter/clutter-device-manager.h +++ b/clutter/clutter/clutter-device-manager.h @@ -155,6 +155,8 @@ void clutter_device_manager_set_kbd_a11y_settings (ClutterDeviceManager *devic CLUTTER_EXPORT void clutter_device_manager_get_kbd_a11y_settings (ClutterDeviceManager *device_manager, ClutterKbdA11ySettings *settings); +CLUTTER_EXPORT +gboolean clutter_device_manager_get_touch_mode (ClutterDeviceManager *device_manager); G_END_DECLS diff --git a/clutter/clutter/evdev/clutter-device-manager-evdev.c b/clutter/clutter/evdev/clutter-device-manager-evdev.c index 84b0aad..78b5b64 100644 --- a/clutter/clutter/evdev/clutter-device-manager-evdev.c +++ b/clutter/clutter/evdev/clutter-device-manager-evdev.c @@ -108,6 +108,19 @@ struct _ClutterDeviceManagerEvdevPrivate gint device_id_next; GList *free_device_ids; + + guint tablet_mode_switch_state : 1; + guint has_touchscreen : 1; + guint has_tablet_switch : 1; + guint has_pointer : 1; + guint touch_mode : 1; +}; + +enum +{ + PROP_0, + PROP_TOUCH_MODE, + N_PROPS }; static void clutter_device_manager_evdev_event_extender_init (ClutterEventExtenderInterface *iface); @@ -765,6 +778,34 @@ clutter_event_source_free (ClutterEventSource *source) g_source_unref (g_source); } +static void +update_touch_mode (ClutterDeviceManagerEvdev *manager_evdev) +{ + ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; + gboolean touch_mode; + + /* No touch mode if we don't have a touchscreen, easy */ + if (!priv->has_touchscreen) + touch_mode = FALSE; + /* If we have a tablet mode switch, honor it being unset */ + else if (priv->has_tablet_switch && !priv->tablet_mode_switch_state) + touch_mode = FALSE; + /* If tablet mode is enabled, go for it */ + else if (priv->has_tablet_switch && priv->tablet_mode_switch_state) + touch_mode = TRUE; + /* If there is no tablet mode switch (eg. kiosk machines), + * assume touch-mode is mutually exclusive with pointers. + */ + else + touch_mode = !priv->has_pointer; + + if (priv->touch_mode != touch_mode) + { + priv->touch_mode = touch_mode; + g_object_notify (G_OBJECT (manager_evdev), "touch-mode"); + } +} + static void evdev_add_device (ClutterDeviceManagerEvdev *manager_evdev, struct libinput_device *libinput_device) @@ -942,19 +983,81 @@ flush_event_queue (void) } } +static gboolean +has_touchscreen (ClutterDeviceManagerEvdev *manager_evdev) +{ + ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; + GSList *l; + + for (l = priv->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_type_is_pointer (ClutterInputDeviceType device_type) +{ + return (device_type == CLUTTER_POINTER_DEVICE || + device_type == CLUTTER_TOUCHPAD_DEVICE); +} + +static gboolean +has_pointer (ClutterDeviceManagerEvdev *manager_evdev) +{ + ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; + GSList *l; + + for (l = priv->devices; l; l = l->next) + { + ClutterInputDeviceType device_type; + + device_type = clutter_input_device_get_device_type (l->data); + + if (device_type_is_pointer (device_type)) + return TRUE; + } + + return FALSE; +} + static gboolean process_base_event (ClutterDeviceManagerEvdev *manager_evdev, struct libinput_event *event) { + ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; ClutterInputDevice *device; struct libinput_device *libinput_device; gboolean handled = TRUE; + gboolean check_touch_mode; switch (libinput_event_get_type (event)) { case LIBINPUT_EVENT_DEVICE_ADDED: libinput_device = libinput_event_get_device (event); + priv->has_touchscreen |= + libinput_device_has_capability (libinput_device, LIBINPUT_DEVICE_CAP_TOUCH); + priv->has_pointer |= + libinput_device_has_capability (libinput_device, LIBINPUT_DEVICE_CAP_POINTER); + check_touch_mode = priv->has_touchscreen | priv->has_pointer; + + if (libinput_device_has_capability (libinput_device, + LIBINPUT_DEVICE_CAP_SWITCH) && + libinput_device_switch_has_switch (libinput_device, + LIBINPUT_SWITCH_TABLET_MODE)) + { + priv->has_tablet_switch = TRUE; + check_touch_mode = TRUE; + } + evdev_add_device (manager_evdev, libinput_device); break; @@ -966,7 +1069,17 @@ process_base_event (ClutterDeviceManagerEvdev *manager_evdev, libinput_device = libinput_event_get_device (event); + check_touch_mode = + libinput_device_has_capability (libinput_device, LIBINPUT_DEVICE_CAP_TOUCH); device = libinput_device_get_user_data (libinput_device); + if (check_touch_mode) + priv->has_touchscreen = has_touchscreen (manager_evdev); + if (device_type_is_pointer (clutter_input_device_get_device_type (device))) + { + priv->has_pointer = has_pointer (manager_evdev); + check_touch_mode = TRUE; + } + evdev_remove_device (manager_evdev, CLUTTER_INPUT_DEVICE_EVDEV (device)); break; @@ -975,6 +1088,9 @@ process_base_event (ClutterDeviceManagerEvdev *manager_evdev, handled = FALSE; } + if (check_touch_mode) + update_touch_mode (manager_evdev); + return handled; } @@ -1752,6 +1868,23 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev, notify_pad_ring (device, time, number, source, group, mode, angle); break; } + case LIBINPUT_EVENT_SWITCH_TOGGLE: + { + ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; + 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) + { + priv->tablet_mode_switch_state = (state == LIBINPUT_SWITCH_STATE_ON); + update_touch_mode (manager_evdev); + } + break; + } default: handled = FALSE; } @@ -1967,6 +2100,10 @@ clutter_device_manager_evdev_constructed (GObject *gobject) source = clutter_event_source_new (manager_evdev); priv->event_source = source; + + priv->has_touchscreen = has_touchscreen (manager_evdev); + priv->has_pointer = has_pointer (manager_evdev); + update_touch_mode (manager_evdev); } static void @@ -2001,6 +2138,43 @@ clutter_device_manager_evdev_dispose (GObject *object) G_OBJECT_CLASS (clutter_device_manager_evdev_parent_class)->dispose (object); } +static void +clutter_device_manager_evdev_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + case PROP_TOUCH_MODE: + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +clutter_device_manager_evdev_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ClutterDeviceManagerEvdev *manager_evdev; + ClutterDeviceManagerEvdevPrivate *priv; + + manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (object); + priv = manager_evdev->priv; + + switch (prop_id) + { + case PROP_TOUCH_MODE: + g_value_set_boolean (value, priv->touch_mode); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + + static void clutter_device_manager_evdev_finalize (GObject *object) { @@ -2036,6 +2210,8 @@ clutter_device_manager_evdev_class_init (ClutterDeviceManagerEvdevClass *klass) gobject_class->constructed = clutter_device_manager_evdev_constructed; gobject_class->finalize = clutter_device_manager_evdev_finalize; gobject_class->dispose = clutter_device_manager_evdev_dispose; + gobject_class->set_property = clutter_device_manager_evdev_set_property; + gobject_class->get_property = clutter_device_manager_evdev_get_property; manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass); manager_class->add_device = clutter_device_manager_evdev_add_device; @@ -2047,6 +2223,9 @@ clutter_device_manager_evdev_class_init (ClutterDeviceManagerEvdevClass *klass) manager_class->get_supported_virtual_device_types = clutter_device_manager_evdev_get_supported_virtual_device_types; manager_class->compress_motion = clutter_device_manager_evdev_compress_motion; manager_class->apply_kbd_a11y_settings = clutter_device_manager_evdev_apply_kbd_a11y_settings; + + g_object_class_override_property (gobject_class, PROP_TOUCH_MODE, + "touch-mode"); } static void -- 2.29.2