From 98e90eaec449a67e0c4216d0aac38ee9896a6a8b Mon Sep 17 00:00:00 2001 From: Michael Forney 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 #include #include +#include #if HAVE_LIBWACOM #include 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 #include #include 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 #include #include +#include #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 #include #include +#include #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 #include #include -#include #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 #include -#include - #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 #include #include #include 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 #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 #include #include +#include #include #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 #include #include +#include #include #include #include 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 #include #include +#include #include #include #include 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 #include #include +#include #include #include "quirks.h" From a6f21673e13efc52fff100d315316ba14c6db848 Mon Sep 17 00:00:00 2001 From: Michael Forney 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 #include #include -#include #if HAVE_LIBWACOM #include #endif +#if HAVE_UDEV +#include +#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 #include #include @@ -33,6 +32,10 @@ #include #endif +#if HAVE_UDEV +#include +#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 #include #include +#include +#ifndef major +#include +#endif #include "linux/input.h" #include #include #include #include #include -#include #include "libinput.h" #include "evdev.h" @@ -50,6 +53,12 @@ #include #endif +#if HAVE_UDEV +#include +#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 #include #include + +#if HAVE_UDEV #include +#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 #include +#if HAVE_UDEV #include +#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 #include -#include #include #include #include +#if HAVE_UDEV +#include +#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 #include #include @@ -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 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 +#include +#include +#include +#include +#include + +#include +#include + +#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