Blob Blame History Raw
From 2a2e870c139e2130b00d582546616269bca27458 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
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