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

xserver-xorg-input-synaptics: Changes to 'upstream-unstable'



Rebased ref, commits from common ancestor:
commit dd650a064b98b1c325a38e1370cc11059c257b07
Author: Peter Hutterer <peter.hutterer@who-t.net>
Date:   Wed Mar 14 08:56:45 2012 +1000

    synaptics 1.5.99.901
    
    Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>

diff --git a/configure.ac b/configure.ac
index 29f6e68..af1bc2a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,7 +23,7 @@
 # Initialize Autoconf
 AC_PREREQ([2.60])
 AC_INIT([xf86-input-synaptics],
-        [1.5.99],
+        [1.5.99.901],
         [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
         [xf86-input-synaptics])
 AC_CONFIG_SRCDIR([Makefile.am])

commit fee18d8567efd2e5abf6b29eb1ae9ee0e3858013
Author: Peter Hutterer <peter.hutterer@who-t.net>
Date:   Tue Mar 13 16:08:12 2012 +1000

    Soft buttons are only available on clickpad devices, disable them otherwise.
    
    If the clickpad support is runtime enabled/disabled, the property
    appears/disappears accordingly.
    
    Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas@canonical.com>

diff --git a/man/synaptics.man b/man/synaptics.man
index aaec35f..23862e3 100644
--- a/man/synaptics.man
+++ b/man/synaptics.man
@@ -520,6 +520,7 @@ the total height of the touchpad. Property: "Synaptics Area"
 .
 .TP
 .BI "Option \*qSoftButtonAreas\*q \*q" "RBL RBR RBT RBB MBL MBR MBT MBB" \*q
+This option is only available on ClickPad devices.
 Enable soft button click area support on ClickPad devices. The first four
 parameters define the area of the right button, and the second four parameters
 define the area of the middle button. The areas are defined by the left, right,
@@ -942,6 +943,7 @@ default.
 
 .TP 7
 .BI "Synaptics Soft Button Areas"
+This property is only available on ClickPad devices.
 The Right and middle soft button areas are used to support right and middle
 click actions on a ClickPad device. Providing 0 for all values of a given button
 disables the button area.
diff --git a/src/properties.c b/src/properties.c
index 5cd3088..783b516 100644
--- a/src/properties.c
+++ b/src/properties.c
@@ -151,6 +151,24 @@ InitFloatAtom(DeviceIntPtr dev, char *name, int nvalues, float *values)
     return atom;
 }
 
