diff --git a/CMakeLists.txt b/CMakeLists.txt index b0342cc44..4f17fc477 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,739 +1,735 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR) project(KWIN) set(PROJECT_VERSION "5.12.80") set(PROJECT_VERSION_MAJOR 5) set(QT_MIN_VERSION "5.9.0") set(KF5_MIN_VERSION "5.42.0") set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH} ) find_package(ECM 5.38 REQUIRED NO_MODULE) include(FeatureSummary) include(WriteBasicConfigVersionFile) include(GenerateExportHeader) # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Concurrent Core DBus Quick QuickWidgets Sensors Script UiTools Widgets X11Extras ) find_package(Qt5Test ${QT_MIN_VERSION} CONFIG QUIET) set_package_properties(Qt5Test PROPERTIES PURPOSE "Required for tests" TYPE OPTIONAL ) add_feature_info("Qt5Test" Qt5Test_FOUND "Required for building tests") if (NOT Qt5Test_FOUND) set(BUILD_TESTING OFF CACHE BOOL "Build the testing tree.") endif() include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMInstallIcons) include(ECMOptionalAddSubdirectory) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0 -DQT_USE_QSTRINGBUILDER) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-inconsistent-missing-override") endif() find_package(Qt5Multimedia QUIET) set_package_properties(Qt5Multimedia PROPERTIES PURPOSE "Runtime-only dependency for effect video playback" TYPE RUNTIME ) # required frameworks by Core find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Config ConfigWidgets CoreAddons Crash GlobalAccel I18n Init Notifications Package Plasma WidgetsAddons WindowSystem IconThemes IdleTime Wayland ) # required frameworks by config modules find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Completion Declarative KCMUtils KIO TextWidgets NewStuff Service XmlGui ) find_package(Threads) set_package_properties(Threads PROPERTIES PURPOSE "Needed for VirtualTerminal support in KWin Wayland" TYPE REQUIRED ) # optional frameworks find_package(KF5Activities ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5Activities PROPERTIES PURPOSE "Enable building of KWin with kactivities support" TYPE OPTIONAL ) add_feature_info("KF5Activities" KF5Activities_FOUND "Enable building of KWin with kactivities support") find_package(KF5DocTools ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5DocTools PROPERTIES PURPOSE "Enable building documentation" TYPE OPTIONAL ) add_feature_info("KF5DocTools" KF5DocTools_FOUND "Enable building documentation") find_package(KDecoration2 CONFIG REQUIRED) find_package(KScreenLocker CONFIG REQUIRED) set_package_properties(KScreenLocker PROPERTIES TYPE REQUIRED PURPOSE "For screenlocker integration in kwin_wayland") find_package(Breeze 5.9.0 CONFIG) set_package_properties(Breeze PROPERTIES TYPE OPTIONAL PURPOSE "For setting the default window decoration plugin") if(${Breeze_FOUND}) if(${BREEZE_WITH_KDECORATION}) set(HAVE_BREEZE_DECO true) else() set(HAVE_BREEZE_DECO FALSE) endif() else() set(HAVE_BREEZE_DECO FALSE) endif() add_feature_info("Breeze-Decoration" HAVE_BREEZE_DECO "Default decoration plugin Breeze") find_package(EGL) set_package_properties(EGL PROPERTIES TYPE RUNTIME PURPOSE "Required to build KWin with EGL support" ) find_package(epoxy) set_package_properties(epoxy PROPERTIES DESCRIPTION "libepoxy" URL "http://github.com/anholt/libepoxy" TYPE REQUIRED PURPOSE "OpenGL dispatch library" ) set(HAVE_DL_LIBRARY FALSE) if(epoxy_HAS_GLX) find_library(DL_LIBRARY dl) if(DL_LIBRARY) set(HAVE_DL_LIBRARY TRUE) endif() endif() find_package(Wayland 1.2 REQUIRED COMPONENTS Cursor OPTIONAL_COMPONENTS Egl) set_package_properties(Wayland PROPERTIES TYPE REQUIRED PURPOSE "Required for building KWin with Wayland support" ) add_feature_info("Wayland::EGL" Wayland_Egl_FOUND "Enable building of Wayland backend and QPA with EGL support.") set(HAVE_WAYLAND_EGL FALSE) if(Wayland_Egl_FOUND) set(HAVE_WAYLAND_EGL TRUE) endif() find_package(XKB 0.7.0) set_package_properties(XKB PROPERTIES TYPE REQUIRED PURPOSE "Required for building KWin with Wayland support" ) -find_package(Libinput 1.5) +find_package(Libinput 1.9) set_package_properties(Libinput PROPERTIES TYPE OPTIONAL PURPOSE "Required for input handling on Wayland.") find_package(UDev) set_package_properties(UDev PROPERTIES URL "http://www.freedesktop.org/software/systemd/libudev/" DESCRIPTION "Linux device library." TYPE OPTIONAL PURPOSE "Required for input handling on Wayland." ) set(HAVE_INPUT FALSE) -set(HAVE_INPUT_1_9 FALSE) if (Libinput_FOUND AND UDEV_FOUND) set(HAVE_INPUT TRUE) - if(${Libinput_VERSION} VERSION_GREATER "1.9.0" OR ${Libinput_VERSION} VERSION_EQUAL "1.9.0") - set(HAVE_INPUT_1_9 TRUE) - endif() endif() set(HAVE_UDEV FALSE) if (UDEV_FOUND) set(HAVE_UDEV TRUE) endif() find_package(Libdrm 2.4.62) set_package_properties(Libdrm PROPERTIES TYPE OPTIONAL PURPOSE "Required for drm output on Wayland.") set(HAVE_DRM FALSE) if(Libdrm_FOUND AND UDEV_FOUND) set(HAVE_DRM TRUE) endif() find_package(gbm) set_package_properties(gbm PROPERTIES TYPE OPTIONAL PURPOSE "Required for egl ouput of drm backend.") set(HAVE_GBM FALSE) if(HAVE_DRM AND gbm_FOUND) set(HAVE_GBM TRUE) endif() find_package(libhybris) set_package_properties(libhybris PROPERTIES TYPE OPTIONAL PURPOSE "Required for libhybris backend") set(HAVE_LIBHYBRIS ${libhybris_FOUND}) find_package(X11) set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" URL "http://www.x.org" TYPE REQUIRED ) add_feature_info("XInput" X11_Xinput_FOUND "Required for poll-free mouse cursor updates") set(HAVE_X11_XINPUT ${X11_Xinput_FOUND}) # All the required XCB components find_package(XCB 1.10 REQUIRED COMPONENTS XCB XFIXES DAMAGE COMPOSITE SHAPE SYNC RENDER RANDR KEYSYMS IMAGE SHM GLX CURSOR ICCCM ) set_package_properties(XCB PROPERTIES TYPE REQUIRED) # and the optional XCB dependencies if (XCB_ICCCM_VERSION VERSION_LESS "0.4") set(XCB_ICCCM_FOUND FALSE) endif() add_feature_info("XCB-ICCCM" XCB_ICCCM_FOUND "Required for building test applications for KWin") find_package(X11_XCB) set_package_properties(X11_XCB PROPERTIES PURPOSE "Required for building X11 windowed backend of kwin_wayland" TYPE OPTIONAL) # dependencies for QPA plugin find_package(Qt5FontDatabaseSupport REQUIRED) find_package(Qt5ThemeSupport REQUIRED) find_package(Qt5EventDispatcherSupport REQUIRED) find_package(Freetype REQUIRED) set_package_properties(Freetype PROPERTIES DESCRIPTION "A font rendering engine" URL "http://www.freetype.org" TYPE REQUIRED PURPOSE "Needed for KWin's QPA plugin." ) find_package(Fontconfig REQUIRED) set_package_properties(Fontconfig PROPERTIES DESCRIPTION "Font access configuration library" URL "http://www.freedesktop.org/wiki/Software/fontconfig" TYPE REQUIRED PURPOSE "Needed for KWin's QPA plugin." ) find_package(Xwayland) set_package_properties(Xwayland PROPERTIES URL "http://x.org" DESCRIPTION "Xwayland X server" TYPE RUNTIME PURPOSE "Needed for running kwin_wayland" ) find_package(Libcap) set_package_properties(Libcap PROPERTIES TYPE OPTIONAL PURPOSE "Needed for running kwin_wayland with real-time scheduling policy" ) set(HAVE_LIBCAP ${Libcap_FOUND}) include(ECMQMLModules) ecm_find_qmlmodule(QtQuick 2.3) ecm_find_qmlmodule(QtQuick.Controls 1.2) ecm_find_qmlmodule(QtQuick.Layouts 1.3) ecm_find_qmlmodule(QtQuick.VirtualKeyboard 2.1) ecm_find_qmlmodule(QtQuick.Window 2.1) ecm_find_qmlmodule(QtMultimedia 5.0) ecm_find_qmlmodule(org.kde.kquickcontrolsaddons 2.0) ecm_find_qmlmodule(org.kde.plasma.core 2.0) ecm_find_qmlmodule(org.kde.plasma.components 2.0) ########### configure tests ############### include(CMakeDependentOption) option(KWIN_BUILD_DECORATIONS "Enable building of KWin decorations." ON) option(KWIN_BUILD_KCMS "Enable building of KWin configuration modules." ON) option(KWIN_BUILD_TABBOX "Enable building of KWin Tabbox functionality" ON) option(KWIN_BUILD_XRENDER_COMPOSITING "Enable building of KWin with XRender Compositing support" ON) cmake_dependent_option(KWIN_BUILD_ACTIVITIES "Enable building of KWin with kactivities support" ON "KF5Activities_FOUND" OFF) # Binary name of KWin set(KWIN_NAME "kwin") set(KWIN_INTERNAL_NAME_X11 "kwin_x11") set(KWIN_INTERNAL_NAME_WAYLAND "kwin_wayland") set(KWIN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) # KWIN_HAVE_XRENDER_COMPOSITING - whether XRender-based compositing support is available: may be disabled if( KWIN_BUILD_XRENDER_COMPOSITING ) set( KWIN_HAVE_XRENDER_COMPOSITING 1 ) endif() include_directories(${XKB_INCLUDE_DIR}) include_directories(${epoxy_INCLUDE_DIR}) set(HAVE_EPOXY_GLX ${epoxy_HAS_GLX}) # for things that are also used by kwin libraries configure_file(libkwineffects/kwinconfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/libkwineffects/kwinconfig.h ) # for kwin internal things set(HAVE_X11_XCB ${X11_XCB_FOUND}) include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckSymbolExists) check_include_files(unistd.h HAVE_UNISTD_H) check_include_files(malloc.h HAVE_MALLOC_H) check_include_file("sys/prctl.h" HAVE_SYS_PRCTL_H) check_symbol_exists(PR_SET_DUMPABLE "sys/prctl.h" HAVE_PR_SET_DUMPABLE) check_symbol_exists(PR_SET_PDEATHSIG "sys/prctl.h" HAVE_PR_SET_PDEATHSIG) check_include_file("sys/procctl.h" HAVE_SYS_PROCCTL_H) check_symbol_exists(PROC_TRACE_CTL "sys/procctl.h" HAVE_PROC_TRACE_CTL) if (HAVE_PR_SET_DUMPABLE OR HAVE_PROC_TRACE_CTL) set(CAN_DISABLE_PTRACE TRUE) endif() add_feature_info("prctl/procctl tracing control" CAN_DISABLE_PTRACE "Required for disallowing ptrace on kwin_wayland process") check_include_file("sys/sysmacros.h" HAVE_SYS_SYSMACROS_H) configure_file(config-kwin.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kwin.h ) check_include_file("linux/vt.h" HAVE_LINUX_VT_H) add_feature_info("linux/vt.h" HAVE_LINUX_VT_H "Required for virtual terminal support under wayland") check_include_file("linux/fb.h" HAVE_LINUX_FB_H) add_feature_info("linux/fb.h" HAVE_LINUX_FB_H "Required for the fbdev backend") check_symbol_exists(SCHED_RESET_ON_FORK "sched.h" HAVE_SCHED_RESET_ON_FORK) add_feature_info("SCHED_RESET_ON_FORK" HAVE_SCHED_RESET_ON_FORK "Required for running kwin_wayland with real-time scheduling") ########### global ############### set(kwin_effects_dbus_xml ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.kwin.Effects.xml) include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/libkwineffects ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libkwineffects ${CMAKE_CURRENT_SOURCE_DIR}/effects ${CMAKE_CURRENT_SOURCE_DIR}/tabbox ${CMAKE_CURRENT_SOURCE_DIR}/platformsupport ) add_subdirectory( libkwineffects ) if(KWIN_BUILD_KCMS) add_subdirectory( kcmkwin ) endif() add_subdirectory( data ) add_subdirectory( effects ) add_subdirectory( scripts ) add_subdirectory( tabbox ) add_subdirectory(scripting) add_subdirectory(helpers) ########### next target ############### set(kwin_KDEINIT_SRCS workspace.cpp dbusinterface.cpp abstract_client.cpp client.cpp client_machine.cpp cursor.cpp debug_console.cpp tabgroup.cpp focuschain.cpp globalshortcuts.cpp input.cpp input_event.cpp input_event_spy.cpp keyboard_input.cpp keyboard_layout.cpp keyboard_layout_switching.cpp keyboard_repeat.cpp pointer_input.cpp touch_input.cpp netinfo.cpp placement.cpp atoms.cpp utils.cpp layers.cpp main.cpp options.cpp outline.cpp events.cpp killwindow.cpp geometrytip.cpp screens.cpp shadow.cpp sm.cpp group.cpp manage.cpp overlaywindow.cpp activation.cpp useractions.cpp geometry.cpp rules.cpp composite.cpp toplevel.cpp unmanaged.cpp scene.cpp screenlockerwatcher.cpp thumbnailitem.cpp lanczosfilter.cpp deleted.cpp effects.cpp effectloader.cpp virtualdesktops.cpp xcbutils.cpp x11eventfilter.cpp logind.cpp onscreennotification.cpp osd.cpp screenedge.cpp scripting/scripting.cpp scripting/workspace_wrapper.cpp scripting/meta.cpp scripting/scriptedeffect.cpp scripting/scriptingutils.cpp scripting/timer.cpp scripting/scripting_model.cpp scripting/dbuscall.cpp scripting/screenedgeitem.cpp scripting/scripting_logging.cpp decorations/decoratedclient.cpp decorations/decorationbridge.cpp decorations/decorationpalette.cpp decorations/settings.cpp decorations/decorationrenderer.cpp decorations/decorations_logging.cpp platform.cpp shell_client.cpp wayland_server.cpp wayland_cursor_theme.cpp virtualkeyboard.cpp virtualkeyboard_dbus.cpp appmenu.cpp modifier_only_shortcuts.cpp xkb.cpp gestures.cpp popup_input_filter.cpp colorcorrection/manager.cpp colorcorrection/colorcorrectdbusinterface.cpp colorcorrection/suncalc.cpp abstract_opengl_context_attribute_builder.cpp egl_context_attribute_builder.cpp was_user_interaction_x11_filter.cpp moving_client_x11_filter.cpp window_property_notify_x11_filter.cpp rootinfo_filter.cpp orientation_sensor.cpp idle_inhibition.cpp ) include(ECMQtDeclareLoggingCategory) ecm_qt_declare_logging_category(kwin_KDEINIT_SRCS HEADER colorcorrect_logging.h IDENTIFIER KWIN_COLORCORRECTION CATEGORY_NAME kwin_colorcorrection DEFAULT_SEVERITY Critical ) if(KWIN_BUILD_TABBOX) set( kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} tabbox/tabbox.cpp tabbox/clientmodel.cpp tabbox/desktopchain.cpp tabbox/desktopmodel.cpp tabbox/switcheritem.cpp tabbox/tabboxconfig.cpp tabbox/tabboxhandler.cpp tabbox/tabbox_logging.cpp tabbox/x11_filter.cpp ) endif() if(KWIN_BUILD_ACTIVITIES) set( kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} activities.cpp ) endif() if(UDEV_FOUND) set(kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} udev.cpp ) endif() if(HAVE_INPUT) set(kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} libinput/context.cpp libinput/connection.cpp libinput/device.cpp libinput/events.cpp libinput/libinput_logging.cpp ) if (HAVE_LINUX_VT_H) set(kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} virtual_terminal.cpp ) endif() endif() kconfig_add_kcfg_files(kwin_KDEINIT_SRCS settings.kcfgc) kconfig_add_kcfg_files(kwin_KDEINIT_SRCS colorcorrection/colorcorrect_settings.kcfgc) qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml dbusinterface.h KWin::DBusInterface ) qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.kwin.Compositing.xml dbusinterface.h KWin::CompositorDBusInterface ) qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.kwin.ColorCorrect.xml colorcorrection/colorcorrectdbusinterface.h KWin::ColorCorrect::ColorCorrectDBusInterface ) qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS ${kwin_effects_dbus_xml} effects.h KWin::EffectsHandlerImpl ) qt5_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.kwin.OrientationSensor.xml orientation_sensor.h KWin::OrientationSensor) qt5_add_dbus_interface( kwin_KDEINIT_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/org.freedesktop.ScreenSaver.xml screenlocker_interface) qt5_add_dbus_interface( kwin_KDEINIT_SRCS org.kde.kappmenu.xml appmenu_interface ) qt5_add_resources( kwin_KDEINIT_SRCS resources.qrc ) ki18n_wrap_ui(kwin_KDEINIT_SRCS debug_console.ui shortcutdialog.ui ) ########### target link libraries ############### set(kwin_OWN_LIBS kwineffects kwin4_effect_builtins ) set(kwin_QT_LIBS Qt5::Concurrent Qt5::DBus Qt5::Quick Qt5::Sensors Qt5::Script ) set(kwin_KDE_LIBS KF5::ConfigCore KF5::CoreAddons KF5::ConfigWidgets KF5::GlobalAccel KF5::GlobalAccelPrivate KF5::I18n KF5::Notifications KF5::Package KF5::Plasma KF5::WindowSystem KF5::QuickAddons KDecoration2::KDecoration KDecoration2::KDecoration2Private PW::KScreenLocker ) set(kwin_XLIB_LIBS ${X11_X11_LIB} ${X11_ICE_LIB} ${X11_SM_LIB} ) set(kwin_XCB_LIBS XCB::XCB XCB::XFIXES XCB::DAMAGE XCB::COMPOSITE XCB::SHAPE XCB::SYNC XCB::RENDER XCB::RANDR XCB::KEYSYMS XCB::SHM XCB::GLX XCB::ICCCM ) set(kwin_WAYLAND_LIBS XKB::XKB KF5::WaylandClient KF5::WaylandServer Wayland::Cursor ${CMAKE_THREAD_LIBS_INIT} ) if(KWIN_BUILD_ACTIVITIES) set(kwin_KDE_LIBS ${kwin_KDE_LIBS} KF5::Activities) endif() set(kwinLibs ${kwin_OWN_LIBS} ${kwin_QT_LIBS} ${kwin_KDE_LIBS} ${kwin_XLIB_LIBS} ${kwin_XCB_LIBS} ${kwin_WAYLAND_LIBS} ) if(UDEV_FOUND) set(kwinLibs ${kwinLibs} ${UDEV_LIBS}) endif() if(HAVE_INPUT) set(kwinLibs ${kwinLibs} Libinput::Libinput) endif() add_library(kwin SHARED ${kwin_KDEINIT_SRCS}) set_target_properties(kwin PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} ) target_link_libraries(kwin ${kwinLibs}) generate_export_header(kwin EXPORT_FILE_NAME kwin_export.h) target_link_libraries(kwin kwinglutils ${epoxy_LIBRARY}) kf5_add_kdeinit_executable(kwin_x11 main_x11.cpp) target_link_libraries(kdeinit_kwin_x11 kwin KF5::Crash Qt5::X11Extras) install(TARGETS kwin ${INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP ) install(TARGETS kdeinit_kwin_x11 ${INSTALL_TARGETS_DEFAULT_ARGS} ) install(TARGETS kwin_x11 ${INSTALL_TARGETS_DEFAULT_ARGS} ) add_executable(kwin_wayland tabletmodemanager.cpp main_wayland.cpp) target_link_libraries(kwin_wayland kwin) if (HAVE_LIBCAP) target_link_libraries(kwin_wayland ${Libcap_LIBRARIES}) endif() install(TARGETS kwin_wayland ${INSTALL_TARGETS_DEFAULT_ARGS} ) if (HAVE_LIBCAP) install( CODE "execute_process( COMMAND ${SETCAP_EXECUTABLE} CAP_SYS_NICE=+ep \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/kwin_wayland)" ) endif() add_subdirectory(platformsupport) add_subdirectory(plugins) ########### install files ############### install( FILES kwin.kcfg DESTINATION ${KCFG_INSTALL_DIR} RENAME ${KWIN_NAME}.kcfg ) install( FILES colorcorrection/colorcorrect_settings.kcfg DESTINATION ${KCFG_INSTALL_DIR} RENAME ${KWIN_NAME}_colorcorrect.kcfg ) install( FILES kwin.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR} RENAME ${KWIN_NAME}.notifyrc) install( FILES org.kde.KWin.xml org.kde.kwin.Compositing.xml org.kde.kwin.ColorCorrect.xml org.kde.kwin.Effects.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/kwin_export.h DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel) # Install the KWin/Script service type install( FILES scripting/kwinscript.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} ) ecm_install_icons( ICONS 16-apps-kwin.png 32-apps-kwin.png 48-apps-kwin.png sc-apps-kwin.svgz DESTINATION ${ICON_INSTALL_DIR} THEME hicolor ) add_subdirectory(qml) add_subdirectory(autotests) add_subdirectory(tests) add_subdirectory(packageplugins) if (KF5DocTools_FOUND) add_subdirectory(doc) endif() feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) include(CMakePackageConfigHelpers) set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KWinDBusInterface") configure_package_config_file(KWinDBusInterfaceConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/KWinDBusInterfaceConfig.cmake" PATH_VARS KDE_INSTALL_DBUSINTERFACEDIR INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KWinDBusInterfaceConfig.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR}) diff --git a/autotests/libinput/CMakeLists.txt b/autotests/libinput/CMakeLists.txt index 7f2ac2de7..bc0fff699 100644 --- a/autotests/libinput/CMakeLists.txt +++ b/autotests/libinput/CMakeLists.txt @@ -1,115 +1,113 @@ include_directories(${Libinput_INCLUDE_DIRS}) include_directories(${UDEV_INCLUDE_DIR}) ######################################################## # Test Devices ######################################################## set( testLibinputDevice_SRCS device_test.cpp mock_libinput.cpp ../../libinput/device.cpp ) add_executable(testLibinputDevice ${testLibinputDevice_SRCS}) target_link_libraries( testLibinputDevice Qt5::Test Qt5::DBus Qt5::Gui KF5::ConfigCore) add_test(NAME kwin-testLibinputDevice COMMAND testLibinputDevice) ecm_mark_as_test(testLibinputDevice) ######################################################## # Test Key Event ######################################################## set( testLibinputKeyEvent_SRCS key_event_test.cpp mock_libinput.cpp ../../libinput/device.cpp ../../libinput/events.cpp ) add_executable(testLibinputKeyEvent ${testLibinputKeyEvent_SRCS}) target_link_libraries( testLibinputKeyEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) add_test(NAME kwin-testLibinputKeyEvent COMMAND testLibinputKeyEvent) ecm_mark_as_test(testLibinputKeyEvent) ######################################################## # Test Pointer Event ######################################################## set( testLibinputPointerEvent_SRCS pointer_event_test.cpp mock_libinput.cpp ../../libinput/device.cpp ../../libinput/events.cpp ) add_executable(testLibinputPointerEvent ${testLibinputPointerEvent_SRCS}) target_link_libraries( testLibinputPointerEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) add_test(NAME kwin-testLibinputPointerEvent COMMAND testLibinputPointerEvent) ecm_mark_as_test(testLibinputPointerEvent) ######################################################## # Test Touch Event ######################################################## set( testLibinputTouchEvent_SRCS touch_event_test.cpp mock_libinput.cpp ../../libinput/device.cpp ../../libinput/events.cpp ) add_executable(testLibinputTouchEvent ${testLibinputTouchEvent_SRCS}) target_link_libraries( testLibinputTouchEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) add_test(NAME kwin-testLibinputTouchEvent COMMAND testLibinputTouchEvent) ecm_mark_as_test(testLibinputTouchEvent) ######################################################## # Test Gesture Event ######################################################## set( testLibinputGestureEvent_SRCS gesture_event_test.cpp mock_libinput.cpp ../../libinput/device.cpp ../../libinput/events.cpp ) add_executable(testLibinputGestureEvent ${testLibinputGestureEvent_SRCS}) target_link_libraries( testLibinputGestureEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) add_test(NAME kwin-testLibinputGestureEvent COMMAND testLibinputGestureEvent) ecm_mark_as_test(testLibinputGestureEvent) ######################################################## # Test Switch Event ######################################################## -if(HAVE_INPUT_1_9) - set( testLibinputSwitchEvent_SRCS - switch_event_test.cpp - mock_libinput.cpp - ../../libinput/device.cpp - ../../libinput/events.cpp - ) - add_executable(testLibinputSwitchEvent ${testLibinputSwitchEvent_SRCS}) - target_link_libraries(testLibinputSwitchEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) - add_test(NAME kwin-testLibinputSwitchEvent COMMAND testLibinputSwitchEvent) - ecm_mark_as_test(testLibinputSwitchEvent) -endif() +set( testLibinputSwitchEvent_SRCS + switch_event_test.cpp + mock_libinput.cpp + ../../libinput/device.cpp + ../../libinput/events.cpp + ) +add_executable(testLibinputSwitchEvent ${testLibinputSwitchEvent_SRCS}) +target_link_libraries(testLibinputSwitchEvent Qt5::Test Qt5::DBus Qt5::Widgets KF5::ConfigCore) +add_test(NAME kwin-testLibinputSwitchEvent COMMAND testLibinputSwitchEvent) +ecm_mark_as_test(testLibinputSwitchEvent) ######################################################## # Test Context ######################################################## set( testLibinputContext_SRCS context_test.cpp mock_libinput.cpp mock_udev.cpp ../../libinput/context.cpp ../../libinput/device.cpp ../../libinput/events.cpp ../../libinput/libinput_logging.cpp ../../logind.cpp ) add_executable(testLibinputContext ${testLibinputContext_SRCS}) target_link_libraries( testLibinputContext Qt5::DBus Qt5::Test Qt5::Widgets KF5::ConfigCore KF5::WindowSystem ) add_test(NAME kwin-testLibinputContext COMMAND testLibinputContext) ecm_mark_as_test(testLibinputContext) ######################################################## # Test Input Events ######################################################## set( testInputEvents_SRCS input_event_test.cpp mock_libinput.cpp ../../libinput/device.cpp ../../input_event.cpp ) add_executable(testInputEvents ${testInputEvents_SRCS}) target_link_libraries( testInputEvents Qt5::Test Qt5::DBus Qt5::Gui KF5::ConfigCore) add_test(NAME kwin-testInputEvents COMMAND testInputEvents) ecm_mark_as_test(testInputEvents) diff --git a/autotests/libinput/device_test.cpp b/autotests/libinput/device_test.cpp index 619d626ca..a93cc4325 100644 --- a/autotests/libinput/device_test.cpp +++ b/autotests/libinput/device_test.cpp @@ -1,2204 +1,2198 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2016 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "mock_libinput.h" #include "../../libinput/device.h" #include #include #include #include using namespace KWin::LibInput; class TestLibinputDevice : public QObject { Q_OBJECT private Q_SLOTS: void testStaticGetter(); void testDeviceType_data(); void testDeviceType(); void testGestureSupport_data(); void testGestureSupport(); void testNames_data(); void testNames(); void testProduct(); void testVendor(); void testTapFingerCount(); void testSize_data(); void testSize(); void testDefaultPointerAcceleration_data(); void testDefaultPointerAcceleration(); void testDefaultPointerAccelerationProfileFlat_data(); void testDefaultPointerAccelerationProfileFlat(); void testDefaultPointerAccelerationProfileAdaptive_data(); void testDefaultPointerAccelerationProfileAdaptive(); void testLeftHandedEnabledByDefault_data(); void testLeftHandedEnabledByDefault(); void testTapEnabledByDefault_data(); void testTapEnabledByDefault(); void testMiddleEmulationEnabledByDefault_data(); void testMiddleEmulationEnabledByDefault(); void testNaturalScrollEnabledByDefault_data(); void testNaturalScrollEnabledByDefault(); void testScrollTwoFingerEnabledByDefault_data(); void testScrollTwoFingerEnabledByDefault(); void testScrollEdgeEnabledByDefault_data(); void testScrollEdgeEnabledByDefault(); void testScrollOnButtonDownEnabledByDefault_data(); void testScrollOnButtonDownEnabledByDefault(); void testDisableWhileTypingEnabledByDefault_data(); void testDisableWhileTypingEnabledByDefault(); void testLmrTapButtonMapEnabledByDefault_data(); void testLmrTapButtonMapEnabledByDefault(); void testSupportsDisableWhileTyping_data(); void testSupportsDisableWhileTyping(); void testSupportsPointerAcceleration_data(); void testSupportsPointerAcceleration(); void testSupportsLeftHanded_data(); void testSupportsLeftHanded(); void testSupportsCalibrationMatrix_data(); void testSupportsCalibrationMatrix(); void testSupportsDisableEvents_data(); void testSupportsDisableEvents(); void testSupportsDisableEventsOnExternalMouse_data(); void testSupportsDisableEventsOnExternalMouse(); void testSupportsMiddleEmulation_data(); void testSupportsMiddleEmulation(); void testSupportsNaturalScroll_data(); void testSupportsNaturalScroll(); void testSupportsScrollTwoFinger_data(); void testSupportsScrollTwoFinger(); void testSupportsScrollEdge_data(); void testSupportsScrollEdge(); void testSupportsScrollOnButtonDown_data(); void testSupportsScrollOnButtonDown(); void testDefaultScrollButton_data(); void testDefaultScrollButton(); void testPointerAcceleration_data(); void testPointerAcceleration(); void testLeftHanded_data(); void testLeftHanded(); void testSupportedButtons_data(); void testSupportedButtons(); void testAlphaNumericKeyboard_data(); void testAlphaNumericKeyboard(); void testEnabled_data(); void testEnabled(); void testTapToClick_data(); void testTapToClick(); void testTapAndDragEnabledByDefault_data(); void testTapAndDragEnabledByDefault(); void testTapAndDrag_data(); void testTapAndDrag(); void testTapDragLockEnabledByDefault_data(); void testTapDragLockEnabledByDefault(); void testTapDragLock_data(); void testTapDragLock(); void testMiddleEmulation_data(); void testMiddleEmulation(); void testNaturalScroll_data(); void testNaturalScroll(); void testScrollTwoFinger_data(); void testScrollTwoFinger(); void testScrollEdge_data(); void testScrollEdge(); void testScrollButtonDown_data(); void testScrollButtonDown(); void testScrollButton_data(); void testScrollButton(); void testDisableWhileTyping_data(); void testDisableWhileTyping(); void testLmrTapButtonMap_data(); void testLmrTapButtonMap(); void testLoadEnabled_data(); void testLoadEnabled(); void testLoadPointerAcceleration_data(); void testLoadPointerAcceleration(); void testLoadPointerAccelerationProfile_data(); void testLoadPointerAccelerationProfile(); void testLoadTapToClick_data(); void testLoadTapToClick(); void testLoadTapAndDrag_data(); void testLoadTapAndDrag(); void testLoadTapDragLock_data(); void testLoadTapDragLock(); void testLoadMiddleButtonEmulation_data(); void testLoadMiddleButtonEmulation(); void testLoadNaturalScroll_data(); void testLoadNaturalScroll(); void testLoadScrollMethod_data(); void testLoadScrollMethod(); void testLoadScrollButton_data(); void testLoadScrollButton(); void testLoadDisableWhileTyping_data(); void testLoadDisableWhileTyping(); void testLoadLmrTapButtonMap_data(); void testLoadLmrTapButtonMap(); void testLoadLeftHanded_data(); void testLoadLeftHanded(); void testScreenId(); void testOrientation_data(); void testOrientation(); void testCalibrationWithDefault(); void testSwitch_data(); void testSwitch(); }; void TestLibinputDevice::testStaticGetter() { // this test verifies that the static getter for Device works as expected QVERIFY(Device::devices().isEmpty()); // create some device libinput_device device1; libinput_device device2; // at the moment not yet known to Device QVERIFY(!Device::getDevice(&device1)); QVERIFY(!Device::getDevice(&device2)); QVERIFY(Device::devices().isEmpty()); // now create a Device for one Device *d1 = new Device(&device1); QCOMPARE(Device::devices().count(), 1); QCOMPARE(Device::devices().first(), d1); QCOMPARE(Device::getDevice(&device1), d1); QVERIFY(!Device::getDevice(&device2)); // and a second Device Device *d2 = new Device(&device2); QCOMPARE(Device::devices().count(), 2); QCOMPARE(Device::devices().first(), d1); QCOMPARE(Device::devices().last(), d2); QCOMPARE(Device::getDevice(&device1), d1); QCOMPARE(Device::getDevice(&device2), d2); // now delete d1 delete d1; QCOMPARE(Device::devices().count(), 1); QCOMPARE(Device::devices().first(), d2); QCOMPARE(Device::getDevice(&device2), d2); QVERIFY(!Device::getDevice(&device1)); // and delete d2 delete d2; QVERIFY(!Device::getDevice(&device1)); QVERIFY(!Device::getDevice(&device2)); QVERIFY(Device::devices().isEmpty()); } void TestLibinputDevice::testDeviceType_data() { QTest::addColumn("keyboard"); QTest::addColumn("pointer"); QTest::addColumn("touch"); QTest::addColumn("tabletTool"); QTest::addColumn("switchDevice"); QTest::newRow("keyboard") << true << false << false << false << false; QTest::newRow("pointer") << false << true << false << false << false; QTest::newRow("touch") << false << false << true << false << false; QTest::newRow("keyboard/pointer") << true << true << false << false << false; QTest::newRow("keyboard/touch") << true << false << true << false << false; QTest::newRow("pointer/touch") << false << true << true << false << false; QTest::newRow("keyboard/pointer/touch") << true << true << true << false << false; QTest::newRow("tabletTool") << false << false << false << true << false; -#if HAVE_INPUT_1_9 QTest::newRow("switch") << false << false << false << false << true; -#endif } void TestLibinputDevice::testDeviceType() { // this test verifies that the device type is recognized correctly QFETCH(bool, keyboard); QFETCH(bool, pointer); QFETCH(bool, touch); QFETCH(bool, tabletTool); QFETCH(bool, switchDevice); libinput_device device; device.keyboard = keyboard; device.pointer = pointer; device.touch = touch; device.tabletTool = tabletTool; device.switchDevice = switchDevice; Device d(&device); QCOMPARE(d.isKeyboard(), keyboard); QCOMPARE(d.property("keyboard").toBool(), keyboard); QCOMPARE(d.isPointer(), pointer); QCOMPARE(d.property("pointer").toBool(), pointer); QCOMPARE(d.isTouch(), touch); QCOMPARE(d.property("touch").toBool(), touch); QCOMPARE(d.isTabletPad(), false); QCOMPARE(d.property("tabletPad").toBool(), false); QCOMPARE(d.isTabletTool(), tabletTool); QCOMPARE(d.property("tabletTool").toBool(), tabletTool); QCOMPARE(d.isSwitch(), switchDevice); QCOMPARE(d.property("switchDevice").toBool(), switchDevice); QCOMPARE(d.device(), &device); } void TestLibinputDevice::testGestureSupport_data() { QTest::addColumn("supported"); QTest::newRow("supported") << true; QTest::newRow("not supported") << false; } void TestLibinputDevice::testGestureSupport() { // this test verifies whether the Device supports gestures QFETCH(bool, supported); libinput_device device; device.gestureSupported = supported; Device d(&device); QCOMPARE(d.supportsGesture(), supported); QCOMPARE(d.property("gestureSupport").toBool(), supported); } void TestLibinputDevice::testNames_data() { QTest::addColumn("name"); QTest::addColumn("sysName"); QTest::addColumn("outputName"); QTest::newRow("empty") << QByteArray() << QByteArrayLiteral("event1") << QByteArray(); QTest::newRow("set") << QByteArrayLiteral("awesome test device") << QByteArrayLiteral("event0") << QByteArrayLiteral("hdmi0"); } void TestLibinputDevice::testNames() { // this test verifies the various name properties of the Device QFETCH(QByteArray, name); QFETCH(QByteArray, sysName); QFETCH(QByteArray, outputName); libinput_device device; device.name = name; device.sysName = sysName; device.outputName = outputName; Device d(&device); QCOMPARE(d.name().toUtf8(), name); QCOMPARE(d.property("name").toString().toUtf8(), name); QCOMPARE(d.sysName().toUtf8(), sysName); QCOMPARE(d.property("sysName").toString().toUtf8(), sysName); QCOMPARE(d.outputName().toUtf8(), outputName); QCOMPARE(d.property("outputName").toString().toUtf8(), outputName); } void TestLibinputDevice::testProduct() { // this test verifies the product property libinput_device device; device.product = 100u; Device d(&device); QCOMPARE(d.product(), 100u); QCOMPARE(d.property("product").toUInt(), 100u); } void TestLibinputDevice::testVendor() { // this test verifies the vendor property libinput_device device; device.vendor = 200u; Device d(&device); QCOMPARE(d.vendor(), 200u); QCOMPARE(d.property("vendor").toUInt(), 200u); } void TestLibinputDevice::testTapFingerCount() { // this test verifies the tap finger count property libinput_device device; device.tapFingerCount = 3; Device d(&device); QCOMPARE(d.tapFingerCount(), 3); QCOMPARE(d.property("tapFingerCount").toInt(), 3); } void TestLibinputDevice::testSize_data() { QTest::addColumn("setSize"); QTest::addColumn("returnValue"); QTest::addColumn("expectedSize"); QTest::newRow("10/20") << QSizeF(10.5, 20.2) << 0 << QSizeF(10.5, 20.2); QTest::newRow("failure") << QSizeF(10, 20) << 1 << QSizeF(); } void TestLibinputDevice::testSize() { // this test verifies that getting the size works correctly including failures QFETCH(QSizeF, setSize); QFETCH(int, returnValue); libinput_device device; device.deviceSize = setSize; device.deviceSizeReturnValue = returnValue; Device d(&device); QTEST(d.size(), "expectedSize"); QTEST(d.property("size").toSizeF(), "expectedSize"); } void TestLibinputDevice::testLeftHandedEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testLeftHandedEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.leftHandedEnabledByDefault = enabled; Device d(&device); QCOMPARE(d.leftHandedEnabledByDefault(), enabled); QCOMPARE(d.property("leftHandedEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testTapEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testTapEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.tapEnabledByDefault = enabled; Device d(&device); QCOMPARE(d.tapToClickEnabledByDefault(), enabled); QCOMPARE(d.property("tapToClickEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testMiddleEmulationEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testMiddleEmulationEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.middleEmulationEnabledByDefault = enabled; Device d(&device); QCOMPARE(d.middleEmulationEnabledByDefault(), enabled); QCOMPARE(d.property("middleEmulationEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testNaturalScrollEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testNaturalScrollEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.naturalScrollEnabledByDefault = enabled; Device d(&device); QCOMPARE(d.naturalScrollEnabledByDefault(), enabled); QCOMPARE(d.property("naturalScrollEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testScrollTwoFingerEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testScrollTwoFingerEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.defaultScrollMethod = enabled ? LIBINPUT_CONFIG_SCROLL_2FG : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; Device d(&device); QCOMPARE(d.scrollTwoFingerEnabledByDefault(), enabled); QCOMPARE(d.property("scrollTwoFingerEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testScrollEdgeEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testScrollEdgeEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.defaultScrollMethod = enabled ? LIBINPUT_CONFIG_SCROLL_EDGE : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; Device d(&device); QCOMPARE(d.scrollEdgeEnabledByDefault(), enabled); QCOMPARE(d.property("scrollEdgeEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testDefaultPointerAccelerationProfileFlat_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testDefaultPointerAccelerationProfileFlat() { QFETCH(bool, enabled); libinput_device device; device.defaultPointerAccelerationProfile = enabled ? LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT : LIBINPUT_CONFIG_ACCEL_PROFILE_NONE; Device d(&device); QCOMPARE(d.defaultPointerAccelerationProfileFlat(), enabled); QCOMPARE(d.property("defaultPointerAccelerationProfileFlat").toBool(), enabled); } void TestLibinputDevice::testDefaultPointerAccelerationProfileAdaptive_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testDefaultPointerAccelerationProfileAdaptive() { QFETCH(bool, enabled); libinput_device device; device.defaultPointerAccelerationProfile = enabled ? LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE : LIBINPUT_CONFIG_ACCEL_PROFILE_NONE; Device d(&device); QCOMPARE(d.defaultPointerAccelerationProfileAdaptive(), enabled); QCOMPARE(d.property("defaultPointerAccelerationProfileAdaptive").toBool(), enabled); } void TestLibinputDevice::testScrollOnButtonDownEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testScrollOnButtonDownEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.defaultScrollMethod = enabled ? LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; Device d(&device); QCOMPARE(d.scrollOnButtonDownEnabledByDefault(), enabled); QCOMPARE(d.property("scrollOnButtonDownEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testDefaultScrollButton_data() { QTest::addColumn("button"); QTest::newRow("0") << 0u; QTest::newRow("BTN_LEFT") << quint32(BTN_LEFT); QTest::newRow("BTN_RIGHT") << quint32(BTN_RIGHT); QTest::newRow("BTN_MIDDLE") << quint32(BTN_MIDDLE); QTest::newRow("BTN_SIDE") << quint32(BTN_SIDE); QTest::newRow("BTN_EXTRA") << quint32(BTN_EXTRA); QTest::newRow("BTN_FORWARD") << quint32(BTN_FORWARD); QTest::newRow("BTN_BACK") << quint32(BTN_BACK); QTest::newRow("BTN_TASK") << quint32(BTN_TASK); } void TestLibinputDevice::testDefaultScrollButton() { libinput_device device; QFETCH(quint32, button); device.defaultScrollButton = button; Device d(&device); QCOMPARE(d.defaultScrollButton(), button); QCOMPARE(d.property("defaultScrollButton").value(), button); } void TestLibinputDevice::testSupportsDisableWhileTyping_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsDisableWhileTyping() { QFETCH(bool, enabled); libinput_device device; device.supportsDisableWhileTyping = enabled; Device d(&device); QCOMPARE(d.supportsDisableWhileTyping(), enabled); QCOMPARE(d.property("supportsDisableWhileTyping").toBool(), enabled); } void TestLibinputDevice::testSupportsPointerAcceleration_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsPointerAcceleration() { QFETCH(bool, enabled); libinput_device device; device.supportsPointerAcceleration = enabled; Device d(&device); QCOMPARE(d.supportsPointerAcceleration(), enabled); QCOMPARE(d.property("supportsPointerAcceleration").toBool(), enabled); } void TestLibinputDevice::testSupportsLeftHanded_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsLeftHanded() { QFETCH(bool, enabled); libinput_device device; device.supportsLeftHanded = enabled; Device d(&device); QCOMPARE(d.supportsLeftHanded(), enabled); QCOMPARE(d.property("supportsLeftHanded").toBool(), enabled); } void TestLibinputDevice::testSupportsCalibrationMatrix_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsCalibrationMatrix() { QFETCH(bool, enabled); libinput_device device; device.supportsCalibrationMatrix = enabled; Device d(&device); QCOMPARE(d.supportsCalibrationMatrix(), enabled); QCOMPARE(d.property("supportsCalibrationMatrix").toBool(), enabled); } void TestLibinputDevice::testSupportsDisableEvents_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsDisableEvents() { QFETCH(bool, enabled); libinput_device device; device.supportsDisableEvents = enabled; Device d(&device); QCOMPARE(d.supportsDisableEvents(), enabled); QCOMPARE(d.property("supportsDisableEvents").toBool(), enabled); } void TestLibinputDevice::testSupportsDisableEventsOnExternalMouse_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsDisableEventsOnExternalMouse() { QFETCH(bool, enabled); libinput_device device; device.supportsDisableEventsOnExternalMouse = enabled; Device d(&device); QCOMPARE(d.supportsDisableEventsOnExternalMouse(), enabled); QCOMPARE(d.property("supportsDisableEventsOnExternalMouse").toBool(), enabled); } void TestLibinputDevice::testSupportsMiddleEmulation_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsMiddleEmulation() { QFETCH(bool, enabled); libinput_device device; device.supportsMiddleEmulation = enabled; Device d(&device); QCOMPARE(d.supportsMiddleEmulation(), enabled); QCOMPARE(d.property("supportsMiddleEmulation").toBool(), enabled); } void TestLibinputDevice::testSupportsNaturalScroll_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsNaturalScroll() { QFETCH(bool, enabled); libinput_device device; device.supportsNaturalScroll = enabled; Device d(&device); QCOMPARE(d.supportsNaturalScroll(), enabled); QCOMPARE(d.property("supportsNaturalScroll").toBool(), enabled); } void TestLibinputDevice::testSupportsScrollTwoFinger_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsScrollTwoFinger() { QFETCH(bool, enabled); libinput_device device; device.supportedScrollMethods = enabled ? LIBINPUT_CONFIG_SCROLL_2FG : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; Device d(&device); QCOMPARE(d.supportsScrollTwoFinger(), enabled); QCOMPARE(d.property("supportsScrollTwoFinger").toBool(), enabled); } void TestLibinputDevice::testSupportsScrollEdge_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsScrollEdge() { QFETCH(bool, enabled); libinput_device device; device.supportedScrollMethods = enabled ? LIBINPUT_CONFIG_SCROLL_EDGE : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; Device d(&device); QCOMPARE(d.supportsScrollEdge(), enabled); QCOMPARE(d.property("supportsScrollEdge").toBool(), enabled); } void TestLibinputDevice::testSupportsScrollOnButtonDown_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testSupportsScrollOnButtonDown() { QFETCH(bool, enabled); libinput_device device; device.supportedScrollMethods = enabled ? LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; Device d(&device); QCOMPARE(d.supportsScrollOnButtonDown(), enabled); QCOMPARE(d.property("supportsScrollOnButtonDown").toBool(), enabled); } void TestLibinputDevice::testDefaultPointerAcceleration_data() { QTest::addColumn("accel"); QTest::newRow("-1.0") << -1.0; QTest::newRow("-0.5") << -0.5; QTest::newRow("0.0") << 0.0; QTest::newRow("0.3") << 0.3; QTest::newRow("1.0") << 1.0; } void TestLibinputDevice::testDefaultPointerAcceleration() { QFETCH(qreal, accel); libinput_device device; device.defaultPointerAcceleration = accel; Device d(&device); QCOMPARE(d.defaultPointerAcceleration(), accel); QCOMPARE(d.property("defaultPointerAcceleration").toReal(), accel); } void TestLibinputDevice::testPointerAcceleration_data() { QTest::addColumn("supported"); QTest::addColumn("setShouldFail"); QTest::addColumn("accel"); QTest::addColumn("setAccel"); QTest::addColumn("expectedAccel"); QTest::addColumn("expectedChanged"); QTest::newRow("-1 -> 2.0") << true << false << -1.0 << 2.0 << 1.0 << true; QTest::newRow("0 -> -1.0") << true << false << 0.0 << -1.0 << -1.0 << true; QTest::newRow("1 -> 1") << true << false << 1.0 << 1.0 << 1.0 << false; QTest::newRow("unsupported") << false << false << 0.0 << 1.0 << 0.0 << false; QTest::newRow("set fails") << true << true << -1.0 << 1.0 << -1.0 << false; } void TestLibinputDevice::testPointerAcceleration() { QFETCH(bool, supported); QFETCH(bool, setShouldFail); QFETCH(qreal, accel); libinput_device device; device.supportsPointerAcceleration = supported; device.pointerAcceleration = accel; device.setPointerAccelerationReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.pointerAcceleration(), accel); QCOMPARE(d.property("pointerAcceleration").toReal(), accel); QSignalSpy pointerAccelChangedSpy(&d, &Device::pointerAccelerationChanged); QVERIFY(pointerAccelChangedSpy.isValid()); QFETCH(qreal, setAccel); d.setPointerAcceleration(setAccel); QTEST(d.pointerAcceleration(), "expectedAccel"); QTEST(!pointerAccelChangedSpy.isEmpty(), "expectedChanged"); } void TestLibinputDevice::testLeftHanded_data() { QTest::addColumn("supported"); QTest::addColumn("setShouldFail"); QTest::addColumn("initValue"); QTest::addColumn("setValue"); QTest::addColumn("expectedValue"); QTest::newRow("unsupported/true") << false << false << true << false << false; QTest::newRow("unsupported/false") << false << false << false << true << false; QTest::newRow("true -> false") << true << false << true << false << false; QTest::newRow("false -> true") << true << false << false << true << true; QTest::newRow("set fails") << true << true << true << false << true; QTest::newRow("true -> true") << true << false << true << true << true; QTest::newRow("false -> false") << true << false << false << false << false; } void TestLibinputDevice::testLeftHanded() { QFETCH(bool, supported); QFETCH(bool, setShouldFail); QFETCH(bool, initValue); libinput_device device; device.supportsLeftHanded = supported; device.leftHanded = initValue; device.setLeftHandedReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.isLeftHanded(), supported && initValue); QCOMPARE(d.property("leftHanded").toBool(), supported && initValue); QSignalSpy leftHandedChangedSpy(&d, &Device::leftHandedChanged); QVERIFY(leftHandedChangedSpy.isValid()); QFETCH(bool, setValue); d.setLeftHanded(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isLeftHanded(), expectedValue); QCOMPARE(leftHandedChangedSpy.isEmpty(), (supported && initValue) == expectedValue); } void TestLibinputDevice::testSupportedButtons_data() { QTest::addColumn("isPointer"); QTest::addColumn("setButtons"); QTest::addColumn("expectedButtons"); QTest::newRow("left") << true << Qt::MouseButtons(Qt::LeftButton) << Qt::MouseButtons(Qt::LeftButton); QTest::newRow("right") << true << Qt::MouseButtons(Qt::RightButton) << Qt::MouseButtons(Qt::RightButton); QTest::newRow("middle") << true << Qt::MouseButtons(Qt::MiddleButton) << Qt::MouseButtons(Qt::MiddleButton); QTest::newRow("extra1") << true << Qt::MouseButtons(Qt::ExtraButton1) << Qt::MouseButtons(Qt::ExtraButton1); QTest::newRow("extra2") << true << Qt::MouseButtons(Qt::ExtraButton2) << Qt::MouseButtons(Qt::ExtraButton2); QTest::newRow("back") << true << Qt::MouseButtons(Qt::BackButton) << Qt::MouseButtons(Qt::BackButton); QTest::newRow("forward") << true << Qt::MouseButtons(Qt::ForwardButton) << Qt::MouseButtons(Qt::ForwardButton); QTest::newRow("task") << true << Qt::MouseButtons(Qt::TaskButton) << Qt::MouseButtons(Qt::TaskButton); QTest::newRow("no pointer/left") << false << Qt::MouseButtons(Qt::LeftButton) << Qt::MouseButtons(); QTest::newRow("no pointer/right") << false << Qt::MouseButtons(Qt::RightButton) << Qt::MouseButtons(); QTest::newRow("no pointer/middle") << false << Qt::MouseButtons(Qt::MiddleButton) << Qt::MouseButtons(); QTest::newRow("no pointer/extra1") << false << Qt::MouseButtons(Qt::ExtraButton1) << Qt::MouseButtons(); QTest::newRow("no pointer/extra2") << false << Qt::MouseButtons(Qt::ExtraButton2) << Qt::MouseButtons(); QTest::newRow("no pointer/back") << false << Qt::MouseButtons(Qt::BackButton) << Qt::MouseButtons(); QTest::newRow("no pointer/forward") << false << Qt::MouseButtons(Qt::ForwardButton) << Qt::MouseButtons(); QTest::newRow("no pointer/task") << false << Qt::MouseButtons(Qt::TaskButton) << Qt::MouseButtons(); QTest::newRow("all") << true << Qt::MouseButtons(Qt::LeftButton | Qt::RightButton | Qt::MiddleButton | Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::BackButton | Qt::ForwardButton | Qt::TaskButton) << Qt::MouseButtons(Qt::LeftButton | Qt::RightButton | Qt::MiddleButton | Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::BackButton | Qt::ForwardButton | Qt::TaskButton); } void TestLibinputDevice::testSupportedButtons() { libinput_device device; QFETCH(bool, isPointer); device.pointer = isPointer; QFETCH(Qt::MouseButtons, setButtons); device.supportedButtons = setButtons; Device d(&device); QCOMPARE(d.isPointer(), isPointer); QTEST(d.supportedButtons(), "expectedButtons"); } void TestLibinputDevice::testAlphaNumericKeyboard_data() { QTest::addColumn>("supportedKeys"); QTest::addColumn("isAlpha"); QVector keys; for (int i = KEY_1; i <= KEY_0; i++) { keys << i; QByteArray row = QByteArrayLiteral("number"); row.append(QByteArray::number(i)); QTest::newRow(row.constData()) << keys << false; } for (int i = KEY_Q; i <= KEY_P; i++) { keys << i; QByteArray row = QByteArrayLiteral("alpha"); row.append(QByteArray::number(i)); QTest::newRow(row.constData()) << keys << false; } for (int i = KEY_A; i <= KEY_L; i++) { keys << i; QByteArray row = QByteArrayLiteral("alpha"); row.append(QByteArray::number(i)); QTest::newRow(row.constData()) << keys << false; } for (int i = KEY_Z; i < KEY_M; i++) { keys << i; QByteArray row = QByteArrayLiteral("alpha"); row.append(QByteArray::number(i)); QTest::newRow(row.constData()) << keys << false; } // adding a different key should not result in it becoming alphanumeric keyboard keys << KEY_SEMICOLON; QTest::newRow("semicolon") << keys << false; // last but not least the M which should turn everything on keys << KEY_M; QTest::newRow("alphanumeric") << keys << true; } void TestLibinputDevice::testAlphaNumericKeyboard() { QFETCH(QVector, supportedKeys); libinput_device device; device.keyboard = true; device.keys = supportedKeys; Device d(&device); QCOMPARE(d.isKeyboard(), true); QTEST(d.isAlphaNumericKeyboard(), "isAlpha"); } void TestLibinputDevice::testEnabled_data() { QTest::addColumn("supported"); QTest::addColumn("setShouldFail"); QTest::addColumn("initValue"); QTest::addColumn("setValue"); QTest::addColumn("expectedValue"); QTest::newRow("unsupported/true") << false << false << true << false << true; QTest::newRow("unsupported/false") << false << false << false << true << true; QTest::newRow("true -> false") << true << false << true << false << false; QTest::newRow("false -> true") << true << false << false << true << true; QTest::newRow("set fails") << true << true << true << false << true; QTest::newRow("true -> true") << true << false << true << true << true; QTest::newRow("false -> false") << true << false << false << false << false; } void TestLibinputDevice::testEnabled() { libinput_device device; QFETCH(bool, supported); QFETCH(bool, setShouldFail); QFETCH(bool, initValue); device.supportsDisableEvents = supported; device.enabled = initValue; device.setEnableModeReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.isEnabled(), !supported || initValue); QCOMPARE(d.property("enabled").toBool(), !supported || initValue); QSignalSpy enabledChangedSpy(&d, &Device::enabledChanged); QVERIFY(enabledChangedSpy.isValid()); QFETCH(bool, setValue); d.setEnabled(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isEnabled(), expectedValue); } void TestLibinputDevice::testTapToClick_data() { QTest::addColumn("fingerCount"); QTest::addColumn("initValue"); QTest::addColumn("setValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("expectedValue"); QTest::newRow("unsupported") << 0 << false << true << true << false; QTest::newRow("true -> false") << 1 << true << false << false << false; QTest::newRow("false -> true") << 2 << false << true << false << true; QTest::newRow("set fails") << 3 << true << false << true << true; QTest::newRow("true -> true") << 2 << true << true << false << true; QTest::newRow("false -> false") << 1 << false << false << false << false; } void TestLibinputDevice::testTapToClick() { libinput_device device; QFETCH(int, fingerCount); QFETCH(bool, initValue); QFETCH(bool, setShouldFail); device.tapFingerCount = fingerCount; device.tapToClick = initValue; device.setTapToClickReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.tapFingerCount(), fingerCount); QCOMPARE(d.isTapToClick(), initValue); QCOMPARE(d.property("tapToClick").toBool(), initValue); QSignalSpy tapToClickChangedSpy(&d, &Device::tapToClickChanged); QVERIFY(tapToClickChangedSpy.isValid()); QFETCH(bool, setValue); d.setTapToClick(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isTapToClick(), expectedValue); QCOMPARE(tapToClickChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testTapAndDragEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testTapAndDragEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.tapAndDragEnabledByDefault = enabled; Device d(&device); QCOMPARE(d.tapAndDragEnabledByDefault(), enabled); QCOMPARE(d.property("tapAndDragEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testTapAndDrag_data() { QTest::addColumn("initValue"); QTest::addColumn("setValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("expectedValue"); QTest::newRow("true -> false") << true << false << false << false; QTest::newRow("false -> true") << false << true << false << true; QTest::newRow("set fails") << true << false << true << true; QTest::newRow("true -> true") << true << true << false << true; QTest::newRow("false -> false") << false << false << false << false; } void TestLibinputDevice::testTapAndDrag() { libinput_device device; QFETCH(bool, initValue); QFETCH(bool, setShouldFail); device.tapAndDrag = initValue; device.setTapAndDragReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.isTapAndDrag(), initValue); QCOMPARE(d.property("tapAndDrag").toBool(), initValue); QSignalSpy tapAndDragChangedSpy(&d, &Device::tapAndDragChanged); QVERIFY(tapAndDragChangedSpy.isValid()); QFETCH(bool, setValue); d.setTapAndDrag(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isTapAndDrag(), expectedValue); QCOMPARE(tapAndDragChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testTapDragLockEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testTapDragLockEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.tapDragLockEnabledByDefault = enabled; Device d(&device); QCOMPARE(d.tapDragLockEnabledByDefault(), enabled); QCOMPARE(d.property("tapDragLockEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testTapDragLock_data() { QTest::addColumn("initValue"); QTest::addColumn("setValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("expectedValue"); QTest::newRow("true -> false") << true << false << false << false; QTest::newRow("false -> true") << false << true << false << true; QTest::newRow("set fails") << true << false << true << true; QTest::newRow("true -> true") << true << true << false << true; QTest::newRow("false -> false") << false << false << false << false; } void TestLibinputDevice::testTapDragLock() { libinput_device device; QFETCH(bool, initValue); QFETCH(bool, setShouldFail); device.tapDragLock = initValue; device.setTapDragLockReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.isTapDragLock(), initValue); QCOMPARE(d.property("tapDragLock").toBool(), initValue); QSignalSpy tapDragLockChangedSpy(&d, &Device::tapDragLockChanged); QVERIFY(tapDragLockChangedSpy.isValid()); QFETCH(bool, setValue); d.setTapDragLock(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isTapDragLock(), expectedValue); QCOMPARE(tapDragLockChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testMiddleEmulation_data() { QTest::addColumn("initValue"); QTest::addColumn("setValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("expectedValue"); QTest::addColumn("supportsMiddleButton"); QTest::newRow("true -> false") << true << false << false << false << true; QTest::newRow("false -> true") << false << true << false << true << true; QTest::newRow("set fails") << true << false << true << true << true; QTest::newRow("true -> true") << true << true << false << true << true; QTest::newRow("false -> false") << false << false << false << false << true; QTest::newRow("false -> true, unsupported") << false << true << true << false << false; } void TestLibinputDevice::testMiddleEmulation() { libinput_device device; QFETCH(bool, initValue); QFETCH(bool, setShouldFail); QFETCH(bool, supportsMiddleButton); device.supportsMiddleEmulation = supportsMiddleButton; device.middleEmulation = initValue; device.setMiddleEmulationReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.isMiddleEmulation(), initValue); QCOMPARE(d.property("middleEmulation").toBool(), initValue); QSignalSpy middleEmulationChangedSpy(&d, &Device::middleEmulationChanged); QVERIFY(middleEmulationChangedSpy.isValid()); QFETCH(bool, setValue); d.setMiddleEmulation(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isMiddleEmulation(), expectedValue); QCOMPARE(d.property("middleEmulation").toBool(), expectedValue); QCOMPARE(middleEmulationChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testNaturalScroll_data() { QTest::addColumn("initValue"); QTest::addColumn("setValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("expectedValue"); QTest::addColumn("supportsNaturalScroll"); QTest::newRow("true -> false") << true << false << false << false << true; QTest::newRow("false -> true") << false << true << false << true << true; QTest::newRow("set fails") << true << false << true << true << true; QTest::newRow("true -> true") << true << true << false << true << true; QTest::newRow("false -> false") << false << false << false << false << true; QTest::newRow("false -> true, unsupported") << false << true << true << false << false; } void TestLibinputDevice::testNaturalScroll() { libinput_device device; QFETCH(bool, initValue); QFETCH(bool, setShouldFail); QFETCH(bool, supportsNaturalScroll); device.supportsNaturalScroll = supportsNaturalScroll; device.naturalScroll = initValue; device.setNaturalScrollReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.isNaturalScroll(), initValue); QCOMPARE(d.property("naturalScroll").toBool(), initValue); QSignalSpy naturalScrollChangedSpy(&d, &Device::naturalScrollChanged); QVERIFY(naturalScrollChangedSpy.isValid()); QFETCH(bool, setValue); d.setNaturalScroll(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isNaturalScroll(), expectedValue); QCOMPARE(d.property("naturalScroll").toBool(), expectedValue); QCOMPARE(naturalScrollChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testScrollTwoFinger_data() { QTest::addColumn("initValue"); QTest::addColumn("otherValue"); QTest::addColumn("setValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("expectedValue"); QTest::addColumn("supportsScrollTwoFinger"); QTest::newRow("true -> false") << true << false << false << false << false << true; QTest::newRow("other -> false") << false << true << false << false << false << true; QTest::newRow("false -> true") << false << false << true << false << true << true; QTest::newRow("set fails") << true << false << false << true << true << true; QTest::newRow("true -> true") << true << false << true << false << true << true; QTest::newRow("false -> false") << false << false << false << false << false << true; QTest::newRow("false -> true, unsupported") << false << false << true << true << false << false; } void TestLibinputDevice::testScrollTwoFinger() { libinput_device device; QFETCH(bool, initValue); QFETCH(bool, otherValue); QFETCH(bool, setShouldFail); QFETCH(bool, supportsScrollTwoFinger); device.supportedScrollMethods = (supportsScrollTwoFinger ? LIBINPUT_CONFIG_SCROLL_2FG : LIBINPUT_CONFIG_SCROLL_NO_SCROLL) | LIBINPUT_CONFIG_SCROLL_EDGE; device.scrollMethod = initValue ? LIBINPUT_CONFIG_SCROLL_2FG : otherValue ? LIBINPUT_CONFIG_SCROLL_EDGE : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; device.setScrollMethodReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.isScrollTwoFinger(), initValue); QCOMPARE(d.property("scrollTwoFinger").toBool(), initValue); QCOMPARE(d.property("scrollEdge").toBool(), otherValue); QSignalSpy scrollMethodChangedSpy(&d, &Device::scrollMethodChanged); QVERIFY(scrollMethodChangedSpy.isValid()); QFETCH(bool, setValue); d.setScrollTwoFinger(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isScrollTwoFinger(), expectedValue); QCOMPARE(d.property("scrollTwoFinger").toBool(), expectedValue); QCOMPARE(scrollMethodChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testScrollEdge_data() { QTest::addColumn("initValue"); QTest::addColumn("otherValue"); QTest::addColumn("setValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("expectedValue"); QTest::addColumn("supportsScrollEdge"); QTest::newRow("true -> false") << true << false << false << false << false << true; QTest::newRow("other -> false") << false << true << false << false << false << true; QTest::newRow("false -> true") << false << false << true << false << true << true; QTest::newRow("set fails") << true << false << false << true << true << true; QTest::newRow("true -> true") << true << false << true << false << true << true; QTest::newRow("false -> false") << false << false << false << false << false << true; QTest::newRow("false -> true, unsupported") << false << false << true << true << false << false; } void TestLibinputDevice::testScrollEdge() { libinput_device device; QFETCH(bool, initValue); QFETCH(bool, otherValue); QFETCH(bool, setShouldFail); QFETCH(bool, supportsScrollEdge); device.supportedScrollMethods = (supportsScrollEdge ? LIBINPUT_CONFIG_SCROLL_EDGE : LIBINPUT_CONFIG_SCROLL_NO_SCROLL) | LIBINPUT_CONFIG_SCROLL_2FG; device.scrollMethod = initValue ? LIBINPUT_CONFIG_SCROLL_EDGE : otherValue ? LIBINPUT_CONFIG_SCROLL_2FG : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; device.setScrollMethodReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.isScrollEdge(), initValue); QCOMPARE(d.property("scrollEdge").toBool(), initValue); QCOMPARE(d.property("scrollTwoFinger").toBool(), otherValue); QSignalSpy scrollMethodChangedSpy(&d, &Device::scrollMethodChanged); QVERIFY(scrollMethodChangedSpy.isValid()); QFETCH(bool, setValue); d.setScrollEdge(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isScrollEdge(), expectedValue); QCOMPARE(d.property("scrollEdge").toBool(), expectedValue); QCOMPARE(scrollMethodChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testScrollButtonDown_data() { QTest::addColumn("initValue"); QTest::addColumn("otherValue"); QTest::addColumn("setValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("expectedValue"); QTest::addColumn("supportsScrollButtonDown"); QTest::newRow("true -> false") << true << false << false << false << false << true; QTest::newRow("other -> false") << false << true << false << false << false << true; QTest::newRow("false -> true") << false << false << true << false << true << true; QTest::newRow("set fails") << true << false << false << true << true << true; QTest::newRow("true -> true") << true << false << true << false << true << true; QTest::newRow("false -> false") << false << false << false << false << false << true; QTest::newRow("false -> true, unsupported") << false << false << true << true << false << false; } void TestLibinputDevice::testScrollButtonDown() { libinput_device device; QFETCH(bool, initValue); QFETCH(bool, otherValue); QFETCH(bool, setShouldFail); QFETCH(bool, supportsScrollButtonDown); device.supportedScrollMethods = (supportsScrollButtonDown ? LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN : LIBINPUT_CONFIG_SCROLL_NO_SCROLL) | LIBINPUT_CONFIG_SCROLL_2FG; device.scrollMethod = initValue ? LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN : otherValue ? LIBINPUT_CONFIG_SCROLL_2FG : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; device.setScrollMethodReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.isScrollOnButtonDown(), initValue); QCOMPARE(d.property("scrollOnButtonDown").toBool(), initValue); QCOMPARE(d.property("scrollTwoFinger").toBool(), otherValue); QSignalSpy scrollMethodChangedSpy(&d, &Device::scrollMethodChanged); QVERIFY(scrollMethodChangedSpy.isValid()); QFETCH(bool, setValue); d.setScrollOnButtonDown(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isScrollOnButtonDown(), expectedValue); QCOMPARE(d.property("scrollOnButtonDown").toBool(), expectedValue); QCOMPARE(scrollMethodChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testScrollButton_data() { QTest::addColumn("initValue"); QTest::addColumn("setValue"); QTest::addColumn("expectedValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("scrollOnButton"); QTest::newRow("BTN_LEFT -> BTN_RIGHT") << quint32(BTN_LEFT) << quint32(BTN_RIGHT) << quint32(BTN_RIGHT) << false << true; QTest::newRow("BTN_LEFT -> BTN_LEFT") << quint32(BTN_LEFT) << quint32(BTN_LEFT) << quint32(BTN_LEFT) << false << true; QTest::newRow("set should fail") << quint32(BTN_LEFT) << quint32(BTN_RIGHT) << quint32(BTN_LEFT) << true << true; QTest::newRow("not scroll on button") << quint32(BTN_LEFT) << quint32(BTN_RIGHT) << quint32(BTN_LEFT) << false << false; } void TestLibinputDevice::testScrollButton() { libinput_device device; QFETCH(quint32, initValue); QFETCH(bool, setShouldFail); QFETCH(bool, scrollOnButton); device.scrollButton = initValue; device.supportedScrollMethods = scrollOnButton ? LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; device.setScrollButtonReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.scrollButton(), initValue); QCOMPARE(d.property("scrollButton").value(), initValue); QSignalSpy scrollButtonChangedSpy(&d, &Device::scrollButtonChanged); QVERIFY(scrollButtonChangedSpy.isValid()); QFETCH(quint32, setValue); d.setScrollButton(setValue); QFETCH(quint32, expectedValue); QCOMPARE(d.scrollButton(), expectedValue); QCOMPARE(d.property("scrollButton").value(), expectedValue); QCOMPARE(scrollButtonChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testDisableWhileTypingEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testDisableWhileTypingEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.disableWhileTypingEnabledByDefault = enabled ? LIBINPUT_CONFIG_DWT_ENABLED : LIBINPUT_CONFIG_DWT_DISABLED; Device d(&device); QCOMPARE(d.disableWhileTypingEnabledByDefault(), enabled); QCOMPARE(d.property("disableWhileTypingEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testLmrTapButtonMapEnabledByDefault_data() { QTest::addColumn("enabled"); QTest::newRow("enabled") << true; QTest::newRow("disabled") << false; } void TestLibinputDevice::testLmrTapButtonMapEnabledByDefault() { QFETCH(bool, enabled); libinput_device device; device.defaultTapButtonMap = enabled ? LIBINPUT_CONFIG_TAP_MAP_LMR : LIBINPUT_CONFIG_TAP_MAP_LRM; Device d(&device); QCOMPARE(d.lmrTapButtonMapEnabledByDefault(), enabled); QCOMPARE(d.property("lmrTapButtonMapEnabledByDefault").toBool(), enabled); } void TestLibinputDevice::testLmrTapButtonMap_data() { QTest::addColumn("initValue"); QTest::addColumn("setValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("expectedValue"); QTest::addColumn("fingerCount"); QTest::newRow("true -> false") << true << false << false << false << 3; QTest::newRow("false -> true") << false << true << false << true << 3; QTest::newRow("true -> false") << true << false << false << false << 2; QTest::newRow("false -> true") << false << true << false << true << 2; QTest::newRow("set fails") << true << false << true << true << 3; QTest::newRow("true -> true") << true << true << false << true << 3; QTest::newRow("false -> false") << false << false << false << false << 3; QTest::newRow("true -> true") << true << true << false << true << 2; QTest::newRow("false -> false") << false << false << false << false << 2; QTest::newRow("false -> true, fingerCount 0") << false << true << true << false << 0; // TODO: is this a fail in libinput? //QTest::newRow("false -> true, fingerCount 1") << false << true << true << false << 1; } void TestLibinputDevice::testLmrTapButtonMap() { libinput_device device; QFETCH(bool, initValue); QFETCH(bool, setShouldFail); QFETCH(int, fingerCount); device.tapFingerCount = fingerCount; device.tapButtonMap = initValue ? LIBINPUT_CONFIG_TAP_MAP_LMR : LIBINPUT_CONFIG_TAP_MAP_LRM; device.setTapButtonMapReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.lmrTapButtonMap(), initValue); QCOMPARE(d.property("lmrTapButtonMap").toBool(), initValue); QSignalSpy tapButtonMapChangedSpy(&d, &Device::tapButtonMapChanged); QVERIFY(tapButtonMapChangedSpy.isValid()); QFETCH(bool, setValue); d.setLmrTapButtonMap(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.lmrTapButtonMap(), expectedValue); QCOMPARE(d.property("lmrTapButtonMap").toBool(), expectedValue); QCOMPARE(tapButtonMapChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testDisableWhileTyping_data() { QTest::addColumn("initValue"); QTest::addColumn("setValue"); QTest::addColumn("setShouldFail"); QTest::addColumn("expectedValue"); QTest::addColumn("supportsDisableWhileTyping"); QTest::newRow("true -> false") << true << false << false << false << true; QTest::newRow("false -> true") << false << true << false << true << true; QTest::newRow("set fails") << true << false << true << true << true; QTest::newRow("true -> true") << true << true << false << true << true; QTest::newRow("false -> false") << false << false << false << false << true; QTest::newRow("false -> true, unsupported") << false << true << true << false << false; } void TestLibinputDevice::testDisableWhileTyping() { libinput_device device; QFETCH(bool, initValue); QFETCH(bool, setShouldFail); QFETCH(bool, supportsDisableWhileTyping); device.supportsDisableWhileTyping = supportsDisableWhileTyping; device.disableWhileTyping = initValue ? LIBINPUT_CONFIG_DWT_ENABLED : LIBINPUT_CONFIG_DWT_DISABLED; device.setDisableWhileTypingReturnValue = setShouldFail; Device d(&device); QCOMPARE(d.isDisableWhileTyping(), initValue); QCOMPARE(d.property("disableWhileTyping").toBool(), initValue); QSignalSpy disableWhileTypingChangedSpy(&d, &Device::disableWhileTypingChanged); QVERIFY(disableWhileTypingChangedSpy.isValid()); QFETCH(bool, setValue); d.setDisableWhileTyping(setValue); QFETCH(bool, expectedValue); QCOMPARE(d.isDisableWhileTyping(), expectedValue); QCOMPARE(d.property("disableWhileTyping").toBool(), expectedValue); QCOMPARE(disableWhileTypingChangedSpy.isEmpty(), initValue == expectedValue); } void TestLibinputDevice::testLoadEnabled_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("false -> true") << false << true; QTest::newRow("true -> false") << true << false; QTest::newRow("true -> true") << true << true; QTest::newRow("false -> false") << false << false; } void TestLibinputDevice::testLoadEnabled() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(bool, configValue); QFETCH(bool, initValue); inputConfig.writeEntry("Enabled", configValue); libinput_device device; device.supportsDisableEvents = true; device.enabled = initValue; device.setEnableModeReturnValue = false; Device d(&device); QCOMPARE(d.isEnabled(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.isEnabled(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.isEnabled(), configValue); // and try to store if (configValue != initValue) { d.setEnabled(initValue); QCOMPARE(inputConfig.readEntry("Enabled", configValue), initValue); } } void TestLibinputDevice::testLoadPointerAcceleration_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("-0.2 -> 0.9") << -0.2 << 0.9; QTest::newRow("0.0 -> -1.0") << 0.0 << -1.0; QTest::newRow("0.123 -> -0.456") << 0.123 << -0.456; QTest::newRow("0.7 -> 0.7") << 0.7 << 0.7; } void TestLibinputDevice::testLoadPointerAcceleration() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(qreal, configValue); QFETCH(qreal, initValue); inputConfig.writeEntry("PointerAcceleration", configValue); libinput_device device; device.supportsPointerAcceleration = true; device.pointerAcceleration = initValue; device.setPointerAccelerationReturnValue = false; Device d(&device); QCOMPARE(d.pointerAcceleration(), initValue); QCOMPARE(d.property("pointerAcceleration").toReal(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.pointerAcceleration(), initValue); QCOMPARE(d.property("pointerAcceleration").toReal(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.pointerAcceleration(), configValue); QCOMPARE(d.property("pointerAcceleration").toReal(), configValue); // and try to store if (configValue != initValue) { d.setPointerAcceleration(initValue); QCOMPARE(inputConfig.readEntry("PointerAcceleration", configValue), initValue); } } void TestLibinputDevice::testLoadPointerAccelerationProfile_data() { QTest::addColumn("initValue"); QTest::addColumn("initValuePropNameString"); QTest::addColumn("configValue"); QTest::addColumn("configValuePropNameString"); QTest::newRow("pointerAccelerationProfileFlat -> pointerAccelerationProfileAdaptive") << (quint32) LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT << "pointerAccelerationProfileFlat" << (quint32) LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE << "pointerAccelerationProfileAdaptive"; QTest::newRow("pointerAccelerationProfileAdaptive -> pointerAccelerationProfileFlat") << (quint32) LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE << "pointerAccelerationProfileAdaptive" << (quint32) LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT << "pointerAccelerationProfileFlat"; QTest::newRow("pointerAccelerationProfileAdaptive -> pointerAccelerationProfileAdaptive") << (quint32) LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE << "pointerAccelerationProfileAdaptive" << (quint32) LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE << "pointerAccelerationProfileAdaptive"; } void TestLibinputDevice::testLoadPointerAccelerationProfile() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(quint32, initValue); QFETCH(quint32, configValue); QFETCH(QString, initValuePropNameString); QFETCH(QString, configValuePropNameString); QByteArray initValuePropName = initValuePropNameString.toLatin1(); QByteArray configValuePropName = configValuePropNameString.toLatin1(); inputConfig.writeEntry("PointerAccelerationProfile", configValue); libinput_device device; device.supportedPointerAccelerationProfiles = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT | LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; device.pointerAccelerationProfile = (libinput_config_accel_profile) initValue; device.setPointerAccelerationProfileReturnValue = false; Device d(&device); QCOMPARE(d.property(initValuePropName).toBool(), true); QCOMPARE(d.property(configValuePropName).toBool(), initValue == configValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.property(initValuePropName).toBool(), true); QCOMPARE(d.property(configValuePropName).toBool(), initValue == configValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.property(initValuePropName).toBool(), initValue == configValue); QCOMPARE(d.property(configValuePropName).toBool(), true); // and try to store if (configValue != initValue) { d.setProperty(initValuePropName, true); QCOMPARE(inputConfig.readEntry("PointerAccelerationProfile", configValue), initValue); } } void TestLibinputDevice::testLoadTapToClick_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("false -> true") << false << true; QTest::newRow("true -> false") << true << false; QTest::newRow("true -> true") << true << true; QTest::newRow("false -> false") << false << false; } void TestLibinputDevice::testLoadTapToClick() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(bool, configValue); QFETCH(bool, initValue); inputConfig.writeEntry("TapToClick", configValue); libinput_device device; device.tapFingerCount = 2; device.tapToClick = initValue; device.setTapToClickReturnValue = false; Device d(&device); QCOMPARE(d.isTapToClick(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.isTapToClick(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.isTapToClick(), configValue); // and try to store if (configValue != initValue) { d.setTapToClick(initValue); QCOMPARE(inputConfig.readEntry("TapToClick", configValue), initValue); } } void TestLibinputDevice::testLoadTapAndDrag_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("false -> true") << false << true; QTest::newRow("true -> false") << true << false; QTest::newRow("true -> true") << true << true; QTest::newRow("false -> false") << false << false; } void TestLibinputDevice::testLoadTapAndDrag() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(bool, configValue); QFETCH(bool, initValue); inputConfig.writeEntry("TapAndDrag", configValue); libinput_device device; device.tapAndDrag = initValue; device.setTapAndDragReturnValue = false; Device d(&device); QCOMPARE(d.isTapAndDrag(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.isTapAndDrag(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.isTapAndDrag(), configValue); // and try to store if (configValue != initValue) { d.setTapAndDrag(initValue); QCOMPARE(inputConfig.readEntry("TapAndDrag", configValue), initValue); } } void TestLibinputDevice::testLoadTapDragLock_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("false -> true") << false << true; QTest::newRow("true -> false") << true << false; QTest::newRow("true -> true") << true << true; QTest::newRow("false -> false") << false << false; } void TestLibinputDevice::testLoadTapDragLock() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(bool, configValue); QFETCH(bool, initValue); inputConfig.writeEntry("TapDragLock", configValue); libinput_device device; device.tapDragLock = initValue; device.setTapDragLockReturnValue = false; Device d(&device); QCOMPARE(d.isTapDragLock(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.isTapDragLock(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.isTapDragLock(), configValue); // and try to store if (configValue != initValue) { d.setTapDragLock(initValue); QCOMPARE(inputConfig.readEntry("TapDragLock", configValue), initValue); } } void TestLibinputDevice::testLoadMiddleButtonEmulation_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("false -> true") << false << true; QTest::newRow("true -> false") << true << false; QTest::newRow("true -> true") << true << true; QTest::newRow("false -> false") << false << false; } void TestLibinputDevice::testLoadMiddleButtonEmulation() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(bool, configValue); QFETCH(bool, initValue); inputConfig.writeEntry("MiddleButtonEmulation", configValue); libinput_device device; device.supportsMiddleEmulation = true; device.middleEmulation = initValue; device.setMiddleEmulationReturnValue = false; Device d(&device); QCOMPARE(d.isMiddleEmulation(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.isMiddleEmulation(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.isMiddleEmulation(), configValue); // and try to store if (configValue != initValue) { d.setMiddleEmulation(initValue); QCOMPARE(inputConfig.readEntry("MiddleButtonEmulation", configValue), initValue); } } void TestLibinputDevice::testLoadNaturalScroll_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("false -> true") << false << true; QTest::newRow("true -> false") << true << false; QTest::newRow("true -> true") << true << true; QTest::newRow("false -> false") << false << false; } void TestLibinputDevice::testLoadNaturalScroll() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(bool, configValue); QFETCH(bool, initValue); inputConfig.writeEntry("NaturalScroll", configValue); libinput_device device; device.supportsNaturalScroll = true; device.naturalScroll = initValue; device.setNaturalScrollReturnValue = false; Device d(&device); QCOMPARE(d.isNaturalScroll(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.isNaturalScroll(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.isNaturalScroll(), configValue); // and try to store if (configValue != initValue) { d.setNaturalScroll(initValue); QCOMPARE(inputConfig.readEntry("NaturalScroll", configValue), initValue); } } void TestLibinputDevice::testLoadScrollMethod_data() { QTest::addColumn("initValue"); QTest::addColumn("initValuePropNameString"); QTest::addColumn("configValue"); QTest::addColumn("configValuePropNameString"); QTest::newRow("scrollTwoFinger -> scrollEdge") << (quint32) LIBINPUT_CONFIG_SCROLL_2FG << "scrollTwoFinger" << (quint32) LIBINPUT_CONFIG_SCROLL_EDGE << "scrollEdge"; QTest::newRow("scrollOnButtonDown -> scrollTwoFinger") << (quint32) LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN << "scrollOnButtonDown" << (quint32) LIBINPUT_CONFIG_SCROLL_2FG << "scrollTwoFinger"; QTest::newRow("scrollEdge -> scrollEdge") << (quint32) LIBINPUT_CONFIG_SCROLL_EDGE << "scrollEdge" << (quint32) LIBINPUT_CONFIG_SCROLL_EDGE << "scrollEdge"; } void TestLibinputDevice::testLoadScrollMethod() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(quint32, initValue); QFETCH(quint32, configValue); QFETCH(QString, initValuePropNameString); QFETCH(QString, configValuePropNameString); QByteArray initValuePropName = initValuePropNameString.toLatin1(); QByteArray configValuePropName = configValuePropNameString.toLatin1(); inputConfig.writeEntry("ScrollMethod", configValue); libinput_device device; device.supportedScrollMethods = LIBINPUT_CONFIG_SCROLL_2FG | LIBINPUT_CONFIG_SCROLL_EDGE | LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; device.scrollMethod = (libinput_config_scroll_method) initValue; device.setScrollMethodReturnValue = false; Device d(&device); QCOMPARE(d.property(initValuePropName).toBool(), true); QCOMPARE(d.property(configValuePropName).toBool(), initValue == configValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.property(initValuePropName).toBool(), true); QCOMPARE(d.property(configValuePropName).toBool(), initValue == configValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.property(initValuePropName).toBool(), initValue == configValue); QCOMPARE(d.property(configValuePropName).toBool(), true); // and try to store if (configValue != initValue) { d.setProperty(initValuePropName, true); QCOMPARE(inputConfig.readEntry("ScrollMethod", configValue), initValue); } } void TestLibinputDevice::testLoadScrollButton_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("BTN_LEFT -> BTN_RIGHT") << quint32(BTN_LEFT) << quint32(BTN_RIGHT); QTest::newRow("BTN_LEFT -> BTN_LEFT") << quint32(BTN_LEFT) << quint32(BTN_LEFT); } void TestLibinputDevice::testLoadScrollButton() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(quint32, configValue); QFETCH(quint32, initValue); inputConfig.writeEntry("ScrollButton", configValue); libinput_device device; device.supportedScrollMethods = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; device.scrollMethod = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; device.scrollButton = initValue; device.setScrollButtonReturnValue = false; Device d(&device); QCOMPARE(d.isScrollOnButtonDown(), true); QCOMPARE(d.scrollButton(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.isScrollOnButtonDown(), true); QCOMPARE(d.scrollButton(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.isScrollOnButtonDown(), true); QCOMPARE(d.scrollButton(), configValue); // and try to store if (configValue != initValue) { d.setScrollButton(initValue); QCOMPARE(inputConfig.readEntry("ScrollButton", configValue), initValue); } } void TestLibinputDevice::testLoadLeftHanded_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("false -> true") << false << true; QTest::newRow("true -> false") << true << false; QTest::newRow("true -> true") << true << true; QTest::newRow("false -> false") << false << false; } void TestLibinputDevice::testLoadLeftHanded() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(bool, configValue); QFETCH(bool, initValue); inputConfig.writeEntry("LeftHanded", configValue); libinput_device device; device.supportsLeftHanded = true; device.leftHanded = initValue; device.setLeftHandedReturnValue = false; Device d(&device); QCOMPARE(d.isLeftHanded(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.isLeftHanded(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.isLeftHanded(), configValue); // and try to store if (configValue != initValue) { d.setLeftHanded(initValue); QCOMPARE(inputConfig.readEntry("LeftHanded", configValue), initValue); } } void TestLibinputDevice::testLoadDisableWhileTyping_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("false -> true") << false << true; QTest::newRow("true -> false") << true << false; QTest::newRow("true -> true") << true << true; QTest::newRow("false -> false") << false << false; } void TestLibinputDevice::testLoadDisableWhileTyping() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(bool, configValue); QFETCH(bool, initValue); inputConfig.writeEntry("DisableWhileTyping", configValue); libinput_device device; device.supportsDisableWhileTyping = true; device.disableWhileTyping = initValue ? LIBINPUT_CONFIG_DWT_ENABLED : LIBINPUT_CONFIG_DWT_DISABLED; device.setDisableWhileTypingReturnValue = false; Device d(&device); QCOMPARE(d.isDisableWhileTyping(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.isDisableWhileTyping(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.isDisableWhileTyping(), configValue); // and try to store if (configValue != initValue) { d.setDisableWhileTyping(initValue); QCOMPARE(inputConfig.readEntry("DisableWhileTyping", configValue), initValue); } } void TestLibinputDevice::testLoadLmrTapButtonMap_data() { QTest::addColumn("initValue"); QTest::addColumn("configValue"); QTest::newRow("false -> true") << false << true; QTest::newRow("true -> false") << true << false; QTest::newRow("true -> true") << true << true; QTest::newRow("false -> false") << false << false; } void TestLibinputDevice::testLoadLmrTapButtonMap() { auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); KConfigGroup inputConfig(config, QStringLiteral("Test")); QFETCH(bool, configValue); QFETCH(bool, initValue); inputConfig.writeEntry("LmrTapButtonMap", configValue); libinput_device device; device.tapFingerCount = 3; device.tapButtonMap = initValue ? LIBINPUT_CONFIG_TAP_MAP_LMR : LIBINPUT_CONFIG_TAP_MAP_LRM; device.setTapButtonMapReturnValue = false; Device d(&device); QCOMPARE(d.lmrTapButtonMap(), initValue); // no config group set, should not change d.loadConfiguration(); QCOMPARE(d.lmrTapButtonMap(), initValue); // set the group d.setConfig(inputConfig); d.loadConfiguration(); QCOMPARE(d.lmrTapButtonMap(), configValue); // and try to store if (configValue != initValue) { d.setLmrTapButtonMap(initValue); QCOMPARE(inputConfig.readEntry("LmrTapButtonMap", configValue), initValue); } } void TestLibinputDevice::testScreenId() { libinput_device device; Device d(&device); QCOMPARE(d.screenId(), 0); d.setScreenId(1); QCOMPARE(d.screenId(), 1); } void TestLibinputDevice::testOrientation_data() { QTest::addColumn("orientation"); QTest::addColumn("m11"); QTest::addColumn("m12"); QTest::addColumn("m13"); QTest::addColumn("m21"); QTest::addColumn("m22"); QTest::addColumn("m23"); QTest::addColumn("defaultIsIdentity"); QTest::newRow("Primary") << Qt::PrimaryOrientation << 1.0f << 2.0f << 3.0f << 4.0f << 5.0f << 6.0f << false; QTest::newRow("Landscape") << Qt::LandscapeOrientation << 1.0f << 2.0f << 3.0f << 4.0f << 5.0f << 6.0f << false; QTest::newRow("Portrait") << Qt::PortraitOrientation << 0.0f << -1.0f << 1.0f << 1.0f << 0.0f << 0.0f << true; QTest::newRow("InvertedLandscape") << Qt::InvertedLandscapeOrientation << -1.0f << 0.0f << 1.0f << 0.0f << -1.0f << 1.0f << true; QTest::newRow("InvertedPortrait") << Qt::InvertedPortraitOrientation << 0.0f << 1.0f << 0.0f << -1.0f << 0.0f << 1.0f << true; } void TestLibinputDevice::testOrientation() { libinput_device device; device.supportsCalibrationMatrix = true; device.defaultCalibrationMatrix = std::array{{1.0, 2.0, 3.0, 4.0, 5.0, 6.0}}; QFETCH(bool, defaultIsIdentity); device.defaultCalibrationMatrixIsIdentity = defaultIsIdentity; Device d(&device); QFETCH(Qt::ScreenOrientation, orientation); d.setOrientation(orientation); QTEST(device.calibrationMatrix[0], "m11"); QTEST(device.calibrationMatrix[1], "m12"); QTEST(device.calibrationMatrix[2], "m13"); QTEST(device.calibrationMatrix[3], "m21"); QTEST(device.calibrationMatrix[4], "m22"); QTEST(device.calibrationMatrix[5], "m23"); } void TestLibinputDevice::testCalibrationWithDefault() { libinput_device device; device.supportsCalibrationMatrix = true; device.defaultCalibrationMatrix = std::array{{2.0, 3.0, 0.0, 4.0, 5.0, 0.0}}; device.defaultCalibrationMatrixIsIdentity = false; Device d(&device); d.setOrientation(Qt::PortraitOrientation); QCOMPARE(device.calibrationMatrix[0], 3.0f); QCOMPARE(device.calibrationMatrix[1], -2.0f); QCOMPARE(device.calibrationMatrix[2], 2.0f); QCOMPARE(device.calibrationMatrix[3], 5.0f); QCOMPARE(device.calibrationMatrix[4], -4.0f); QCOMPARE(device.calibrationMatrix[5], 4.0f); } void TestLibinputDevice::testSwitch_data() { QTest::addColumn("lid"); QTest::addColumn("tablet"); QTest::newRow("lid") << true << false; QTest::newRow("tablet") << false << true; } void TestLibinputDevice::testSwitch() { -#if HAVE_INPUT_1_9 libinput_device device; device.switchDevice = true; QFETCH(bool, lid); QFETCH(bool, tablet); device.lidSwitch = lid; device.tabletModeSwitch = tablet; Device d(&device); QCOMPARE(d.isSwitch(), true); QCOMPARE(d.isLidSwitch(), lid); QCOMPARE(d.property("lidSwitch").toBool(), lid); QCOMPARE(d.isTabletModeSwitch(), tablet); QCOMPARE(d.property("tabletModeSwitch").toBool(), tablet); -#else - QSKIP("Requires libinput 1.9"); -#endif } QTEST_GUILESS_MAIN(TestLibinputDevice) #include "device_test.moc" diff --git a/autotests/libinput/mock_libinput.cpp b/autotests/libinput/mock_libinput.cpp index 74aced6ce..a412078dd 100644 --- a/autotests/libinput/mock_libinput.cpp +++ b/autotests/libinput/mock_libinput.cpp @@ -1,864 +1,858 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2016 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include #include "mock_libinput.h" #include #include int libinput_device_keyboard_has_key(struct libinput_device *device, uint32_t code) { return device->keys.contains(code); } int libinput_device_has_capability(struct libinput_device *device, enum libinput_device_capability capability) { switch (capability) { case LIBINPUT_DEVICE_CAP_KEYBOARD: return device->keyboard; case LIBINPUT_DEVICE_CAP_POINTER: return device->pointer; case LIBINPUT_DEVICE_CAP_TOUCH: return device->touch; case LIBINPUT_DEVICE_CAP_GESTURE: return device->gestureSupported; case LIBINPUT_DEVICE_CAP_TABLET_TOOL: return device->tabletTool; -#if HAVE_INPUT_1_9 case LIBINPUT_DEVICE_CAP_SWITCH: return device->switchDevice; -#endif default: return 0; } } const char *libinput_device_get_name(struct libinput_device *device) { return device->name.constData(); } const char *libinput_device_get_sysname(struct libinput_device *device) { return device->sysName.constData(); } const char *libinput_device_get_output_name(struct libinput_device *device) { return device->outputName.constData(); } unsigned int libinput_device_get_id_product(struct libinput_device *device) { return device->product; } unsigned int libinput_device_get_id_vendor(struct libinput_device *device) { return device->vendor; } int libinput_device_config_tap_get_finger_count(struct libinput_device *device) { return device->tapFingerCount; } enum libinput_config_tap_state libinput_device_config_tap_get_enabled(struct libinput_device *device) { if (device->tapToClick) { return LIBINPUT_CONFIG_TAP_ENABLED; } else { return LIBINPUT_CONFIG_TAP_DISABLED; } } enum libinput_config_status libinput_device_config_tap_set_enabled(struct libinput_device *device, enum libinput_config_tap_state enable) { if (device->setTapToClickReturnValue == 0) { device->tapToClick = (enable == LIBINPUT_CONFIG_TAP_ENABLED); return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } enum libinput_config_tap_state libinput_device_config_tap_get_default_enabled(struct libinput_device *device) { if (device->tapEnabledByDefault) { return LIBINPUT_CONFIG_TAP_ENABLED; } else { return LIBINPUT_CONFIG_TAP_DISABLED; } } enum libinput_config_drag_state libinput_device_config_tap_get_default_drag_enabled(struct libinput_device *device) { if (device->tapAndDragEnabledByDefault) { return LIBINPUT_CONFIG_DRAG_ENABLED; } else { return LIBINPUT_CONFIG_DRAG_DISABLED; } } enum libinput_config_drag_state libinput_device_config_tap_get_drag_enabled(struct libinput_device *device) { if (device->tapAndDrag) { return LIBINPUT_CONFIG_DRAG_ENABLED; } else { return LIBINPUT_CONFIG_DRAG_DISABLED; } } enum libinput_config_status libinput_device_config_tap_set_drag_enabled(struct libinput_device *device, enum libinput_config_drag_state enable) { if (device->setTapAndDragReturnValue == 0) { device->tapAndDrag = (enable == LIBINPUT_CONFIG_DRAG_ENABLED); return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } enum libinput_config_drag_lock_state libinput_device_config_tap_get_default_drag_lock_enabled(struct libinput_device *device) { if (device->tapDragLockEnabledByDefault) { return LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; } else { return LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; } } enum libinput_config_drag_lock_state libinput_device_config_tap_get_drag_lock_enabled(struct libinput_device *device) { if (device->tapDragLock) { return LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; } else { return LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; } } enum libinput_config_status libinput_device_config_tap_set_drag_lock_enabled(struct libinput_device *device, enum libinput_config_drag_lock_state enable) { if (device->setTapDragLockReturnValue == 0) { device->tapDragLock = (enable == LIBINPUT_CONFIG_DRAG_LOCK_ENABLED); return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } int libinput_device_config_dwt_is_available(struct libinput_device *device) { return device->supportsDisableWhileTyping; } enum libinput_config_status libinput_device_config_dwt_set_enabled(struct libinput_device *device, enum libinput_config_dwt_state state) { if (device->setDisableWhileTypingReturnValue == 0) { if (!device->supportsDisableWhileTyping) { return LIBINPUT_CONFIG_STATUS_INVALID; } device->disableWhileTyping = state; return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } enum libinput_config_dwt_state libinput_device_config_dwt_get_enabled(struct libinput_device *device) { return device->disableWhileTyping; } enum libinput_config_dwt_state libinput_device_config_dwt_get_default_enabled(struct libinput_device *device) { return device->disableWhileTypingEnabledByDefault; } int libinput_device_config_accel_is_available(struct libinput_device *device) { return device->supportsPointerAcceleration; } int libinput_device_config_calibration_has_matrix(struct libinput_device *device) { return device->supportsCalibrationMatrix; } enum libinput_config_status libinput_device_config_calibration_set_matrix(struct libinput_device *device, const float matrix[6]) { for (std::size_t i = 0; i < 6; i++) { device->calibrationMatrix[i] = matrix[i]; } return LIBINPUT_CONFIG_STATUS_SUCCESS; } int libinput_device_config_calibration_get_default_matrix(struct libinput_device *device, float matrix[6]) { for (std::size_t i = 0; i < 6; i++) { matrix[i] = device->defaultCalibrationMatrix[i]; } return device->defaultCalibrationMatrixIsIdentity ? 0 : 1; } int libinput_device_config_left_handed_is_available(struct libinput_device *device) { return device->supportsLeftHanded; } uint32_t libinput_device_config_send_events_get_modes(struct libinput_device *device) { uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; if (device->supportsDisableEvents) { modes |= LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; } if (device->supportsDisableEventsOnExternalMouse) { modes |= LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; } return modes; } int libinput_device_config_left_handed_get(struct libinput_device *device) { return device->leftHanded; } double libinput_device_config_accel_get_default_speed(struct libinput_device *device) { return device->defaultPointerAcceleration; } int libinput_device_config_left_handed_get_default(struct libinput_device *device) { return device->leftHandedEnabledByDefault; } double libinput_device_config_accel_get_speed(struct libinput_device *device) { return device->pointerAcceleration; } uint32_t libinput_device_config_accel_get_profiles(struct libinput_device *device) { return device->supportedPointerAccelerationProfiles; } enum libinput_config_accel_profile libinput_device_config_accel_get_default_profile(struct libinput_device *device) { return device->defaultPointerAccelerationProfile; } enum libinput_config_status libinput_device_config_accel_set_profile(struct libinput_device *device, enum libinput_config_accel_profile profile) { if (device->setPointerAccelerationProfileReturnValue == 0) { if (!(device->supportedPointerAccelerationProfiles & profile) && profile!= LIBINPUT_CONFIG_ACCEL_PROFILE_NONE) { return LIBINPUT_CONFIG_STATUS_INVALID; } device->pointerAccelerationProfile = profile; return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } enum libinput_config_accel_profile libinput_device_config_accel_get_profile(struct libinput_device *device) { return device->pointerAccelerationProfile; } uint32_t libinput_device_config_send_events_get_mode(struct libinput_device *device) { if (device->enabled) { return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; } else { // TODO: disabled on eternal mouse return LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; } } struct libinput_device *libinput_device_ref(struct libinput_device *device) { return device; } struct libinput_device *libinput_device_unref(struct libinput_device *device) { return device; } int libinput_device_get_size(struct libinput_device *device, double *width, double *height) { if (device->deviceSizeReturnValue) { return device->deviceSizeReturnValue; } if (width) { *width = device->deviceSize.width(); } if (height) { *height = device->deviceSize.height(); } return device->deviceSizeReturnValue; } int libinput_device_pointer_has_button(struct libinput_device *device, uint32_t code) { switch (code) { case BTN_LEFT: return device->supportedButtons.testFlag(Qt::LeftButton); case BTN_MIDDLE: return device->supportedButtons.testFlag(Qt::MiddleButton); case BTN_RIGHT: return device->supportedButtons.testFlag(Qt::RightButton); case BTN_SIDE: return device->supportedButtons.testFlag(Qt::ExtraButton1); case BTN_EXTRA: return device->supportedButtons.testFlag(Qt::ExtraButton2); case BTN_BACK: return device->supportedButtons.testFlag(Qt::BackButton); case BTN_FORWARD: return device->supportedButtons.testFlag(Qt::ForwardButton); case BTN_TASK: return device->supportedButtons.testFlag(Qt::TaskButton); default: return 0; } } enum libinput_config_status libinput_device_config_left_handed_set(struct libinput_device *device, int left_handed) { if (device->setLeftHandedReturnValue == 0) { device->leftHanded = left_handed; return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } enum libinput_config_status libinput_device_config_accel_set_speed(struct libinput_device *device, double speed) { if (device->setPointerAccelerationReturnValue == 0) { device->pointerAcceleration = speed; return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } enum libinput_config_status libinput_device_config_send_events_set_mode(struct libinput_device *device, uint32_t mode) { if (device->setEnableModeReturnValue == 0) { device->enabled = (mode == LIBINPUT_CONFIG_SEND_EVENTS_ENABLED); return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } enum libinput_event_type libinput_event_get_type(struct libinput_event *event) { return event->type; } struct libinput_device *libinput_event_get_device(struct libinput_event *event) { return event->device; } void libinput_event_destroy(struct libinput_event *event) { delete event; } struct libinput_event_keyboard *libinput_event_get_keyboard_event(struct libinput_event *event) { if (event->type == LIBINPUT_EVENT_KEYBOARD_KEY) { return reinterpret_cast(event); } return nullptr; } struct libinput_event_pointer *libinput_event_get_pointer_event(struct libinput_event *event) { if (event->type == LIBINPUT_EVENT_POINTER_MOTION || event->type == LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE || event->type == LIBINPUT_EVENT_POINTER_BUTTON || event->type == LIBINPUT_EVENT_POINTER_AXIS) { return reinterpret_cast(event); } return nullptr; } struct libinput_event_touch *libinput_event_get_touch_event(struct libinput_event *event) { if (event->type == LIBINPUT_EVENT_TOUCH_DOWN || event->type == LIBINPUT_EVENT_TOUCH_UP || event->type == LIBINPUT_EVENT_TOUCH_MOTION || event->type == LIBINPUT_EVENT_TOUCH_CANCEL || event->type == LIBINPUT_EVENT_TOUCH_FRAME) { return reinterpret_cast(event); } return nullptr; } struct libinput_event_gesture *libinput_event_get_gesture_event(struct libinput_event *event) { if (event->type == LIBINPUT_EVENT_GESTURE_PINCH_BEGIN || event->type == LIBINPUT_EVENT_GESTURE_PINCH_UPDATE || event->type == LIBINPUT_EVENT_GESTURE_PINCH_END || event->type == LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN || event->type == LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE || event->type == LIBINPUT_EVENT_GESTURE_SWIPE_END) { return reinterpret_cast(event); } return nullptr; } int libinput_event_gesture_get_cancelled(struct libinput_event_gesture *event) { if (event->type == LIBINPUT_EVENT_GESTURE_PINCH_END || event->type == LIBINPUT_EVENT_GESTURE_SWIPE_END) { return event->cancelled; } return 0; } uint32_t libinput_event_gesture_get_time(struct libinput_event_gesture *event) { return event->time; } int libinput_event_gesture_get_finger_count(struct libinput_event_gesture *event) { return event->fingerCount; } double libinput_event_gesture_get_dx(struct libinput_event_gesture *event) { if (event->type == LIBINPUT_EVENT_GESTURE_PINCH_UPDATE || event->type == LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE) { return event->delta.width(); } return 0.0; } double libinput_event_gesture_get_dy(struct libinput_event_gesture *event) { if (event->type == LIBINPUT_EVENT_GESTURE_PINCH_UPDATE || event->type == LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE) { return event->delta.height(); } return 0.0; } double libinput_event_gesture_get_scale(struct libinput_event_gesture *event) { switch (event->type) { case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: return 1.0; case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: case LIBINPUT_EVENT_GESTURE_PINCH_END: return event->scale; default: return 0.0; } } double libinput_event_gesture_get_angle_delta(struct libinput_event_gesture *event) { if (event->type == LIBINPUT_EVENT_GESTURE_PINCH_UPDATE) { return event->angleDelta; } return 0.0; } uint32_t libinput_event_keyboard_get_key(struct libinput_event_keyboard *event) { return event->key; } enum libinput_key_state libinput_event_keyboard_get_key_state(struct libinput_event_keyboard *event) { return event->state; } uint32_t libinput_event_keyboard_get_time(struct libinput_event_keyboard *event) { return event->time; } double libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event) { return event->absolutePos.x(); } double libinput_event_pointer_get_absolute_y(struct libinput_event_pointer *event) { return event->absolutePos.y(); } double libinput_event_pointer_get_absolute_x_transformed(struct libinput_event_pointer *event, uint32_t width) { double deviceWidth = 0.0; double deviceHeight = 0.0; libinput_device_get_size(event->device, &deviceWidth, &deviceHeight); return event->absolutePos.x() / deviceWidth * width; } double libinput_event_pointer_get_absolute_y_transformed(struct libinput_event_pointer *event, uint32_t height) { double deviceWidth = 0.0; double deviceHeight = 0.0; libinput_device_get_size(event->device, &deviceWidth, &deviceHeight); return event->absolutePos.y() / deviceHeight * height; } double libinput_event_pointer_get_dx(struct libinput_event_pointer *event) { return event->delta.width(); } double libinput_event_pointer_get_dy(struct libinput_event_pointer *event) { return event->delta.height(); } double libinput_event_pointer_get_dx_unaccelerated(struct libinput_event_pointer *event) { return event->delta.width(); } double libinput_event_pointer_get_dy_unaccelerated(struct libinput_event_pointer *event) { return event->delta.height(); } uint32_t libinput_event_pointer_get_time(struct libinput_event_pointer *event) { return event->time; } uint64_t libinput_event_pointer_get_time_usec(struct libinput_event_pointer *event) { return quint64(event->time * 1000); } uint32_t libinput_event_pointer_get_button(struct libinput_event_pointer *event) { return event->button; } enum libinput_button_state libinput_event_pointer_get_button_state(struct libinput_event_pointer *event) { return event->buttonState; } int libinput_event_pointer_has_axis(struct libinput_event_pointer *event, enum libinput_pointer_axis axis) { if (axis == LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL) { return event->verticalAxis; } else { return event->horizontalAxis; } } double libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event, enum libinput_pointer_axis axis) { if (axis == LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL) { return event->verticalAxisValue; } else { return event->horizontalAxisValue; } } uint32_t libinput_event_touch_get_time(struct libinput_event_touch *event) { return event->time; } double libinput_event_touch_get_x(struct libinput_event_touch *event) { return event->absolutePos.x(); } double libinput_event_touch_get_y(struct libinput_event_touch *event) { return event->absolutePos.y(); } double libinput_event_touch_get_x_transformed(struct libinput_event_touch *event, uint32_t width) { double deviceWidth = 0.0; double deviceHeight = 0.0; libinput_device_get_size(event->device, &deviceWidth, &deviceHeight); return event->absolutePos.x() / deviceWidth * width; } double libinput_event_touch_get_y_transformed(struct libinput_event_touch *event, uint32_t height) { double deviceWidth = 0.0; double deviceHeight = 0.0; libinput_device_get_size(event->device, &deviceWidth, &deviceHeight); return event->absolutePos.y() / deviceHeight * height; } int32_t libinput_event_touch_get_slot(struct libinput_event_touch *event) { return event->slot; } struct libinput *libinput_udev_create_context(const struct libinput_interface *interface, void *user_data, struct udev *udev) { if (!udev) { return nullptr; } Q_UNUSED(interface) Q_UNUSED(user_data) return new libinput; } void libinput_log_set_priority(struct libinput *libinput, enum libinput_log_priority priority) { Q_UNUSED(libinput) Q_UNUSED(priority) } void libinput_log_set_handler(struct libinput *libinput, libinput_log_handler log_handler) { Q_UNUSED(libinput) Q_UNUSED(log_handler) } struct libinput *libinput_unref(struct libinput *libinput) { libinput->refCount--; if (libinput->refCount == 0) { delete libinput; return nullptr; } return libinput; } int libinput_udev_assign_seat(struct libinput *libinput, const char *seat_id) { if (libinput->assignSeatRetVal == 0) { libinput->seat = QByteArray(seat_id); } return libinput->assignSeatRetVal; } int libinput_get_fd(struct libinput *libinput) { Q_UNUSED(libinput) return -1; } int libinput_dispatch(struct libinput *libinput) { Q_UNUSED(libinput) return 0; } struct libinput_event *libinput_get_event(struct libinput *libinput) { Q_UNUSED(libinput) return nullptr; } void libinput_suspend(struct libinput *libinput) { Q_UNUSED(libinput) } int libinput_resume(struct libinput *libinput) { Q_UNUSED(libinput) return 0; } int libinput_device_config_middle_emulation_is_available(struct libinput_device *device) { return device->supportsMiddleEmulation; } enum libinput_config_status libinput_device_config_middle_emulation_set_enabled(struct libinput_device *device, enum libinput_config_middle_emulation_state enable) { if (device->setMiddleEmulationReturnValue == 0) { if (!device->supportsMiddleEmulation) { return LIBINPUT_CONFIG_STATUS_INVALID; } device->middleEmulation = (enable == LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED); return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } enum libinput_config_middle_emulation_state libinput_device_config_middle_emulation_get_enabled(struct libinput_device *device) { if (device->middleEmulation) { return LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; } else { return LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; } } enum libinput_config_middle_emulation_state libinput_device_config_middle_emulation_get_default_enabled(struct libinput_device *device) { if (device->middleEmulationEnabledByDefault) { return LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; } else { return LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; } } int libinput_device_config_scroll_has_natural_scroll(struct libinput_device *device) { return device->supportsNaturalScroll; } enum libinput_config_status libinput_device_config_scroll_set_natural_scroll_enabled(struct libinput_device *device, int enable) { if (device->setNaturalScrollReturnValue == 0) { if (!device->supportsNaturalScroll) { return LIBINPUT_CONFIG_STATUS_INVALID; } device->naturalScroll = enable; return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } int libinput_device_config_scroll_get_natural_scroll_enabled(struct libinput_device *device) { return device->naturalScroll; } int libinput_device_config_scroll_get_default_natural_scroll_enabled(struct libinput_device *device) { return device->naturalScrollEnabledByDefault; } enum libinput_config_tap_button_map libinput_device_config_tap_get_default_button_map(struct libinput_device *device) { return device->defaultTapButtonMap; } enum libinput_config_status libinput_device_config_tap_set_button_map(struct libinput_device *device, enum libinput_config_tap_button_map map) { if (device->setTapButtonMapReturnValue == 0) { if (device->tapFingerCount == 0) { return LIBINPUT_CONFIG_STATUS_INVALID; } device->tapButtonMap = map; return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } enum libinput_config_tap_button_map libinput_device_config_tap_get_button_map(struct libinput_device *device) { return device->tapButtonMap; } uint32_t libinput_device_config_scroll_get_methods(struct libinput_device *device) { return device->supportedScrollMethods; } enum libinput_config_scroll_method libinput_device_config_scroll_get_default_method(struct libinput_device *device) { return device->defaultScrollMethod; } enum libinput_config_status libinput_device_config_scroll_set_method(struct libinput_device *device, enum libinput_config_scroll_method method) { if (device->setScrollMethodReturnValue == 0) { if (!(device->supportedScrollMethods & method) && method != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) { return LIBINPUT_CONFIG_STATUS_INVALID; } device->scrollMethod = method; return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } enum libinput_config_scroll_method libinput_device_config_scroll_get_method(struct libinput_device *device) { return device->scrollMethod; } enum libinput_config_status libinput_device_config_scroll_set_button(struct libinput_device *device, uint32_t button) { if (device->setScrollButtonReturnValue == 0) { if (!(device->supportedScrollMethods & LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN)) { return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; } device->scrollButton = button; return LIBINPUT_CONFIG_STATUS_SUCCESS; } return LIBINPUT_CONFIG_STATUS_INVALID; } uint32_t libinput_device_config_scroll_get_button(struct libinput_device *device) { return device->scrollButton; } uint32_t libinput_device_config_scroll_get_default_button(struct libinput_device *device) { return device->defaultScrollButton; } -#if HAVE_INPUT_1_9 - int libinput_device_switch_has_switch(struct libinput_device *device, enum libinput_switch sw) { switch (sw) { case LIBINPUT_SWITCH_LID: return device->lidSwitch; case LIBINPUT_SWITCH_TABLET_MODE: return device->tabletModeSwitch; default: Q_UNREACHABLE(); } return 0; } struct libinput_event_switch *libinput_event_get_switch_event(struct libinput_event *event) { if (event->type == LIBINPUT_EVENT_SWITCH_TOGGLE) { return reinterpret_cast(event); } else { return nullptr; } } enum libinput_switch_state libinput_event_switch_get_switch_state(struct libinput_event_switch *event) { switch (event->state) { case libinput_event_switch::State::On: return LIBINPUT_SWITCH_STATE_ON; case libinput_event_switch::State::Off: return LIBINPUT_SWITCH_STATE_OFF; default: Q_UNREACHABLE(); } } uint32_t libinput_event_switch_get_time(struct libinput_event_switch *event) { return event->time;; } uint64_t libinput_event_switch_get_time_usec(struct libinput_event_switch *event) { return event->timeMicroseconds; } - -#endif diff --git a/config-kwin.h.cmake b/config-kwin.h.cmake index ebae8aef0..1566d649f 100644 --- a/config-kwin.h.cmake +++ b/config-kwin.h.cmake @@ -1,45 +1,44 @@ #cmakedefine KWIN_BUILD_DECORATIONS 1 #cmakedefine KWIN_BUILD_TABBOX 1 #cmakedefine KWIN_BUILD_ACTIVITIES 1 #define KWIN_NAME "${KWIN_NAME}" #define KWIN_INTERNAL_NAME_X11 "${KWIN_INTERNAL_NAME_X11}" #define KWIN_CONFIG "${KWIN_NAME}rc" #define KWIN_VERSION_STRING "${PROJECT_VERSION}" #define XCB_VERSION_STRING "${XCB_VERSION}" #define KWIN_KILLER_BIN "${CMAKE_INSTALL_FULL_LIBEXECDIR}/kwin_killer_helper" #define KWIN_RULES_DIALOG_BIN "${CMAKE_INSTALL_FULL_LIBEXECDIR}/kwin_rules_dialog" #define KWIN_XCLIPBOARD_SYNC_BIN "${CMAKE_INSTALL_FULL_LIBEXECDIR}/org_kde_kwin_xclipboard_syncer" #cmakedefine01 HAVE_INPUT -#cmakedefine01 HAVE_INPUT_1_9 #cmakedefine01 HAVE_X11_XCB #cmakedefine01 HAVE_X11_XINPUT #cmakedefine01 HAVE_DRM #cmakedefine01 HAVE_GBM #cmakedefine01 HAVE_LIBHYBRIS #cmakedefine01 HAVE_WAYLAND_EGL #cmakedefine01 HAVE_SYS_PRCTL_H #cmakedefine01 HAVE_PR_SET_DUMPABLE #cmakedefine01 HAVE_PR_SET_PDEATHSIG #cmakedefine01 HAVE_SYS_PROCCTL_H #cmakedefine01 HAVE_PROC_TRACE_CTL #cmakedefine01 HAVE_SYS_SYSMACROS_H #cmakedefine01 HAVE_BREEZE_DECO #cmakedefine01 HAVE_UDEV #cmakedefine01 HAVE_LIBCAP #cmakedefine01 HAVE_SCHED_RESET_ON_FORK #if HAVE_BREEZE_DECO #define BREEZE_KDECORATION_PLUGIN_ID "${BREEZE_KDECORATION_PLUGIN_ID}" #endif /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_MALLOC_H 1 #cmakedefine XCB_ICCCM_FOUND 1 #ifndef XCB_ICCCM_FOUND #define XCB_ICCCM_WM_STATE_WITHDRAWN 0 #define XCB_ICCCM_WM_STATE_NORMAL 1 #define XCB_ICCCM_WM_STATE_ICONIC 3 #endif diff --git a/libinput/connection.cpp b/libinput/connection.cpp index 9e74d6f52..38f00b23f 100644 --- a/libinput/connection.cpp +++ b/libinput/connection.cpp @@ -1,691 +1,689 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2014 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "connection.h" #include "context.h" #include "device.h" #include "events.h" #ifndef KWIN_BUILD_TESTING #include "../screens.h" #endif #include "../logind.h" #include "../udev.h" #include "libinput_logging.h" #include #include #include #include #include #include #include #include #include namespace KWin { namespace LibInput { class ConnectionAdaptor : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.InputDeviceManager") Q_PROPERTY(QStringList devicesSysNames READ devicesSysNames CONSTANT) private: Connection *m_con; public: ConnectionAdaptor(Connection *con) : m_con(con) { connect(con, &Connection::deviceAddedSysName, this, &ConnectionAdaptor::deviceAdded, Qt::QueuedConnection); connect(con, &Connection::deviceRemovedSysName, this, &ConnectionAdaptor::deviceRemoved, Qt::QueuedConnection); QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin/InputDevice"), QStringLiteral("org.kde.KWin.InputDeviceManager"), this, QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSignals ); } ~ConnectionAdaptor() { QDBusConnection::sessionBus().unregisterObject(QStringLiteral("/org/kde/KWin/InputDeviceManager")); } QStringList devicesSysNames() { // TODO: is this allowed? directly calling function of object in another thread!? // otherwise use signal-slot mechanism return m_con->devicesSysNames(); } Q_SIGNALS: void deviceAdded(QString sysName); void deviceRemoved(QString sysName); }; Connection *Connection::s_self = nullptr; QPointer Connection::s_thread; static ConnectionAdaptor *s_adaptor = nullptr; static Context *s_context = nullptr; static quint32 toLibinputLEDS(Xkb::LEDs leds) { quint32 libinputLeds = 0; if (leds.testFlag(Xkb::LED::NumLock)) { libinputLeds = libinputLeds | LIBINPUT_LED_NUM_LOCK; } if (leds.testFlag(Xkb::LED::CapsLock)) { libinputLeds = libinputLeds | LIBINPUT_LED_CAPS_LOCK; } if (leds.testFlag(Xkb::LED::ScrollLock)) { libinputLeds = libinputLeds | LIBINPUT_LED_SCROLL_LOCK; } return libinputLeds; } Connection::Connection(QObject *parent) : Connection(nullptr, parent) { // only here to fix build, using will crash, BUG 343529 } void Connection::createThread() { if (s_thread) { return; } s_thread = new QThread(); s_thread->setObjectName(QStringLiteral("libinput-connection")); s_thread->start(); } Connection *Connection::create(QObject *parent) { Q_ASSERT(!s_self); static Udev s_udev; if (!s_udev.isValid()) { qCWarning(KWIN_LIBINPUT) << "Failed to initialize udev"; return nullptr; } if (!s_context) { s_context = new Context(s_udev); if (!s_context->isValid()) { qCWarning(KWIN_LIBINPUT) << "Failed to create context from udev"; delete s_context; s_context = nullptr; return nullptr; } // TODO: don't hardcode seat name if (!s_context->assignSeat("seat0")) { qCWarning(KWIN_LIBINPUT) << "Failed to assign seat seat0"; delete s_context; s_context = nullptr; return nullptr; } } Connection::createThread(); s_self = new Connection(s_context); s_self->moveToThread(s_thread); QObject::connect(s_thread, &QThread::finished, s_self, &QObject::deleteLater); QObject::connect(s_thread, &QThread::finished, s_thread, &QObject::deleteLater); QObject::connect(parent, &QObject::destroyed, s_thread, &QThread::quit); if (!s_adaptor) { s_adaptor = new ConnectionAdaptor(s_self); } return s_self; } Connection::Connection(Context *input, QObject *parent) : QObject(parent) , m_input(input) , m_notifier(nullptr) , m_mutex(QMutex::Recursive) , m_leds() { Q_ASSERT(m_input); // need to connect to KGlobalSettings as the mouse KCM does not emit a dedicated signal QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"), QStringLiteral("notifyChange"), this, SLOT(slotKGlobalSettingsNotifyChange(int,int))); } Connection::~Connection() { delete s_adaptor; s_adaptor = nullptr; s_self = nullptr; delete s_context; s_context = nullptr; } void Connection::setup() { QMetaObject::invokeMethod(this, "doSetup", Qt::QueuedConnection); } void Connection::doSetup() { connect(s_self, &Connection::deviceAdded, s_self, [](Device* device) { emit s_self->deviceAddedSysName(device->sysName()); }); connect(s_self, &Connection::deviceRemoved, s_self, [](Device* device) { emit s_self->deviceRemovedSysName(device->sysName()); }); Q_ASSERT(!m_notifier); m_notifier = new QSocketNotifier(m_input->fileDescriptor(), QSocketNotifier::Read, this); connect(m_notifier, &QSocketNotifier::activated, this, &Connection::handleEvent); LogindIntegration *logind = LogindIntegration::self(); connect(logind, &LogindIntegration::sessionActiveChanged, this, [this](bool active) { if (active) { if (!m_input->isSuspended()) { return; } m_input->resume(); wasSuspended = true; } else { deactivate(); } } ); handleEvent(); } void Connection::deactivate() { if (m_input->isSuspended()) { return; } m_keyboardBeforeSuspend = hasKeyboard(); m_alphaNumericKeyboardBeforeSuspend = hasAlphaNumericKeyboard(); m_pointerBeforeSuspend = hasPointer(); m_touchBeforeSuspend = hasTouch(); m_input->suspend(); handleEvent(); } void Connection::handleEvent() { QMutexLocker locker(&m_mutex); const bool wasEmpty = m_eventQueue.isEmpty(); do { m_input->dispatch(); Event *event = m_input->event(); if (!event) { break; } m_eventQueue << event; } while (true); if (wasEmpty && !m_eventQueue.isEmpty()) { emit eventsRead(); } } void Connection::processEvents() { QMutexLocker locker(&m_mutex); while (!m_eventQueue.isEmpty()) { QScopedPointer event(m_eventQueue.takeFirst()); switch (event->type()) { case LIBINPUT_EVENT_DEVICE_ADDED: { auto device = new Device(event->nativeDevice()); device->moveToThread(s_thread); m_devices << device; if (device->isKeyboard()) { m_keyboard++; if (device->isAlphaNumericKeyboard()) { m_alphaNumericKeyboard++; if (m_alphaNumericKeyboard == 1) { emit hasAlphaNumericKeyboardChanged(true); } } if (m_keyboard == 1) { emit hasKeyboardChanged(true); } } if (device->isPointer()) { m_pointer++; if (m_pointer == 1) { emit hasPointerChanged(true); } } if (device->isTouch()) { m_touch++; if (m_touch == 1) { emit hasTouchChanged(true); } } applyDeviceConfig(device); applyScreenToDevice(device); // enable possible leds libinput_device_led_update(device->device(), static_cast(toLibinputLEDS(m_leds))); emit deviceAdded(device); break; } case LIBINPUT_EVENT_DEVICE_REMOVED: { auto it = std::find_if(m_devices.begin(), m_devices.end(), [&event] (Device *d) { return event->device() == d; } ); if (it == m_devices.end()) { // we don't know this device break; } auto device = *it; m_devices.erase(it); emit deviceRemoved(device); if (device->isKeyboard()) { m_keyboard--; if (device->isAlphaNumericKeyboard()) { m_alphaNumericKeyboard--; if (m_alphaNumericKeyboard == 0) { emit hasAlphaNumericKeyboardChanged(false); } } if (m_keyboard == 0) { emit hasKeyboardChanged(false); } } if (device->isPointer()) { m_pointer--; if (m_pointer == 0) { emit hasPointerChanged(false); } } if (device->isTouch()) { m_touch--; if (m_touch == 0) { emit hasTouchChanged(false); } } device->deleteLater(); break; } case LIBINPUT_EVENT_KEYBOARD_KEY: { KeyEvent *ke = static_cast(event.data()); emit keyChanged(ke->key(), ke->state(), ke->time(), ke->device()); break; } case LIBINPUT_EVENT_POINTER_AXIS: { PointerEvent *pe = static_cast(event.data()); struct Axis { qreal delta = 0.0; quint32 time = 0; }; QMap deltas; auto update = [&deltas] (PointerEvent *pe) { const auto axis = pe->axis(); for (auto it = axis.begin(); it != axis.end(); ++it) { deltas[*it].delta += pe->axisValue(*it); deltas[*it].time = pe->time(); } }; update(pe); auto it = m_eventQueue.begin(); while (it != m_eventQueue.end()) { if ((*it)->type() == LIBINPUT_EVENT_POINTER_AXIS) { QScopedPointer p(static_cast(*it)); update(p.data()); it = m_eventQueue.erase(it); } else { break; } } for (auto it = deltas.constBegin(); it != deltas.constEnd(); ++it) { emit pointerAxisChanged(it.key(), it.value().delta, it.value().time, pe->device()); } break; } case LIBINPUT_EVENT_POINTER_BUTTON: { PointerEvent *pe = static_cast(event.data()); emit pointerButtonChanged(pe->button(), pe->buttonState(), pe->time(), pe->device()); break; } case LIBINPUT_EVENT_POINTER_MOTION: { PointerEvent *pe = static_cast(event.data()); auto delta = pe->delta(); auto deltaNonAccel = pe->deltaUnaccelerated(); quint32 latestTime = pe->time(); quint64 latestTimeUsec = pe->timeMicroseconds(); auto it = m_eventQueue.begin(); while (it != m_eventQueue.end()) { if ((*it)->type() == LIBINPUT_EVENT_POINTER_MOTION) { QScopedPointer p(static_cast(*it)); delta += p->delta(); deltaNonAccel += p->deltaUnaccelerated(); latestTime = p->time(); latestTimeUsec = p->timeMicroseconds(); it = m_eventQueue.erase(it); } else { break; } } emit pointerMotion(delta, deltaNonAccel, latestTime, latestTimeUsec, pe->device()); break; } case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: { PointerEvent *pe = static_cast(event.data()); emit pointerMotionAbsolute(pe->absolutePos(), pe->absolutePos(m_size), pe->time(), pe->device()); break; } case LIBINPUT_EVENT_TOUCH_DOWN: { #ifndef KWIN_BUILD_TESTING TouchEvent *te = static_cast(event.data()); const auto &geo = screens()->geometry(te->device()->screenId()); emit touchDown(te->id(), geo.topLeft() + te->absolutePos(geo.size()), te->time(), te->device()); break; #endif } case LIBINPUT_EVENT_TOUCH_UP: { TouchEvent *te = static_cast(event.data()); emit touchUp(te->id(), te->time(), te->device()); break; } case LIBINPUT_EVENT_TOUCH_MOTION: { #ifndef KWIN_BUILD_TESTING TouchEvent *te = static_cast(event.data()); const auto &geo = screens()->geometry(te->device()->screenId()); emit touchMotion(te->id(), geo.topLeft() + te->absolutePos(geo.size()), te->time(), te->device()); break; #endif } case LIBINPUT_EVENT_TOUCH_CANCEL: { emit touchCanceled(event->device()); break; } case LIBINPUT_EVENT_TOUCH_FRAME: { emit touchFrame(event->device()); break; } case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: { PinchGestureEvent *pe = static_cast(event.data()); emit pinchGestureBegin(pe->fingerCount(), pe->time(), pe->device()); break; } case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: { PinchGestureEvent *pe = static_cast(event.data()); emit pinchGestureUpdate(pe->scale(), pe->angleDelta(), pe->delta(), pe->time(), pe->device()); break; } case LIBINPUT_EVENT_GESTURE_PINCH_END: { PinchGestureEvent *pe = static_cast(event.data()); if (pe->isCancelled()) { emit pinchGestureCancelled(pe->time(), pe->device()); } else { emit pinchGestureEnd(pe->time(), pe->device()); } break; } case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: { SwipeGestureEvent *se = static_cast(event.data()); emit swipeGestureBegin(se->fingerCount(), se->time(), se->device()); break; } case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: { SwipeGestureEvent *se = static_cast(event.data()); emit swipeGestureUpdate(se->delta(), se->time(), se->device()); break; } case LIBINPUT_EVENT_GESTURE_SWIPE_END: { SwipeGestureEvent *se = static_cast(event.data()); if (se->isCancelled()) { emit swipeGestureCancelled(se->time(), se->device()); } else { emit swipeGestureEnd(se->time(), se->device()); } break; } -#if HAVE_INPUT_1_9 case LIBINPUT_EVENT_SWITCH_TOGGLE: { SwitchEvent *se = static_cast(event.data()); switch (se->state()) { case SwitchEvent::State::Off: emit switchToggledOff(se->time(), se->timeMicroseconds(), se->device()); break; case SwitchEvent::State::On: emit switchToggledOn(se->time(), se->timeMicroseconds(), se->device()); break; default: Q_UNREACHABLE(); } break; } -#endif default: // nothing break; } } if (wasSuspended) { if (m_keyboardBeforeSuspend && !m_keyboard) { emit hasKeyboardChanged(false); } if (m_alphaNumericKeyboardBeforeSuspend && !m_alphaNumericKeyboard) { emit hasAlphaNumericKeyboardChanged(false); } if (m_pointerBeforeSuspend && !m_pointer) { emit hasPointerChanged(false); } if (m_touchBeforeSuspend && !m_touch) { emit hasTouchChanged(false); } wasSuspended = false; } } void Connection::setScreenSize(const QSize &size) { m_size = size; } void Connection::updateScreens() { QMutexLocker locker(&m_mutex); for (auto device: qAsConst(m_devices)) { applyScreenToDevice(device); } } void Connection::applyScreenToDevice(Device *device) { #ifndef KWIN_BUILD_TESTING QMutexLocker locker(&m_mutex); if (!device->isTouch()) { return; } int id = -1; // let's try to find a screen for it if (screens()->count() == 1) { id = 0; } if (id == -1 && !device->outputName().isEmpty()) { // we have an output name, try to find a screen with matching name for (int i = 0; i < screens()->count(); i++) { if (screens()->name(i) == device->outputName()) { id = i; break; } } } if (id == -1) { // do we have an internal screen? int internalId = -1; for (int i = 0; i < screens()->count(); i++) { if (screens()->isInternal(i)) { internalId = i; break; } } auto testScreenMatches = [device] (int id) { const auto &size = device->size(); const auto &screenSize = screens()->physicalSize(id); return std::round(size.width()) == std::round(screenSize.width()) && std::round(size.height()) == std::round(screenSize.height()); }; if (internalId != -1 && testScreenMatches(internalId)) { id = internalId; } // let's compare all screens for size for (int i = 0; i < screens()->count(); i++) { if (testScreenMatches(i)) { id = i; break; } } if (id == -1) { // still not found if (internalId != -1) { // we have an internal id, so let's use that id = internalId; } else { // just take first screen, we have no clue id = 0; } } } device->setScreenId(id); device->setOrientation(screens()->orientation(id)); #else Q_UNUSED(device) #endif } bool Connection::isSuspended() const { if (!s_context) { return false; } return s_context->isSuspended(); } void Connection::applyDeviceConfig(Device *device) { // pass configuration to Device device->setConfig(m_config->group("Libinput").group(QString::number(device->vendor())).group(QString::number(device->product())).group(device->name())); device->loadConfiguration(); if (device->isPointer() && !device->isTouchpad()) { const KConfigGroup group = m_config->group("Mouse"); device->setLeftHanded(group.readEntry("MouseButtonMapping", "RightHanded") == QLatin1String("LeftHanded")); qreal accel = group.readEntry("Acceleration", -1.0); if (qFuzzyCompare(accel, -1.0) || qFuzzyCompare(accel, 1.0)) { // default value device->setPointerAcceleration(0.0); } else { // the X11-based config is mapped in [0.1,20.0] with 1.0 being the "normal" setting - we assume that's the default if (accel < 1.0) { device->setPointerAcceleration(-1.0 + ((accel * 10.0) - 1.0) / 9.0); } else { device->setPointerAcceleration((accel -1.0)/19.0); } } } } void Connection::slotKGlobalSettingsNotifyChange(int type, int arg) { if (type == 3 /**SettingsChanged**/ && arg == 0 /** SETTINGS_MOUSE **/) { m_config->reparseConfiguration(); for (auto it = m_devices.constBegin(), end = m_devices.constEnd(); it != end; ++it) { if ((*it)->isPointer()) { applyDeviceConfig(*it); } } } } void Connection::toggleTouchpads() { bool changed = false; m_touchpadsEnabled = !m_touchpadsEnabled; for (auto it = m_devices.constBegin(); it != m_devices.constEnd(); ++it) { auto device = *it; if (!device->isTouchpad()) { continue; } const bool old = device->isEnabled(); device->setEnabled(m_touchpadsEnabled); if (old != device->isEnabled()) { changed = true; } } if (changed) { // send OSD message QDBusMessage msg = QDBusMessage::createMethodCall( QStringLiteral("org.kde.plasmashell"), QStringLiteral("/org/kde/osdService"), QStringLiteral("org.kde.osdService"), QStringLiteral("touchpadEnabledChanged") ); msg.setArguments({m_touchpadsEnabled}); QDBusConnection::sessionBus().asyncCall(msg); } } void Connection::enableTouchpads() { if (m_touchpadsEnabled) { return; } toggleTouchpads(); } void Connection::disableTouchpads() { if (!m_touchpadsEnabled) { return; } toggleTouchpads(); } void Connection::updateLEDs(Xkb::LEDs leds) { if (m_leds == leds) { return; } m_leds = leds; // update on devices const libinput_led l = static_cast(toLibinputLEDS(leds)); for (auto it = m_devices.constBegin(), end = m_devices.constEnd(); it != end; ++it) { libinput_device_led_update((*it)->device(), l); } } QStringList Connection::devicesSysNames() const { QStringList sl; foreach (Device *d, m_devices) { sl.append(d->sysName()); } return sl; } } } #include "connection.moc" diff --git a/libinput/device.cpp b/libinput/device.cpp index c92f3d587..330499d39 100644 --- a/libinput/device.cpp +++ b/libinput/device.cpp @@ -1,502 +1,500 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2016 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "device.h" #include #include #include namespace KWin { namespace LibInput { static bool checkAlphaNumericKeyboard(libinput_device *device) { for (uint i = KEY_1; i <= KEY_0; i++) { if (libinput_device_keyboard_has_key(device, i) == 0) { return false; } } for (uint i = KEY_Q; i <= KEY_P; i++) { if (libinput_device_keyboard_has_key(device, i) == 0) { return false; } } for (uint i = KEY_A; i <= KEY_L; i++) { if (libinput_device_keyboard_has_key(device, i) == 0) { return false; } } for (uint i = KEY_Z; i <= KEY_M; i++) { if (libinput_device_keyboard_has_key(device, i) == 0) { return false; } } return true; } QVector Device::s_devices; Device *Device::getDevice(libinput_device *native) { auto it = std::find_if(s_devices.constBegin(), s_devices.constEnd(), [native] (const Device *d) { return d->device() == native; } ); if (it != s_devices.constEnd()) { return *it; } return nullptr; } enum class ConfigKey { Enabled, LeftHanded, DisableWhileTyping, PointerAcceleration, PointerAccelerationProfile, TapToClick, LmrTapButtonMap, TapAndDrag, TapDragLock, MiddleButtonEmulation, NaturalScroll, ScrollMethod, ScrollButton }; struct ConfigData { explicit ConfigData(QByteArray _key, void (Device::*_setter)(bool), bool (Device::*_defaultValue)() const = nullptr) : key(_key) { booleanSetter.setter = _setter; booleanSetter.defaultValue = _defaultValue; } explicit ConfigData(QByteArray _key, void (Device::*_setter)(quint32), quint32 (Device::*_defaultValue)() const = nullptr) : key(_key) { quint32Setter.setter = _setter; quint32Setter.defaultValue = _defaultValue; } explicit ConfigData(QByteArray _key, void (Device::*_setter)(QString), QString (Device::*_defaultValue)() const = nullptr) : key(_key) { stringSetter.setter = _setter; stringSetter.defaultValue = _defaultValue; } QByteArray key; struct { void (Device::*setter)(bool) = nullptr; bool (Device::*defaultValue)() const; } booleanSetter; struct { void (Device::*setter)(quint32) = nullptr; quint32 (Device::*defaultValue)() const; } quint32Setter; struct { void (Device::*setter)(QString) = nullptr; QString (Device::*defaultValue)() const; } stringSetter; }; static const QMap s_configData { {ConfigKey::Enabled, ConfigData(QByteArrayLiteral("Enabled"), &Device::setEnabled)}, {ConfigKey::LeftHanded, ConfigData(QByteArrayLiteral("LeftHanded"), &Device::setLeftHanded, &Device::leftHandedEnabledByDefault)}, {ConfigKey::DisableWhileTyping, ConfigData(QByteArrayLiteral("DisableWhileTyping"), &Device::setDisableWhileTyping, &Device::disableWhileTypingEnabledByDefault)}, {ConfigKey::PointerAcceleration, ConfigData(QByteArrayLiteral("PointerAcceleration"), &Device::setPointerAccelerationFromString, &Device::defaultPointerAccelerationToString)}, {ConfigKey::PointerAccelerationProfile, ConfigData(QByteArrayLiteral("PointerAccelerationProfile"), &Device::setPointerAccelerationProfileFromInt, &Device::defaultPointerAccelerationProfileToInt)}, {ConfigKey::TapToClick, ConfigData(QByteArrayLiteral("TapToClick"), &Device::setTapToClick, &Device::tapToClickEnabledByDefault)}, {ConfigKey::TapAndDrag, ConfigData(QByteArrayLiteral("TapAndDrag"), &Device::setTapAndDrag, &Device::tapAndDragEnabledByDefault)}, {ConfigKey::TapDragLock, ConfigData(QByteArrayLiteral("TapDragLock"), &Device::setTapDragLock, &Device::tapDragLockEnabledByDefault)}, {ConfigKey::MiddleButtonEmulation, ConfigData(QByteArrayLiteral("MiddleButtonEmulation"), &Device::setMiddleEmulation, &Device::middleEmulationEnabledByDefault)}, {ConfigKey::LmrTapButtonMap, ConfigData(QByteArrayLiteral("LmrTapButtonMap"), &Device::setLmrTapButtonMap, &Device::lmrTapButtonMapEnabledByDefault)}, {ConfigKey::NaturalScroll, ConfigData(QByteArrayLiteral("NaturalScroll"), &Device::setNaturalScroll, &Device::naturalScrollEnabledByDefault)}, {ConfigKey::ScrollMethod, ConfigData(QByteArrayLiteral("ScrollMethod"), &Device::activateScrollMethodFromInt, &Device::defaultScrollMethodToInt)}, {ConfigKey::ScrollButton, ConfigData(QByteArrayLiteral("ScrollButton"), &Device::setScrollButton, &Device::defaultScrollButton)} }; namespace { QMatrix4x4 defaultCalibrationMatrix(libinput_device *device) { float matrix[6]; const int ret = libinput_device_config_calibration_get_default_matrix(device, matrix); if (ret == 0) { return QMatrix4x4(); } return QMatrix4x4{ matrix[0], matrix[1], matrix[2], 0.0f, matrix[3], matrix[4], matrix[5], 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; } } Device::Device(libinput_device *device, QObject *parent) : QObject(parent) , m_device(device) , m_keyboard(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_KEYBOARD)) , m_pointer(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_POINTER)) , m_touch(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_TOUCH)) , m_tabletTool(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_TABLET_TOOL)) #if 0 // next libinput version , m_tabletPad(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_TABLET_PAD)) #else , m_tabletPad(false) #endif , m_supportsGesture(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_GESTURE)) -#if HAVE_INPUT_1_9 , m_switch(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_SWITCH)) , m_lidSwitch(m_switch ? libinput_device_switch_has_switch(m_device, LIBINPUT_SWITCH_LID) : false) , m_tabletSwitch(m_switch ? libinput_device_switch_has_switch(m_device, LIBINPUT_SWITCH_TABLET_MODE) : false) -#endif , m_name(QString::fromLocal8Bit(libinput_device_get_name(m_device))) , m_sysName(QString::fromLocal8Bit(libinput_device_get_sysname(m_device))) , m_outputName(QString::fromLocal8Bit(libinput_device_get_output_name(m_device))) , m_product(libinput_device_get_id_product(m_device)) , m_vendor(libinput_device_get_id_vendor(m_device)) , m_tapFingerCount(libinput_device_config_tap_get_finger_count(m_device)) , m_defaultTapButtonMap(libinput_device_config_tap_get_default_button_map(m_device)) , m_tapButtonMap(libinput_device_config_tap_get_button_map(m_device)) , m_tapToClickEnabledByDefault(libinput_device_config_tap_get_default_enabled(m_device) == LIBINPUT_CONFIG_TAP_ENABLED) , m_tapToClick(libinput_device_config_tap_get_enabled(m_device)) , m_tapAndDragEnabledByDefault(libinput_device_config_tap_get_default_drag_enabled(m_device)) , m_tapAndDrag(libinput_device_config_tap_get_drag_enabled(m_device)) , m_tapDragLockEnabledByDefault(libinput_device_config_tap_get_default_drag_lock_enabled(m_device)) , m_tapDragLock(libinput_device_config_tap_get_drag_lock_enabled(m_device)) , m_supportsDisableWhileTyping(libinput_device_config_dwt_is_available(m_device)) , m_supportsPointerAcceleration(libinput_device_config_accel_is_available(m_device)) , m_supportsLeftHanded(libinput_device_config_left_handed_is_available(m_device)) , m_supportsCalibrationMatrix(libinput_device_config_calibration_has_matrix(m_device)) , m_supportsDisableEvents(libinput_device_config_send_events_get_modes(m_device) & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED) , m_supportsDisableEventsOnExternalMouse(libinput_device_config_send_events_get_modes(m_device) & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE) , m_supportsMiddleEmulation(libinput_device_config_middle_emulation_is_available(m_device)) , m_supportsNaturalScroll(libinput_device_config_scroll_has_natural_scroll(m_device)) , m_supportedScrollMethods(libinput_device_config_scroll_get_methods(m_device)) , m_leftHandedEnabledByDefault(libinput_device_config_left_handed_get_default(m_device)) , m_middleEmulationEnabledByDefault(libinput_device_config_middle_emulation_get_default_enabled(m_device) == LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED) , m_naturalScrollEnabledByDefault(libinput_device_config_scroll_get_default_natural_scroll_enabled(m_device)) , m_defaultScrollMethod(libinput_device_config_scroll_get_default_method(m_device)) , m_defaultScrollButton(libinput_device_config_scroll_get_default_button(m_device)) , m_disableWhileTypingEnabledByDefault(libinput_device_config_dwt_get_default_enabled(m_device)) , m_disableWhileTyping(m_supportsDisableWhileTyping ? libinput_device_config_dwt_get_enabled(m_device) == LIBINPUT_CONFIG_DWT_ENABLED : false) , m_middleEmulation(libinput_device_config_middle_emulation_get_enabled(m_device) == LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED) , m_leftHanded(m_supportsLeftHanded ? libinput_device_config_left_handed_get(m_device) : false) , m_naturalScroll(m_supportsNaturalScroll ? libinput_device_config_scroll_get_natural_scroll_enabled(m_device) : false) , m_scrollMethod(libinput_device_config_scroll_get_method(m_device)) , m_scrollButton(libinput_device_config_scroll_get_button(m_device)) , m_defaultPointerAcceleration(libinput_device_config_accel_get_default_speed(m_device)) , m_pointerAcceleration(libinput_device_config_accel_get_speed(m_device)) , m_supportedPointerAccelerationProfiles(libinput_device_config_accel_get_profiles(m_device)) , m_defaultPointerAccelerationProfile(libinput_device_config_accel_get_default_profile(m_device)) , m_pointerAccelerationProfile(libinput_device_config_accel_get_profile(m_device)) , m_enabled(m_supportsDisableEvents ? libinput_device_config_send_events_get_mode(m_device) == LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : true) , m_config() , m_defaultCalibrationMatrix(m_supportsCalibrationMatrix ? defaultCalibrationMatrix(m_device) : QMatrix4x4{}) { libinput_device_ref(m_device); qreal width = 0; qreal height = 0; if (libinput_device_get_size(m_device, &width, &height) == 0) { m_size = QSizeF(width, height); } if (m_pointer) { if (libinput_device_pointer_has_button(m_device, BTN_LEFT) == 1) { m_supportedButtons |= Qt::LeftButton; } if (libinput_device_pointer_has_button(m_device, BTN_MIDDLE) == 1) { m_supportedButtons |= Qt::MiddleButton; } if (libinput_device_pointer_has_button(m_device, BTN_RIGHT) == 1) { m_supportedButtons |= Qt::RightButton; } if (libinput_device_pointer_has_button(m_device, BTN_SIDE) == 1) { m_supportedButtons |= Qt::ExtraButton1; } if (libinput_device_pointer_has_button(m_device, BTN_EXTRA) == 1) { m_supportedButtons |= Qt::ExtraButton2; } if (libinput_device_pointer_has_button(m_device, BTN_BACK) == 1) { m_supportedButtons |= Qt::BackButton; } if (libinput_device_pointer_has_button(m_device, BTN_FORWARD) == 1) { m_supportedButtons |= Qt::ForwardButton; } if (libinput_device_pointer_has_button(m_device, BTN_TASK) == 1) { m_supportedButtons |= Qt::TaskButton; } } if (m_keyboard) { m_alphaNumericKeyboard = checkAlphaNumericKeyboard(m_device); } s_devices << this; QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin/InputDevice/") + m_sysName, QStringLiteral("org.kde.KWin.InputDevice"), this, QDBusConnection::ExportAllProperties ); } Device::~Device() { s_devices.removeOne(this); QDBusConnection::sessionBus().unregisterObject(QStringLiteral("/org/kde/KWin/InputDevice/") + m_sysName); libinput_device_unref(m_device); } template void Device::writeEntry(const ConfigKey &key, const T &value) { if (!m_config.isValid()) { return; } if (m_loading) { return; } auto it = s_configData.find(key); Q_ASSERT(it != s_configData.end()); m_config.writeEntry(it.value().key.constData(), value); m_config.sync(); } template void Device::readEntry(const QByteArray &key, const Setter &s, const T &defaultValue) { if (!s.setter) { return; } (this->*(s.setter))(m_config.readEntry(key.constData(), s.defaultValue ? (this->*(s.defaultValue))() : defaultValue)); } void Device::loadConfiguration() { if (!m_config.isValid()) { return; } m_loading = true; for (auto it = s_configData.begin(), end = s_configData.end(); it != end; ++it) { const auto key = it.value().key; if (!m_config.hasKey(key.constData())) { continue; } readEntry(key, it.value().booleanSetter, true); readEntry(key, it.value().quint32Setter, 0); readEntry(key, it.value().stringSetter, ""); }; m_loading = false; } void Device::setPointerAcceleration(qreal acceleration) { if (!m_supportsPointerAcceleration) { return; } acceleration = qBound(-1.0, acceleration, 1.0); if (libinput_device_config_accel_set_speed(m_device, acceleration) == LIBINPUT_CONFIG_STATUS_SUCCESS) { if (m_pointerAcceleration != acceleration) { m_pointerAcceleration = acceleration; emit pointerAccelerationChanged(); writeEntry(ConfigKey::PointerAcceleration, QString::number(acceleration, 'f', 3)); } } } void Device::setScrollButton(quint32 button) { if (!(m_supportedScrollMethods & LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN)) { return; } if (libinput_device_config_scroll_set_button(m_device, button) == LIBINPUT_CONFIG_STATUS_SUCCESS) { if (m_scrollButton != button) { m_scrollButton = button; writeEntry(ConfigKey::ScrollButton, m_scrollButton); emit scrollButtonChanged(); } } } void Device::setPointerAccelerationProfile(bool set, enum libinput_config_accel_profile profile) { if (!(m_supportedPointerAccelerationProfiles & profile)) { return; } if (!set) { profile = (profile == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT) ? LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE : LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; if (!(m_supportedPointerAccelerationProfiles & profile)) { return; } } if (libinput_device_config_accel_set_profile(m_device, profile) == LIBINPUT_CONFIG_STATUS_SUCCESS) { if (m_pointerAccelerationProfile != profile) { m_pointerAccelerationProfile = profile; emit pointerAccelerationProfileChanged(); writeEntry(ConfigKey::PointerAccelerationProfile, (quint32) profile); } } } void Device::setScrollMethod(bool set, enum libinput_config_scroll_method method) { if (!(m_supportedScrollMethods & method)) { return; } bool isCurrent = m_scrollMethod == method; if (!set) { if (isCurrent) { method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL; isCurrent = false; } else { return; } } if (libinput_device_config_scroll_set_method(m_device, method) == LIBINPUT_CONFIG_STATUS_SUCCESS) { if (!isCurrent) { m_scrollMethod = method; emit scrollMethodChanged(); writeEntry(ConfigKey::ScrollMethod, (quint32) method); } } } void Device::setLmrTapButtonMap(bool set) { enum libinput_config_tap_button_map map = set ? LIBINPUT_CONFIG_TAP_MAP_LMR : LIBINPUT_CONFIG_TAP_MAP_LRM; if (m_tapFingerCount < 2) { return; } if (!set) { map = LIBINPUT_CONFIG_TAP_MAP_LRM; } if (libinput_device_config_tap_set_button_map(m_device, map) == LIBINPUT_CONFIG_STATUS_SUCCESS) { if (m_tapButtonMap != map) { m_tapButtonMap = map; writeEntry(ConfigKey::LmrTapButtonMap, set); emit tapButtonMapChanged(); } } } #define CONFIG(method, condition, function, variable, key) \ void Device::method(bool set) \ { \ if (condition) { \ return; \ } \ if (libinput_device_config_##function(m_device, set) == LIBINPUT_CONFIG_STATUS_SUCCESS) { \ if (m_##variable != set) { \ m_##variable = set; \ writeEntry(ConfigKey::key, m_##variable); \ emit variable##Changed(); \ }\ } \ } CONFIG(setLeftHanded, !m_supportsLeftHanded, left_handed_set, leftHanded, LeftHanded) CONFIG(setNaturalScroll, !m_supportsNaturalScroll, scroll_set_natural_scroll_enabled, naturalScroll, NaturalScroll) #undef CONFIG #define CONFIG(method, condition, function, enum, variable, key) \ void Device::method(bool set) \ { \ if (condition) { \ return; \ } \ if (libinput_device_config_##function(m_device, set ? LIBINPUT_CONFIG_##enum##_ENABLED : LIBINPUT_CONFIG_##enum##_DISABLED) == LIBINPUT_CONFIG_STATUS_SUCCESS) { \ if (m_##variable != set) { \ m_##variable = set; \ writeEntry(ConfigKey::key, m_##variable); \ emit variable##Changed(); \ }\ } \ } CONFIG(setEnabled, !m_supportsDisableEvents, send_events_set_mode, SEND_EVENTS, enabled, Enabled) CONFIG(setDisableWhileTyping, !m_supportsDisableWhileTyping, dwt_set_enabled, DWT, disableWhileTyping, DisableWhileTyping) CONFIG(setTapToClick, m_tapFingerCount == 0, tap_set_enabled, TAP, tapToClick, TapToClick) CONFIG(setTapAndDrag, false, tap_set_drag_enabled, DRAG, tapAndDrag, TapAndDrag) CONFIG(setTapDragLock, false, tap_set_drag_lock_enabled, DRAG_LOCK, tapDragLock, TapDragLock) CONFIG(setMiddleEmulation, m_supportsMiddleEmulation == false, middle_emulation_set_enabled, MIDDLE_EMULATION, middleEmulation, MiddleButtonEmulation) #undef CONFIG void Device::setOrientation(Qt::ScreenOrientation orientation) { if (!m_supportsCalibrationMatrix) { return; } // 90 deg cw: static const QMatrix4x4 portraitMatrix{ 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; // 180 deg cw: static const QMatrix4x4 invertedLandscapeMatrix{ -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; // 270 deg cw static const QMatrix4x4 invertedPortraitMatrix{ 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; QMatrix4x4 matrix; switch (orientation) { case Qt::PortraitOrientation: matrix = portraitMatrix; break; case Qt::InvertedLandscapeOrientation: matrix = invertedLandscapeMatrix; break; case Qt::InvertedPortraitOrientation: matrix = invertedPortraitMatrix; break; case Qt::PrimaryOrientation: case Qt::LandscapeOrientation: default: break; } const auto combined = m_defaultCalibrationMatrix * matrix; const auto columnOrder = combined.constData(); float m[6] = { columnOrder[0], columnOrder[4], columnOrder[8], columnOrder[1], columnOrder[5], columnOrder[9] }; libinput_device_config_calibration_set_matrix(m_device, m); } } } diff --git a/libinput/events.cpp b/libinput/events.cpp index cf52fc2b0..17efc6425 100644 --- a/libinput/events.cpp +++ b/libinput/events.cpp @@ -1,336 +1,322 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2014 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "events.h" #include "device.h" #include namespace KWin { namespace LibInput { Event *Event::create(libinput_event *event) { if (!event) { return nullptr; } const auto t = libinput_event_get_type(event); // TODO: add touch events // TODO: add device notify events switch (t) { case LIBINPUT_EVENT_KEYBOARD_KEY: return new KeyEvent(event); case LIBINPUT_EVENT_POINTER_AXIS: case LIBINPUT_EVENT_POINTER_BUTTON: case LIBINPUT_EVENT_POINTER_MOTION: case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: return new PointerEvent(event, t); case LIBINPUT_EVENT_TOUCH_DOWN: case LIBINPUT_EVENT_TOUCH_UP: case LIBINPUT_EVENT_TOUCH_MOTION: case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_FRAME: return new TouchEvent(event, t); case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: case LIBINPUT_EVENT_GESTURE_SWIPE_END: return new SwipeGestureEvent(event, t); case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: case LIBINPUT_EVENT_GESTURE_PINCH_END: return new PinchGestureEvent(event, t); -#if HAVE_INPUT_1_9 case LIBINPUT_EVENT_SWITCH_TOGGLE: return new SwitchEvent(event, t); -#endif default: return new Event(event, t); } } Event::Event(libinput_event *event, libinput_event_type type) : m_event(event) , m_type(type) , m_device(Device::getDevice(libinput_event_get_device(m_event))) { } Event::~Event() { libinput_event_destroy(m_event); } libinput_device *Event::nativeDevice() const { if (m_device) { return m_device->device(); } return libinput_event_get_device(m_event); } KeyEvent::KeyEvent(libinput_event *event) : Event(event, LIBINPUT_EVENT_KEYBOARD_KEY) , m_keyboardEvent(libinput_event_get_keyboard_event(event)) { } KeyEvent::~KeyEvent() = default; uint32_t KeyEvent::key() const { return libinput_event_keyboard_get_key(m_keyboardEvent); } InputRedirection::KeyboardKeyState KeyEvent::state() const { switch (libinput_event_keyboard_get_key_state(m_keyboardEvent)) { case LIBINPUT_KEY_STATE_PRESSED: return InputRedirection::KeyboardKeyPressed; case LIBINPUT_KEY_STATE_RELEASED: return InputRedirection::KeyboardKeyReleased; } abort(); } uint32_t KeyEvent::time() const { return libinput_event_keyboard_get_time(m_keyboardEvent); } PointerEvent::PointerEvent(libinput_event *event, libinput_event_type type) : Event(event, type) , m_pointerEvent(libinput_event_get_pointer_event(event)) { } PointerEvent::~PointerEvent() = default; QPointF PointerEvent::absolutePos() const { Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE); return QPointF(libinput_event_pointer_get_absolute_x(m_pointerEvent), libinput_event_pointer_get_absolute_y(m_pointerEvent)); } QPointF PointerEvent::absolutePos(const QSize &size) const { Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE); return QPointF(libinput_event_pointer_get_absolute_x_transformed(m_pointerEvent, size.width()), libinput_event_pointer_get_absolute_y_transformed(m_pointerEvent, size.height())); } QSizeF PointerEvent::delta() const { Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION); return QSizeF(libinput_event_pointer_get_dx(m_pointerEvent), libinput_event_pointer_get_dy(m_pointerEvent)); } QSizeF PointerEvent::deltaUnaccelerated() const { Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_MOTION); return QSizeF(libinput_event_pointer_get_dx_unaccelerated(m_pointerEvent), libinput_event_pointer_get_dy_unaccelerated(m_pointerEvent)); } uint32_t PointerEvent::time() const { return libinput_event_pointer_get_time(m_pointerEvent); } quint64 PointerEvent::timeMicroseconds() const { return libinput_event_pointer_get_time_usec(m_pointerEvent); } uint32_t PointerEvent::button() const { Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_BUTTON); return libinput_event_pointer_get_button(m_pointerEvent); } InputRedirection::PointerButtonState PointerEvent::buttonState() const { Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_BUTTON); switch (libinput_event_pointer_get_button_state(m_pointerEvent)) { case LIBINPUT_BUTTON_STATE_PRESSED: return InputRedirection::PointerButtonPressed; case LIBINPUT_BUTTON_STATE_RELEASED: return InputRedirection::PointerButtonReleased; } abort(); } QVector PointerEvent::axis() const { Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS); QVector a; if (libinput_event_pointer_has_axis(m_pointerEvent, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) { a << InputRedirection::PointerAxisHorizontal; } if (libinput_event_pointer_has_axis(m_pointerEvent, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) { a << InputRedirection::PointerAxisVertical; } return a; } qreal PointerEvent::axisValue(InputRedirection::PointerAxis axis) const { Q_ASSERT(type() == LIBINPUT_EVENT_POINTER_AXIS); const libinput_pointer_axis a = axis == InputRedirection::PointerAxisHorizontal ? LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL : LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL; return libinput_event_pointer_get_axis_value(m_pointerEvent, a); } TouchEvent::TouchEvent(libinput_event *event, libinput_event_type type) : Event(event, type) , m_touchEvent(libinput_event_get_touch_event(event)) { } TouchEvent::~TouchEvent() = default; quint32 TouchEvent::time() const { return libinput_event_touch_get_time(m_touchEvent); } QPointF TouchEvent::absolutePos() const { Q_ASSERT(type() == LIBINPUT_EVENT_TOUCH_DOWN || type() == LIBINPUT_EVENT_TOUCH_MOTION); return QPointF(libinput_event_touch_get_x(m_touchEvent), libinput_event_touch_get_y(m_touchEvent)); } QPointF TouchEvent::absolutePos(const QSize &size) const { Q_ASSERT(type() == LIBINPUT_EVENT_TOUCH_DOWN || type() == LIBINPUT_EVENT_TOUCH_MOTION); return QPointF(libinput_event_touch_get_x_transformed(m_touchEvent, size.width()), libinput_event_touch_get_y_transformed(m_touchEvent, size.height())); } qint32 TouchEvent::id() const { Q_ASSERT(type() != LIBINPUT_EVENT_TOUCH_CANCEL && type() != LIBINPUT_EVENT_TOUCH_FRAME); const qint32 slot = libinput_event_touch_get_slot(m_touchEvent); return slot == -1 ? 0 : slot; } GestureEvent::GestureEvent(libinput_event *event, libinput_event_type type) : Event(event, type) , m_gestureEvent(libinput_event_get_gesture_event(event)) { } GestureEvent::~GestureEvent() = default; quint32 GestureEvent::time() const { return libinput_event_gesture_get_time(m_gestureEvent); } int GestureEvent::fingerCount() const { return libinput_event_gesture_get_finger_count(m_gestureEvent); } QSizeF GestureEvent::delta() const { return QSizeF(libinput_event_gesture_get_dx(m_gestureEvent), libinput_event_gesture_get_dy(m_gestureEvent)); } bool GestureEvent::isCancelled() const { return libinput_event_gesture_get_cancelled(m_gestureEvent) != 0; } PinchGestureEvent::PinchGestureEvent(libinput_event *event, libinput_event_type type) : GestureEvent(event, type) { } PinchGestureEvent::~PinchGestureEvent() = default; qreal PinchGestureEvent::scale() const { return libinput_event_gesture_get_scale(m_gestureEvent); } qreal PinchGestureEvent::angleDelta() const { return libinput_event_gesture_get_angle_delta(m_gestureEvent); } SwipeGestureEvent::SwipeGestureEvent(libinput_event *event, libinput_event_type type) : GestureEvent(event, type) { } SwipeGestureEvent::~SwipeGestureEvent() = default; SwitchEvent::SwitchEvent(libinput_event *event, libinput_event_type type) : Event(event, type) -#if HAVE_INPUT_1_9 , m_switchEvent(libinput_event_get_switch_event(event)) -#else - , m_switchEvent(nullptr) -#endif { } SwitchEvent::~SwitchEvent() = default; SwitchEvent::State SwitchEvent::state() const { -#if HAVE_INPUT_1_9 switch (libinput_event_switch_get_switch_state(m_switchEvent)) { case LIBINPUT_SWITCH_STATE_OFF: return State::Off; case LIBINPUT_SWITCH_STATE_ON: return State::On; default: Q_UNREACHABLE(); } -#endif return State::Off; } quint32 SwitchEvent::time() const { -#if HAVE_INPUT_1_9 return libinput_event_switch_get_time(m_switchEvent); -#endif - return 0; } quint64 SwitchEvent::timeMicroseconds() const { -#if HAVE_INPUT_1_9 return libinput_event_switch_get_time_usec(m_switchEvent); -#endif - return 0; } } } diff --git a/libinput/events.h b/libinput/events.h index f9f6bb429..28d68a6b5 100644 --- a/libinput/events.h +++ b/libinput/events.h @@ -1,208 +1,203 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2014 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #ifndef KWIN_LIBINPUT_EVENTS_H #define KWIN_LIBINPUT_EVENTS_H #include "../input.h" #include -#include -#if !(HAVE_INPUT_1_9) -struct libinput_event_switch; -#endif - namespace KWin { namespace LibInput { class Device; class Event { public: virtual ~Event(); libinput_event_type type() const; Device *device() const { return m_device; } libinput_device *nativeDevice() const; operator libinput_event*() { return m_event; } operator libinput_event*() const { return m_event; } static Event *create(libinput_event *event); protected: Event(libinput_event *event, libinput_event_type type); private: libinput_event *m_event; libinput_event_type m_type; Device *m_device; }; class KeyEvent : public Event { public: KeyEvent(libinput_event *event); virtual ~KeyEvent(); uint32_t key() const; InputRedirection::KeyboardKeyState state() const; uint32_t time() const; operator libinput_event_keyboard*() { return m_keyboardEvent; } operator libinput_event_keyboard*() const { return m_keyboardEvent; } private: libinput_event_keyboard *m_keyboardEvent; }; class PointerEvent : public Event { public: PointerEvent(libinput_event* event, libinput_event_type type); virtual ~PointerEvent(); QPointF absolutePos() const; QPointF absolutePos(const QSize &size) const; QSizeF delta() const; QSizeF deltaUnaccelerated() const; uint32_t button() const; InputRedirection::PointerButtonState buttonState() const; uint32_t time() const; quint64 timeMicroseconds() const; QVector axis() const; qreal axisValue(InputRedirection::PointerAxis a) const; operator libinput_event_pointer*() { return m_pointerEvent; } operator libinput_event_pointer*() const { return m_pointerEvent; } private: libinput_event_pointer *m_pointerEvent; }; class TouchEvent : public Event { public: TouchEvent(libinput_event *event, libinput_event_type type); virtual ~TouchEvent(); quint32 time() const; QPointF absolutePos() const; QPointF absolutePos(const QSize &size) const; qint32 id() const; operator libinput_event_touch*() { return m_touchEvent; } operator libinput_event_touch*() const { return m_touchEvent; } private: libinput_event_touch *m_touchEvent; }; class GestureEvent : public Event { public: virtual ~GestureEvent(); quint32 time() const; int fingerCount() const; QSizeF delta() const; bool isCancelled() const; operator libinput_event_gesture*() { return m_gestureEvent; } operator libinput_event_gesture*() const { return m_gestureEvent; } protected: GestureEvent(libinput_event *event, libinput_event_type type); libinput_event_gesture *m_gestureEvent; }; class PinchGestureEvent : public GestureEvent { public: PinchGestureEvent(libinput_event *event, libinput_event_type type); virtual ~PinchGestureEvent(); qreal scale() const; qreal angleDelta() const; }; class SwipeGestureEvent : public GestureEvent { public: SwipeGestureEvent(libinput_event *event, libinput_event_type type); virtual ~SwipeGestureEvent(); }; class SwitchEvent : public Event { public: SwitchEvent(libinput_event *event, libinput_event_type type); ~SwitchEvent() override; enum class State { Off, On }; State state() const; quint32 time() const; quint64 timeMicroseconds() const; private: libinput_event_switch *m_switchEvent; }; inline libinput_event_type Event::type() const { return m_type; } } } #endif