diff options
| author | Cem Keylan <cem@ckyln.com> | 2020-10-04 22:51:57 +0300 | 
|---|---|---|
| committer | Cem Keylan <cem@ckyln.com> | 2020-10-04 22:51:57 +0300 | 
| commit | bd36e113fed47de6ac33e411daf7a0b2a34bcbf6 (patch) | |
| tree | af403d84dc696fe517683cd563a5bbb3fdccac29 /extra/libinput/patches | |
| parent | 7bc852f77943f4f92a548b3a0f43d6a0a303b585 (diff) | |
| download | repository-bd36e113fed47de6ac33e411daf7a0b2a34bcbf6.tar.gz | |
move non xorg specific packages to extra
Diffstat (limited to 'extra/libinput/patches')
| -rw-r--r-- | extra/libinput/patches/libinput-optional-udev.patch | 2378 | 
1 files changed, 2378 insertions, 0 deletions
| 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 + | 