+static void
+InitSoftButtonProperty(InputInfoPtr pInfo)
+{
+    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
+    SynapticsParameters *para = &priv->synpara;
+    int values[8];
+
+    values[0] = para->softbutton_areas[0][0];
+    values[1] = para->softbutton_areas[0][1];
+    values[2] = para->softbutton_areas[0][2];
+    values[3] = para->softbutton_areas[0][3];
+    values[4] = para->softbutton_areas[1][0];
+    values[5] = para->softbutton_areas[1][1];
+    values[6] = para->softbutton_areas[1][2];
+    values[7] = para->softbutton_areas[1][3];
+    prop_softbutton_areas = InitAtom(pInfo->dev, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 8, values);
+}
+
 void
 InitDeviceProperties(InputInfoPtr pInfo)
 {
@@ -301,15 +319,8 @@ InitDeviceProperties(InputInfoPtr pInfo)
     values[3] = para->area_bottom_edge;
     prop_area = InitAtom(pInfo->dev, SYNAPTICS_PROP_AREA, 32, 4, values);
 
-    values[0] = para->softbutton_areas[0][0];
-    values[1] = para->softbutton_areas[0][1];
-    values[2] = para->softbutton_areas[0][2];
-    values[3] = para->softbutton_areas[0][3];
-    values[4] = para->softbutton_areas[1][0];
-    values[5] = para->softbutton_areas[1][1];
-    values[6] = para->softbutton_areas[1][2];
-    values[7] = para->softbutton_areas[1][3];
-    prop_softbutton_areas = InitAtom(pInfo->dev, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 8, values);
+    if (para->clickpad)
+        InitSoftButtonProperty(pInfo);
 
     values[0] = para->hyst_x;
     values[1] = para->hyst_y;
@@ -407,9 +418,20 @@ SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
         para->tap_time_2         = timeouts[1];
         para->click_time         = timeouts[2];
     } else if (property == prop_clickpad) {
+        BOOL value;
+
         if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
             return BadMatch;
 
+        value = *(BOOL*)prop->data;
+        if (!para->clickpad && value && !prop_softbutton_areas)
+            InitSoftButtonProperty(pInfo);
+        else if (para->clickpad && !value && prop_softbutton_areas)
+        {
+            XIDeleteDeviceProperty(dev, prop_softbutton_areas, FALSE);
+            prop_softbutton_areas = 0;
+        }
+
         para->clickpad = *(BOOL*)prop->data;
     } else if (property == prop_tap_fast)
     {
diff --git a/src/synaptics.c b/src/synaptics.c
index 4275d2a..898130e 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -516,6 +516,9 @@ static void set_softbutton_areas_option(InputInfoPtr pInfo)
     char *end_str;
     int i;
 
+    if (!pars->clickpad)
+        return;
+
     option_string = xf86CheckStrOption(pInfo->options, "SoftButtonAreas", NULL);
     if (!option_string)
         return;

commit c546779b32d8be23475b3b062e3ebc9235365c0d
Author: Chase Douglas <chase.douglas@canonical.com>
Date:   Thu Feb 9 16:56:29 2012 -0800

    Ignore motion during touch count changes on semi-mt devices
    
    Semi-mt devices do not track touches. The locations of touches are
    unknown, we only have the bounding box of two of them. When the number of
    fingers changes, the bounding box coordinates may change as well, but
    the cumulative relative motion updates at that instant are invalid.
    
    To work around this, ignore changes in cumulative relative motion if the
    touch count changes.
    
    Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>

diff --git a/src/synaptics.c b/src/synaptics.c
index 1164918..4275d2a 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -1598,6 +1598,14 @@ ReadInput(InputInfoPtr pInfo)
     SynapticsResetTouchHwState(hw);
 
     while (SynapticsGetHwState(pInfo, priv, hw)) {
+	/* Semi-mt device touch slots do not track touches. When there is a
+	 * change in the number of touches, we must disregard the temporary
+	 * motion changes. */
+	if (priv->has_semi_mt && hw->numFingers != priv->hwState->numFingers) {
+	    hw->cumulative_dx = priv->hwState->cumulative_dx;
+	    hw->cumulative_dy = priv->hwState->cumulative_dy;
+	}
+
 	SynapticsCopyHwState(priv->hwState, hw);
 	delay = HandleState(pInfo, hw, hw->millis, FALSE);
 	SynapticsCopyHwState(priv->old_hw_state, priv->hwState);

commit 405f1643e26b57ee97063e76e71179ba8e9fbc92
Author: Chase Douglas <chase.douglas@canonical.com>
Date:   Mon Feb 6 17:33:11 2012 -0800

    Add soft button areas property
    
    Some clickpad devices have button areas painted on them. Set this
    property to the area of the right and middle buttons to enable proper
    click actions when clicking in the areas.
    
    Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>

diff --git a/include/synaptics-properties.h b/include/synaptics-properties.h
index 140f14b..8c20a0c 100644
--- a/include/synaptics-properties.h
+++ b/include/synaptics-properties.h
@@ -158,6 +158,9 @@
 /* 32 bit, 4 values, left, right, top, bottom */
 #define SYNAPTICS_PROP_AREA "Synaptics Area"
 
+/* 32 bit, 4 values, left, right, top, buttom */
+#define SYNAPTICS_PROP_SOFTBUTTON_AREAS "Synaptics Soft Button Areas"
+
 /* 32 Bit Integer, 2 values, horizontal hysteresis, vertical hysteresis */
 #define SYNAPTICS_PROP_NOISE_CANCELLATION "Synaptics Noise Cancellation"
 
diff --git a/man/synaptics.man b/man/synaptics.man
index 8edc2f0..aaec35f 100644
--- a/man/synaptics.man
+++ b/man/synaptics.man
@@ -518,6 +518,20 @@ AreaBottomEdge option to any integer value other than zero. If supported by the
 server (version 1.9 and later), the edge may be specified in percent of
 the total height of the touchpad. Property: "Synaptics Area"
 .
+.TP
+.BI "Option \*qSoftButtonAreas\*q \*q" "RBL RBR RBT RBB MBL MBR MBT MBB" \*q
+Enable soft button click area support on ClickPad devices. The first four
+parameters define the area of the right button, and the second four parameters
+define the area of the middle button. The areas are defined by the left, right,
+top, and bottom edges as sequential values of the property. If any edge is set
+to 0, the button is assumed to extend to infinity in the given direction.
+.
+When the user performs a click within the defined soft button areas, the right
+or middle click action is performed.
+.
+The use of soft button areas is disabled by setting all the values for the area
+to 0. Property: "Synaptics Soft Button Areas"
+.
 
 .SH CONFIGURATION DETAILS
 .SS Area handling
@@ -927,6 +941,14 @@ default.
 32 bit, 4 values, left, right, top, bottom. 0 disables an element.
 
 .TP 7
+.BI "Synaptics Soft Button Areas"
+The Right and middle soft button areas are used to support right and middle
+click actions on a ClickPad device. Providing 0 for all values of a given button
+disables the button area.
+
+32 bit, 8 values, RBL, RBR, RBT, RBB, MBL, MBR, MBT, MBB.
+
+.TP 7
 .BI "Synaptics Capabilities"
 This read-only property expresses the physical capability of the touchpad,
 most notably whether the touchpad hardware supports multi-finger tapping and
diff --git a/src/properties.c b/src/properties.c
index 38f21b2..5cd3088 100644
--- a/src/properties.c
+++ b/src/properties.c
@@ -92,6 +92,7 @@ Atom prop_gestures              = 0;
 Atom prop_capabilities          = 0;
 Atom prop_resolution            = 0;
 Atom prop_area                  = 0;
+Atom prop_softbutton_areas      = 0;
 Atom prop_noise_cancellation    = 0;
 Atom prop_product_id            = 0;
 Atom prop_device_node           = 0;
@@ -300,6 +301,16 @@ InitDeviceProperties(InputInfoPtr pInfo)
     values[3] = para->area_bottom_edge;
     prop_area = InitAtom(pInfo->dev, SYNAPTICS_PROP_AREA, 32, 4, values);
 
+    values[0] = para->softbutton_areas[0][0];
+    values[1] = para->softbutton_areas[0][1];
+    values[2] = para->softbutton_areas[0][2];
+    values[3] = para->softbutton_areas[0][3];
+    values[4] = para->softbutton_areas[1][0];
+    values[5] = para->softbutton_areas[1][1];
+    values[6] = para->softbutton_areas[1][2];
+    values[7] = para->softbutton_areas[1][3];
+    prop_softbutton_areas = InitAtom(pInfo->dev, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 8, values);
+
     values[0] = para->hyst_x;
     values[1] = para->hyst_y;
     prop_noise_cancellation = InitAtom(pInfo->dev,
@@ -711,6 +722,19 @@ SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
         para->area_right_edge  = area[1];
         para->area_top_edge    = area[2];
         para->area_bottom_edge = area[3];
+    } else if (property == prop_softbutton_areas)
+    {
+        int *areas;
+
+        if (prop->size != 8 || prop->format != 32 || prop->type != XA_INTEGER)
+            return BadMatch;
+
+        areas = (int*)prop->data;
+        if (!SynapticsIsSoftButtonAreasValid(areas))
+            return BadValue;
+
+        memcpy(para->softbutton_areas[0], areas, 4 * sizeof(int));
+        memcpy(para->softbutton_areas[1], areas + 4, 4 * sizeof(int));
     } else if (property == prop_noise_cancellation) {
         INT32 *hyst;
         if (prop->size != 2 || prop->format != 32 || prop->type != XA_INTEGER)
diff --git a/src/synaptics.c b/src/synaptics.c
index 2770bd8..1164918 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -429,6 +429,126 @@ static int set_percent_option(pointer options, const char* optname,
     return result;
 }
 
+Bool SynapticsIsSoftButtonAreasValid(int *values)
+{
+    Bool right_disabled = FALSE;
+    Bool middle_disabled = FALSE;
+
+    /* Check right button area */
+    if ((((values[0] != 0) && (values[1] != 0)) && (values[0] > values[1])) ||
+        (((values[2] != 0) && (values[3] != 0)) && (values[2] > values[3])))
+        return FALSE;
+
+    /* Check middle button area */
+    if ((((values[4] != 0) && (values[5] != 0)) && (values[4] > values[5])) ||
+        (((values[6] != 0) && (values[7] != 0)) && (values[6] > values[7])))
+        return FALSE;
+
+    if (values[0] == 0 && values[1] == 0 && values[2] == 0 && values[3] == 0)
+        right_disabled = TRUE;
+
+    if (values[4] == 0 && values[5] == 0 && values[6] == 0 && values[7] == 0)
+        middle_disabled = TRUE;
+
+    if (!right_disabled &&
+            ((values[0] && values[0] == values[1]) ||
+             (values[2] && values[2] == values[3])))
+        return FALSE;
+
+    if (!middle_disabled &&
+        ((values[4] && values[4] == values[5]) ||
+         (values[6] && values[6] == values[7])))
+        return FALSE;
+
+    /* Check for overlapping button areas */
+    if (!right_disabled && !middle_disabled)
+    {
+        int right_left = values[0] ? values[0] : INT_MIN;
+        int right_right = values[1] ? values[1] : INT_MAX;
+        int right_top = values[2] ? values[2] : INT_MIN;
+        int right_bottom = values[3] ? values[3] : INT_MAX;
+        int middle_left = values[4] ? values[4] : INT_MIN;
+        int middle_right = values[5] ? values[5] : INT_MAX;
+        int middle_top = values[6] ? values[6] : INT_MIN;
+        int middle_bottom = values[7] ? values[7] : INT_MAX;
+
+        /* If areas overlap in the Y axis */
+        if ((right_bottom <= middle_bottom && right_bottom >= middle_top) ||
+            (right_top <= middle_bottom && right_top >= middle_top))
+        {
+            /* Check for overlapping left edges */
+            if ((right_left < middle_left && right_right >= middle_left) ||
+                (middle_left < right_left && middle_right >= right_left))
+                return FALSE;
+
+            /* Check for overlapping right edges */
+            if ((right_right > middle_right && right_left <= middle_right) ||
+                (middle_right > right_right && middle_left <= right_right))
+                return FALSE;
+        }
+
+        /* If areas overlap in the X axis */
+        if ((right_left >= middle_left && right_left <= middle_right) ||
+            (right_right >= middle_left && right_right <= middle_right))
+        {
+            /* Check for overlapping top edges */
+            if ((right_top < middle_top && right_bottom >= middle_top) ||
+                (middle_top < right_top && middle_bottom >= right_top))
+                return FALSE;
+
+            /* Check for overlapping bottom edges */
+            if ((right_bottom > middle_bottom && right_top <= middle_bottom) ||
+                (middle_bottom > right_bottom && middle_top <= right_bottom))
+                return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+static void set_softbutton_areas_option(InputInfoPtr pInfo)
+{
+    SynapticsPrivate *priv = pInfo->private;
+    SynapticsParameters *pars = &priv->synpara;
+    int values[8];
+    char *option_string;
+    char *next_num;
+    char *end_str;
+    int i;
+
+    option_string = xf86CheckStrOption(pInfo->options, "SoftButtonAreas", NULL);
+    if (!option_string)
+        return;
+
+    next_num = option_string;
+
+    for (i = 0; i < 8 && *next_num != '\0'; i++)
+    {
+        long int value = strtol(next_num, &end_str, 0);
+        if (value > INT_MAX || value < -INT_MAX)
+            goto fail;
+
+        values[i] = value;
+
+        if (next_num != end_str)
+            next_num = end_str;
+        else
+            goto fail;
+    }
+
+    if (i < 8 || *next_num != '\0' || !SynapticsIsSoftButtonAreasValid(values))
+        goto fail;
+
+    memcpy(pars->softbutton_areas[0], values, 4 * sizeof(int));
+    memcpy(pars->softbutton_areas[1], values + 4, 4 * sizeof(int));
+
+    return;
+
+fail:
+    xf86IDrvMsg(pInfo, X_ERROR, "invalid SoftButtonAreas value '%s', keeping defaults\n",
+                option_string);
+}
+
 static void set_default_parameters(InputInfoPtr pInfo)
 {
     SynapticsPrivate *priv = pInfo->private; /* read-only */
@@ -623,6 +743,8 @@ static void set_default_parameters(InputInfoPtr pInfo)
 	pars->bottom_edge = tmp;
 	xf86IDrvMsg(pInfo, X_WARNING, "TopEdge is bigger than BottomEdge. Fixing.\n");
     }
+
+    set_softbutton_areas_option(pInfo);
 }
 
 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 14
@@ -1381,6 +1503,45 @@ is_inside_active_area(SynapticsPrivate *priv, int x, int y)
     return inside_area;
 }
 
+static Bool
+is_inside_button_area(SynapticsParameters *para, int which, int x, int y)
+{
+    Bool inside_area = TRUE;
+
+    if (para->softbutton_areas[which][0] == 0 &&
+        para->softbutton_areas[which][1] == 0 &&
+        para->softbutton_areas[which][2] == 0 &&
+        para->softbutton_areas[which][3] == 0)
+        return FALSE;
+
+    if (para->softbutton_areas[which][0] &&
+        x < para->softbutton_areas[which][0])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[which][1] &&
+             x > para->softbutton_areas[which][1])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[which][2] &&
+             y < para->softbutton_areas[which][2])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[which][3] &&
+             y > para->softbutton_areas[which][3])
+	inside_area = FALSE;
+
+    return inside_area;
+}
+
+static Bool
+is_inside_rightbutton_area(SynapticsParameters *para, int x, int y)
+{
+    return is_inside_button_area(para, 0, x, y);
+}
+
+static Bool
+is_inside_middlebutton_area(SynapticsParameters *para, int x, int y)
+{
+    return is_inside_button_area(para, 1, x, y);
+}
+
 static CARD32
 timerFunc(OsTimerPtr timer, CARD32 now, pointer arg)
 {
@@ -2589,6 +2750,22 @@ update_hw_button_state(const InputInfoPtr pInfo, struct SynapticsHwState *hw,
     /* 3rd button emulation */
     hw->middle |= HandleMidButtonEmulation(priv, hw, now, delay);
 
+    /* If this is a clickpad and the user clicks in a soft button area, press
+     * the soft button instead. */
+    if (para->clickpad && hw->left && !hw->right && !hw->middle)
+    {
+        if (is_inside_rightbutton_area(para, hw->x, hw->y))
+        {
+            hw->left = 0;
+            hw->right = 1;
+        }
+        else if (is_inside_middlebutton_area(para, hw->x, hw->y))
+        {
+            hw->left = 0;
+            hw->middle = 1;
+        }
+    }
+
     /* Fingers emulate other buttons. ClickFinger can only be
        triggered on transition, when left is pressed
      */
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 84c8a97..fcefc46 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -181,6 +181,7 @@ typedef struct _SynapticsParameters
     unsigned int resolution_horiz;          /* horizontal resolution of touchpad in units/mm */
     unsigned int resolution_vert;           /* vertical resolution of touchpad in units/mm */
     int area_left_edge, area_right_edge, area_top_edge, area_bottom_edge; /* area coordinates absolute */
+    int softbutton_areas[2][4];             /* soft button area coordinates, 0 => right, 1 => middle button */
     int hyst_x, hyst_y;                     /* x and y width of hysteresis box */
 } SynapticsParameters;
 
diff --git a/src/synproto.h b/src/synproto.h
index 41284b3..95ebc92 100644
--- a/src/synproto.h
+++ b/src/synproto.h
@@ -120,4 +120,6 @@ extern void SynapticsCopyHwState(struct SynapticsHwState *dst,
                                  const struct SynapticsHwState *src);
 extern void SynapticsResetTouchHwState(struct SynapticsHwState *hw);
 
+extern Bool SynapticsIsSoftButtonAreasValid(int *values);
+
 #endif /* _SYNPROTO_H_ */
diff --git a/tools/synclient.c b/tools/synclient.c
index 6e77ee8..942312a 100644
--- a/tools/synclient.c
+++ b/tools/synclient.c
@@ -38,6 +38,7 @@
 #include <string.h>
 #include <stddef.h>
 #include <math.h>
+#include <limits.h>
 
 #include <X11/Xdefs.h>
 #include <X11/Xatom.h>
@@ -145,6 +146,14 @@ static struct Parameter params[] = {
     {"HorizHysteresis",       PT_INT,    0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32,	0},
     {"VertHysteresis",        PT_INT,    0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32,	1},
     {"ClickPad",              PT_BOOL,   0, 1,     SYNAPTICS_PROP_CLICKPAD,	8,	0},
+    {"RightButtonAreaLeft",   PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	0},
+    {"RightButtonAreaRight",  PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	1},
+    {"RightButtonAreaTop",    PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	2},
+    {"RightButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	3},
+    {"MiddleButtonAreaLeft",  PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	4},
+    {"MiddleButtonAreaRight", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	5},
+    {"MiddleButtonAreaTop",   PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	6},
+    {"MiddleButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	7},
     { NULL, 0, 0, 0, 0 }
 };
 

commit f198522064501726d76bef4e11c02cfc778bb0c5
Author: Chase Douglas <chase.douglas@canonical.com>
Date:   Thu Feb 9 11:18:25 2012 -0800

    Calculate touch data for semi-mt devices, but don't send touch events
    
    Previously, all touch data from semi-mt devices was ignored because the
    X server doesn't support them. However, the touch data must be used for
    proper clickpad handling.
    
    Instead of ignoring semi-mt device touch events, mark the device as
    being semi-mt and allow initialization of the touch state. The touches
    will then be used in calculating the cumulative_d{x,y} values that are
    needed for clickpad support.
    
    When handling the touch data for X event processing, simply skip over
    reporting the touches.
    
    Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>

diff --git a/src/eventcomm.c b/src/eventcomm.c
index d52cb6c..f199c24 100644
--- a/src/eventcomm.c
+++ b/src/eventcomm.c
@@ -764,7 +764,7 @@ event_query_touch(InputInfoPtr pInfo)
     {
         xf86IDrvMsg(pInfo, X_INFO,
                     "ignoring touch events for semi-multitouch device\n");
-        return;
+        priv->has_semi_mt = TRUE;
     }
 
     if (rc >= 0 && BitIsOn(&prop, INPUT_PROP_BUTTONPAD))
diff --git a/src/synaptics.c b/src/synaptics.c
index d422f0f..2770bd8 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -2788,6 +2788,9 @@ HandleTouches(InputInfoPtr pInfo, struct SynapticsHwState *hw)
             new_active_touches--;
     }
 
+    if (priv->has_semi_mt)
+        goto out;
+
     if (priv->num_active_touches < min_touches &&
         new_active_touches < min_touches)
     {
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index ecf186f..84c8a97 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -269,6 +269,7 @@ struct _SynapticsPrivateRec
     Bool has_pressure;			/* device reports pressure */
     Bool has_width;			/* device reports finger width */
     Bool has_scrollbuttons;		/* device has physical scrollbuttons */
+    Bool has_semi_mt;			/* device is only semi-multitouch capable */
 
     enum TouchpadModel model;		/* The detected model */
     unsigned short id_vendor;		/* vendor id */

commit a6361e2d2c093c4170bab63307526702fe9903ad
Author: Chase Douglas <chase.douglas@canonical.com>
Date:   Tue Feb 14 14:46:07 2012 -0800

    Disable scrolling when beginning a clickpad press
    
    There really isn't a point to scrolling while a clickpad is pressed. In
    particular, the clickpad button areas and the horizontal edge scrolling
    areas overlap, so horizontal edge scrolling must be disabled. Also,
    performing two finger scrolling while a third finger presses the button
    would require us to inhibit touch events until four touches are present.
    That is enough reason to disable two finger scrolling as well.
    
    Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>

diff --git a/src/synaptics.c b/src/synaptics.c
index 7a6d55f..d422f0f 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -1877,6 +1877,12 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
 	}
 	break;
     case TS_CLICKPAD_MOVE:
+	/* Disable scrolling once a button is pressed on a clickpad */
+	priv->vert_scroll_edge_on = FALSE;
+	priv->horiz_scroll_edge_on = FALSE;
+	priv->vert_scroll_twofinger_on = FALSE;
+	priv->horiz_scroll_twofinger_on = FALSE;
+
         /* Assume one touch is only for holding the clickpad button down */
 	if (hw->numFingers > 1)
 	    hw->numFingers--;

commit de75ad6b073c1a36d5a60190de5ffe6611520637
Author: Chase Douglas <chase.douglas@canonical.com>
Date:   Thu Feb 9 10:57:00 2012 -0800

    Enable clickpad click and drag with two fingers
    
    Use cumulative relative touch motion when the clickpad is pressed. If
    more than one touch is active, assume one of the touches is designated
    solely for pressing the clickpad button. Thus, decrement the number of
    reported touches.
    
    Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>

diff --git a/src/synaptics.c b/src/synaptics.c
index 7ee0238..7a6d55f 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -1722,7 +1722,7 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
 		    Bool inside_active_area)
 {
     SynapticsParameters *para = &priv->synpara;
-    Bool touch, release, is_timeout, move;
+    Bool touch, release, is_timeout, move, press;
     int timeleft, timeout;
     edge_type edge;
     int delay = 1000000000;
@@ -1736,6 +1736,7 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
 	     (priv->tap_max_fingers <= ((priv->horiz_scroll_twofinger_on || priv->vert_scroll_twofinger_on)? 2 : 1)) &&
 	     ((abs(hw->x - priv->touch_on.x) >= para->tap_move) ||
 	     (abs(hw->y - priv->touch_on.y) >= para->tap_move)));
+    press = (hw->left || hw->right || hw->middle);
 
     if (touch) {
 	priv->touch_on.x = hw->x;
@@ -1758,6 +1759,10 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
 	    SetTapState(priv, TS_1, now);
 	break;
     case TS_1:
+	if (para->clickpad && press) {
+	    SetTapState(priv, TS_CLICKPAD_MOVE, now);
+	    goto restart;
+	}
 	if (move) {
 	    SetMovingState(priv, MS_TOUCHPAD_RELATIVE, now);
 	    SetTapState(priv, TS_MOVE, now);
@@ -1781,6 +1786,10 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
 	}
 	break;
     case TS_MOVE:
+	if (para->clickpad && press) {
+	    SetTapState(priv, TS_CLICKPAD_MOVE, now);
+	    goto restart;
+	}
 	if (move && priv->moving_state == MS_TRACKSTICK) {
 	    SetMovingState(priv, MS_TOUCHPAD_RELATIVE, now);
 	}
@@ -1835,6 +1844,10 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
 	}
 	break;
     case TS_DRAG:
+	if (para->clickpad && press) {
+	    SetTapState(priv, TS_CLICKPAD_MOVE, now);
+	    goto restart;
+	}
 	if (move)
 	    SetMovingState(priv, MS_TOUCHPAD_RELATIVE, now);
 	if (release) {
@@ -1863,6 +1876,17 @@ HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
 	    SetTapState(priv, TS_START, now);
 	}
 	break;
+    case TS_CLICKPAD_MOVE:
+        /* Assume one touch is only for holding the clickpad button down */
+	if (hw->numFingers > 1)
+	    hw->numFingers--;
+	SetMovingState(priv, MS_TOUCHPAD_RELATIVE, now);
+	if (!press) {
+	    SetMovingState(priv, MS_FALSE, now);
+	    SetTapState(priv, TS_MOVE, now);
+	    priv->count_packet_finger = 0;
+	}
+	break;
     }
 
     timeout = GetTimeOut(priv);
@@ -2872,6 +2896,14 @@ HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw, CARD32 now,
 	return delay;
     }
 
