touchpad: implement conditional disabling
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 3 Sep 2014 05:45:57 +0000 (15:45 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Thu, 18 Sep 2014 03:29:42 +0000 (13:29 +1000)
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
src/evdev-mt-touchpad.c
test/device.c

index c6bfd1d..d9f6fd7 100644 (file)
@@ -676,12 +676,67 @@ tp_resume(struct tp_dispatch *tp, struct evdev_device *device)
        evdev_device_resume(device);
 }
 
+static void
+tp_device_added(struct evdev_device *device,
+               struct evdev_device *added_device)
+{
+       struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;
+
+       if (tp->sendevents.current_mode !=
+           LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
+               return;
+
+       if (added_device->tags & EVDEV_TAG_EXTERNAL_MOUSE)
+               tp_suspend(tp, device);
+}
+
+static void
+tp_device_removed(struct evdev_device *device,
+                 struct evdev_device *removed_device)
+{
+       struct tp_dispatch *tp = (struct tp_dispatch*)device->dispatch;
+       struct libinput_device *dev;
+
+       if (tp->sendevents.current_mode !=
+           LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
+               return;
+
+       list_for_each(dev, &device->base.seat->devices_list, link) {
+               struct evdev_device *d = (struct evdev_device*)dev;
+               if (d != removed_device &&
+                   (d->tags & EVDEV_TAG_EXTERNAL_MOUSE)) {
+                       return;
+               }
+       }
+
+       tp_resume(tp, device);
+}
+
+static void
+tp_tag_device(struct evdev_device *device,
+             struct udev_device *udev_device)
+{
+       int bustype;
+
+       /* simple approach: touchpads on USB or Bluetooth are considered
+        * external, anything else is internal. Exception is Apple -
+        * internal touchpads are connected over USB and it doesn't have
+        * external USB touchpads anyway.
+        */
+       bustype = libevdev_get_id_bustype(device->evdev);
+       if (bustype == BUS_USB) {
+                if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
+                        device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
+       } else if (bustype != BUS_BLUETOOTH)
+               device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
+}
+
 static struct evdev_dispatch_interface tp_interface = {
        tp_process,
        tp_destroy,
-       NULL, /* device_added */
-       NULL, /* device_removed */
-       NULL, /* tag_device */
+       tp_device_added,
+       tp_device_removed,
+       tp_tag_device,
 };
 
 static void
@@ -877,8 +932,29 @@ tp_init(struct tp_dispatch *tp,
 static uint32_t
 tp_sendevents_get_modes(struct libinput_device *device)
 {
-       return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED |
-              LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
+       struct evdev_device *evdev = (struct evdev_device*)device;
+       uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED |
+                        LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
+
+       if (evdev->tags & EVDEV_TAG_INTERNAL_TOUCHPAD)
+               modes |= LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
+
+       return modes;
+}
+
+static void
+tp_suspend_conditional(struct tp_dispatch *tp,
+                      struct evdev_device *device)
+{
+       struct libinput_device *dev;
+
+       list_for_each(dev, &device->base.seat->devices_list, link) {
+               struct evdev_device *d = (struct evdev_device*)dev;
+               if (d->tags & EVDEV_TAG_EXTERNAL_MOUSE) {
+                       tp_suspend(tp, device);
+                       return;
+               }
+       }
 }
 
 static enum libinput_config_status
@@ -898,6 +974,9 @@ tp_sendevents_set_mode(struct libinput_device *device,
        case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED:
                tp_suspend(tp, evdev);
                break;
+       case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE:
+               tp_suspend_conditional(tp, evdev);
+               break;
        default:
                return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
        }
index cf20632..3f7ec4c 100644 (file)
@@ -47,6 +47,22 @@ START_TEST(device_sendevents_config)
 }
 END_TEST
 
+START_TEST(device_sendevents_config_touchpad)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput_device *device;
+       uint32_t modes;
+
+       device = dev->libinput_device;
+
+       modes = libinput_device_config_send_events_get_modes(device);
+       ck_assert_int_eq(modes,
+                        LIBINPUT_CONFIG_SEND_EVENTS_ENABLED|
+                        LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE|
+                        LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
+}
+END_TEST
+
 START_TEST(device_sendevents_config_default)
 {
        struct litest_device *dev = litest_current_device();
@@ -495,7 +511,8 @@ END_TEST
 
 int main (int argc, char **argv)
 {
-       litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_ANY);
+       litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_TOUCHPAD);
+       litest_add("device:sendevents", device_sendevents_config_touchpad, LITEST_TOUCHPAD, LITEST_ANY);
        litest_add("device:sendevents", device_sendevents_config_default, LITEST_ANY, LITEST_ANY);
        litest_add("device:sendevents", device_disable, LITEST_POINTER, LITEST_ANY);
        litest_add("device:sendevents", device_disable_touchpad, LITEST_TOUCHPAD, LITEST_ANY);