[mutter/wip/carlosg/touch-mode: 3/3] backends: Implement ClutterSeat::touch-mode on MetaSeatNative



commit acbaca8df76e53f0678425348564c3bd04fec90f
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Feb 10 20:00:52 2020 +0100

    backends: Implement ClutterSeat::touch-mode on MetaSeatNative
    
    This taps on:
    1) Touchscreen availability
    2) Availability of external keyboards
    3) Tablet mode switch, if existent
    
    So we get this property enabled whenever it makes sense to show touch
    focused features (eg. the OSK).
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/1044

 src/backends/native/meta-seat-native.c | 140 ++++++++++++++++++++++++++++++++-
 src/backends/native/meta-seat-native.h |   8 ++
 2 files changed, 147 insertions(+), 1 deletion(-)
---
diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c
index fd8048ff4..c9939bb98 100644
--- a/src/backends/native/meta-seat-native.c
+++ b/src/backends/native/meta-seat-native.c
@@ -106,7 +106,10 @@ enum
 {
   PROP_0,
   PROP_SEAT_ID,
-  N_PROPS
+  N_PROPS,
+
+  /* This property is overridden */
+  PROP_TOUCH_MODE,
 };
 
 GParamSpec *props[N_PROPS] = { NULL };
@@ -1343,6 +1346,75 @@ meta_event_source_free (MetaEventSource *source)
   g_source_unref (g_source);
 }
 
+static gboolean
+has_touchscreen (MetaSeatNative *seat)
+{
+  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_external_keyboard (MetaSeatNative *seat)
+{
+  GList *devices, *l;
+  gboolean has_external = FALSE;
+
+  devices = g_udev_client_query_by_subsystem (seat->udev_client, "input");
+
+  for (l = devices; l; l = l->next)
+    {
+      if (!g_udev_device_has_property (l->data, "ID_INPUT_KEYBOARD"))
+        continue;
+
+      /* May be "hid" or something else, we don't care. This property
+       * will not be present in virtual "AT Translated Set 2 keyboard"
+       * devices.
+       */
+      if (!g_udev_device_has_property (l->data, "ID_TYPE"))
+        break;
+
+      has_external = TRUE;
+      break;
+    }
+
+  g_list_free_full (devices, g_object_unref);
+
+  return has_external;
+}
+
+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_mode && !seat->tablet_mode_switch_state)
+    touch_mode = FALSE;
+  /* If tablet mode is enabled, or if there is no tablet mode switch
+   * (eg. kiosk machines), check availability of external keyboards.
+   */
+  else
+    touch_mode = !seat->has_external_keyboard;
+
+  if (seat->touch_mode != touch_mode)
+    {
+      seat->touch_mode = touch_mode;
+      g_object_notify (G_OBJECT (seat), "touch-mode");
+    }
+}
+
 static void
 evdev_add_device (MetaSeatNative         *seat,
                   struct libinput_device *libinput_device)
@@ -1373,6 +1445,29 @@ evdev_add_device (MetaSeatNative         *seat,
     }
 
   g_signal_emit_by_name (seat, "device-added", device);
+
+  if (type == CLUTTER_KEYBOARD_DEVICE)
+    {
+      seat->has_external_keyboard = has_external_keyboard (seat);
+      check_touch_mode = TRUE;
+    }
+  else if (type == CLUTTER_TOUCHSCREEN_DEVICE)
+    {
+      seat->has_touchscreen = TRUE;
+      check_touch_mode = TRUE;
+    }
+
+  if (libinput_device_has_capability (libinput_device,
+                                      LIBINPUT_DEVICE_CAP_SWITCH) &&
+      libinput_device_switch_has_switch (libinput_device,
+                                         LIBINPUT_SWITCH_TABLET_MODE))
+    {
+      seat->has_tablet_switch = TRUE;
+      check_touch_mode = TRUE;
+    }
+
+  if (check_touch_mode)
+    update_touch_mode (seat);
 }
 
 static void