+    /* If a physical button is pressed on a clickpad, use cumulative relative
+     * touch movements for motion */
+    if (para->clickpad && (hw->left || hw->right || hw->middle))
+    {
+        hw->x = hw->cumulative_dx;
+        hw->y = hw->cumulative_dy;
+    }
+
     /* apply hysteresis before doing anything serious. This cancels
      * out a lot of noise which might surface in strange phenomena
      * like flicker in scrolling or noise motion. */
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index a6e94e3..ecf186f 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -99,7 +99,8 @@ enum TapState {
     TS_3,			/* After second touch */
     TS_DRAG,			/* Pointer drag enabled */
     TS_4,			/* After release when "locked drags" enabled */
-    TS_5			/* After touch when "locked drags" enabled */
+    TS_5,			/* After touch when "locked drags" enabled */
+    TS_CLICKPAD_MOVE,		/* After left button press on a clickpad */
 };
 
 enum TapButtonState {

commit 500243ac60ffeb5372e2edbce2f4443a07877d2e
Author: Chase Douglas <chase.douglas@canonical.com>
Date:   Thu Feb 9 10:43:08 2012 -0800

    Add cumulative_d{x,y} to SynapticsHwState
    
    These values will be used for clickpad press and drag with two fingers.
    
    While the clickpad button is not pressed, cumulative_d{x,y} will match x
    and y values. Once the clickpad button is pressed, cumulative_d{x,y}
    will be updated with the relative motion of each active touch on the
    touchpad. This allows for dragging with one finger while another finger
    stays stationary holding the clickpad button down.
    
    This is an easier and less latent approach than trying to guess which
    touch was the "dragging" touch.
    
    [fixed build error for mt off]
    
    Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
    Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>

diff --git a/src/eventcomm.c b/src/eventcomm.c
index d031eb4..d52cb6c 100644
--- a/src/eventcomm.c
+++ b/src/eventcomm.c
@@ -525,6 +525,20 @@ SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev)
     return rc;
 }
 
