backends/x11: Support input-synaptics, if present.
authorDaniel van Vugt <daniel.van.vugt@canonical.com>
Sun, 18 Mar 2018 16:56:36 +0000 (12:56 -0400)
committerSimon McVittie <smcv@debian.org>
Sun, 8 Jul 2018 10:32:56 +0000 (11:32 +0100)
Add support for configuring the Xorg synaptics touchpad driver.

Turns out it's very simple to support both libinput and synaptics
simultaneously, both under the heading of XI2.

Bug-Ubuntu: https://launchpad.net/bugs/1686081
Forwarded: https://gitlab.gnome.org/GNOME/mutter/merge_requests/37
Applied-upstream: no, rejected as not long-term sustainable
Last-Update: 2018-03-16

Gbp-Pq: Topic debian
Gbp-Pq: Name synaptics-support.patch

clutter/clutter/x11/clutter-device-manager-xi2.c
src/backends/x11/meta-input-settings-x11.c

index 62f5583803ff95d3dd948632c177d971c8337fa9..b22982ae02bd3c904e3be8bd3e68c712c42f04b4 100644 (file)
@@ -267,8 +267,9 @@ is_touch_device (XIAnyClassInfo         **classes,
 }
 
 static gboolean
-is_touchpad_device (ClutterBackendX11 *backend_x11,
-                    XIDeviceInfo      *info)
+has_8bit_property (ClutterBackendX11 *backend_x11,
+                   XIDeviceInfo      *info,
+                   const char        *name)
 {
   gulong nitems, bytes_after;
   guint32 *data = NULL;
@@ -276,7 +277,7 @@ is_touchpad_device (ClutterBackendX11 *backend_x11,
   Atom type;
   Atom prop;
 
-  prop = XInternAtom (backend_x11->xdpy, "libinput Tapping Enabled", True);
+  prop = XInternAtom (backend_x11->xdpy, name, True);
   if (prop == None)
     return FALSE;
 
@@ -297,6 +298,14 @@ is_touchpad_device (ClutterBackendX11 *backend_x11,
   return TRUE;
 }
 
+static gboolean
+is_touchpad_device (ClutterBackendX11 *backend_x11,
+                    XIDeviceInfo      *info)
+{
+  return has_8bit_property (backend_x11, info, "libinput Tapping Enabled") ||
+         has_8bit_property (backend_x11, info, "Synaptics Off");
+}
+
 static gboolean
 get_device_ids (ClutterBackendX11  *backend_x11,
                 XIDeviceInfo       *info,
index 9687fb36feb71b316eb37b5a5cfb01d429baf414..43752df09614366bc6c3a8fe458d6390dbf88435 100644 (file)
@@ -169,8 +169,6 @@ meta_input_settings_x11_set_send_events (MetaInputSettings        *settings,
 
   available = get_property (device, "libinput Send Events Modes Available",
                             XA_INTEGER, 8, 2);
-  if (!available)
-    return;
 
   switch (mode)
     {
@@ -184,6 +182,11 @@ meta_input_settings_x11_set_send_events (MetaInputSettings        *settings,
       break;
     }
 
+  change_property (device, "Synaptics Off", XA_INTEGER, 8, &values, 1);
+
+  if (!available)
+    return;
+
   if ((values[0] && !available[0]) || (values[1] && !available[1]))
     g_warning ("Device '%s' does not support sendevents mode %d\n",
                clutter_input_device_get_device_name (device), mode);
@@ -217,11 +220,23 @@ meta_input_settings_x11_set_speed (MetaInputSettings  *settings,
 {
   MetaBackend *backend = meta_get_backend ();
   Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
-  gfloat value = speed;
+  gfloat *accel = get_property (device, "libinput Accel Speed",
+                                XInternAtom (xdisplay, "FLOAT", False), 32, 1);
 
-  change_property (device, "libinput Accel Speed",
-                   XInternAtom (xdisplay, "FLOAT", False),
-                   32, &value, 1);
+  if (accel)
+    {
+      *accel = speed; /* Sounds confused, but libinput is confused. */
+      change_property (device, "libinput Accel Speed",
+                       XInternAtom (xdisplay, "FLOAT", False), 32, accel, 1);
+      meta_XFree (accel);
+    }
+  else
+    {
+      gfloat scale = (speed <= -1.0) ? 1.0 : (speed + 1.0) * 12.5;
+
+      change_property (device, "Device Accel Velocity Scaling",
+                       XInternAtom (xdisplay, "FLOAT", False), 32, &scale, 1);
+    }
 }
 
 static void
@@ -259,6 +274,9 @@ meta_input_settings_x11_set_disable_while_typing (MetaInputSettings  *settings,
 
   change_property (device, "libinput Disable While Typing Enabled",
                    XA_INTEGER, 8, &value, 1);
+
+  change_property (device, "Synaptics Palm Detection",
+                   XA_INTEGER, 8, &value, 1);
 }
 
 static void
@@ -267,9 +285,13 @@ meta_input_settings_x11_set_tap_enabled (MetaInputSettings  *settings,
                                          gboolean            enabled)
 {
   guchar value = (enabled) ? 1 : 0;
+  gint32 tap_time = (enabled) ? 180 : 0;
 
   change_property (device, "libinput Tapping Enabled",
                    XA_INTEGER, 8, &value, 1);
+
+  change_property (device, "Synaptics Tap Time",
+                   XA_INTEGER, 32, &tap_time, 1);
 }
 
 static void
@@ -281,6 +303,9 @@ meta_input_settings_x11_set_tap_and_drag_enabled (MetaInputSettings  *settings,
 
   change_property (device, "libinput Tapping Drag Enabled",
                    XA_INTEGER, 8, &value, 1);
+
+  change_property (device, "Synaptics Gestures",
+                   XA_INTEGER, 8, &value, 1);
 }
 
 static void
@@ -288,10 +313,22 @@ meta_input_settings_x11_set_invert_scroll (MetaInputSettings  *settings,
                                            ClutterInputDevice *device,
                                            gboolean            inverted)
 {
-  guchar value = (inverted) ? 1 : 0;
+  gint32 *scroll_dist = get_property (device, "Synaptics Scrolling Distance",
+                                      XA_INTEGER, 32, 2);
+  if (scroll_dist)
+    {
+      scroll_dist[0] = inverted ? -ABS (scroll_dist[0]) : ABS (scroll_dist[0]);
+      change_property (device, "Synaptics Scrolling Distance",
+                       XA_INTEGER, 32, scroll_dist, 2);
+      meta_XFree (scroll_dist);
+    }
+  else
+    {
+      guchar value = (inverted) ? 1 : 0;
 
-  change_property (device, "libinput Natural Scrolling Enabled",
-                   XA_INTEGER, 8, &value, 1);
+      change_property (device, "libinput Natural Scrolling Enabled",
+                       XA_INTEGER, 8, &value, 1);
+    }
 }
 
 static void
@@ -303,6 +340,16 @@ meta_input_settings_x11_set_edge_scroll (MetaInputSettings            *settings,
   guchar *current = NULL;
   guchar *available = NULL;
 
+  current = get_property (device, "Synaptics Edge Scrolling",
+                          XA_INTEGER, 8, 3);
+  if (current)
+    {
+      current[0] = current[1] = !!edge_scroll_enabled;
+      change_property (device, "Synaptics Edge Scrolling",
+                       XA_INTEGER, 8, current, 3);
+      goto out;
+    }
+
   available = get_property (device, "libinput Scroll Methods Available",
                             XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
   if (!available || !available[SCROLL_METHOD_FIELD_EDGE])
@@ -332,6 +379,16 @@ meta_input_settings_x11_set_two_finger_scroll (MetaInputSettings            *set
   guchar *current = NULL;
   guchar *available = NULL;
 
+  current = get_property (device, "Synaptics Two-Finger Scrolling",
+                          XA_INTEGER, 8, 2);
+  if (current)
+    {
+      current[0] = current[1] = !!two_finger_scroll_enabled;
+      change_property (device, "Synaptics Two-Finger Scrolling",
+                       XA_INTEGER, 8, current, 2);
+      goto out;
+    }
+
   available = get_property (device, "libinput Scroll Methods Available",
                             XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
   if (!available || !available[SCROLL_METHOD_FIELD_2FG])
@@ -359,10 +416,19 @@ meta_input_settings_x11_has_two_finger_scroll (MetaInputSettings  *settings,
   guchar *available = NULL;
   gboolean has_two_finger = TRUE;
 
-  available = get_property (device, "libinput Scroll Methods Available",
-                            XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
-  if (!available || !available[SCROLL_METHOD_FIELD_2FG])
-    has_two_finger = FALSE;
+  available = get_property (device, "Synaptics Two-Finger Scrolling",
+                            XA_INTEGER, 8, 2);
+  if (available)
+    {
+      has_two_finger = available[0] || available[1];
+    }
+  else
+    {
+      available = get_property (device, "libinput Scroll Methods Available",
+                                XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
+      if (!available || !available[SCROLL_METHOD_FIELD_2FG])
+        has_two_finger = FALSE;
+    }
 
   meta_XFree (available);
   return has_two_finger;
@@ -377,6 +443,58 @@ meta_input_settings_x11_set_scroll_button (MetaInputSettings  *settings,
                    XA_INTEGER, 32, &button, 1);
 }
 
+static void
+meta_input_settings_x11_set_click_method_synaptics (MetaInputSettings *settings,
+                                          ClutterInputDevice          *device,
+                                          GDesktopTouchpadClickMethod  mode)
+{
+  /* { RT corner, RB, LT, LB, 1 finger, 2 fingers, 3 fingers } */
+  guchar tap_action_default[7] = { 2, 3, 0, 0, 1, 3, 0 };
+  guchar tap_action_areas[7]   = { 2, 3, 0, 0, 1, 0, 0 };
+  guchar tap_action_fingers[7] = { 0, 0, 0, 0, 1, 3, 2 };
+  guchar tap_action_none[7]    = { 0, 0, 0, 0, 1, 0, 0 };
+  guchar *tap_action = tap_action_default;
+
+  /* TODO On startup save the default value of 'Synaptics Soft Button Areas',
+          but save it where? */
+  gint32 zero_button_areas[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+  gint32 *button_areas_known = NULL;
+
+  switch (mode)
+    {
+    case G_DESKTOP_TOUCHPAD_CLICK_METHOD_DEFAULT:
+      tap_action = tap_action_default;
+      /* Doing nothing right now will give the correct default, unless changed
+         during the session */
+      break;
+    case G_DESKTOP_TOUCHPAD_CLICK_METHOD_NONE:
+      tap_action = tap_action_none;
+      button_areas_known = zero_button_areas;
+      break;
+    case G_DESKTOP_TOUCHPAD_CLICK_METHOD_AREAS:
+      tap_action = tap_action_areas;
+      /* Doing nothing right now will give the correct default, unless changed
+         during the session */
+      break;
+    case G_DESKTOP_TOUCHPAD_CLICK_METHOD_FINGERS:
+      tap_action = tap_action_fingers;
+      button_areas_known = zero_button_areas;
+      break;
+    default:
+      g_assert_not_reached ();
+      return;
+    }
+
+  change_property (device, "Synaptics Tap Action",
+                   XA_INTEGER, 8, tap_action, 7);
+  change_property (device, "Synaptics Click Action",
+                   XA_INTEGER, 8, tap_action + 4, 3);
+
+  if (button_areas_known)
+    change_property (device, "Synaptics Soft Button Areas",
+                     XA_INTEGER, 32, button_areas_known, 8);
+}
+
 static void
 meta_input_settings_x11_set_click_method (MetaInputSettings           *settings,
                                           ClutterInputDevice          *device,
@@ -388,7 +506,11 @@ meta_input_settings_x11_set_click_method (MetaInputSettings           *settings,
   available = get_property (device, "libinput Click Methods Available",
                             XA_INTEGER, 8, 2);
   if (!available)
-    return;
+    {
+      meta_input_settings_x11_set_click_method_synaptics (settings, device,
+                                                          mode);
+      return;
+    }
 
   switch (mode)
     {