kwin/src/tabletmodemanager.cpp
Vlad Zahorodnii ef72bae42f Introduce base InputDevice class
The main motivation behind this change is to prepare input abstractions
for virtual input devices so the wl_seat can properly advertise caps or
the cursor getting properly mapped/unmapped when a fake pointer is
added/removed on a system without a hardware mouse connected.

With this, there are three abstractions - InputDevice, InputBackend, and
InputRedirection.

An InputDevice represents an input device such as a mouse, a keyboard, a
tablet, etc. The InputBackend class notifies the InputRedirection about
(dis-)connected devices. The InputRedirection manages the input devices.

Such design allows to unify the event flow for real and virtual input
devices.

There can be several input backends active. For example, the libinput
backend and an input backend that provides virtual input devices, e.g.
libeis or org_kde_kwin_fake_input.
2021-11-01 16:27:16 +02:00

148 lines
3.9 KiB
C++

/*
SPDX-FileCopyrightText: 2018 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "tabletmodemanager.h"
#include "input.h"
#include "inputdevice.h"
#include "input_event.h"
#include "input_event_spy.h"
#include <QDBusConnection>
namespace KWin
{
KWIN_SINGLETON_FACTORY_VARIABLE(TabletModeManager, s_manager)
class TabletModeSwitchEventSpy : public QObject, public InputEventSpy
{
public:
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();
}
}
private:
TabletModeManager * const m_parent;
};
class TabletModeTouchpadRemovedSpy : public QObject
{
public:
explicit TabletModeTouchpadRemovedSpy(TabletModeManager *parent)
: QObject(parent)
, m_parent(parent)
{
connect(input(), &InputRedirection::deviceAdded, this, &TabletModeTouchpadRemovedSpy::refresh);
connect(input(), &InputRedirection::deviceRemoved, this, &TabletModeTouchpadRemovedSpy::refresh);
check();
}
void refresh(InputDevice *inputDevice)
{
if (inputDevice->isTouch() || inputDevice->isPointer()) {
check();
}
}
void check()
{
const auto devices = input()->devices();
const bool hasTouch = std::any_of(devices.constBegin(), devices.constEnd(), [](InputDevice *device) { return device->isTouch(); });
m_parent->setTabletModeAvailable(hasTouch);
const bool hasPointer = std::any_of(devices.constBegin(), devices.constEnd(), [](InputDevice *device) { return device->isPointer(); });
m_parent->setIsTablet(hasTouch && !hasPointer);
}
private:
TabletModeManager * const m_parent;
};
TabletModeManager::TabletModeManager(QObject *parent)
: QObject(parent)
{
if (input()->hasTabletModeSwitch()) {
input()->installInputEventSpy(new TabletModeSwitchEventSpy(this));
} else {
hasTabletModeInputChanged(false);
}
QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin"),
QStringLiteral("org.kde.KWin.TabletModeManager"),
this,
QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSignals
);
connect(input(), &InputRedirection::hasTabletModeSwitchChanged, this, &TabletModeManager::hasTabletModeInputChanged);
}
void KWin::TabletModeManager::hasTabletModeInputChanged(bool set)
{
if (set) {
input()->installInputEventSpy(new TabletModeSwitchEventSpy(this));
setTabletModeAvailable(true);
} else {
auto spy = new TabletModeTouchpadRemovedSpy(this);
connect(input(), &InputRedirection::hasTabletModeSwitchChanged, spy, [spy](bool set) {
if (set) {
spy->deleteLater();
}
});
}
}
bool TabletModeManager::isTabletModeAvailable() const
{
return m_detecting;
}
bool TabletModeManager::isTablet() const
{
return m_isTabletMode;
}
void TabletModeManager::setIsTablet(bool tablet)
{
if (m_isTabletMode == tablet) {
return;
}
m_isTabletMode = tablet;
Q_EMIT tabletModeChanged(tablet);
}
void KWin::TabletModeManager::setTabletModeAvailable(bool detecting)
{
if (m_detecting != detecting) {
m_detecting = detecting;
Q_EMIT tabletModeAvailableChanged(detecting);
}
}
} // namespace KWin