+#ifdef HAVE_MULTITOUCH
+static Bool
+EventTouchSlotPreviouslyOpen(SynapticsPrivate *priv, int slot)
+{
+    int i;
+
+    for (i = 0; i < priv->num_active_touches; i++)
+        if (priv->open_slots[i] == slot)
+            return TRUE;
+
+    return FALSE;
+}
+#endif
+
 static void
 EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw,
                        struct input_event *ev)
@@ -565,8 +579,20 @@ EventProcessTouchEvent(InputInfoPtr pInfo, struct SynapticsHwState *hw,
             int map = proto_data->axis_map[ev->code - ABS_MT_TOUCH_MAJOR];
             valuator_mask_set(hw->mt_mask[slot_index], map, ev->value);
             if (slot_index >= 0)
-                valuator_mask_set(proto_data->last_mt_vals[slot_index], map,
-                                  ev->value);
+            {
+                ValuatorMask *mask = proto_data->last_mt_vals[slot_index];
+                int last_val = valuator_mask_get(mask, map);
+
+                if (EventTouchSlotPreviouslyOpen(priv, slot_index))
+                {
+                    if (ev->code == ABS_MT_POSITION_X)
+                        hw->cumulative_dx += ev->value - last_val;
+                    else if (ev->code == ABS_MT_POSITION_Y)
+                        hw->cumulative_dy += ev->value - last_val;
+                }
+
+                valuator_mask_set(mask, map, ev->value);
+            }
         }
     }
 #endif
