diff --git a/libinput/connection.h b/libinput/connection.h
index 44495ed190..b45beecaef 100644
--- a/libinput/connection.h
+++ b/libinput/connection.h
@@ -43,7 +43,7 @@ class Event;
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
index e325a29437..0c827ad2e8 100644
--- a/libinput/device.h
+++ b/libinput/device.h
@@ -28,6 +28,7 @@ along with this program. If not, see .
#include
#include
#include
+#include "kwin_export.h"
struct libinput_device;
@@ -37,7 +38,7 @@ namespace LibInput
{
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/tabletmodemanager.cpp b/tabletmodemanager.cpp
index 9776706093..09d7d9ed3a 100644
--- a/tabletmodemanager.cpp
+++ b/tabletmodemanager.cpp
@@ -25,53 +25,92 @@
#include "input_event_spy.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 hasTouch = std::any_of(devices.constBegin(), devices.constEnd(), [](LibInput::Device* device){ return device->isTouch(); });
+ m_parent->setTabletModeAvailable(hasTouch);
+ const bool hasPointer = std::any_of(devices.constBegin(), devices.constEnd(), [](LibInput::Device* device){ return device->isPointer(); });
+ 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 {
+ hasTabletModeInputChanged(false);
+ }
QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin"),
QStringLiteral("org.kde.KWin.TabletModeManager"),
@@ -82,9 +121,29 @@ TabletModeManager::TabletModeManager(QObject *parent)
connect(input(), &InputRedirection::hasTabletModeSwitchChanged, this, &TabletModeManager::tabletModeAvailableChanged);
}
+void KWin::TabletModeManager::hasTabletModeInputChanged(bool set)
+{
+ if (set) {
+ input()->installInputEventSpy(new TabletModeSwitchEventSpy(this));
+ setTabletModeAvailable(true);
+ } else {
+ auto setupDetector = [this] {
+ auto spy = new TabletModeTouchpadRemovedSpy(this);
+ connect(input(), &InputRedirection::hasTabletModeSwitchChanged, spy, [spy](bool set){
+ if (set)
+ spy->deleteLater();
+ });
+ };
+ if (LibInput::Connection::self())
+ setupDetector();
+ else
+ QTimer::singleShot(2000, this, setupDetector);
+ }
+}
+
bool TabletModeManager::isTabletModeAvailable() const
{
- return input()->hasTabletModeSwitch();
+ return m_detecting;
}
bool TabletModeManager::isTablet() const
@@ -101,3 +160,11 @@ void TabletModeManager::setIsTablet(bool tablet)
m_isTabletMode = tablet;
emit tabletModeChanged(tablet);
}
+
+void KWin::TabletModeManager::setTabletModeAvailable(bool detecting)
+{
+ if (m_detecting != detecting) {
+ m_detecting = detecting;
+ tabletModeAvailableChanged(detecting);
+ }
+}
diff --git a/tabletmodemanager.h b/tabletmodemanager.h
index 83ee27cfc4..add1076cb6 100644
--- a/tabletmodemanager.h
+++ b/tabletmodemanager.h
@@ -27,8 +27,6 @@
namespace KWin {
-class TabletModeInputEventSpy;
-
class TabletModeManager : public QObject
{
Q_OBJECT
@@ -40,6 +38,7 @@ class TabletModeManager : public QObject
public:
~TabletModeManager() = default;
+ void setTabletModeAvailable(bool detecting);
bool isTabletModeAvailable() const;
bool isTablet() const;
@@ -50,9 +49,11 @@ Q_SIGNALS:
void tabletModeChanged(bool tabletMode);
private:
+ void hasTabletModeInputChanged(bool set);
+
bool m_tabletModeAvailable = false;
bool m_isTabletMode = false;
- TabletModeInputEventSpy *m_spy;
+ bool m_detecting = false;
KWIN_SINGLETON_VARIABLE(TabletModeManager, s_manager)
};
}