@@ -1380,12 +1475,26 @@ evdev_remove_device (MetaSeatNative        *seat,
                      MetaInputDeviceNative *device_evdev)
 {
   ClutterInputDevice *device;
+  ClutterInputDeviceType device_type;
 
   device = CLUTTER_INPUT_DEVICE (device_evdev);
   seat->devices = g_slist_remove (seat->devices, device);
 
   g_signal_emit_by_name (seat, "device-removed", device);
 
+  device_type = clutter_input_device_get_device_type (device);
+
+  if (device_type == CLUTTER_KEYBOARD_DEVICE)
+    {
+      seat->has_external_keyboard = has_external_keyboard (seat);
+      update_touch_mode (seat);
+    }
+  else if (device_type == CLUTTER_TOUCHSCREEN_DEVICE)
+    {
+      seat->has_touchscreen = has_touchscreen (seat);
+      update_touch_mode (seat);
+    }
+
   if (seat->repeat_timer && seat->repeat_device == device)
     meta_seat_native_clear_repeat_timer (seat);
 
@@ -2215,6 +2324,22 @@ process_device_event (MetaSeatNative        *seat,
         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;
     }
@@ -2393,6 +2518,10 @@ meta_seat_native_constructed (GObject *object)
         xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_SCROLL);
     }
 
+  seat->udev_client = g_udev_client_new ((const gchar *[]) { "input", NULL });
+  seat->has_external_keyboard = has_external_keyboard (seat);
+  seat->has_touchscreen = has_touchscreen (seat);
+
   if (G_OBJECT_CLASS (meta_seat_native_parent_class)->constructed)
     G_OBJECT_CLASS (meta_seat_native_parent_class)->constructed (object);
 }
@@ -2410,6 +2539,7 @@ meta_seat_native_set_property (GObject      *object,
     case PROP_SEAT_ID:
       seat_native->seat_id = g_value_dup_string (value);
       break;
+    case PROP_TABLET_MODE:
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -2428,6 +2558,9 @@ meta_seat_native_get_property (GObject    *object,
     case PROP_SEAT_ID:
       g_value_set_string (value, seat_native->seat_id);
       break;
+    case PROP_TABLET_MODE:
+      g_value_set_boolean (value, seat_native->tablet_mode);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -2471,6 +2604,8 @@ meta_seat_native_finalize (GObject *object)
   g_slist_free (seat->devices);
   g_free (seat->touch_states);
 
+  g_object_unref (seat->udev_client);
+
   meta_event_source_free (seat->event_source);
 
   xkb_state_unref (seat->xkb);
@@ -2661,6 +2796,9 @@ meta_seat_native_class_init (MetaSeatNativeClass *klass)
                          G_PARAM_CONSTRUCT_ONLY);
 
   g_object_class_install_properties (object_class, N_PROPS, props);
+
+  g_object_class_override_property (object_class, PROP_TABLET_MODE,
+                                    "tablet-mode");
 }
 
 static void
diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h
index a351d9327..2d780618f 100644
--- a/src/backends/native/meta-seat-native.h
+++ b/src/backends/native/meta-seat-native.h
@@ -23,6 +23,7 @@
 #ifndef META_SEAT_NATIVE_H
 #define META_SEAT_NATIVE_H
 
+#include <gudev/gudev.h>
 #include <libinput.h>
 #include <linux/input-event-codes.h>
 
@@ -117,6 +118,13 @@ struct _MetaSeatNative
 
   MetaKeymapNative *keymap;
 
+  GUdevClient *udev_client;
+  guint tablet_mode_switch_state : 1;
+  guint has_external_keyboard    : 1;
+  guint has_touchscreen          : 1;
+  guint has_tablet_switch        : 1;
+  guint touch_mode               : 1;
+
   /* keyboard repeat */
   gboolean repeat;
   uint32_t repeat_delay;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]