@@ -614,6 +640,13 @@ EventReadHwState(InputInfoPtr pInfo,
 
     SynapticsResetTouchHwState(hw);
 
+    /* Reset cumulative values if buttons were not previously pressed */
+    if (!hw->left && !hw->right && !hw->middle)
+    {
+        hw->cumulative_dx = hw->x;
+        hw->cumulative_dy = hw->y;
+    }
+
     while (SynapticsReadEvent(pInfo, &ev)) {
 	switch (ev.type) {
 	case EV_SYN:
diff --git a/src/synproto.c b/src/synproto.c
index 21e88c4..bdf2d21 100644
--- a/src/synproto.c
+++ b/src/synproto.c
@@ -120,6 +120,8 @@ SynapticsCopyHwState(struct SynapticsHwState *dst,
     dst->x = src->x;
     dst->y = src->y;
     dst->z = src->z;
+    dst->cumulative_dx = src->cumulative_dx;
+    dst->cumulative_dy = src->cumulative_dy;
     dst->numFingers = src->numFingers;
     dst->fingerWidth = src->fingerWidth;
     dst->left = src->left & BTN_EMULATED_FLAG ? 0 : src->left;
diff --git a/src/synproto.h b/src/synproto.h
index 5e8a804..41284b3 100644
--- a/src/synproto.h
+++ b/src/synproto.h
@@ -56,6 +56,8 @@ struct SynapticsHwState {
     int x;			/* X position of finger */
     int y;			/* Y position of finger */
     int z;			/* Finger pressure */
+    int cumulative_dx;		/* Cumulative delta X for clickpad dragging */
+    int cumulative_dy;		/* Cumulative delta Y for clickpad dragging */
     int numFingers;
     int fingerWidth;
 
diff --git a/test/fake-symbols.c b/test/fake-symbols.c
index 7f3f0ac..65fad46 100644
--- a/test/fake-symbols.c
+++ b/test/fake-symbols.c
@@ -461,6 +461,11 @@ _X_EXPORT void valuator_mask_free(ValuatorMask **mask)
 {
 }
 
+_X_EXPORT int valuator_mask_get(const ValuatorMask *mask, int valuator)
+{
+    return 0;
+}
+
 _X_EXPORT void valuator_mask_set(ValuatorMask *mask, int valuator, int data)
 {
 }

commit 420e0abef663729b3ce6e9d26360e616b7270ba6
Author: Peter Hutterer <peter.hutterer@who-t.net>
Date:   Fri Mar 9 14:30:58 2012 +1000

    Guess the number of clickpad ClickFingers based on finger distance
    
    The actual distance should be done in cm, based on touchpad resolution etc.
    That is left as an exercise for the reader.
    
    Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
    Reviewed-by: Chase Douglas <chase.douglas@canonical.com>

diff --git a/src/synaptics.c b/src/synaptics.c
index c2e3943..7ee0238 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -2386,11 +2386,73 @@ HandleScrolling(SynapticsPrivate *priv, struct SynapticsHwState *hw,
     return delay;
 }
 
+/**
+ * Check if any 2+ fingers are close enough together to assume this is a
+ * ClickFinger action.
+ */
+static int
+clickpad_guess_clickfingers(SynapticsPrivate *priv, struct SynapticsHwState *hw)
+{
+    int nfingers = 0;
+#if HAVE_MULTITOUCH
+    int i, j;
+    for (i = 0; i < hw->num_mt_mask - 1; i++) {
+        ValuatorMask *f1;
+
+        /* you can't click on open, you're not fast enough */
+        if (hw->slot_state[i] != SLOTSTATE_UPDATE)
+            continue;
+
+        f1 = hw->mt_mask[i];
+
+        for (j = i + 1; j < hw->num_mt_mask; j++) {
+            ValuatorMask *f2;
+            double x1, x2, y1, y2;
+
+            if (hw->slot_state[j] != SLOTSTATE_UPDATE)
+                continue;
+
+            f2 = hw->mt_mask[j];
+
+            x1 = valuator_mask_get_double(f1, 0);
+            y1 = valuator_mask_get_double(f1, 1);
+
+            x2 = valuator_mask_get_double(f2, 0);
+            y2 = valuator_mask_get_double(f2, 1);
+
+            /* FIXME: fingers closer together than 30% of touchpad width, but
+             * really, this should be dependent on the touchpad size. Also,
+             * you'll need to find a touchpad that doesn't lie about it's
+             * size. Good luck. */
+            if (abs(x1 - x2) < (priv->maxx - priv->minx) * .3 &&
+                abs(y1 - y2) < (priv->maxy - priv->miny) * .3)
+                nfingers++;
+        }
+    }
+#endif
+
+    /* 1 doesn't make sense */
+    return nfingers ? nfingers + 1 : 0;
+}
+
+
 static void
-handle_clickfinger(SynapticsParameters *para, struct SynapticsHwState *hw)
+handle_clickfinger(SynapticsPrivate *priv, struct SynapticsHwState *hw)
 {
+    SynapticsParameters *para = &priv->synpara;
     int action = 0;
-    switch(hw->numFingers){
+    int nfingers = hw->numFingers;
+
+    /* if this is a clickpad, clickfinger handling is:
+     * one finger down: no action, this is a normal click
+     * two fingers down: F2_CLICK
+     * three fingers down: F3_CLICK
+     */
+
+    if (para->clickpad)
+        nfingers = clickpad_guess_clickfingers(priv, hw);
+
+    switch(nfingers) {
         case 1:
             action = para->click_action[F1_CLICK1];
             break;
@@ -2501,7 +2563,7 @@ update_hw_button_state(const InputInfoPtr pInfo, struct SynapticsHwState *hw,
        triggered on transition, when left is pressed
      */
     if(hw->left && !old->left && hw->numFingers >= 1) {
-        handle_clickfinger(para, hw);
+        handle_clickfinger(priv, hw);
     }
 
     /* Two finger emulation */

commit 739cf056685772e69744f009f567e54324bc9dd0
Author: Peter Hutterer <peter.hutterer@who-t.net>
Date:   Fri Mar 9 15:33:56 2012 +1000

    Disable middle mouse button emulation on clickpads
    
    Because, well, really, how?
    
    Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>


Reply to: