Changeset View
Changeset View
Standalone View
Standalone View
tabletmodemanager.cpp
Show All 19 Lines | |||||
20 | */ | 20 | */ | ||
21 | 21 | | |||
22 | #include "tabletmodemanager.h" | 22 | #include "tabletmodemanager.h" | ||
23 | #include "input.h" | 23 | #include "input.h" | ||
24 | #include "input_event.h" | 24 | #include "input_event.h" | ||
25 | #include "input_event_spy.h" | 25 | #include "input_event_spy.h" | ||
26 | 26 | | |||
27 | #include "libinput/device.h" | 27 | #include "libinput/device.h" | ||
28 | #include "libinput/connection.h" | ||||
28 | 29 | | |||
30 | #include <QTimer> | ||||
29 | #include <QDBusConnection> | 31 | #include <QDBusConnection> | ||
30 | 32 | | |||
31 | using namespace KWin; | 33 | using namespace KWin; | ||
32 | 34 | | |||
33 | KWIN_SINGLETON_FACTORY_VARIABLE(TabletModeManager, s_manager) | 35 | KWIN_SINGLETON_FACTORY_VARIABLE(TabletModeManager, s_manager) | ||
34 | 36 | | |||
35 | class KWin::TabletModeInputEventSpy : public InputEventSpy | 37 | class TabletModeSwitchEventSpy : public QObject, public InputEventSpy | ||
36 | { | 38 | { | ||
37 | public: | 39 | public: | ||
38 | explicit TabletModeInputEventSpy(TabletModeManager *parent); | 40 | explicit TabletModeSwitchEventSpy(TabletModeManager *parent) | ||
39 | 41 | : QObject(parent) | |||
40 | void switchEvent(SwitchEvent *event) override; | 42 | , m_parent(parent) | ||
41 | private: | | |||
42 | TabletModeManager *m_parent; | | |||
43 | }; | | |||
44 | | ||||
45 | TabletModeInputEventSpy::TabletModeInputEventSpy(TabletModeManager *parent) | | |||
46 | : m_parent(parent) | | |||
47 | { | 43 | { | ||
48 | } | 44 | } | ||
49 | 45 | | |||
50 | void TabletModeInputEventSpy::switchEvent(SwitchEvent *event) | 46 | void switchEvent(SwitchEvent *event) override | ||
51 | { | 47 | { | ||
52 | if (!event->device()->isTabletModeSwitch()) { | 48 | if (!event->device()->isTabletModeSwitch()) { | ||
53 | return; | 49 | return; | ||
54 | } | 50 | } | ||
55 | 51 | | |||
56 | switch (event->state()) { | 52 | switch (event->state()) { | ||
57 | case SwitchEvent::State::Off: | 53 | case SwitchEvent::State::Off: | ||
58 | m_parent->setIsTablet(false); | 54 | m_parent->setIsTablet(false); | ||
59 | break; | 55 | break; | ||
60 | case SwitchEvent::State::On: | 56 | case SwitchEvent::State::On: | ||
61 | m_parent->setIsTablet(true); | 57 | m_parent->setIsTablet(true); | ||
62 | break; | 58 | break; | ||
63 | default: | 59 | default: | ||
64 | Q_UNREACHABLE(); | 60 | Q_UNREACHABLE(); | ||
65 | } | 61 | } | ||
66 | } | 62 | } | ||
67 | 63 | | |||
64 | private: | ||||
65 | TabletModeManager * const m_parent; | ||||
66 | }; | ||||
68 | 67 | | |||
69 | 68 | | |||
69 | class TabletModeTouchpadRemovedSpy : public QObject | ||||
70 | { | ||||
71 | public: | ||||
72 | explicit TabletModeTouchpadRemovedSpy(TabletModeManager *parent) | ||||
73 | : QObject(parent) | ||||
74 | , m_parent(parent) | ||||
75 | { | ||||
76 | auto c = LibInput::Connection::self(); | ||||
77 | connect(c, &LibInput::Connection::deviceAdded, this, &TabletModeTouchpadRemovedSpy::refresh); | ||||
78 | connect(c, &LibInput::Connection::deviceRemoved, this, &TabletModeTouchpadRemovedSpy::refresh); | ||||
79 | | ||||
80 | check(); | ||||
81 | } | ||||
82 | | ||||
83 | void refresh(LibInput::Device* d) { | ||||
84 | if (!d->isTouch() && !d->isPointer()) | ||||
85 | return; | ||||
86 | check(); | ||||
87 | } | ||||
88 | | ||||
89 | void check() { | ||||
90 | if (!LibInput::Connection::self()) { | ||||
91 | qDebug() << "no libinput :("; | ||||
92 | return; | ||||
93 | } | ||||
94 | const auto devices = LibInput::Connection::self()->devices(); | ||||
95 | const bool hasTouch = std::any_of(devices.constBegin(), devices.constEnd(), [](LibInput::Device* device){ return device->isTouch(); }); | ||||
96 | m_parent->setTabletModeAvailable(hasTouch); | ||||
97 | | ||||
98 | const bool hasPointer = std::any_of(devices.constBegin(), devices.constEnd(), [](LibInput::Device* device){ return device->isPointer(); }); | ||||
99 | m_parent->setIsTablet(hasTouch && !hasPointer); | ||||
100 | } | ||||
101 | | ||||
102 | private: | ||||
103 | TabletModeManager * const m_parent; | ||||
104 | }; | ||||
105 | | ||||
70 | TabletModeManager::TabletModeManager(QObject *parent) | 106 | TabletModeManager::TabletModeManager(QObject *parent) | ||
71 | : QObject(parent), | 107 | : QObject(parent) | ||
72 | m_spy(new TabletModeInputEventSpy(this)) | | |||
73 | { | 108 | { | ||
74 | input()->installInputEventSpy(m_spy); | 109 | if (input()->hasTabletModeSwitch()) { | ||
110 | input()->installInputEventSpy(new TabletModeSwitchEventSpy(this)); | ||||
111 | } else { | ||||
112 | hasTabletModeInputChanged(false); | ||||
davidedmundson: I'd prefer using kwin.kcfg
| |||||
113 | } | ||||
75 | 114 | | |||
maybe checking touchpad and mouse? ie maybe i detached the keyboard from my transformable laptop but iattached usb mouse and keyboard, i would expect in this case to go in desktop mode mart: maybe checking touchpad and mouse? ie maybe i detached the keyboard from my transformable… | |||||
76 | QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin"), | 115 | QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin"), | ||
77 | QStringLiteral("org.kde.KWin.TabletModeManager"), | 116 | QStringLiteral("org.kde.KWin.TabletModeManager"), | ||
If you do have tabletModeSwitch we're still detecting a tablet mode regardless of this setting. "SetTabletModeOnTouchPadRemoval" ? davidedmundson: If you do have tabletModeSwitch we're still detecting a tablet mode regardless of this setting. | |||||
78 | this, | 117 | this, | ||
79 | QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSignals | 118 | QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSignals | ||
80 | ); | 119 | ); | ||
81 | 120 | | |||
82 | connect(input(), &InputRedirection::hasTabletModeSwitchChanged, this, &TabletModeManager::tabletModeAvailableChanged); | 121 | connect(input(), &InputRedirection::hasTabletModeSwitchChanged, this, &TabletModeManager::tabletModeAvailableChanged); | ||
83 | } | 122 | } | ||
84 | 123 | | |||
124 | void KWin::TabletModeManager::hasTabletModeInputChanged(bool set) | ||||
125 | { | ||||
126 | if (set) { | ||||
127 | input()->installInputEventSpy(new TabletModeSwitchEventSpy(this)); | ||||
128 | setTabletModeAvailable(true); | ||||
129 | } else { | ||||
130 | auto setupDetector = [this] { | ||||
131 | auto spy = new TabletModeTouchpadRemovedSpy(this); | ||||
132 | connect(input(), &InputRedirection::hasTabletModeSwitchChanged, spy, [spy](bool set){ | ||||
133 | if (set) | ||||
134 | spy->deleteLater(); | ||||
135 | }); | ||||
136 | }; | ||||
137 | if (LibInput::Connection::self()) | ||||
138 | setupDetector(); | ||||
139 | else | ||||
140 | QTimer::singleShot(2000, this, setupDetector); | ||||
141 | } | ||||
142 | } | ||||
143 | | ||||
85 | bool TabletModeManager::isTabletModeAvailable() const | 144 | bool TabletModeManager::isTabletModeAvailable() const | ||
86 | { | 145 | { | ||
87 | return input()->hasTabletModeSwitch(); | 146 | return m_detecting; | ||
I don't really how this is meant to be used but should this be only true when there's a touch screen? davidedmundson: I don't really how this is meant to be used but should this be only true when there's a touch… | |||||
We could be a bit more specific, yes. But at this point, if it has requested through a config check to do the detection, I'd say it's fine to announce it as such. If you really want to, I can check that there's a touchscreen before initialising the Spy. apol: We could be a bit more specific, yes. But at this point, if it has requested through a config… | |||||
88 | } | 147 | } | ||
89 | 148 | | |||
90 | bool TabletModeManager::isTablet() const | 149 | bool TabletModeManager::isTablet() const | ||
91 | { | 150 | { | ||
92 | return m_isTabletMode; | 151 | return m_isTabletMode; | ||
93 | } | 152 | } | ||
94 | 153 | | |||
95 | void TabletModeManager::setIsTablet(bool tablet) | 154 | void TabletModeManager::setIsTablet(bool tablet) | ||
96 | { | 155 | { | ||
97 | if (m_isTabletMode == tablet) { | 156 | if (m_isTabletMode == tablet) { | ||
98 | return; | 157 | return; | ||
99 | } | 158 | } | ||
100 | 159 | | |||
101 | m_isTabletMode = tablet; | 160 | m_isTabletMode = tablet; | ||
102 | emit tabletModeChanged(tablet); | 161 | emit tabletModeChanged(tablet); | ||
103 | } | 162 | } | ||
163 | | ||||
164 | void KWin::TabletModeManager::setTabletModeAvailable(bool detecting) | ||||
165 | { | ||||
166 | if (m_detecting != detecting) { | ||||
167 | m_detecting = detecting; | ||||
168 | tabletModeAvailableChanged(detecting); | ||||
169 | } | ||||
170 | } |
I'd prefer using kwin.kcfg