aboutsummaryrefslogtreecommitdiff
path: root/extra/libinput
diff options
context:
space:
mode:
authorCem Keylan <cem@ckyln.com>2020-10-04 22:51:57 +0300
committerCem Keylan <cem@ckyln.com>2020-10-04 22:51:57 +0300
commitbd36e113fed47de6ac33e411daf7a0b2a34bcbf6 (patch)
treeaf403d84dc696fe517683cd563a5bbb3fdccac29 /extra/libinput
parent7bc852f77943f4f92a548b3a0f43d6a0a303b585 (diff)
downloadrepository-bd36e113fed47de6ac33e411daf7a0b2a34bcbf6.tar.gz
move non xorg specific packages to extra
Diffstat (limited to 'extra/libinput')
-rwxr-xr-xextra/libinput/build18
-rw-r--r--extra/libinput/checksums2
-rw-r--r--extra/libinput/depends5
-rw-r--r--extra/libinput/message11
-rw-r--r--extra/libinput/patches/libinput-optional-udev.patch2378
-rw-r--r--extra/libinput/sources2
-rw-r--r--extra/libinput/version1
7 files changed, 2417 insertions, 0 deletions
diff --git a/extra/libinput/build b/extra/libinput/build
new file mode 100755
index 00000000..4dc16c29
--- /dev/null
+++ b/extra/libinput/build
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+
+export DESTDIR="$1"
+
+meson \
+ --prefix=/usr \
+ --sysconfdir=/etc \
+ --mandir=/usr/share/man \
+ -Ddebug-gui=false \
+ -Ddocumentation=false \
+ -Dtests=false \
+ -Dlibwacom=false \
+ -Dudev=true \
+ -Dtools=true \
+ . output
+
+ninja -C output
+ninja -C output install
diff --git a/extra/libinput/checksums b/extra/libinput/checksums
new file mode 100644
index 00000000..2857ef1c
--- /dev/null
+++ b/extra/libinput/checksums
@@ -0,0 +1,2 @@
+7ba7d1aeedd15168bb21d17e9e628aa1c27957963a423a3fea3938a501758539 libinput-1.16.1.tar.xz
+e7cadd402e0c7c8e01c2b9a6720c3648b4e44ccee9d7731d1a28413e0b4c5e98 libinput-optional-udev.patch
diff --git a/extra/libinput/depends b/extra/libinput/depends
new file mode 100644
index 00000000..d27020cb
--- /dev/null
+++ b/extra/libinput/depends
@@ -0,0 +1,5 @@
+eudev
+libevdev
+linux-headers make
+meson make
+mtdev
diff --git a/extra/libinput/message b/extra/libinput/message
new file mode 100644
index 00000000..0705708f
--- /dev/null
+++ b/extra/libinput/message
@@ -0,0 +1,11 @@
+NOTE: You must be a part of the input group
+ for libinput to work.
+
+NOTE: This groups based permissions model may not
+ be suitable if Carbs Linux will be used as a multi
+ user system. Further configuration can be
+ done at your own discretion.
+
+-> addgroup USER input
+
+NOTE: You also need xf86-input-libinput.
diff --git a/extra/libinput/patches/libinput-optional-udev.patch b/extra/libinput/patches/libinput-optional-udev.patch
new file mode 100644
index 00000000..e948b801
--- /dev/null
+++ b/extra/libinput/patches/libinput-optional-udev.patch
@@ -0,0 +1,2378 @@
+From 98e90eaec449a67e0c4216d0aac38ee9896a6a8b Mon Sep 17 00:00:00 2001
+From: Michael Forney <mforney@mforney.org>
+Date: Fri, 3 Jan 2020 17:18:10 -0800
+Subject: [PATCH] Use forward-declarations of udev structures in headers
+
+This way, it is possible for the libinput API to be implemented without
+requiring udev.
+---
+ meson.build | 7 ++-----
+ src/evdev-mt-touchpad.c | 1 +
+ src/evdev-tablet-pad-leds.c | 1 +
+ src/evdev.c | 1 +
+ src/libinput.c | 1 +
+ src/libinput.h | 4 +++-
+ src/quirks.h | 4 ++--
+ src/udev-seat.c | 1 +
+ src/udev-seat.h | 1 -
+ test/litest.h | 1 +
+ tools/libinput-debug-gui.c | 1 +
+ tools/libinput-debug-tablet.c | 1 +
+ tools/libinput-quirks.c | 1 +
+ 13 files changed, 16 insertions(+), 9 deletions(-)
+
+diff --git a/meson.build b/meson.build
+index af4c87e8..e65ac51e 100644
+--- a/meson.build
++++ b/meson.build
+@@ -278,7 +278,7 @@ src_libinput_util = [
+ ]
+ libinput_util = static_library('libinput-util',
+ src_libinput_util,
+- dependencies : [dep_udev, dep_libevdev, dep_libwacom],
++ dependencies : [dep_libevdev, dep_libwacom],
+ include_directories : includes_include)
+ dep_libinput_util = declare_dependency(link_with : libinput_util)
+
+@@ -296,7 +296,7 @@ src_libfilter = [
+ 'src/filter-private.h'
+ ]
+ libfilter = static_library('filter', src_libfilter,
+- dependencies : [dep_udev, dep_libwacom],
++ dependencies : [dep_libwacom],
+ include_directories : includes_include)
+ dep_libfilter = declare_dependency(link_with : libfilter)
+
+@@ -726,14 +726,12 @@ test('symbols-leak-test',
+ # build-test only
+ executable('test-build-pedantic',
+ 'test/build-pedantic.c',
+- dependencies : [dep_udev],
+ include_directories : [includes_src, includes_include],
+ c_args : ['-std=c99', '-pedantic', '-Werror'],
+ install : false)
+ # build-test only
+ executable('test-build-std-gnuc90',
+ 'test/build-pedantic.c',
+- dependencies : [dep_udev],
+ include_directories : [includes_src, includes_include],
+ c_args : ['-std=gnu89', '-Werror'],
+ install : false)
+@@ -747,7 +745,6 @@ executable('test-build-linker',
+ if add_languages('cpp', required: false)
+ executable('test-build-cxx',
+ 'test/build-cxx.cc',
+- dependencies : [dep_udev],
+ include_directories : [includes_src, includes_include],
+ install : false)
+ endif
+diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
+index 4ffc4a39..29faf59e 100644
+--- a/src/evdev-mt-touchpad.c
++++ b/src/evdev-mt-touchpad.c
+@@ -27,6 +27,7 @@
+ #include <math.h>
+ #include <stdbool.h>
+ #include <limits.h>
++#include <libudev.h>
+
+ #if HAVE_LIBWACOM
+ #include <libwacom/libwacom.h>
+diff --git a/src/evdev-tablet-pad-leds.c b/src/evdev-tablet-pad-leds.c
+index ff21878f..70df1d06 100644
+--- a/src/evdev-tablet-pad-leds.c
++++ b/src/evdev-tablet-pad-leds.c
+@@ -23,6 +23,7 @@
+
+ #include "config.h"
+
++#include <libudev.h>
+ #include <limits.h>
+ #include <fcntl.h>
+
+diff --git a/src/evdev.c b/src/evdev.c
+index bf85aa24..ba889b6a 100644
+--- a/src/evdev.c
++++ b/src/evdev.c
+@@ -37,6 +37,7 @@
+ #include <mtdev-plumbing.h>
+ #include <assert.h>
+ #include <math.h>
++#include <libudev.h>
+
+ #include "libinput.h"
+ #include "evdev.h"
+diff --git a/src/libinput.c b/src/libinput.c
+index e764375b..b532f1e3 100644
+--- a/src/libinput.c
++++ b/src/libinput.c
+@@ -33,6 +33,7 @@
+ #include <sys/epoll.h>
+ #include <unistd.h>
+ #include <assert.h>
++#include <libudev.h>
+
+ #include "libinput.h"
+ #include "libinput-private.h"
+diff --git a/src/libinput.h b/src/libinput.h
+index 5a19f79d..f5ae835d 100644
+--- a/src/libinput.h
++++ b/src/libinput.h
+@@ -32,12 +32,14 @@ extern "C" {
+ #include <stdlib.h>
+ #include <stdint.h>
+ #include <stdarg.h>
+-#include <libudev.h>
+
+ #define LIBINPUT_ATTRIBUTE_PRINTF(_format, _args) \
+ __attribute__ ((format (printf, _format, _args)))
+ #define LIBINPUT_ATTRIBUTE_DEPRECATED __attribute__ ((deprecated))
+
++struct udev;
++struct udev_device;
++
+ /**
+ * @ingroup base
+ * @struct libinput
+diff --git a/src/quirks.h b/src/quirks.h
+index 88159b59..526177c0 100644
+--- a/src/quirks.h
++++ b/src/quirks.h
+@@ -28,10 +28,10 @@
+ #include <stdbool.h>
+ #include <stdint.h>
+
+-#include <libudev.h>
+-
+ #include "libinput.h"
+
++struct udev_device;
++
+ /**
+ * Handle to the quirks context.
+ */
+diff --git a/src/udev-seat.c b/src/udev-seat.c
+index ce96ece3..3af01606 100644
+--- a/src/udev-seat.c
++++ b/src/udev-seat.c
+@@ -24,6 +24,7 @@
+
+ #include "config.h"
+
++#include <libudev.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <string.h>
+diff --git a/src/udev-seat.h b/src/udev-seat.h
+index ee54b422..196561db 100644
+--- a/src/udev-seat.h
++++ b/src/udev-seat.h
+@@ -26,7 +26,6 @@
+
+ #include "config.h"
+
+-#include <libudev.h>
+ #include "libinput-private.h"
+
+ struct udev_seat {
+diff --git a/test/litest.h b/test/litest.h
+index ab66ff9e..9d6598be 100644
+--- a/test/litest.h
++++ b/test/litest.h
+@@ -33,6 +33,7 @@
+ #include <libevdev/libevdev.h>
+ #include <libevdev/libevdev-uinput.h>
+ #include <libinput.h>
++#include <libudev.h>
+ #include <math.h>
+
+ #include "check-double-macros.h"
+diff --git a/tools/libinput-debug-gui.c b/tools/libinput-debug-gui.c
+index d68f1ea1..ae9364e6 100644
+--- a/tools/libinput-debug-gui.c
++++ b/tools/libinput-debug-gui.c
+@@ -29,6 +29,7 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <getopt.h>
++#include <libudev.h>
+ #include <math.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+diff --git a/tools/libinput-debug-tablet.c b/tools/libinput-debug-tablet.c
+index b2406d68..a5959fa7 100644
+--- a/tools/libinput-debug-tablet.c
++++ b/tools/libinput-debug-tablet.c
+@@ -28,6 +28,7 @@
+ #include <fcntl.h>
+ #include <inttypes.h>
+ #include <getopt.h>
++#include <libudev.h>
+ #include <poll.h>
+ #include <stdio.h>
+ #include <string.h>
+diff --git a/tools/libinput-quirks.c b/tools/libinput-quirks.c
+index 1a80f367..6aac4b1e 100644
+--- a/tools/libinput-quirks.c
++++ b/tools/libinput-quirks.c
+@@ -27,6 +27,7 @@
+ #include <stdlib.h>
+ #include <errno.h>
+ #include <getopt.h>
++#include <libudev.h>
+ #include <sys/stat.h>
+
+ #include "quirks.h"
+
+From a6f21673e13efc52fff100d315316ba14c6db848 Mon Sep 17 00:00:00 2001
+From: Michael Forney <mforney@mforney.org>
+Date: Fri, 3 Jan 2020 21:51:55 -0800
+Subject: [PATCH] Make udev optional
+
+---
+ meson.build | 568 +++++++++++++++++++-----------------
+ meson_options.txt | 8 +
+ src/evdev-mt-touchpad.c | 9 +-
+ src/evdev-tablet-pad-leds.c | 15 +-
+ src/evdev.c | 117 +++++++-
+ src/evdev.h | 5 +-
+ src/libinput.c | 5 +
+ src/path-seat.c | 115 +++++---
+ src/quirks.c | 46 +--
+ src/udev-seat.c | 25 +-
+ 10 files changed, 564 insertions(+), 349 deletions(-)
+
+diff --git a/meson.build b/meson.build
+index e65ac51e..75b393f4 100644
+--- a/meson.build
++++ b/meson.build
+@@ -122,7 +122,6 @@ endif
+
+ # Dependencies
+ pkgconfig = import('pkgconfig')
+-dep_udev = dependency('libudev')
+ dep_mtdev = dependency('mtdev', version : '>= 1.1.0')
+ dep_libevdev = dependency('libevdev')
+ dep_lm = cc.find_library('m', required : false)
+@@ -152,46 +151,54 @@ endif
+
+ ############ udev bits ############
+
+-executable('libinput-device-group',
+- 'udev/libinput-device-group.c',
+- dependencies : [dep_udev, dep_libwacom],
+- include_directories : [includes_src, includes_include],
+- install : true,
+- install_dir : dir_udev_callouts)
+-executable('libinput-fuzz-extract',
+- 'udev/libinput-fuzz-extract.c',
+- 'src/util-strings.c',
+- 'src/util-prop-parsers.c',
+- dependencies : [dep_udev, dep_libevdev, dep_lm],
+- include_directories : [includes_src, includes_include],
+- install : true,
+- install_dir : dir_udev_callouts)
+-executable('libinput-fuzz-to-zero',
+- 'udev/libinput-fuzz-to-zero.c',
+- dependencies : [dep_udev, dep_libevdev],
+- include_directories : [includes_src, includes_include],
+- install : true,
+- install_dir : dir_udev_callouts)
+-
+-udev_rules_config = configuration_data()
+-udev_rules_config.set('UDEV_TEST_PATH', '')
+-configure_file(input : 'udev/80-libinput-device-groups.rules.in',
+- output : '80-libinput-device-groups.rules',
+- install_dir : dir_udev_rules,
+- configuration : udev_rules_config)
+-configure_file(input : 'udev/90-libinput-fuzz-override.rules.in',
+- output : '90-libinput-fuzz-override.rules',
+- install_dir : dir_udev_rules,
+- configuration : udev_rules_config)
+-
+-litest_udev_rules_config = configuration_data()
+-litest_udev_rules_config.set('UDEV_TEST_PATH', meson.current_build_dir() + '/')
+-litest_groups_rules_file = configure_file(input : 'udev/80-libinput-device-groups.rules.in',
+- output : '80-libinput-device-groups-litest.rules',
+- configuration : litest_udev_rules_config)
+-litest_fuzz_override_file = configure_file(input : 'udev/90-libinput-fuzz-override.rules.in',
+- output : '90-libinput-fuzz-override-litest.rules',
+- configuration : litest_udev_rules_config)
++have_udev = get_option('udev')
++config_h.set10('HAVE_UDEV', have_udev)
++if have_udev
++ dep_udev = dependency('libudev')
++
++ executable('libinput-device-group',
++ 'udev/libinput-device-group.c',
++ dependencies : [dep_udev, dep_libwacom],
++ include_directories : [includes_src, includes_include],
++ install : true,
++ install_dir : dir_udev_callouts)
++ executable('libinput-fuzz-extract',
++ 'udev/libinput-fuzz-extract.c',
++ 'src/util-strings.c',
++ 'src/util-prop-parsers.c',
++ dependencies : [dep_udev, dep_libevdev, dep_lm],
++ include_directories : [includes_src, includes_include],
++ install : true,
++ install_dir : dir_udev_callouts)
++ executable('libinput-fuzz-to-zero',
++ 'udev/libinput-fuzz-to-zero.c',
++ dependencies : [dep_udev, dep_libevdev],
++ include_directories : [includes_src, includes_include],
++ install : true,
++ install_dir : dir_udev_callouts)
++
++ udev_rules_config = configuration_data()
++ udev_rules_config.set('UDEV_TEST_PATH', '')
++ configure_file(input : 'udev/80-libinput-device-groups.rules.in',
++ output : '80-libinput-device-groups.rules',
++ install_dir : dir_udev_rules,
++ configuration : udev_rules_config)
++ configure_file(input : 'udev/90-libinput-fuzz-override.rules.in',
++ output : '90-libinput-fuzz-override.rules',
++ install_dir : dir_udev_rules,
++ configuration : udev_rules_config)
++
++ litest_udev_rules_config = configuration_data()
++ litest_udev_rules_config.set('UDEV_TEST_PATH', meson.current_build_dir() + '/')
++ litest_groups_rules_file = configure_file(input : 'udev/80-libinput-device-groups.rules.in',
++ output : '80-libinput-device-groups-litest.rules',
++ configuration : litest_udev_rules_config)
++ litest_fuzz_override_file = configure_file(input : 'udev/90-libinput-fuzz-override.rules.in',
++ output : '90-libinput-fuzz-override-litest.rules',
++ configuration : litest_udev_rules_config)
++else
++ dep_udev = declare_dependency()
++endif
+
+ ############ Check for leftover udev rules ########
+
+@@ -465,256 +472,267 @@ endif
+ subdir('completion/zsh')
+
+ ############ tools ############
+-libinput_tool_path = dir_libexec
+-config_h.set_quoted('LIBINPUT_TOOL_PATH', libinput_tool_path)
+-tools_shared_sources = [ 'tools/shared.c',
+- 'tools/shared.h',
+- 'src/builddir.h' ]
+-deps_tools_shared = [ dep_libinput, dep_libevdev ]
+-lib_tools_shared = static_library('tools_shared',
+- tools_shared_sources,
+- include_directories : [includes_src, includes_include],
+- dependencies : deps_tools_shared)
+-dep_tools_shared = declare_dependency(link_with : lib_tools_shared,
+- dependencies : deps_tools_shared)
+-
+-man_config = configuration_data()
+-man_config.set('LIBINPUT_VERSION', meson.project_version())
+-man_config.set('LIBINPUT_DATA_DIR', dir_data)
+-
+-deps_tools = [ dep_tools_shared, dep_libinput ]
+-libinput_debug_events_sources = [
+- 'tools/libinput-debug-events.c',
+- libinput_version_h,
+-]
+-executable('libinput-debug-events',
+- libinput_debug_events_sources,
+- dependencies : deps_tools,
+- include_directories : [includes_src, includes_include],
+- install_dir : libinput_tool_path,
+- install : true
+- )
+-configure_file(input : 'tools/libinput-debug-events.man',
+- output : 'libinput-debug-events.1',
+- configuration : man_config,
+- install_dir : dir_man1,
+- )
+-
+-libinput_debug_tablet_sources = [ 'tools/libinput-debug-tablet.c' ]
+-executable('libinput-debug-tablet',
+- libinput_debug_tablet_sources,
+- dependencies : deps_tools,
+- include_directories : [includes_src, includes_include],
+- install_dir : libinput_tool_path,
+- install : true)
+-
+-configure_file(input : 'tools/libinput-debug-tablet.man',
+- output : 'libinput-debug-tablet.1',
+- configuration : man_config,
+- install_dir : dir_man1,
+- )
+-
+-libinput_quirks_sources = [ 'tools/libinput-quirks.c' ]
+-libinput_quirks = executable('libinput-quirks',
+- libinput_quirks_sources,
+- dependencies : [dep_libquirks, dep_tools_shared, dep_libinput],
+- include_directories : [includes_src, includes_include],
+- install_dir : libinput_tool_path,
+- install : true
+- )
+-test('validate-quirks',
+- libinput_quirks,
+- args: ['validate', '--data-dir=@0@'.format(dir_src_quirks)],
+- suite : ['all']
+- )
+
+-configure_file(input : 'tools/libinput-quirks.man',
+- output : 'libinput-quirks.1',
+- configuration : man_config,
+- install_dir : dir_man1,
+- )
+-# Same man page for the subtools to stay consistent with the other tools
+-configure_file(input : 'tools/libinput-quirks.man',
+- output : 'libinput-quirks-list.1',
+- configuration : man_config,
+- install_dir : dir_man1,
+- )
+-configure_file(input : 'tools/libinput-quirks.man',
+- output : 'libinput-quirks-validate.1',
+- configuration : man_config,
+- install_dir : dir_man1,
+- )
+-
+-libinput_list_devices_sources = [ 'tools/libinput-list-devices.c' ]
+-libinput_list_devices = executable('libinput-list-devices',
+- libinput_list_devices_sources,
+- dependencies : deps_tools,
+- include_directories : [includes_src, includes_include],
+- install_dir : libinput_tool_path,
+- install : true,
+- )
+-test('list-devices',
+- libinput_list_devices,
+- suite : ['all', 'root', 'hardware'])
+-
+-configure_file(input : 'tools/libinput-list-devices.man',
+- output : 'libinput-list-devices.1',
+- configuration : man_config,
+- install_dir : dir_man1,
+- )
+-
+-libinput_measure_sources = [ 'tools/libinput-measure.c' ]
+-executable('libinput-measure',
+- libinput_measure_sources,
+- dependencies : deps_tools,
+- include_directories : [includes_src, includes_include],
+- install_dir : libinput_tool_path,
+- install : true,
+- )
+-configure_file(input : 'tools/libinput-measure.man',
+- output : 'libinput-measure.1',
+- configuration : man_config,
+- install_dir : dir_man1,
+- )
+-
+-src_python_tools = files(
+- 'tools/libinput-measure-fuzz.py',
+- 'tools/libinput-measure-touchpad-tap.py',
+- 'tools/libinput-measure-touchpad-pressure.py',
+- 'tools/libinput-measure-touch-size.py',
+-)
++if get_option('tools')
++ if not have_udev
++ error('tools require -Dudev=true')
++ endif
+
+-config_noop = configuration_data()
+-# Set a dummy replacement to silence meson warnings:
+-# meson.build:487: WARNING: Got an empty configuration_data() object and
+-# found no substitutions in the input file 'foo'. If you
+-# want to copy a file to the build dir, use the 'copy:'
+-# keyword argument added in 0.47.0
+-config_noop.set('dummy', 'dummy')
+-foreach t : src_python_tools
+- configure_file(input: t,
+- output: '@BASENAME@',
+- configuration : config_noop,
+- install_dir : libinput_tool_path
+- )
+-endforeach
++ libinput_tool_path = dir_libexec
++ config_h.set_quoted('LIBINPUT_TOOL_PATH', libinput_tool_path)
++ tools_shared_sources = [ 'tools/shared.c',
++ 'tools/shared.h',
++ 'src/builddir.h' ]
++ deps_tools_shared = [ dep_libinput, dep_libevdev ]
++ lib_tools_shared = static_library('tools_shared',
++ tools_shared_sources,
++ include_directories : [includes_src, includes_include],
++ dependencies : deps_tools_shared)
++ dep_tools_shared = declare_dependency(link_with : lib_tools_shared,
++ dependencies : deps_tools_shared)
++
++ man_config = configuration_data()
++ man_config.set('LIBINPUT_VERSION', meson.project_version())
++ man_config.set('LIBINPUT_DATA_DIR', dir_data)
++
++ deps_tools = [ dep_tools_shared, dep_libinput ]
++ libinput_debug_events_sources = [
++ 'tools/libinput-debug-events.c',
++ libinput_version_h,
++ ]
++ executable('libinput-debug-events',
++ libinput_debug_events_sources,
++ dependencies : deps_tools,
++ include_directories : [includes_src, includes_include],
++ install_dir : libinput_tool_path,
++ install : true
++ )
++ configure_file(input : 'tools/libinput-debug-events.man',
++ output : 'libinput-debug-events.1',
++ configuration : man_config,
++ install_dir : dir_man1,
++ )
+
+-src_man = files(
+- 'tools/libinput-measure-fuzz.man',
+- 'tools/libinput-measure-touchpad-tap.man',
+- 'tools/libinput-measure-touchpad-pressure.man',
+- 'tools/libinput-measure-touch-size.man',
+-)
++ libinput_debug_tablet_sources = [ 'tools/libinput-debug-tablet.c' ]
++ executable('libinput-debug-tablet',
++ libinput_debug_tablet_sources,
++ dependencies : deps_tools,
++ include_directories : [includes_src, includes_include],
++ install_dir : libinput_tool_path,
++ install : true)
+
+-foreach m : src_man
+- configure_file(input : m,
+- output : '@BASENAME@.1',
++ configure_file(input : 'tools/libinput-debug-tablet.man',
++ output : 'libinput-debug-tablet.1',
+ configuration : man_config,
+- install_dir : dir_man1)
+-endforeach
++ install_dir : dir_man1,
++ )
+
+-libinput_record_sources = [ 'tools/libinput-record.c', git_version_h ]
+-executable('libinput-record',
+- libinput_record_sources,
+- dependencies : deps_tools + [dep_udev],
+- include_directories : [includes_src, includes_include],
+- install_dir : libinput_tool_path,
+- install : true,
+- )
+-configure_file(input : 'tools/libinput-record.man',
+- output : 'libinput-record.1',
+- configuration : man_config,
+- install_dir : dir_man1,
+- )
+-
+-install_data('tools/libinput-replay',
+- install_dir : libinput_tool_path)
+-configure_file(input : 'tools/libinput-replay.man',
+- output : 'libinput-replay.1',
+- configuration : man_config,
+- install_dir : dir_man1,
+- )
+-
+-if get_option('debug-gui')
+- dep_gtk = dependency('gtk+-3.0', version : '>= 3.20')
+- dep_cairo = dependency('cairo')
+- dep_glib = dependency('glib-2.0')
+-
+- debug_gui_sources = [ 'tools/libinput-debug-gui.c' ]
+- deps_debug_gui = [
+- dep_gtk,
+- dep_cairo,
+- dep_glib,
+- ] + deps_tools
+- executable('libinput-debug-gui',
+- debug_gui_sources,
+- dependencies : deps_debug_gui,
++ libinput_quirks_sources = [ 'tools/libinput-quirks.c' ]
++ libinput_quirks = executable('libinput-quirks',
++ libinput_quirks_sources,
++ dependencies : [dep_libquirks, dep_tools_shared, dep_libinput],
++ include_directories : [includes_src, includes_include],
++ install_dir : libinput_tool_path,
++ install : true
++ )
++ test('validate-quirks',
++ libinput_quirks,
++ args: ['validate', '--data-dir=@0@'.format(dir_src_quirks)],
++ suite : ['all']
++ )
++
++ configure_file(input : 'tools/libinput-quirks.man',
++ output : 'libinput-quirks.1',
++ configuration : man_config,
++ install_dir : dir_man1,
++ )
++ # Same man page for the subtools to stay consistent with the other tools
++ configure_file(input : 'tools/libinput-quirks.man',
++ output : 'libinput-quirks-list.1',
++ configuration : man_config,
++ install_dir : dir_man1,
++ )
++ configure_file(input : 'tools/libinput-quirks.man',
++ output : 'libinput-quirks-validate.1',
++ configuration : man_config,
++ install_dir : dir_man1,
++ )
++
++ libinput_list_devices_sources = [ 'tools/libinput-list-devices.c' ]
++ libinput_list_devices = executable('libinput-list-devices',
++ libinput_list_devices_sources,
++ dependencies : deps_tools,
++ include_directories : [includes_src, includes_include],
++ install_dir : libinput_tool_path,
++ install : true,
++ )
++ test('list-devices',
++ libinput_list_devices,
++ suite : ['all', 'root', 'hardware'])
++
++ configure_file(input : 'tools/libinput-list-devices.man',
++ output : 'libinput-list-devices.1',
++ configuration : man_config,
++ install_dir : dir_man1,
++ )
++
++ libinput_measure_sources = [ 'tools/libinput-measure.c' ]
++ executable('libinput-measure',
++ libinput_measure_sources,
++ dependencies : deps_tools,
+ include_directories : [includes_src, includes_include],
+ install_dir : libinput_tool_path,
+- install : true
++ install : true,
+ )
+- configure_file(input : 'tools/libinput-debug-gui.man',
+- output : 'libinput-debug-gui.1',
++ configure_file(input : 'tools/libinput-measure.man',
++ output : 'libinput-measure.1',
++ configuration : man_config,
++ install_dir : dir_man1,
++ )
++
++ src_python_tools = files(
++ 'tools/libinput-measure-fuzz.py',
++ 'tools/libinput-measure-touchpad-tap.py',
++ 'tools/libinput-measure-touchpad-pressure.py',
++ 'tools/libinput-measure-touch-size.py',
++ )
++
++ config_noop = configuration_data()
++ # Set a dummy replacement to silence meson warnings:
++ # meson.build:487: WARNING: Got an empty configuration_data() object and
++ # found no substitutions in the input file 'foo'. If you
++ # want to copy a file to the build dir, use the 'copy:'
++ # keyword argument added in 0.47.0
++ config_noop.set('dummy', 'dummy')
++ foreach t : src_python_tools
++ configure_file(input: t,
++ output: '@BASENAME@',
++ configuration : config_noop,
++ install_dir : libinput_tool_path
++ )
++ endforeach
++
++ src_man = files(
++ 'tools/libinput-measure-fuzz.man',
++ 'tools/libinput-measure-touchpad-tap.man',
++ 'tools/libinput-measure-touchpad-pressure.man',
++ 'tools/libinput-measure-touch-size.man',
++ )
++
++ foreach m : src_man
++ configure_file(input : m,
++ output : '@BASENAME@.1',
++ configuration : man_config,
++ install_dir : dir_man1)
++ endforeach
++
++ libinput_record_sources = [ 'tools/libinput-record.c', git_version_h ]
++ executable('libinput-record',
++ libinput_record_sources,
++ dependencies : deps_tools + [dep_udev],
++ include_directories : [includes_src, includes_include],
++ install_dir : libinput_tool_path,
++ install : true,
++ )
++ configure_file(input : 'tools/libinput-record.man',
++ output : 'libinput-record.1',
+ configuration : man_config,
+ install_dir : dir_man1,
+ )
+-endif
+
+-libinput_sources = [ 'tools/libinput-tool.c' ]
++ install_data('tools/libinput-replay',
++ install_dir : libinput_tool_path)
++ configure_file(input : 'tools/libinput-replay.man',
++ output : 'libinput-replay.1',
++ configuration : man_config,
++ install_dir : dir_man1,
++ )
+
+-libinput_tool = executable('libinput',
+- libinput_sources,
+- dependencies : deps_tools,
++ if get_option('debug-gui')
++ if not have_udev
++ error('debug-gui requires -Dudev=true')
++ endif
++
++ dep_gtk = dependency('gtk+-3.0', version : '>= 3.20')
++ dep_cairo = dependency('cairo')
++ dep_glib = dependency('glib-2.0')
++
++ debug_gui_sources = [ 'tools/libinput-debug-gui.c' ]
++ deps_debug_gui = [
++ dep_gtk,
++ dep_cairo,
++ dep_glib,
++ ] + deps_tools
++ executable('libinput-debug-gui',
++ debug_gui_sources,
++ dependencies : deps_debug_gui,
+ include_directories : [includes_src, includes_include],
++ install_dir : libinput_tool_path,
+ install : true
+- )
+-configure_file(input : 'tools/libinput.man',
+- output : 'libinput.1',
+- configuration : man_config,
+- install_dir : dir_man1,
+- )
+-
+-ptraccel_debug_sources = [ 'tools/ptraccel-debug.c' ]
+-executable('ptraccel-debug',
+- ptraccel_debug_sources,
+- dependencies : [ dep_libfilter, dep_libinput ],
+- include_directories : [includes_src, includes_include],
+- install : false
+- )
++ )
++ configure_file(input : 'tools/libinput-debug-gui.man',
++ output : 'libinput-debug-gui.1',
++ configuration : man_config,
++ install_dir : dir_man1,
++ )
++ endif
+
+-# Don't run the test during a release build because we rely on the magic
+-# subtool lookup
+-if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized'
+- config_tool_option_test = configuration_data()
+- config_tool_option_test.set('MESON_ENABLED_DEBUG_GUI', get_option('debug-gui'))
+- tool_option_test = configure_file(input: 'tools/test-tool-option-parsing.py',
+- output: '@BASENAME@',
+- configuration : config_tool_option_test)
+- test('tool-option-parsing',
+- tool_option_test,
+- args : ['--tool-path', libinput_tool.full_path()],
+- suite : ['all', 'root'],
+- timeout : 240)
+-endif
++ libinput_sources = [ 'tools/libinput-tool.c' ]
+
+-# the libinput tools check whether we execute from the builddir, this is
+-# the test to verify that lookup. We test twice, once as normal test
+-# run from the builddir, once after copying to /tmp
+-test_builddir_lookup = executable('test-builddir-lookup',
+- 'test/test-builddir-lookup.c',
+- dependencies : [ dep_tools_shared],
+- include_directories : [includes_src, includes_include],
+- install : false)
+-test('tools-builddir-lookup',
+- test_builddir_lookup,
+- args : ['--builddir-is-set'],
+- suite : ['all'])
+-test('tools-builddir-lookup-installed',
+- find_program('test/helper-copy-and-exec-from-tmp.sh'),
+- args : [test_builddir_lookup.full_path(), '--builddir-is-null'],
+- env : ['LD_LIBRARY_PATH=@0@'.format(meson.current_build_dir())],
+- suite : ['all'],
+- workdir : '/tmp')
++ libinput_tool = executable('libinput',
++ libinput_sources,
++ dependencies : deps_tools,
++ include_directories : [includes_src, includes_include],
++ install : true
++ )
++ configure_file(input : 'tools/libinput.man',
++ output : 'libinput.1',
++ configuration : man_config,
++ install_dir : dir_man1,
++ )
++
++ ptraccel_debug_sources = [ 'tools/ptraccel-debug.c' ]
++ executable('ptraccel-debug',
++ ptraccel_debug_sources,
++ dependencies : [ dep_libfilter, dep_libinput ],
++ include_directories : [includes_src, includes_include],
++ install : false
++ )
++
++ # Don't run the test during a release build because we rely on the magic
++ # subtool lookup
++ if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized'
++ config_tool_option_test = configuration_data()
++ config_tool_option_test.set('MESON_ENABLED_DEBUG_GUI', get_option('debug-gui'))
++ tool_option_test = configure_file(input: 'tools/test-tool-option-parsing.py',
++ output: '@BASENAME@',
++ configuration : config_tool_option_test)
++ test('tool-option-parsing',
++ tool_option_test,
++ args : ['--tool-path', libinput_tool.full_path()],
++ suite : ['all', 'root'],
++ timeout : 240)
++ endif
++
++ # the libinput tools check whether we execute from the builddir, this is
++ # the test to verify that lookup. We test twice, once as normal test
++ # run from the builddir, once after copying to /tmp
++ test_builddir_lookup = executable('test-builddir-lookup',
++ 'test/test-builddir-lookup.c',
++ dependencies : [ dep_tools_shared],
++ include_directories : [includes_src, includes_include],
++ install : false)
++ test('tools-builddir-lookup',
++ test_builddir_lookup,
++ args : ['--builddir-is-set'],
++ suite : ['all'])
++ test('tools-builddir-lookup-installed',
++ find_program('test/helper-copy-and-exec-from-tmp.sh'),
++ args : [test_builddir_lookup.full_path(), '--builddir-is-null'],
++ env : ['LD_LIBRARY_PATH=@0@'.format(meson.current_build_dir())],
++ suite : ['all'],
++ workdir : '/tmp')
++endif
+
+ ############ tests ############
+
+@@ -752,6 +770,10 @@ endif
+ # This is the test suite runner, we allow disabling that one because of
+ # dependencies
+ if get_option('tests')
++ if not have_udev
++ error('tests require -Dudev=true')
++ endif
++
+ dep_check = dependency('check', version : '>= 0.9.10')
+
+ gstack = find_program('gstack', required : false)
+diff --git a/meson_options.txt b/meson_options.txt
+index 7819449c..c1cf43a6 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -10,6 +10,10 @@ option('libwacom',
+ type: 'boolean',
+ value: true,
+ description: 'Use libwacom for tablet identification (default=true)')
++option('udev',
++ type: 'boolean',
++ value: true,
++ description: 'Use libudev for device detection (default=true)')
+ option('debug-gui',
+ type: 'boolean',
+ value: true,
+@@ -18,6 +22,10 @@ option('tests',
+ type: 'boolean',
+ value: true,
+ description: 'Build the tests [default=true]')
++option('tools',
++ type: 'boolean',
++ value: true,
++ description: 'Build the tools [default=true]')
+ option('install-tests',
+ type: 'boolean',
+ value: false,
+diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
+index 29faf59e..3f605c73 100644
+--- a/src/evdev-mt-touchpad.c
++++ b/src/evdev-mt-touchpad.c
+@@ -27,12 +27,15 @@
+ #include <math.h>
+ #include <stdbool.h>
+ #include <limits.h>
+-#include <libudev.h>
+
+ #if HAVE_LIBWACOM
+ #include <libwacom/libwacom.h>
+ #endif
+
++#if HAVE_UDEV
++#include <libudev.h>
++#endif
++
+ #include "quirks.h"
+ #include "evdev-mt-touchpad.h"
+
+@@ -2609,8 +2612,12 @@ evdev_tag_touchpad(struct evdev_device *device,
+ int bustype, vendor;
+ const char *prop;
+
++#if HAVE_UDEV
+ prop = udev_device_get_property_value(udev_device,
+ "ID_INPUT_TOUCHPAD_INTEGRATION");
++#else
++ prop = NULL;
++#endif
+ if (prop) {
+ if (streq(prop, "internal")) {
+ evdev_tag_touchpad_internal(device);
+diff --git a/src/evdev-tablet-pad-leds.c b/src/evdev-tablet-pad-leds.c
+index 70df1d06..2cdda68c 100644
+--- a/src/evdev-tablet-pad-leds.c
++++ b/src/evdev-tablet-pad-leds.c
+@@ -23,7 +23,6 @@
+
+ #include "config.h"
+
+-#include <libudev.h>
+ #include <limits.h>
+ #include <fcntl.h>
+
+@@ -33,6 +32,10 @@
+ #include <libwacom/libwacom.h>
+ #endif
+
++#if HAVE_UDEV
++#include <libudev.h>
++#endif
++
+ struct pad_led_group {
+ struct libinput_tablet_pad_mode_group base;
+ struct list led_list;
+@@ -187,8 +190,12 @@ pad_group_new_basic(struct pad_dispatch *pad,
+ static inline bool
+ is_litest_device(struct evdev_device *device)
+ {
++#if HAVE_UDEV
+ return !!udev_device_get_property_value(device->udev_device,
+ "LIBINPUT_TEST_DEVICE");
++#else
++ return false;
++#endif
+ }
+
+ static inline struct pad_led_group *
+@@ -240,6 +247,7 @@ pad_led_get_sysfs_base_path(struct evdev_device *device,
+ char *path_out,
+ size_t path_out_sz)
+ {
++#if HAVE_UDEV
+ struct udev_device *parent, *udev_device;
+ const char *test_path;
+ int rc;
+@@ -268,6 +276,9 @@ pad_led_get_sysfs_base_path(struct evdev_device *device,
+ udev_device_get_sysname(parent));
+
+ return rc != -1;
++#else
++ return false;
++#endif
+ }
+
+ #if HAVE_LIBWACOM
+@@ -499,7 +510,7 @@ pad_init_leds_from_libwacom(struct pad_dispatch *pad,
+ goto out;
+
+ wacom = libwacom_new_from_path(db,
+- udev_device_get_devnode(device->udev_device),
++ device->devnode,
+ WFALLBACK_NONE,
+ NULL);
+ if (!wacom)
+diff --git a/src/evdev.c b/src/evdev.c
+index ba889b6a..34a9d67d 100644
+--- a/src/evdev.c
++++ b/src/evdev.c
+@@ -31,13 +31,16 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/stat.h>
++#include <sys/types.h>
++#ifndef major
++#include <sys/sysmacros.h>
++#endif
+ #include "linux/input.h"
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <mtdev-plumbing.h>
+ #include <assert.h>
+ #include <math.h>
+-#include <libudev.h>
+
+ #include "libinput.h"
+ #include "evdev.h"
+@@ -50,6 +53,12 @@
+ #include <libwacom/libwacom.h>
+ #endif
+
++#if HAVE_UDEV
++#include <libudev.h>
++#endif
++
++#define INPUT_MAJOR 13
++
+ #define DEFAULT_WHEEL_CLICK_ANGLE 15
+ #define DEFAULT_BUTTON_SCROLL_TIMEOUT ms2us(200)
+
+@@ -73,6 +82,7 @@ struct evdev_udev_tag_match {
+ enum evdev_device_udev_tags tag;
+ };
+
++#if HAVE_UDEV
+ static const struct evdev_udev_tag_match evdev_udev_tag_matches[] = {
+ {"ID_INPUT", EVDEV_UDEV_TAG_INPUT},
+ {"ID_INPUT_KEYBOARD", EVDEV_UDEV_TAG_KEYBOARD},
+@@ -88,6 +98,7 @@ static const struct evdev_udev_tag_match evdev_udev_tag_matches[] = {
+ {"ID_INPUT_TRACKBALL", EVDEV_UDEV_TAG_TRACKBALL},
+ {"ID_INPUT_SWITCH", EVDEV_UDEV_TAG_SWITCH},
+ };
++#endif
+
+ static inline bool
+ parse_udev_flag(struct evdev_device *device,
+@@ -96,7 +107,11 @@ parse_udev_flag(struct evdev_device *device,
+ {
+ const char *val;
+
++#if HAVE_UDEV
+ val = udev_device_get_property_value(udev_device, property);
++#else
++ val = NULL;
++#endif
+ if (!val)
+ return false;
+
+@@ -1207,7 +1222,11 @@ evdev_read_wheel_click_prop(struct evdev_device *device,
+ int val;
+
+ *angle = DEFAULT_WHEEL_CLICK_ANGLE;
++#if HAVE_UDEV
+ prop = udev_device_get_property_value(device->udev_device, prop);
++#else
++ prop = NULL;
++#endif
+ if (!prop)
+ return false;
+
+@@ -1232,7 +1251,11 @@ evdev_read_wheel_click_count_prop(struct evdev_device *device,
+ {
+ int val;
+
++#if HAVE_UDEV
+ prop = udev_device_get_property_value(device->udev_device, prop);
++#else
++ prop = NULL;
++#endif
+ if (!prop)
+ return false;
+
+@@ -1356,8 +1379,12 @@ evdev_read_dpi_prop(struct evdev_device *device)
+ if (device->tags & EVDEV_TAG_TRACKPOINT)
+ return DEFAULT_MOUSE_DPI;
+
++#if HAVE_UDEV
+ mouse_dpi = udev_device_get_property_value(device->udev_device,
+ "MOUSE_DPI");
++#else
++ mouse_dpi = NULL;
++#endif
+ if (mouse_dpi) {
+ dpi = parse_mouse_dpi_property(mouse_dpi);
+ if (!dpi) {
+@@ -1558,9 +1585,9 @@ evdev_device_get_udev_tags(struct evdev_device *device,
+ struct udev_device *udev_device)
+ {
+ enum evdev_device_udev_tags tags = 0;
+- int i;
+
+- for (i = 0; i < 2 && udev_device; i++) {
++#if HAVE_UDEV
++ for (int i = 0; i < 2 && udev_device; i++) {
+ unsigned j;
+ for (j = 0; j < ARRAY_LENGTH(evdev_udev_tag_matches); j++) {
+ const struct evdev_udev_tag_match match = evdev_udev_tag_matches[j];
+@@ -1571,6 +1598,29 @@ evdev_device_get_udev_tags(struct evdev_device *device,
+ }
+ udev_device = udev_device_get_parent(udev_device);
+ }
++#else
++ struct libevdev *evdev = device->evdev;
++ struct stat st;
++ if (fstat(device->fd, &st) < 0)
++ return 0;
++ if (major(st.st_rdev) == INPUT_MAJOR)
++ tags |= EVDEV_UDEV_TAG_INPUT;
++ if (libevdev_has_event_code(evdev, EV_KEY, KEY_ENTER))
++ tags |= EVDEV_UDEV_TAG_KEYBOARD;
++ if (libevdev_has_event_code(evdev, EV_REL, REL_X) &&
++ libevdev_has_event_code(evdev, EV_REL, REL_Y) &&
++ libevdev_has_event_code(evdev, EV_KEY, BTN_MOUSE))
++ tags |= EVDEV_UDEV_TAG_MOUSE;
++ if (libevdev_has_event_code(evdev, EV_ABS, ABS_X) &&
++ libevdev_has_event_code(evdev, EV_ABS, ABS_Y)) {
++ if (libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_FINGER) &&
++ !libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_PEN)) {
++ tags |= EVDEV_UDEV_TAG_TOUCHPAD;
++ } else if (libevdev_has_event_code(evdev, EV_KEY, BTN_MOUSE)) {
++ tags |= EVDEV_UDEV_TAG_MOUSE;
++ }
++ }
++#endif
+
+ return tags;
+ }
+@@ -1969,6 +2019,7 @@ evdev_notify_added_device(struct evdev_device *device)
+ static bool
+ evdev_device_have_same_syspath(struct udev_device *udev_device, int fd)
+ {
++#if HAVE_UDEV
+ struct udev *udev = udev_device_get_udev(udev_device);
+ struct udev_device *udev_device_new = NULL;
+ struct stat st;
+@@ -1987,6 +2038,9 @@ evdev_device_have_same_syspath(struct udev_device *udev_device, int fd)
+ if (udev_device_new)
+ udev_device_unref(udev_device_new);
+ return rc;
++#else
++ return true;
++#endif
+ }
+
+ static bool
+@@ -1997,8 +2051,12 @@ evdev_set_device_group(struct evdev_device *device,
+ struct libinput_device_group *group = NULL;
+ const char *udev_group;
+
++#if HAVE_UDEV
+ udev_group = udev_device_get_property_value(udev_device,
+ "LIBINPUT_DEVICE_GROUP");
++#else
++ udev_group = NULL;
++#endif
+ if (udev_group)
+ group = libinput_device_group_find_group(libinput, udev_group);
+
+@@ -2105,7 +2163,7 @@ libevdev_log_func(const struct libevdev *evdev,
+ struct libinput *libinput = data;
+ enum libinput_log_priority pri = LIBINPUT_LOG_PRIORITY_ERROR;
+ const char prefix[] = "libevdev: ";
+- char fmt[strlen(format) + strlen(prefix) + 1];
++ char fmt[1024];
+
+ switch (priority) {
+ case LIBEVDEV_LOG_ERROR:
+@@ -2129,23 +2187,33 @@ udev_device_should_be_ignored(struct udev_device *udev_device)
+ {
+ const char *value;
+
++#if HAVE_UDEV
+ value = udev_device_get_property_value(udev_device,
+ "LIBINPUT_IGNORE_DEVICE");
++#else
++ value = NULL;
++#endif
+
+ return value && !streq(value, "0");
+ }
+
+ struct evdev_device *
+ evdev_device_create(struct libinput_seat *seat,
+- struct udev_device *udev_device)
++ struct udev_device *udev_device,
++ const char *devnode, const char *sysname)
+ {
+ struct libinput *libinput = seat->libinput;
+ struct evdev_device *device = NULL;
+ int rc;
+ int fd;
+ int unhandled_device = 0;
+- const char *devnode = udev_device_get_devnode(udev_device);
+- const char *sysname = udev_device_get_sysname(udev_device);
++
++#if HAVE_UDEV
++ if (udev_device) {
++ devnode = udev_device_get_devnode(udev_device);
++ sysname = udev_device_get_sysname(udev_device);
++ }
++#endif
+
+ if (!devnode) {
+ log_info(libinput, "%s: no device node associated\n", sysname);
+@@ -2193,10 +2261,16 @@ evdev_device_create(struct libinput_seat *seat,
+ device->seat_caps = 0;
+ device->is_mt = 0;
+ device->mtdev = NULL;
++#if HAVE_UDEV
+ device->udev_device = udev_device_ref(udev_device);
++#else
++ device->udev_device = NULL;
++#endif
+ device->dispatch = NULL;
+ device->fd = fd;
++ device->devnode = devnode;
+ device->devname = libevdev_get_name(device->evdev);
++ device->sysname = sysname;
+ device->scroll.threshold = 5.0; /* Default may be overridden */
+ device->scroll.direction_lock_threshold = 5.0; /* Default may be overridden */
+ device->scroll.direction = 0;
+@@ -2255,7 +2329,11 @@ evdev_device_get_output(struct evdev_device *device)
+ const char *
+ evdev_device_get_sysname(struct evdev_device *device)
+ {
++#if HAVE_UDEV
+ return udev_device_get_sysname(device->udev_device);
++#else
++ return device->sysname;
++#endif
+ }
+
+ const char *
+@@ -2279,7 +2357,11 @@ evdev_device_get_id_vendor(struct evdev_device *device)
+ struct udev_device *
+ evdev_device_get_udev_device(struct evdev_device *device)
+ {
++#if HAVE_UDEV
+ return udev_device_ref(device->udev_device);
++#else
++ return NULL;
++#endif
+ }
+
+ void
+@@ -2360,8 +2442,12 @@ evdev_read_calibration_prop(struct evdev_device *device)
+ const char *prop;
+ float calibration[6];
+
++#if HAVE_UDEV
+ prop = udev_device_get_property_value(device->udev_device,
+ "LIBINPUT_CALIBRATION_MATRIX");
++#else
++ prop = NULL;
++#endif
+
+ if (prop == NULL)
+ return;
+@@ -2396,7 +2482,11 @@ evdev_read_fuzz_prop(struct evdev_device *device, unsigned int code)
+ if (rc == -1)
+ return 0;
+
++#if HAVE_UDEV
+ prop = udev_device_get_property_value(device->udev_device, name);
++#else
++ prop = NULL;
++#endif
+ if (prop && (safe_atoi(prop, &fuzz) == false || fuzz < 0)) {
+ evdev_log_bug_libinput(device,
+ "invalid LIBINPUT_FUZZ property value: %s\n",
+@@ -2726,7 +2816,6 @@ evdev_device_resume(struct evdev_device *device)
+ {
+ struct libinput *libinput = evdev_libinput_context(device);
+ int fd;
+- const char *devnode;
+ struct input_event ev;
+ enum libevdev_read_status status;
+
+@@ -2736,11 +2825,7 @@ evdev_device_resume(struct evdev_device *device)
+ if (device->was_removed)
+ return -ENODEV;
+
+- devnode = udev_device_get_devnode(device->udev_device);
+- if (!devnode)
+- return -ENODEV;
+-
+- fd = open_restricted(libinput, devnode,
++ fd = open_restricted(libinput, device->devnode,
+ O_RDWR | O_NONBLOCK | O_CLOEXEC);
+
+ if (fd < 0)
+@@ -2839,7 +2924,9 @@ evdev_device_destroy(struct evdev_device *device)
+ libinput_timer_destroy(&device->middlebutton.timer);
+ libinput_seat_unref(device->base.seat);
+ libevdev_free(device->evdev);
++#if HAVE_UDEV
+ udev_device_unref(device->udev_device);
++#endif
+ free(device);
+ }
+
+@@ -2852,17 +2939,15 @@ evdev_tablet_has_left_handed(struct evdev_device *device)
+ WacomDeviceDatabase *db = NULL;
+ WacomDevice *d = NULL;
+ WacomError *error;
+- const char *devnode;
+
+ db = libinput_libwacom_ref(li);
+ if (!db)
+ goto out;
+
+ error = libwacom_error_new();
+- devnode = udev_device_get_devnode(device->udev_device);
+
+ d = libwacom_new_from_path(db,
+- devnode,
++ device->devnode,
+ WFALLBACK_NONE,
+ error);
+
+diff --git a/src/evdev.h b/src/evdev.h
+index e95f7e60..490d542e 100644
+--- a/src/evdev.h
++++ b/src/evdev.h
+@@ -167,7 +167,9 @@ struct evdev_device {
+ struct libevdev *evdev;
+ struct udev_device *udev_device;
+ char *output_name;
++ const char *devnode;
+ const char *devname;
++ const char *sysname;
+ bool was_removed;
+ int fd;
+ enum evdev_device_seat_capability seat_caps;
+@@ -375,7 +377,8 @@ evdev_verify_dispatch_type(struct evdev_dispatch *dispatch,
+
+ struct evdev_device *
+ evdev_device_create(struct libinput_seat *seat,
+- struct udev_device *device);
++ struct udev_device *device,
++ const char *devnode, const char *sysname);
+
+ static inline struct libinput *
+ evdev_libinput_context(const struct evdev_device *device)
+diff --git a/src/libinput.c b/src/libinput.c
+index b532f1e3..76c41d6f 100644
+--- a/src/libinput.c
++++ b/src/libinput.c
+@@ -33,7 +33,10 @@
+ #include <sys/epoll.h>
+ #include <unistd.h>
+ #include <assert.h>
++
++#if HAVE_UDEV
+ #include <libudev.h>
++#endif
+
+ #include "libinput.h"
+ #include "libinput-private.h"
+@@ -1974,9 +1977,11 @@ close_restricted(struct libinput *libinput, int fd)
+ bool
+ ignore_litest_test_suite_device(struct udev_device *device)
+ {
++#if HAVE_UDEV
+ if (!getenv("LIBINPUT_RUNNING_TEST_SUITE") &&
+ udev_device_get_property_value(device, "LIBINPUT_TEST_DEVICE"))
+ return true;
++#endif
+
+ return false;
+ }
+diff --git a/src/path-seat.c b/src/path-seat.c
+index 99b089a4..22bf06c9 100644
+--- a/src/path-seat.c
++++ b/src/path-seat.c
+@@ -25,7 +25,9 @@
+
+ #include <string.h>
+ #include <sys/stat.h>
++#if HAVE_UDEV
+ #include <libudev.h>
++#endif
+
+ #include "evdev.h"
+
+@@ -38,6 +40,8 @@ struct path_input {
+ struct path_device {
+ struct list link;
+ struct udev_device *udev_device;
++ const char *devnode;
++ const char *sysname;
+ };
+
+ struct path_seat {
+@@ -121,33 +125,36 @@ path_seat_get_named(struct path_input *input,
+
+ static struct path_seat *
+ path_seat_get_for_device(struct path_input *input,
+- struct udev_device *udev_device,
++ struct path_device *dev,
+ const char *seat_logical_name_override)
+ {
+ struct path_seat *seat = NULL;
+ char *seat_name = NULL, *seat_logical_name = NULL;
+ const char *seat_prop;
+
+- const char *devnode, *sysname;
+-
+- devnode = udev_device_get_devnode(udev_device);
+- sysname = udev_device_get_sysname(udev_device);
+-
+- seat_prop = udev_device_get_property_value(udev_device, "ID_SEAT");
++#if HAVE_UDEV
++ seat_prop = udev_device_get_property_value(dev->udev_device, "ID_SEAT");
++#else
++ seat_prop = NULL;
++#endif
+ seat_name = safe_strdup(seat_prop ? seat_prop : default_seat);
+
+ if (seat_logical_name_override) {
+ seat_logical_name = safe_strdup(seat_logical_name_override);
+ } else {
+- seat_prop = udev_device_get_property_value(udev_device, "WL_SEAT");
++#if HAVE_UDEV
++ seat_prop = udev_device_get_property_value(dev->udev_device, "WL_SEAT");
++#else
++ seat_prop = NULL;
++#endif
+ seat_logical_name = strdup(seat_prop ? seat_prop : default_seat_name);
+ }
+
+ if (!seat_logical_name) {
+ log_error(&input->base,
+ "%s: failed to create seat name for device '%s'.\n",
+- sysname,
+- devnode);
++ dev->sysname,
++ dev->devnode);
+ goto out;
+ }
+
+@@ -158,8 +165,8 @@ path_seat_get_for_device(struct path_input *input,
+ if (!seat) {
+ log_info(&input->base,
+ "%s: failed to create seat for device '%s'.\n",
+- sysname,
+- devnode);
++ dev->sysname,
++ dev->devnode);
+ goto out;
+ }
+
+@@ -173,41 +180,41 @@ path_seat_get_for_device(struct path_input *input,
+
+ static struct libinput_device *
+ path_device_enable(struct path_input *input,
+- struct udev_device *udev_device,
++ struct path_device *dev,
+ const char *seat_logical_name_override)
+ {
+ struct path_seat *seat;
+ struct evdev_device *device = NULL;
+ const char *output_name;
+- const char *devnode, *sysname;
+-
+- devnode = udev_device_get_devnode(udev_device);
+- sysname = udev_device_get_sysname(udev_device);
+
+- seat = path_seat_get_for_device(input, udev_device, seat_logical_name_override);
++ seat = path_seat_get_for_device(input, dev, seat_logical_name_override);
+ if (!seat)
+ goto out;
+
+- device = evdev_device_create(&seat->base, udev_device);
++ device = evdev_device_create(&seat->base, dev->udev_device, dev->devnode, dev->sysname);
+ libinput_seat_unref(&seat->base);
+
+ if (device == EVDEV_UNHANDLED_DEVICE) {
+ device = NULL;
+ log_info(&input->base,
+ "%-7s - not using input device '%s'.\n",
+- sysname,
+- devnode);
++ dev->sysname,
++ dev->devnode);
+ goto out;
+ } else if (device == NULL) {
+ log_info(&input->base,
+ "%-7s - failed to create input device '%s'.\n",
+- sysname,
+- devnode);
++ dev->sysname,
++ dev->devnode);
+ goto out;
+ }
+
+ evdev_read_calibration_prop(device);
+- output_name = udev_device_get_property_value(udev_device, "WL_OUTPUT");
++#if HAVE_UDEV
++ output_name = udev_device_get_property_value(dev->udev_device, "WL_OUTPUT");
++#else
++ output_name = NULL;
++#endif
+ device->output_name = safe_strdup(output_name);
+
+ out:
+@@ -221,7 +228,7 @@ path_input_enable(struct libinput *libinput)
+ struct path_device *dev;
+
+ list_for_each(dev, &input->path_list, link) {
+- if (path_device_enable(input, dev->udev_device, NULL) == NULL) {
++ if (path_device_enable(input, dev, NULL) == NULL) {
+ path_input_disable(libinput);
+ return -1;
+ }
+@@ -234,7 +241,11 @@ static void
+ path_device_destroy(struct path_device *dev)
+ {
+ list_remove(&dev->link);
++#if HAVE_UDEV
+ udev_device_unref(dev->udev_device);
++#else
++ free((char *)dev->devnode);
++#endif
+ free(dev);
+ }
+
+@@ -244,16 +255,18 @@ path_input_destroy(struct libinput *input)
+ struct path_input *path_input = (struct path_input*)input;
+ struct path_device *dev, *tmp;
+
++#if HAVE_UDEV
+ udev_unref(path_input->udev);
++#endif
+
+ list_for_each_safe(dev, tmp, &path_input->path_list, link)
+ path_device_destroy(dev);
+-
+ }
+
+ static struct libinput_device *
+ path_create_device(struct libinput *libinput,
+ struct udev_device *udev_device,
++ const char *devnode,
+ const char *seat_name)
+ {
+ struct path_input *input = (struct path_input*)libinput;
+@@ -261,11 +274,23 @@ path_create_device(struct libinput *libinput,
+ struct libinput_device *device;
+
+ dev = zalloc(sizeof *dev);
++#if HAVE_UDEV
+ dev->udev_device = udev_device_ref(udev_device);
++ dev->devnode = udev_device_get_devnode(udev_device);
++ dev->sysname = udev_device_get_sysname(udev_device);
++#else
++ dev->udev_device = NULL;
++ dev->devnode = safe_strdup(devnode);
++ dev->sysname = strrchr(devnode, '/');
++ if (dev->sysname)
++ ++dev->sysname;
++ else
++ dev->sysname = "";
++#endif
+
+ list_insert(&input->path_list, &dev->link);
+
+- device = path_device_enable(input, udev_device, seat_name);
++ device = path_device_enable(input, dev, seat_name);
+
+ if (!device)
+ path_device_destroy(dev);
+@@ -280,15 +305,24 @@ path_device_change_seat(struct libinput_device *device,
+ struct libinput *libinput = device->seat->libinput;
+ struct evdev_device *evdev = evdev_device(device);
+ struct udev_device *udev_device = NULL;
++ char *devnode = NULL;
+ int rc = -1;
+
++#if HAVE_UDEV
+ udev_device = evdev->udev_device;
+ udev_device_ref(udev_device);
++#else
++ devnode = strdup(evdev->devnode);
++ if (!devnode)
++ return -1;
++#endif
+ libinput_path_remove_device(device);
+
+- if (path_create_device(libinput, udev_device, seat_name) != NULL)
++ if (path_create_device(libinput, udev_device, devnode, seat_name) != NULL)
+ rc = 0;
++#if HAVE_UDEV
+ udev_device_unref(udev_device);
++#endif
+ return rc;
+ }
+
+@@ -309,14 +343,20 @@ libinput_path_create_context(const struct libinput_interface *interface,
+ if (!interface)
+ return NULL;
+
++#if HAVE_UDEV
+ udev = udev_new();
+ if (!udev)
+ return NULL;
++#else
++ udev = NULL;
++#endif
+
+ input = zalloc(sizeof *input);
+ if (libinput_init(&input->base, interface,
+ &interface_backend, user_data) != 0) {
++#if HAVE_UDEV
+ udev_unref(udev);
++#endif
+ free(input);
+ return NULL;
+ }
+@@ -327,6 +367,7 @@ libinput_path_create_context(const struct libinput_interface *interface,
+ return &input->base;
+ }
+
++#if HAVE_UDEV
+ static inline struct udev_device *
+ udev_device_from_devnode(struct libinput *libinput,
+ struct udev *udev,
+@@ -356,13 +397,12 @@ udev_device_from_devnode(struct libinput *libinput,
+
+ return dev;
+ }
++#endif
+
+ LIBINPUT_EXPORT struct libinput_device *
+ libinput_path_add_device(struct libinput *libinput,
+ const char *path)
+ {
+- struct path_input *input = (struct path_input *)libinput;
+- struct udev *udev = input->udev;
+ struct udev_device *udev_device;
+ struct libinput_device *device;
+
+@@ -378,7 +418,10 @@ libinput_path_add_device(struct libinput *libinput,
+ return NULL;
+ }
+
+- udev_device = udev_device_from_devnode(libinput, udev, path);
++#if HAVE_UDEV
++ struct path_input *input = (struct path_input *)libinput;
++
++ udev_device = udev_device_from_devnode(libinput, input->udev, path);
+ if (!udev_device) {
+ log_bug_client(libinput, "Invalid path %s\n", path);
+ return NULL;
+@@ -388,6 +431,9 @@ libinput_path_add_device(struct libinput *libinput,
+ udev_device_unref(udev_device);
+ return NULL;
+ }
++#else
++ udev_device = NULL;
++#endif
+
+ /* We cannot do this during path_create_context because the log
+ * handler isn't set up there but we really want to log to the right
+@@ -396,8 +442,10 @@ libinput_path_add_device(struct libinput *libinput,
+ */
+ libinput_init_quirks(libinput);
+
+- device = path_create_device(libinput, udev_device, NULL);
++ device = path_create_device(libinput, udev_device, path, NULL);
++#if HAVE_UDEV
+ udev_device_unref(udev_device);
++#endif
+ return device;
+ }
+
+@@ -416,7 +464,8 @@ libinput_path_remove_device(struct libinput_device *device)
+ }
+
+ list_for_each(dev, &input->path_list, link) {
+- if (dev->udev_device == evdev->udev_device) {
++ if (dev->udev_device == evdev->udev_device &&
++ dev->devnode == evdev->devnode) {
+ path_device_destroy(dev);
+ break;
+ }
+diff --git a/src/quirks.c b/src/quirks.c
+index 8c0bb96e..ea13f9a7 100644
+--- a/src/quirks.c
++++ b/src/quirks.c
+@@ -31,11 +31,14 @@
+ #undef NDEBUG /* You don't get to disable asserts here */
+ #include <assert.h>
+ #include <stdlib.h>
+-#include <libudev.h>
+ #include <dirent.h>
+ #include <fnmatch.h>
+ #include <libgen.h>
+
++#if HAVE_UDEV
++#include <libudev.h>
++#endif
++
+ #include "libinput-versionsort.h"
+ #include "libinput-util.h"
+
+@@ -348,34 +351,22 @@ property_cleanup(struct property *p)
+ static inline char *
+ init_dmi(void)
+ {
+- struct udev *udev;
+- struct udev_device *udev_device;
+- const char *modalias = NULL;
++ char modalias[1024];
+ char *copy = NULL;
+- const char *syspath = "/sys/devices/virtual/dmi/id";
++ const char *syspath = "/sys/devices/virtual/dmi/id/modalias";
++ FILE *fp;
+
+ if (getenv("LIBINPUT_RUNNING_TEST_SUITE"))
+ return safe_strdup("dmi:");
+
+- udev = udev_new();
+- if (!udev)
++ fp = fopen(syspath, "r");
++ if (!fp)
+ return NULL;
+
+- udev_device = udev_device_new_from_syspath(udev, syspath);
+- if (udev_device)
+- modalias = udev_device_get_property_value(udev_device,
+- "MODALIAS");
+-
+- /* Not sure whether this could ever really fail, if so we should
+- * open the sysfs file directly. But then udev wouldn't have failed,
+- * so... */
+- if (!modalias)
+- modalias = "dmi:*";
++ if (fgets(modalias, sizeof(modalias), fp))
++ copy = safe_strdup(modalias);
+
+- copy = safe_strdup(modalias);
+-
+- udev_device_unref(udev_device);
+- udev_unref(udev);
++ fclose(fp);
+
+ return copy;
+ }
+@@ -1100,6 +1091,7 @@ quirks_context_unref(struct quirks_context *ctx)
+ return NULL;
+ }
+
++#if HAVE_UDEV
+ static struct quirks *
+ quirks_new(void)
+ {
+@@ -1112,6 +1104,7 @@ quirks_new(void)
+
+ return q;
+ }
++#endif
+
+ struct quirks *
+ quirks_unref(struct quirks *q)
+@@ -1142,13 +1135,16 @@ quirks_unref(struct quirks *q)
+ static const char *
+ udev_prop(struct udev_device *device, const char *prop)
+ {
+- struct udev_device *d = device;
+ const char *value = NULL;
+
++#if HAVE_UDEV
++ struct udev_device *d = device;
++
+ do {
+ value = udev_device_get_property_value(d, prop);
+ d = udev_device_get_parent(d);
+ } while (value == NULL && d != NULL);
++#endif
+
+ return value;
+ }
+@@ -1262,6 +1258,7 @@ match_fill_dmi_dt(struct match *m, char *dmi, char *dt)
+ }
+ }
+
++#if HAVE_UDEV
+ static struct match *
+ match_new(struct udev_device *device,
+ char *dmi, char *dt)
+@@ -1387,11 +1384,13 @@ quirk_match_section(struct quirks_context *ctx,
+
+ return true;
+ }
++#endif
+
+ struct quirks *
+ quirks_fetch_for_device(struct quirks_context *ctx,
+ struct udev_device *udev_device)
+ {
++#if HAVE_UDEV
+ struct quirks *q = NULL;
+ struct section *s;
+ struct match *m;
+@@ -1420,6 +1419,9 @@ quirks_fetch_for_device(struct quirks_context *ctx,
+ list_insert(&ctx->quirks, &q->link);
+
+ return q;
++#else
++ return NULL;
++#endif
+ }
+
+
+diff --git a/src/udev-seat.c b/src/udev-seat.c
+index 3af01606..df280d9a 100644
+--- a/src/udev-seat.c
++++ b/src/udev-seat.c
+@@ -24,6 +24,8 @@
+
+ #include "config.h"
+
++#if HAVE_UDEV
++
+ #include <libudev.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+@@ -81,7 +83,7 @@ device_added(struct udev_device *udev_device,
+ return -1;
+ }
+
+- device = evdev_device_create(&seat->base, udev_device);
++ device = evdev_device_create(&seat->base, udev_device, NULL, NULL);
+ libinput_seat_unref(&seat->base);
+
+ if (device == EVDEV_UNHANDLED_DEVICE) {
+@@ -412,3 +414,24 @@ libinput_udev_assign_seat(struct libinput *libinput,
+
+ return 0;
+ }
++
++#else
++
++#include "udev-seat.h"
++
++LIBINPUT_EXPORT struct libinput *
++libinput_udev_create_context(const struct libinput_interface *interface,
++ void *user_data,
++ struct udev *udev)
++{
++ return NULL;
++}
++
++LIBINPUT_EXPORT int
++libinput_udev_assign_seat(struct libinput *libinput,
++ const char *seat_id)
++{
++ return -1;
++}
++
++#endif /* HAVE_UDEV */
+
+From 597b16f5134b8d095039efb3a27a4d0b643718c3 Mon Sep 17 00:00:00 2001
+From: Michael Forney <mforney@mforney.org>
+Date: Fri, 3 Jan 2020 22:08:41 -0800
+Subject: [PATCH] Add netlink seat
+
+---
+ meson.build | 2 +
+ src/libinput.h | 42 +++++
+ src/netlink-seat.c | 373 +++++++++++++++++++++++++++++++++++++++++++++
+ src/netlink-seat.h | 42 +++++
+ 4 files changed, 459 insertions(+)
+ create mode 100644 src/netlink-seat.c
+ create mode 100644 src/netlink-seat.h
+
+diff --git a/meson.build b/meson.build
+index 75b393f4..7d66eba2 100644
+--- a/meson.build
++++ b/meson.build
+@@ -392,6 +392,8 @@ src_libinput = src_libfilter + [
+ 'src/evdev-tablet-pad.c',
+ 'src/evdev-tablet-pad.h',
+ 'src/evdev-tablet-pad-leds.c',
++ 'src/netlink-seat.c',
++ 'src/netlink-seat.h',
+ 'src/path-seat.c',
+ 'src/udev-seat.c',
+ 'src/udev-seat.h',
+diff --git a/src/libinput.h b/src/libinput.h
+index f5ae835d..b90cb4ab 100644
+--- a/src/libinput.h
++++ b/src/libinput.h
+@@ -3304,6 +3304,7 @@ libinput_event_switch_get_time_usec(struct libinput_event_switch *event);
+ *
+ * @see libinput_udev_create_context
+ * @see libinput_path_create_context
++ * @see libinput_netlink_create_context
+ */
+ struct libinput_interface {
+ /**
+@@ -3439,6 +3440,47 @@ libinput_path_add_device(struct libinput *libinput,
+ void
+ libinput_path_remove_device(struct libinput_device *device);
+
++/**
++ * @ingroup base
++ *
++ * Create a new libinput context from netlink. This context is inactive until
++ * assigned a seat ID with libinput_netlink_assign_seat().
++ *
++ * @param interface The callback interface
++ * @param user_data Caller-specific data passed to the various callback
++ * interfaces.
++ *
++ * @return An initialized, but inactive libinput context or NULL on error
++ */
++struct libinput *
++libinput_netlink_create_context(const struct libinput_interface *interface,
++ void *user_data);
++
++/**
++ * @ingroup base
++ *
++ * Assign a seat to this libinput context. New devices or the removal of
++ * existing devices will appear as events during libinput_dispatch().
++ *
++ * libinput_netlink_assign_seat() succeeds even if no input devices are currently
++ * available on this seat, or if devices are available but fail to open in
++ * @ref libinput_interface::open_restricted. Devices that do not have the
++ * minimum capabilities to be recognized as pointer, keyboard or touch
++ * device are ignored. Such devices and those that failed to open
++ * ignored until the next call to libinput_resume().
++ *
++ * This function may only be called once per context.
++ *
++ * @param libinput A libinput context initialized with
++ * libinput_udev_create_context()
++ * @param seat_id A seat identifier. This string must not be NULL.
++ *
++ * @return 0 on success or -1 on failure.
++ */
++int
++libinput_netlink_assign_seat(struct libinput *libinput,
++ const char *seat_id);
++
+ /**
+ * @ingroup base
+ *
+diff --git a/src/netlink-seat.c b/src/netlink-seat.c
+new file mode 100644
+index 00000000..d22a2821
+--- /dev/null
++++ b/src/netlink-seat.c
+@@ -0,0 +1,373 @@
++/*
++ * Copyright © 2013 Intel Corporation
++ * Copyright © 2013-2015 Red Hat, Inc.
++ * Copyright © 2017 Michael Forney
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ */
++
++#include "config.h"
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <dirent.h>
++
++#include <sys/socket.h>
++#include <linux/netlink.h>
++
++#include "evdev.h"
++#include "netlink-seat.h"
++
++#define INPUT_MAJOR 13
++
++static const char default_seat[] = "seat0";
++static const char default_seat_name[] = "default";
++
++static struct netlink_seat *
++netlink_seat_create(struct netlink_input *input,
++ const char *device_seat,
++ const char *seat_name);
++static struct netlink_seat *
++netlink_seat_get_named(struct netlink_input *input, const char *seat_name);
++
++static int
++device_added(struct netlink_input *input,
++ const char *devnode)
++{
++ struct evdev_device *device;
++ const char *device_seat, *seat_name, *sysname;
++ struct netlink_seat *seat;
++
++ device_seat = default_seat;
++ seat_name = default_seat_name;
++ seat = netlink_seat_get_named(input, seat_name);
++
++ if (seat)
++ libinput_seat_ref(&seat->base);
++ else {
++ seat = netlink_seat_create(input, device_seat, seat_name);
++ if (!seat)
++ return -1;
++ }
++
++ sysname = strrchr(devnode, '/');
++ if (sysname)
++ ++sysname;
++ else
++ sysname = "";
++
++ device = evdev_device_create(&seat->base, NULL, devnode, sysname);
++ libinput_seat_unref(&seat->base);
++
++ if (device == EVDEV_UNHANDLED_DEVICE) {
++ log_info(&input->base,
++ "%-7s - not using input device '%s'\n",
++ sysname,
++ devnode);
++ return 0;
++ } else if (device == NULL) {
++ log_info(&input->base,
++ "%-7s - failed to create input device '%s'\n",
++ sysname,
++ devnode);
++ return 0;
++ }
++
++ evdev_read_calibration_prop(device);
++
++ return 0;
++}
++
++static void
++device_removed(struct netlink_input *input, const char *devnode)
++{
++ struct evdev_device *device, *next;
++ struct netlink_seat *seat;
++
++ list_for_each(seat, &input->base.seat_list, base.link) {
++ list_for_each_safe(device, next,
++ &seat->base.devices_list, base.link) {
++ if (streq(devnode, device->devnode)) {
++ evdev_device_remove(device);
++ break;
++ }
++ }
++ }
++}
++
++static int
++select_device(const struct dirent *entry)
++{
++ const char *p;
++
++ if (strncmp(entry->d_name, "event", 5) != 0)
++ return 0;
++ for (p = entry->d_name + 5; '0' <= *p && *p <= '9'; ++p)
++ ;
++ return *p == '\0';
++}
++
++static int
++netlink_input_add_devices(struct netlink_input *input)
++{
++ struct dirent **devices;
++ char path[PATH_MAX];
++ int i, n, len;
++
++ n = scandir("/dev/input", &devices, &select_device, &alphasort);
++ if (n == -1)
++ return -1;
++ for (i = 0; i < n; ++i) {
++ len = snprintf(path, sizeof(path), "/dev/input/%s", devices[i]->d_name);
++ free(devices[i]);
++ if (len < 0 || (size_t)len >= sizeof(path)) {
++ free(devices);
++ return -1;
++ }
++ device_added(input, path);
++ }
++ free(devices);
++
++ return 0;
++}
++
++static void
++netlink_input_remove_devices(struct netlink_input *input)
++{
++ struct evdev_device *device, *next;
++ struct netlink_seat *seat, *tmp;
++
++ list_for_each_safe(seat, tmp, &input->base.seat_list, base.link) {
++ libinput_seat_ref(&seat->base);
++ list_for_each_safe(device, next,
++ &seat->base.devices_list, base.link) {
++ evdev_device_remove(device);
++ }
++ libinput_seat_unref(&seat->base);
++ }
++}
++
++static void
++netlink_input_disable(struct libinput *libinput)
++{
++ struct netlink_input *input = (struct netlink_input*)libinput;
++
++ if (input->sock == -1)
++ return;
++
++ close(input->sock);
++ input->sock = -1;
++ libinput_remove_source(&input->base, input->source);
++ input->source = NULL;
++
++ netlink_input_remove_devices(input);
++}
++
++static void
++netlink_handler(void *data)
++{
++ struct netlink_input *input = data;
++ char buf[BUFSIZ], *key, *val;
++ ssize_t n;
++ size_t len;
++ char *action = NULL, *devname = NULL, *devnode, *sysname;
++
++ n = read(input->sock, buf, sizeof(buf));
++ if (n <= 0)
++ return;
++ for (key = buf; key < buf + n; key += len + 1) {
++ len = strlen(key);
++ val = strchr(key, '=');
++ if (!val)
++ continue;
++ *val++ = '\0';
++ if (strcmp(key, "ACTION") == 0) {
++ action = val;
++ } else if (strcmp(key, "SUBSYSTEM") == 0) {
++ if (strcmp(val, "input") != 0)
++ return;
++ } else if (strcmp(key, "DEVNAME") == 0) {
++ devname = val;
++ }
++ }
++ if (!action || !devname)
++ return;
++ sysname = strrchr(devname, '/');
++ if (sysname)
++ ++sysname;
++ else
++ sysname = devname;
++ if (strncmp(sysname, "event", 5) != 0)
++ return;
++ devnode = devname - 5;
++ memcpy(devnode, "/dev/", 5);
++ if (strcmp(action, "add") == 0)
++ device_added(input, devnode);
++ else if (strcmp(action, "remove") == 0)
++ device_removed(input, devnode);
++}
++
++static int
++netlink_input_enable(struct libinput *libinput)
++{
++ int s;
++ struct sockaddr_nl addr = {
++ .nl_family = AF_NETLINK,
++ .nl_groups = 1,
++ };
++ struct netlink_input *input = (struct netlink_input*)libinput;
++
++ if (input->sock != -1)
++ return 0;
++ s = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
++ if (s == -1)
++ return -1;
++ if (bind(s, (void *)&addr, sizeof(addr)) < 0) {
++ close(s);
++ return -1;
++ }
++ input->source = libinput_add_fd(&input->base, s, netlink_handler, input);
++ if (!input->source) {
++ close(s);
++ return -1;
++ }
++ input->sock = s;
++ if (netlink_input_add_devices(input) < 0) {
++ netlink_input_disable(libinput);
++ return -1;
++ }
++
++ return 0;
++}
++
++static void
++netlink_input_destroy(struct libinput *input)
++{
++}
++
++static void
++netlink_seat_destroy(struct libinput_seat *seat)
++{
++ struct netlink_seat *nseat = (struct netlink_seat*)seat;
++ free(nseat);
++}
++
++static struct netlink_seat *
++netlink_seat_create(struct netlink_input *input,
++ const char *device_seat,
++ const char *seat_name)
++{
++ struct netlink_seat *seat;
++
++ seat = zalloc(sizeof(*seat));
++
++ libinput_seat_init(&seat->base, &input->base,
++ device_seat, seat_name,
++ netlink_seat_destroy);
++
++ return seat;
++}
++
++static struct netlink_seat *
++netlink_seat_get_named(struct netlink_input *input, const char *seat_name)
++{
++ struct netlink_seat *seat;
++
++ list_for_each(seat, &input->base.seat_list, base.link) {
++ if (streq(seat->base.logical_name, seat_name))
++ return seat;
++ }
++
++ return NULL;
++}
++
++static int
++netlink_device_change_seat(struct libinput_device *device,
++ const char *seat_name)
++{
++ struct libinput *libinput = device->seat->libinput;
++ struct netlink_input *input = (struct netlink_input *)libinput;
++ struct evdev_device *evdev = evdev_device(device);
++ char *devnode;
++ int rc;
++
++ devnode = safe_strdup(evdev->devnode);
++ device_removed(input, devnode);
++ rc = device_added(input, devnode);
++ free(devnode);
++
++ return rc;
++}
++
++static const struct libinput_interface_backend interface_backend = {
++ .resume = netlink_input_enable,
++ .suspend = netlink_input_disable,
++ .destroy = netlink_input_destroy,
++ .device_change_seat = netlink_device_change_seat,
++};
++
++LIBINPUT_EXPORT struct libinput *
++libinput_netlink_create_context(const struct libinput_interface *interface,
++ void *user_data)
++{
++ struct netlink_input *input;
++
++ if (!interface)
++ return NULL;
++
++ input = zalloc(sizeof(*input));
++ input->sock = -1;
++
++ if (libinput_init(&input->base, interface,
++ &interface_backend, user_data) != 0) {
++ libinput_unref(&input->base);
++ free(input);
++ return NULL;
++ }
++
++ return &input->base;
++}
++
++LIBINPUT_EXPORT int
++libinput_netlink_assign_seat(struct libinput *libinput,
++ const char *seat_id)
++{
++ struct netlink_input *input = (struct netlink_input*)libinput;
++
++ if (libinput->interface_backend != &interface_backend) {
++ log_bug_client(libinput, "Mismatching backends.\n");
++ return -1;
++ }
++
++ /* We cannot do this during netlink_create_context because the log
++ * handler isn't set up there but we really want to log to the right
++ * place if the quirks run into parser errors. So we have to do it
++ * here since we can expect the log handler to be set up by now.
++ */
++ libinput_init_quirks(libinput);
++
++ if (netlink_input_enable(&input->base) < 0)
++ return -1;
++
++ return 0;
++}
+diff --git a/src/netlink-seat.h b/src/netlink-seat.h
+new file mode 100644
+index 00000000..cd8d3ef2
+--- /dev/null
++++ b/src/netlink-seat.h
+@@ -0,0 +1,42 @@
++/*
++ * Copyright © 2013 Intel Corporation
++ * Copyright © 2017 Michael Forney
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ */
++
++#ifndef _NETLINK_SEAT_H_
++#define _NETLINK_SEAT_H_
++
++#include "config.h"
++
++#include "libinput-private.h"
++
++struct netlink_seat {
++ struct libinput_seat base;
++};
++
++struct netlink_input {
++ struct libinput base;
++ struct libinput_source *source;
++ int sock;
++};
++
++#endif
+
diff --git a/extra/libinput/sources b/extra/libinput/sources
new file mode 100644
index 00000000..d7163f0e
--- /dev/null
+++ b/extra/libinput/sources
@@ -0,0 +1,2 @@
+https://www.freedesktop.org/software/libinput/libinput-1.16.1.tar.xz
+patches/libinput-optional-udev.patch
diff --git a/extra/libinput/version b/extra/libinput/version
new file mode 100644
index 00000000..541e5c6e
--- /dev/null
+++ b/extra/libinput/version
@@ -0,0 +1 @@
+1.16.1 1