diff --git a/kwin.kcfg b/kwin.kcfg --- a/kwin.kcfg +++ b/kwin.kcfg @@ -304,4 +304,9 @@ thumbnails + + + false + + diff --git a/libinput/connection.h b/libinput/connection.h --- a/libinput/connection.h +++ b/libinput/connection.h @@ -43,7 +43,7 @@ class Device; class Context; -class Connection : public QObject +class KWIN_EXPORT Connection : public QObject { Q_OBJECT diff --git a/libinput/device.h b/libinput/device.h --- a/libinput/device.h +++ b/libinput/device.h @@ -28,6 +28,7 @@ #include #include #include +#include "kwin_export.h" struct libinput_device; @@ -37,7 +38,7 @@ { enum class ConfigKey; -class Device : public QObject +class KWIN_EXPORT Device : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.InputDevice") diff --git a/settings.kcfgc b/settings.kcfgc --- a/settings.kcfgc +++ b/settings.kcfgc @@ -5,3 +5,4 @@ # placement.h is needed for Placement::Policy IncludeFiles=\"options.h\", \"placement.h\" UseEnumTypes=true +Visibility=Q_DECL_EXPORT diff --git a/tabletmodemanager.h b/tabletmodemanager.h --- a/tabletmodemanager.h +++ b/tabletmodemanager.h @@ -27,8 +27,6 @@ namespace KWin { -class TabletModeInputEventSpy; - class TabletModeManager : public QObject { Q_OBJECT @@ -52,7 +50,7 @@ private: bool m_tabletModeAvailable = false; bool m_isTabletMode = false; - TabletModeInputEventSpy *m_spy; + bool m_detecting = false; KWIN_SINGLETON_VARIABLE(TabletModeManager, s_manager) }; } diff --git a/tabletmodemanager.cpp b/tabletmodemanager.cpp --- a/tabletmodemanager.cpp +++ b/tabletmodemanager.cpp @@ -23,55 +23,99 @@ #include "input.h" #include "input_event.h" #include "input_event_spy.h" +#include "settings.h" #include "libinput/device.h" +#include "libinput/connection.h" +#include #include using namespace KWin; KWIN_SINGLETON_FACTORY_VARIABLE(TabletModeManager, s_manager) -class KWin::TabletModeInputEventSpy : public InputEventSpy +class TabletModeSwitchEventSpy : public QObject, public InputEventSpy { public: - explicit TabletModeInputEventSpy(TabletModeManager *parent); + explicit TabletModeSwitchEventSpy(TabletModeManager *parent) + : QObject(parent) + , m_parent(parent) + { + } + + void switchEvent(SwitchEvent *event) override + { + if (!event->device()->isTabletModeSwitch()) { + return; + } + + switch (event->state()) { + case SwitchEvent::State::Off: + m_parent->setIsTablet(false); + break; + case SwitchEvent::State::On: + m_parent->setIsTablet(true); + break; + default: + Q_UNREACHABLE(); + } + } - void switchEvent(SwitchEvent *event) override; private: - TabletModeManager *m_parent; + TabletModeManager * const m_parent; }; -TabletModeInputEventSpy::TabletModeInputEventSpy(TabletModeManager *parent) - : m_parent(parent) -{ -} -void TabletModeInputEventSpy::switchEvent(SwitchEvent *event) +class TabletModeTouchpadRemovedSpy : public QObject { - if (!event->device()->isTabletModeSwitch()) { - return; +public: + explicit TabletModeTouchpadRemovedSpy(TabletModeManager *parent) + : QObject(parent) + , m_parent(parent) + { + auto c = LibInput::Connection::self(); + connect(c, &LibInput::Connection::deviceAdded, this, &TabletModeTouchpadRemovedSpy::refresh); + connect(c, &LibInput::Connection::deviceRemoved, this, &TabletModeTouchpadRemovedSpy::refresh); + + check(); } - switch (event->state()) { - case SwitchEvent::State::Off: - m_parent->setIsTablet(false); - break; - case SwitchEvent::State::On: - m_parent->setIsTablet(true); - break; - default: - Q_UNREACHABLE(); + void refresh(LibInput::Device* d) { + if (!d->isTouch() && !d->isPointer()) + return; + check(); } -} + void check() { + if (!LibInput::Connection::self()) { + qDebug() << "no libinput :("; + return; + } + + const auto devices = LibInput::Connection::self()->devices(); + const bool hasPointer = std::any_of(devices.constBegin(), devices.constEnd(), [](LibInput::Device* device){ return device->isPointer(); }); + const bool hasTouch = std::any_of(devices.constBegin(), devices.constEnd(), [](LibInput::Device* device){ return device->isTouch(); }); + m_parent->setIsTablet(hasTouch && !hasPointer); + } +private: + TabletModeManager * const m_parent; +}; TabletModeManager::TabletModeManager(QObject *parent) - : QObject(parent), - m_spy(new TabletModeInputEventSpy(this)) + : QObject(parent) { - input()->installInputEventSpy(m_spy); + if (input()->hasTabletModeSwitch()) { + input()->installInputEventSpy(new TabletModeSwitchEventSpy(this)); + } else { + // to enable: kwriteconfig5 --file kwin.cfg --group TabletMode --key TabletModeOnTouchPadRemoval true + Settings settings(kwinApp()->config()); + if (settings.tabletModeOnTouchPadRemoval()) { + m_detecting = true; + QTimer::singleShot(2000, this, [this] {new TabletModeTouchpadRemovedSpy(this);}); + } + } QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin"), QStringLiteral("org.kde.KWin.TabletModeManager"), @@ -84,7 +128,7 @@ bool TabletModeManager::isTabletModeAvailable() const { - return input()->hasTabletModeSwitch(); + return input()->hasTabletModeSwitch() || m_detecting; } bool TabletModeManager::isTablet() const