Hello community,
here is the log from the commit of package xf86-input-libinput for openSUSE:Factory checked in at 2015-12-29 13:00:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/xf86-input-libinput (Old)
and /work/SRC/openSUSE:Factory/.xf86-input-libinput.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "xf86-input-libinput"
Changes:
--------
--- /work/SRC/openSUSE:Factory/xf86-input-libinput/xf86-input-libinput.changes 2015-12-16 17:45:16.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.xf86-input-libinput.new/xf86-input-libinput.changes 2015-12-29 13:00:15.000000000 +0100
@@ -1,0 +2,16 @@
+Thu Dec 24 12:47:56 UTC 2015 - tobias.johannes.klausmann@mni.thm.de
+
+- Update to version 0.16.0:
+ This release fixes a long-standing issue with mixed devices that expose a
+ pointer and a keyboard interface at the same time. X requires a strict
+ separation between pointers and keyboards, these devices were usually
+ initialized as pointers and exhibited some keyboard functionality issues
+ (e.g. XKB layouts didn't get applied correctly). With this release, the xorg
+ libinput driver splits such devices into multiple X devices, one for the
+ keyboard and one for the pointer, routing the events as necessary and thus
+ fixing those issues.
+- Changes to package:
+ + Remove patch U_xf86_input_libinput_mem_leak_fix.patch: included in this
+ release.
+
+-------------------------------------------------------------------
Old:
----
U_xf86_input_libinput_mem_leak_fix.patch
xf86-input-libinput-0.15.0.tar.bz2
xf86-input-libinput-0.15.0.tar.bz2.sig
New:
----
xf86-input-libinput-0.16.0.tar.bz2
xf86-input-libinput-0.16.0.tar.bz2.sig
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ xf86-input-libinput.spec ++++++
--- /var/tmp/diff_new_pack.sVdLzm/_old 2015-12-29 13:00:16.000000000 +0100
+++ /var/tmp/diff_new_pack.sVdLzm/_new 2015-12-29 13:00:16.000000000 +0100
@@ -17,7 +17,7 @@
Name: xf86-input-libinput
-Version: 0.15.0
+Version: 0.16.0
Release: 0
Summary: Libinput driver for the Xorg X server
License: MIT
@@ -27,7 +27,6 @@
Source1: http://xorg.freedesktop.org/releases/individual/driver/%{name}-%{version}.tar.bz2.sig
Source2: %{name}.keyring
Patch0: n_enable-tapping.patch
-Patch1: U_xf86_input_libinput_mem_leak_fix.patch
BuildRequires: pkg-config
BuildRequires: pkgconfig(inputproto)
BuildRequires: pkgconfig(libinput) >= 1.0.901
@@ -59,7 +58,6 @@
%prep
%setup -q
%patch0 -p1
-%patch1 -p1
%build
%configure
@@ -78,6 +76,7 @@
%defattr(-,root,root)
%doc COPYING*
%dir %{_libdir}/xorg/modules/input
+%dir %{_sysconfdir}/X11/xorg.conf.d
%{_libdir}/xorg/modules/input/libinput_drv.so
%{_datadir}/man/man4/libinput.4%{?ext_man}
%config %{_sysconfdir}/X11/xorg.conf.d/90-libinput.conf
++++++ xf86-input-libinput-0.15.0.tar.bz2 -> xf86-input-libinput-0.16.0.tar.bz2 ++++++
++++ 21172 lines of diff (skipped)
++++ retrying with extended exclude list
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xf86-input-libinput-0.15.0/ChangeLog new/xf86-input-libinput-0.16.0/ChangeLog
--- old/xf86-input-libinput-0.15.0/ChangeLog 2015-10-27 08:17:42.000000000 +0100
+++ new/xf86-input-libinput-0.16.0/ChangeLog 2015-12-23 04:55:18.000000000 +0100
@@ -1,3 +1,245 @@
+commit 0d1851a000c5a80ba9b5787f516d2d72c62ce35e
+Author: Peter Hutterer
+Date: Wed Dec 23 13:53:38 2015 +1000
+
+ xf86-input-libinput 0.16.0
+
+ Signed-off-by: Peter Hutterer
+
+commit ad8483b91387e99282a9b5a8360e8de7eed70257
+Author: Peter Hutterer
+Date: Tue Dec 15 13:20:55 2015 +1000
+
+ Drain the fd after opening
+
+ Make sure we don't send any events that may have been enqueued before we
+ initialized ourselves. Specifically, if we're using systemd-logind the fd
+ remains open when we disable/enable the device, allowing events to queue up on
+ the fd. These events are then replayed once the device is re-opened.
+
+ This is not the case when VT-switching, in that case logind closes the fd for
+ us.
+
+ Signed-off-by: Peter Hutterer
+ Reviewed-by: Keith Packard
+
+commit 1f43f3921f6ceebd9a0cb92ef998a930d5fc3a3e
+Author: Peter Hutterer
+Date: Wed Nov 11 10:10:58 2015 +1000
+
+ Split mixed pointer/keyboard devices into two separate X devices
+
+ The server struggles with devices that are both, the protocol (especially XI2)
+ requires a fairly strict separation of pointer vs keyboard devices. Though the
+ server has a couple of hacks to route events correctly, mixed
+ devices still experience bugs like [1].
+
+ Instead of advertising the device as a single mixed device, split the device
+ into two X devices, one with only a pointer/touch component, one with only a
+ keyboard component. This ensures that the device is effectively attached to
+ both the VCP and the VCK, something the XI2 protocol doesn't really allow.
+
+ This patch drops the keyboard capability on a mixed device, duplicates the
+ input options and attributes and queues a NewInputDeviceRequest call. The new
+ device only has the keyboard capability but is otherwise unchanged. The
+ wacom driver has used this approach for years.
+
+ The WorkProc is necessary to avoid inconsistent state, the server doesn't
+ handle a NewInputDeviceRequest during PreInit well.
+
+ The approach:
+ During pre-init we create a struct xf86libinput_device with the
+ libinput_device and a unique ID. The child device has that ID added to the
+ options and will look for the other device during its pre-init. The two
+ devices then share the xf86libinput_device struct.
+
+ We only have a single epollfd for all devices and the server calls read_input
+ on the first device in the list with the epollfd as pInfo->fd. That shared
+ struct is used as the userdata on the libinput_device we get back from the
+ event, and each device is in the xorg_list device_list of that shared struct.
+ We loop through those to find the ones with the right capabilities and
+ post the event through that device.
+
+ Since devices can be enabled and disabled independently, the rest of the code
+ makes sure that we only ever add the device to libinput when the first shared
+ device is enabled, and remove it accordingly.
+
+ The server uses pInfo->major/minor to detect if another device is using the
+ same path for a logind-controlled fd. If so, it reuses that device's
+ pInfo->fd and sets the "fd" option to that value. That pInfo->fd is the
+ libinput epollfd though, not the actual device fd.
+
+ This doesn't matter for us, since we manage the fds largely ourselves and the
+ pInfo->fd we use is the epollfd anyway. On unplug however, the udev code
+ triggers a device removal for all devices, including the duplicated ones. When
+ we disable device, we restore the pInfo->fd from the "fd" option so that the
+ server can request logind to close the fd.
+
+ That only works if the "fd" option is correct, otherwise the server asks
+ logind to close the epollfd and everyone is unhappy.
+
+ [1] https://bugs.freedesktop.org/show_bug.cgi?id=49950
+
+ https://bugs.freedesktop.org/show_bug.cgi?id=92896
+
+ Signed-off-by: Peter Hutterer
+ Reviewed-by: Hans de Goede
+
+commit 83dfd31ec8ec2596648c33059fffb93b19691fae
+Author: Peter Hutterer
+Date: Fri Nov 20 10:51:38 2015 +1000
+
+ Revert "Split mixed pointer/keyboard devices into two separate X devices"
+
+ When using logind, this causes the server to hang when a split device is
+ unplugged. The reason is mostly in the server, when open the device by
+ requesting the logind fd, the server loops through the device list to check if
+ any other device has the same major/minor (see systemd_logind_take_fd()) and
+ returns the pInfo->fd for that device instead of requesting the fd again from
+ logind.
+
+ For libinput devices, the pInfo->fd is the epollfd, not the actual device, so
+ our second device gets the epollfd assigned. When the devices are removed, we
+ keep the device fd open and release the epollfd through logind.
+
+ This reverts commit c943739a2bfd4c380db0b21bc35b73deb7496c8a.
+
+commit c943739a2bfd4c380db0b21bc35b73deb7496c8a
+Author: Peter Hutterer
+Date: Wed Nov 11 10:10:58 2015 +1000
+
+ Split mixed pointer/keyboard devices into two separate X devices
+
+ The server struggles with devices that are both, the protocol (especially XI2)
+ requires a fairly strict separation of pointer vs keyboard devices. Though the
+ server has a couple of hacks to route events correctly, mixed
+ devices still experience bugs like [1].
+
+ Instead of advertising the device as a single mixed device, split the device
+ into two X devices, one with only a pointer/touch component, one with only a
+ keyboard component. This ensures that the device is effectively attached to
+ both the VCP and the VCK, something the XI2 protocol doesn't really allow.
+
+ This patch drops the keyboard capability on a mixed device, duplicates the
+ input options and attributes and queues a NewInputDeviceRequest call. The new
+ device only has the keyboard capability but is otherwise unchanged. The
+ wacom driver has used this approach for years.
+
+ The WorkProc is necessary to avoid inconsistent state, the server doesn't
+ handle a NewInputDeviceRequest during PreInit well.
+
+ The approach:
+ During pre-init we create a struct xf86libinput_device with the
+ libinput_device and a unique ID. The child device has that ID added to the
+ options and will look for the other device during its pre-init. The two
+ devices then share the xf86libinput_device struct.
+
+ We only have a single epollfd for all devices and the server calls read_input
+ on the first device in the list with the epollfd as pInfo->fd. That shared
+ struct is used as the userdata on the libinput_device we get back from the
+ event, and each device is in the xorg_list device_list of that shared struct.
+ We loop through those to find the ones with the right capabilities and
+ post the event through that device.
+
+ Since devices can be enabled and disabled independently, the rest of the code
+ makes sure that we only ever add the device to libinput when the first shared
+ device is enabled, and remove it accordingly.
+
+ [1] https://bugs.freedesktop.org/show_bug.cgi?id=49950
+
+ https://bugs.freedesktop.org/show_bug.cgi?id=92896
+
+ Signed-off-by: Peter Hutterer
+ Reviewed-by: Hans de Goede
+
+commit a72e96538af2c4a94ead48f96e8e59a2a4980a64
+Author: Peter Hutterer
+Date: Fri Nov 13 09:39:29 2015 +1000
+
+ Add a helper function for the driver context initialization
+
+ Signed-off-by: Peter Hutterer
+ Reviewed-by: Hans de Goede
+
+commit b1a9bea6079550fa8be4fa0b2e18ea810b0ea68c
+Author: Peter Hutterer
+Date: Wed Nov 11 09:12:33 2015 +1000
+
+ Copy the device capabilities to the X driver struct
+
+ And use those copied caps instead of the direct device capability calls.
+
+ No functional changes at this point, this is preparation work for selectively
+ disabling capabilities on a device.
+
+ Signed-off-by: Peter Hutterer
+ Reviewed-by: Hans de Goede
+
+commit a6aad69a97c68fa96e0a836e735b1a7f319b92df
+Author: Peter Hutterer
+Date: Wed Nov 11 09:02:22 2015 +1000
+
+ Split type_name detection out into a helper function
+
+ No functional changes
+
+ Signed-off-by: Peter Hutterer
+ Reviewed-by: Hans de Goede
+
+commit 6fa5f30129ea770bcc5e50b0785a993a8254a418
+Author: Peter Hutterer
+Date: Tue Nov 17 14:59:22 2015 +1000
+
+ Unref the libinput context on pre_init failure
+
+ A device that fails pre_init has a ref to the libinput context but may not
+ have a pInfo->private. For those devices we never call libinput_unref() and
+ the libinput struct never gets freed.
+
+ Thus if at least one device didn't pass pre_init, we never cleaned up after
+ ourselves.
+
+ Signed-off-by: Peter Hutterer
+ Reviewed-by: Hans de Goede
+
+commit c53dde1a503ace84f755a2a8d0022fba48ad89c2
+Author: Peter Hutterer
+Date: Fri Nov 13 10:48:02 2015 +1000
+
+ Don't fail DEVICE_CLOSE
+
+ We're not doing anything here, so no reason to fail.
+
+ Signed-off-by: Peter Hutterer
+
+commit d7331f6e34cedde2a1b8159d58aec0f68796f180
+Author: Peter Hutterer
+Date: Fri Nov 13 13:01:45 2015 +1000
+
+ Remove unused server_fds list
+
+ Obsolete as of 353c52f2bec03
+
+ Signed-off-by: Peter Hutterer
+
+commit fb56f6d7a5139445a36b3468ef7dc61d1c127335
+Author: Peter Hutterer
+Date: Fri Nov 13 10:02:16 2015 +1000
+
+ Set the device to NULL after unref
+
+ No real effect in the current code, but it adds a bit of safety.
+
+ Signed-off-by: Peter Hutterer
+
+commit c8861d2a2fd9ef875501a05b8c894045ce96ecc6
+Author: Peter Hutterer
+Date: Thu Nov 12 10:02:38 2015 +1000
+
+ Plug two memory leaks
+
+ Signed-off-by: Peter Hutterer
+
commit 44f4b2ed7075d424e3621f30815e11875b364c27
Author: Peter Hutterer
Date: Tue Oct 27 17:08:59 2015 +1000
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xf86-input-libinput-0.15.0/config.h.in new/xf86-input-libinput-0.16.0/config.h.in
--- old/xf86-input-libinput-0.15.0/config.h.in 2015-10-27 08:09:22.000000000 +0100
+++ new/xf86-input-libinput-0.16.0/config.h.in 2015-12-23 04:54:42.000000000 +0100
@@ -30,8 +30,7 @@
/* Define to 1 if you have the header file. */
#undef HAVE_UNISTD_H
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
- */
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
/* Name of package */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xf86-input-libinput-0.15.0/configure.ac new/xf86-input-libinput-0.16.0/configure.ac
--- old/xf86-input-libinput-0.15.0/configure.ac 2015-10-27 08:08:47.000000000 +0100
+++ new/xf86-input-libinput-0.16.0/configure.ac 2015-12-23 04:52:26.000000000 +0100
@@ -23,7 +23,7 @@
# Initialize Autoconf
AC_PREREQ([2.60])
AC_INIT([xf86-input-libinput],
- [0.15.0],
+ [0.16.0],
[https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
[xf86-input-libinput])
AC_CONFIG_SRCDIR([Makefile.am])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/xf86-input-libinput-0.15.0/src/xf86libinput.c new/xf86-input-libinput-0.16.0/src/xf86libinput.c
--- old/xf86-input-libinput-0.15.0/src/xf86libinput.c 2015-10-26 01:02:19.000000000 +0100
+++ new/xf86-input-libinput-0.16.0/src/xf86libinput.c 2015-12-23 04:52:01.000000000 +0100
@@ -66,17 +66,30 @@
*/
#define TOUCH_AXIS_MAX 0xffff
+#define CAP_KEYBOARD 0x1
+#define CAP_POINTER 0x2
+#define CAP_TOUCH 0x4
+
struct xf86libinput_driver {
struct libinput *libinput;
int device_enabled_count;
- struct xorg_list server_fds;
};
static struct xf86libinput_driver driver_context;
+struct xf86libinput_device {
+ int refcount;
+ int enabled_count;
+ uint32_t id;
+ struct libinput_device *device;
+ struct xorg_list device_list;
+ int server_fd;
+};
+
struct xf86libinput {
+ InputInfoPtr pInfo;
char *path;
- struct libinput_device *device;
+ uint32_t capabilities;
struct {
int vdist;
@@ -118,6 +131,9 @@
} options;
struct draglock draglock;
+
+ struct xf86libinput_device *shared_device;
+ struct xorg_list shared_device_link;
};
static inline int
@@ -160,6 +176,141 @@
return button;
}
+static inline InputInfoPtr
+xf86libinput_get_parent(InputInfoPtr pInfo)
+{
+ InputInfoPtr parent;
+ int parent_id;
+
+ parent_id = xf86CheckIntOption(pInfo->options, "_libinput/shared-device", -1);
+ if (parent_id == -1)
+ return NULL;
+
+ nt_list_for_each_entry(parent, xf86FirstLocalDevice(), next) {
+ int id = xf86CheckIntOption(parent->options,
+ "_libinput/shared-device",
+ -1);
+ if (id == parent_id)
+ return parent;
+ }
+
+ return NULL;
+}
+
+static inline struct xf86libinput_device*
+xf86libinput_shared_create(struct libinput_device *device)
+{
+ static uint32_t next_shared_device_id;
+ struct xf86libinput_device *shared_device;
+
+ shared_device = calloc(1, sizeof(*shared_device));
+ if (!shared_device)
+ return NULL;
+
+ shared_device->device = device;
+ shared_device->refcount = 1;
+ shared_device->id = ++next_shared_device_id;
+ xorg_list_init(&shared_device->device_list);
+
+ return shared_device;
+}
+
+static inline struct xf86libinput_device*
+xf86libinput_shared_ref(struct xf86libinput_device *shared_device)
+{
+ shared_device->refcount++;
+
+ return shared_device;
+}
+
+static inline struct xf86libinput_device*
+xf86libinput_shared_unref(struct xf86libinput_device *shared_device)
+{
+ shared_device->refcount--;
+
+ if (shared_device->refcount > 0)
+ return shared_device;
+
+ free(shared_device);
+
+ return NULL;
+}
+
+static inline struct libinput_device *
+xf86libinput_shared_enable(InputInfoPtr pInfo,
+ struct xf86libinput_device *shared_device,
+ const char *path)
+{
+ struct libinput_device *device;
+ struct libinput *libinput = driver_context.libinput;
+
+ /* With systemd-logind the server requests the fd from logind, sets
+ * pInfo->fd and sets the "fd" option to the fd number.
+ *
+ * If we have a second device that uses the same path, the server
+ * checks all pInfo->major/minor for a match and returns the matched
+ * device's pInfo->fd. In this driver, this fd is the epollfd, not
+ * the actual device. This causes troubles when removing the
+ * device.
+ *
+ * What we need to do here is: after enabling the device the first
+ * time extract the real fd and store it in the shared device
+ * struct. The second device replaces the pInfo->options "fd" with
+ * the real fd we're using.
+ *
+ * When the device is unplugged, the server now correctly finds two
+ * devices on the real fd and releases them in order.
+ */
+ shared_device->enabled_count++;
+ if (shared_device->enabled_count > 1) {
+ if (pInfo->flags & XI86_SERVER_FD) {
+ pInfo->options = xf86ReplaceIntOption(pInfo->options,
+ "fd",
+ shared_device->server_fd);
+ }
+
+ return shared_device->device;
+ }
+
+ device = libinput_path_add_device(libinput, path);
+ if (!device)
+ return NULL;
+
+ libinput_device_set_user_data(device, shared_device);
+ shared_device->device = libinput_device_ref(device);
+
+ if (pInfo->flags & XI86_SERVER_FD)
+ shared_device->server_fd = xf86CheckIntOption(pInfo->options,
+ "fd",
+ -1);
+ return device;
+}
+
+static inline void
+xf86libinput_shared_disable(struct xf86libinput_device *shared_device)
+{
+ struct libinput_device *device = shared_device->device;
+
+ shared_device->enabled_count--;
+
+ if (shared_device->enabled_count > 0)
+ return;
+
+ if (!device)
+ return;
+
+ libinput_device_set_user_data(device, NULL);
+ libinput_path_remove_device(device);
+ device = libinput_device_unref(device);
+ shared_device->device = NULL;
+}
+
+static inline bool
+xf86libinput_shared_is_enabled(struct xf86libinput_device *shared_device)
+{
+ return shared_device->enabled_count > 0;
+}
+
static int
LibinputSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
BOOL checkonly);
@@ -171,7 +322,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
unsigned int scroll_button;
if (libinput_device_config_send_events_get_modes(device) != LIBINPUT_CONFIG_SEND_EVENTS_ENABLED &&
@@ -312,17 +463,16 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
+ struct xf86libinput_device *shared_device = driver_data->shared_device;
struct libinput *libinput = driver_context.libinput;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device;
- device = libinput_path_add_device(libinput, driver_data->path);
+ device = xf86libinput_shared_enable(pInfo,
+ shared_device,
+ driver_data->path);
if (!device)
return !Success;
- libinput_device_ref(device);
- libinput_device_set_user_data(device, pInfo);
- driver_data->device = device;
-
/* if we use server fds, overwrite the fd with the one from
libinput nonetheless, otherwise the server won't call ReadInput
for our device. This must be swapped back to the real fd in
@@ -347,6 +497,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
+ struct xf86libinput_device *shared_device = driver_data->shared_device;
if (--driver_context.device_enabled_count == 0) {
RemoveEnabledDevice(pInfo->fd);
@@ -360,10 +511,7 @@
dev->public.on = FALSE;
- libinput_device_set_user_data(driver_data->device, NULL);
- libinput_path_remove_device(driver_data->device);
- libinput_device_unref(driver_data->device);
- driver_data->device = NULL;
+ xf86libinput_shared_disable(shared_device);
return Success;
}
@@ -417,6 +565,7 @@
{
DeviceIntPtr dev= pInfo->dev;
struct xf86libinput *driver_data = pInfo->private;
+ struct libinput_device *device = driver_data->shared_device->device;
int min, max, res;
int nbuttons = 7;
int i;
@@ -425,7 +574,7 @@
Atom axislabels[TOUCHPAD_NUM_AXES];
for (i = BTN_JOYSTICK - 1; i >= BTN_SIDE; i--) {
- if (libinput_device_pointer_has_button(driver_data->device, i)) {
+ if (libinput_device_pointer_has_button(device, i)) {
nbuttons += i - BTN_SIDE + 1;
break;
}
@@ -464,6 +613,7 @@
{
DeviceIntPtr dev= pInfo->dev;
struct xf86libinput *driver_data = pInfo->private;
+ struct libinput_device *device = driver_data->shared_device->device;
int min, max, res;
int nbuttons = 7;
int i;
@@ -472,7 +622,7 @@
Atom axislabels[TOUCHPAD_NUM_AXES];
for (i = BTN_BACK; i >= BTN_SIDE; i--) {
- if (libinput_device_pointer_has_button(driver_data->device, i)) {
+ if (libinput_device_pointer_has_button(device, i)) {
nbuttons += i - BTN_SIDE + 1;
break;
}
@@ -524,7 +674,7 @@
enum libinput_led leds = 0;
InputInfoPtr pInfo = device->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *ldevice = driver_data->device;
+ struct libinput_device *ldevice = driver_data->shared_device->device;
while (bits[i].xbit) {
if (ctrl->leds & bits[i].xbit)
@@ -608,29 +758,37 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct xf86libinput_device *shared_device = driver_data->shared_device;
+ struct libinput_device *device = shared_device->device;
+
+ BUG_RETURN_VAL(device == NULL, !Success);
dev->public.on = FALSE;
- if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD))
+ if (driver_data->capabilities & CAP_KEYBOARD)
xf86libinput_init_keyboard(pInfo);
- if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) {
+ if (driver_data->capabilities & CAP_POINTER) {
if (libinput_device_config_calibration_has_matrix(device) &&
!libinput_device_config_accel_is_available(device))
xf86libinput_init_pointer_absolute(pInfo);
else
xf86libinput_init_pointer(pInfo);
}
- if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH))
+ if (driver_data->capabilities & CAP_TOUCH)
xf86libinput_init_touch(pInfo);
LibinputApplyConfig(dev);
LibinputInitProperty(dev);
XIRegisterPropertyHandler(dev, LibinputSetProperty, NULL, NULL);
- /* unref the device now, because we'll get a new ref during
- DEVICE_ON */
- libinput_device_unref(device);
+ /* If we have a device but it's not yet enabled it's the
+ * already-removed device from PreInit. Drop the ref to clean up,
+ * we'll get a new libinput_device during DEVICE_ON when we re-add
+ * it. */
+ if (!xf86libinput_shared_is_enabled(shared_device)) {
+ libinput_device_unref(device);
+ shared_device->device = NULL;
+ }
return 0;
}
@@ -638,6 +796,13 @@
static void
xf86libinput_destroy(DeviceIntPtr dev)
{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ struct xf86libinput *driver_data = pInfo->private;
+ struct xf86libinput_device *shared_device = driver_data->shared_device;
+
+ xorg_list_del(&driver_data->shared_device_link);
+
+ xf86libinput_shared_unref(shared_device);
}
static int
@@ -657,6 +822,7 @@
break;
case DEVICE_CLOSE:
xf86libinput_destroy(dev);
+ rc = Success;
break;
}
@@ -671,6 +837,9 @@
ValuatorMask *mask = driver_data->valuators;
double x, y;
+ if ((driver_data->capabilities & CAP_POINTER) == 0)
+ return;
+
x = libinput_event_pointer_get_dx(event);
y = libinput_event_pointer_get_dy(event);
@@ -708,6 +877,9 @@
return;
}
+ if ((driver_data->capabilities & CAP_POINTER) == 0)
+ return;
+
x = libinput_event_pointer_get_absolute_x_transformed(event, TOUCH_AXIS_MAX);
y = libinput_event_pointer_get_absolute_y_transformed(event, TOUCH_AXIS_MAX);
@@ -726,6 +898,9 @@
int button;
int is_press;
+ if ((driver_data->capabilities & CAP_POINTER) == 0)
+ return;
+
button = btn_linux2xorg(libinput_event_pointer_get_button(event));
is_press = (libinput_event_pointer_get_button_state(event) == LIBINPUT_BUTTON_STATE_PRESSED);
@@ -740,9 +915,13 @@
xf86libinput_handle_key(InputInfoPtr pInfo, struct libinput_event_keyboard *event)
{
DeviceIntPtr dev = pInfo->dev;
+ struct xf86libinput *driver_data = pInfo->private;
int is_press;
int key = libinput_event_keyboard_get_key(event);
+ if ((driver_data->capabilities & CAP_KEYBOARD) == 0)
+ return;
+
key += XORG_KEYCODE_OFFSET;
is_press = (libinput_event_keyboard_get_key_state(event) == LIBINPUT_KEY_STATE_PRESSED);
@@ -759,6 +938,9 @@
enum libinput_pointer_axis axis;
enum libinput_pointer_axis_source source;
+ if ((driver_data->capabilities & CAP_POINTER) == 0)
+ return;
+
valuator_mask_zero(mask);
source = libinput_event_pointer_get_axis_source(event);
@@ -817,6 +999,9 @@
static unsigned int next_touchid;
static unsigned int touchids[TOUCH_MAX_SLOTS] = {0};
+ if ((driver_data->capabilities & CAP_TOUCH) == 0)
+ return;
+
slot = libinput_event_touch_get_slot(event);
switch (event_type) {
@@ -847,19 +1032,50 @@
xf86PostTouchEvent(dev, touchids[slot], type, 0, m);
}
+static InputInfoPtr
+xf86libinput_pick_device(struct xf86libinput_device *shared_device,
+ enum libinput_event_type type)
+{
+ struct xf86libinput *driver_data;
+ uint32_t needed_cap;
+
+ if (shared_device == NULL)
+ return NULL;
+
+ switch(type) {
+ case LIBINPUT_EVENT_KEYBOARD_KEY:
+ needed_cap = CAP_KEYBOARD;
+ break;
+ default:
+ needed_cap = ~CAP_KEYBOARD;
+ break;
+ }
+
+ xorg_list_for_each_entry(driver_data,
+ &shared_device->device_list,
+ shared_device_link) {
+ if (driver_data->capabilities & needed_cap)
+ return driver_data->pInfo;
+ }
+
+ return NULL;
+}
+
static void
xf86libinput_handle_event(struct libinput_event *event)
{
struct libinput_device *device;
+ enum libinput_event_type type;
InputInfoPtr pInfo;
+ type = libinput_event_get_type(event);
device = libinput_event_get_device(event);
- pInfo = libinput_device_get_user_data(device);
+ pInfo = xf86libinput_pick_device(libinput_device_get_user_data(device), type);
if (!pInfo || !pInfo->dev->public.on)
return;
- switch (libinput_event_get_type(event)) {
+ switch (type) {
case LIBINPUT_EVENT_NONE:
case LIBINPUT_EVENT_DEVICE_ADDED:
case LIBINPUT_EVENT_DEVICE_REMOVED:
@@ -959,7 +1175,12 @@
}
fd = xf86OpenSerial(pInfo->options);
- return fd < 0 ? -errno : fd;
+ if (fd < 0)
+ return -errno;
+
+ xf86FlushInput(fd);
+
+ return fd;
}
static void
@@ -1122,6 +1343,8 @@
profile = libinput_device_config_accel_get_profile(device);
}
+ free(str);
+
return profile;
}
@@ -1472,21 +1695,131 @@
xf86libinput_parse_buttonmap_option(pInfo,
options->btnmap,
sizeof(options->btnmap));
- if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) {
+ if (driver_data->capabilities & CAP_POINTER) {
xf86libinput_parse_draglock_option(pInfo, driver_data);
options->horiz_scrolling_enabled = xf86libinput_parse_horiz_scroll_option(pInfo);
}
}
+static const char*
+xf86libinput_get_type_name(struct libinput_device *device,
+ struct xf86libinput *driver_data)
+{
+ const char *type_name;
+
+ /* now pick an actual type */
+ if (libinput_device_config_tap_get_finger_count(device) > 0)
+ type_name = XI_TOUCHPAD;
+ else if (driver_data->capabilities & CAP_TOUCH)
+ type_name = XI_TOUCHSCREEN;
+ else if (driver_data->capabilities & CAP_POINTER)
+ type_name = XI_MOUSE;
+ else
+ type_name = XI_KEYBOARD;
+
+ return type_name;
+}
+
+static void
+xf86libinput_init_driver_context(void)
+{
+ if (!driver_context.libinput) {
+ driver_context.libinput = libinput_path_create_context(&interface, &driver_context);
+ libinput_log_set_handler(driver_context.libinput,
+ xf86libinput_log_handler);
+ /* we want all msgs, let the server filter */
+ libinput_log_set_priority(driver_context.libinput,
+ LIBINPUT_LOG_PRIORITY_DEBUG);
+ } else {
+ libinput_ref(driver_context.libinput);
+ }
+}
+
+struct xf86libinput_hotplug_info {
+ InputAttributes *attrs;
+ InputOption *input_options;
+};
+
+static Bool
+xf86libinput_hotplug_device(ClientPtr client, pointer closure)
+{
+ struct xf86libinput_hotplug_info *hotplug = closure;
+ DeviceIntPtr unused;
+
+ NewInputDeviceRequest(hotplug->input_options,
+ hotplug->attrs,
+ &unused);
+
+ input_option_free_list(&hotplug->input_options);
+ FreeInputAttributes(hotplug->attrs);
+ free(hotplug);
+
+ return TRUE;
+}
+
+static void
+xf86libinput_create_keyboard_subdevice(InputInfoPtr pInfo)
+{
+ struct xf86libinput *driver_data = pInfo->private;
+ struct xf86libinput_device *shared_device;
+ struct xf86libinput_hotplug_info *hotplug;
+ InputOption *iopts = NULL;
+ XF86OptionPtr options, o;
+
+ shared_device = driver_data->shared_device;
+ pInfo->options = xf86ReplaceIntOption(pInfo->options,
+ "_libinput/shared-device",
+ shared_device->id);
+
+ options = xf86OptionListDuplicate(pInfo->options);
+ options = xf86ReplaceStrOption(options, "_source", "_driver/libinput");
+ options = xf86ReplaceStrOption(options, "_libinput/caps", "keyboard");
+
+ /* need convert from one option list to the other. woohoo. */
+ o = options;
+ while (o) {
+ iopts = input_option_new(iopts,
+ xf86OptionName(o),
+ xf86OptionValue(o));
+ o = xf86NextOption(o);
+ }
+ xf86OptionListFree(options);
+
+ hotplug = calloc(1, sizeof(*hotplug));
+ if (!hotplug)
+ return;
+
+ hotplug->input_options = iopts;
+ hotplug->attrs = DuplicateInputAttributes(pInfo->attrs);
+
+ xf86IDrvMsg(pInfo, X_INFO, "needs a virtual subdevice\n");
+ QueueWorkProc(xf86libinput_hotplug_device, serverClient, hotplug);
+}
+
+static BOOL
+xf86libinput_is_subdevice(InputInfoPtr pInfo)
+{
+ char *source;
+ BOOL is_subdevice;
+
+ source = xf86SetStrOption(pInfo->options, "_source", "");
+ is_subdevice = strcmp(source, "_driver/libinput") == 0;
+ free(source);
+
+ return is_subdevice;
+}
+
static int
xf86libinput_pre_init(InputDriverPtr drv,
InputInfoPtr pInfo,
int flags)
{
struct xf86libinput *driver_data = NULL;
- struct libinput *libinput = NULL;
+ struct xf86libinput_device *shared_device = NULL;
+ struct libinput *libinput = NULL;
struct libinput_device *device;
char *path = NULL;
+ bool is_subdevice;
pInfo->type_name = 0;
pInfo->device_control = xf86libinput_device_control;
@@ -1506,25 +1839,11 @@
if (!driver_data->valuators_unaccelerated)
goto fail;
- driver_data->scroll.vdist = 15;
- driver_data->scroll.hdist = 15;
-
path = xf86SetStrOption(pInfo->options, "Device", NULL);
if (!path)
goto fail;
- if (!driver_context.libinput) {
- driver_context.libinput = libinput_path_create_context(&interface, &driver_context);
- libinput_log_set_handler(driver_context.libinput,
- xf86libinput_log_handler);
- /* we want all msgs, let the server filter */
- libinput_log_set_priority(driver_context.libinput,
- LIBINPUT_LOG_PRIORITY_DEBUG);
- xorg_list_init(&driver_context.server_fds);
- } else {
- libinput_ref(driver_context.libinput);
- }
-
+ xf86libinput_init_driver_context();
libinput = driver_context.libinput;
if (libinput == NULL) {
@@ -1532,21 +1851,60 @@
goto fail;
}
- device = libinput_path_add_device(libinput, path);
- if (!device) {
- xf86IDrvMsg(pInfo, X_ERROR, "Failed to create a device for %s\n", path);
- goto fail;
- }
+ is_subdevice = xf86libinput_is_subdevice(pInfo);
+ if (!is_subdevice) {
+ device = libinput_path_add_device(libinput, path);
+ if (!device) {
+ xf86IDrvMsg(pInfo, X_ERROR, "Failed to create a device for %s\n", path);
+ goto fail;
+ }
- /* We ref the device but remove it afterwards. The hope is that
- between now and DEVICE_INIT/DEVICE_ON, the device doesn't change.
- */
- libinput_device_ref(device);
- libinput_path_remove_device(device);
+ /* We ref the device above, then remove it. It get's
+ re-added with the same path in DEVICE_ON, we hope
+ it doesn't change until then */
+ libinput_device_ref(device);
+ libinput_path_remove_device(device);
+
+ shared_device = xf86libinput_shared_create(device);
+ if (!shared_device) {
+ libinput_device_unref(device);
+ goto fail;
+ }
+ } else {
+ InputInfoPtr parent;
+ struct xf86libinput *parent_driver_data;
+
+ parent = xf86libinput_get_parent(pInfo);
+ if (!parent) {
+ xf86IDrvMsg(pInfo, X_ERROR, "Failed to find parent device\n");
+ goto fail;
+ }
+ xf86IDrvMsg(pInfo, X_INFO, "is a virtual subdevice\n");
+
+ parent_driver_data = parent->private;
+ shared_device = xf86libinput_shared_ref(parent_driver_data->shared_device);
+ device = shared_device->device;
+ }
pInfo->private = driver_data;
+ driver_data->pInfo = pInfo;
+ driver_data->scroll.vdist = 15;
+ driver_data->scroll.hdist = 15;
driver_data->path = path;
- driver_data->device = device;
+ driver_data->shared_device = shared_device;
+ xorg_list_append(&driver_data->shared_device_link,
+ &shared_device->device_list);
+
+ if (!is_subdevice) {
+ if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER))
+ driver_data->capabilities |= CAP_POINTER;
+ if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD))
+ driver_data->capabilities |= CAP_KEYBOARD;
+ if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH))
+ driver_data->capabilities |= CAP_TOUCH;
+ } else {
+ driver_data->capabilities = CAP_KEYBOARD;
+ }
/* Disable acceleration in the server, libinput does it for us */
pInfo->options = xf86ReplaceIntOption(pInfo->options, "AccelerationProfile", -1);
@@ -1554,17 +1912,16 @@
xf86libinput_parse_options(pInfo, driver_data, device);
- /* now pick an actual type */
- if (libinput_device_config_tap_get_finger_count(device) > 0)
- pInfo->type_name = XI_TOUCHPAD;
- else if (libinput_device_has_capability(device,
- LIBINPUT_DEVICE_CAP_TOUCH))
- pInfo->type_name = XI_TOUCHSCREEN;
- else if (libinput_device_has_capability(device,
- LIBINPUT_DEVICE_CAP_POINTER))
- pInfo->type_name = XI_MOUSE;
- else
- pInfo->type_name = XI_KEYBOARD;
+ /* Device is both keyboard and pointer. Drop the keyboard cap from
+ * this device, create a separate device instead */
+ if (!is_subdevice &&
+ driver_data->capabilities & CAP_KEYBOARD &&
+ driver_data->capabilities & (CAP_POINTER|CAP_TOUCH)) {
+ driver_data->capabilities &= ~CAP_KEYBOARD;
+ xf86libinput_create_keyboard_subdevice(pInfo);
+ }
+
+ pInfo->type_name = xf86libinput_get_type_name(device, driver_data);
return Success;
fail:
@@ -1573,7 +1930,11 @@
if (driver_data->valuators_unaccelerated)
valuator_mask_free(&driver_data->valuators_unaccelerated);
free(path);
+ if (shared_device)
+ xf86libinput_shared_unref(shared_device);
free(driver_data);
+ if (libinput)
+ driver_context.libinput = libinput_unref(libinput);
return BadValue;
}
@@ -1586,6 +1947,7 @@
if (driver_data) {
driver_context.libinput = libinput_unref(driver_context.libinput);
valuator_mask_free(&driver_data->valuators);
+ valuator_mask_free(&driver_data->valuators_unaccelerated);
free(driver_data->path);
free(driver_data);
pInfo->private = NULL;
@@ -1680,7 +2042,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
if (device == NULL) {
BUG_WARN(dev->public.on);
@@ -1702,7 +2064,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
BOOL* data;
if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
@@ -1733,7 +2095,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
BOOL* data;
if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
@@ -1764,7 +2126,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
float* data;
if (val->format != 32 || val->size != 9 || val->type != prop_float)
@@ -1800,7 +2162,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
float* data;
if (val->format != 32 || val->size != 1 || val->type != prop_float)
@@ -1832,7 +2194,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
BOOL* data;
uint32_t profiles = 0;
@@ -1873,7 +2235,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
BOOL* data;
if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
@@ -1905,7 +2267,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
BOOL* data;
uint32_t modes = 0;
@@ -1944,7 +2306,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
BOOL* data;
if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
@@ -1977,7 +2339,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
BOOL* data;
uint32_t modes = 0;
@@ -2020,7 +2382,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
CARD32* data;
if (val->format != 32 || val->size != 1 || val->type != XA_CARDINAL)
@@ -2054,7 +2416,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
BOOL* data;
uint32_t modes = 0;
@@ -2095,7 +2457,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
BOOL* data;
if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
@@ -2126,7 +2488,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
BOOL* data;
if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
@@ -2835,8 +3197,7 @@
size_t sz;
int dl_values[MAX_BUTTONS + 1];
- if (!libinput_device_has_capability(driver_data->device,
- LIBINPUT_DEVICE_CAP_POINTER))
+ if ((driver_data->capabilities & CAP_POINTER) == 0)
return;
switch (draglock_get_mode(&driver_data->draglock)) {
@@ -2876,7 +3237,7 @@
{
InputInfoPtr pInfo = dev->public.devicePrivate;
struct xf86libinput *driver_data = pInfo->private;
- struct libinput_device *device = driver_data->device;
+ struct libinput_device *device = driver_data->shared_device->device;
const char *device_node;
CARD32 product[2];
int rc;