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
@@ -50,9 +48,12 @@
void tabletModeChanged(bool tabletMode);
private:
+ void hasTabletModeInputChanged(bool set);
+ void manualTabletModeDetection();
+
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,95 @@
#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 TabletModeOnPointerRemoval true
+ QTimer::singleShot(2000, this, [this] { hasTabletModeInputChanged(false); });
+ }
QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin"),
QStringLiteral("org.kde.KWin.TabletModeManager"),
@@ -82,9 +122,34 @@
connect(input(), &InputRedirection::hasTabletModeSwitchChanged, this, &TabletModeManager::tabletModeAvailableChanged);
}
+void KWin::TabletModeManager::hasTabletModeInputChanged(bool set)
+{
+ const auto was = m_detecting;
+ if (set) {
+ input()->installInputEventSpy(new TabletModeSwitchEventSpy(this));
+ m_detecting = true;
+ } else {
+ Settings settings(kwinApp()->config());
+ if (settings.tabletModeOnPointerRemoval()) {
+ auto spy = new TabletModeTouchpadRemovedSpy(this);
+ connect(input(), &InputRedirection::hasTabletModeSwitchChanged, spy, [spy](bool set){
+ if (set)
+ spy->deleteLater();
+ });
+ m_detecting = true;
+ } else {
+ m_detecting = false;
+ }
+ }
+
+ if (m_detecting != was) {
+ Q_EMIT tabletModeChanged(true);
+ }
+}
+
bool TabletModeManager::isTabletModeAvailable() const
{
- return input()->hasTabletModeSwitch();
+ return input()->hasTabletModeSwitch() || m_detecting;
}
bool TabletModeManager::isTablet() const