Advance KWin Wayland port for Red Bear desktop session

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-18 17:58:57 +01:00
parent 5451f25a7a
commit 85a5ceaa3c
59 changed files with 726 additions and 509 deletions
@@ -8,11 +8,8 @@
#include "tabletmodemanager.h"
#include "backends/libinput/device.h"
#include "core/inputdevice.h"
#include "input.h"
#include "input_event.h"
#include "input_event_spy.h"
#include "main.h"
#include "wayland_server.h"
@@ -21,99 +18,8 @@
namespace KWin
{
static bool blocksTabletMode(InputDevice *device)
{
if (auto libinputDevice = qobject_cast<LibInput::Device *>(device)) {
bool ignore = false;
if (auto udev = libinput_device_get_udev_device(libinputDevice->device()); udev) {
ignore = udev_device_has_tag(udev, "kwin-ignore-tablet-mode");
udev_device_unref(udev);
}
return !ignore;
}
return false;
}
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 SwitchState::Off:
m_parent->setIsTablet(false);
break;
case SwitchState::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() && blocksTabletMode(device);
});
m_parent->setTabletModeAvailable(hasTouch);
const bool hasPointer = std::any_of(devices.constBegin(), devices.constEnd(), [](InputDevice *device) {
return device->isPointer() && blocksTabletMode(device);
});
m_parent->setIsTablet(hasTouch && !hasPointer);
}
private:
TabletModeManager *const m_parent;
};
TabletModeManager::TabletModeManager()
{
if (waylandServer()) {
if (input()->hasTabletModeSwitch()) {
input()->installInputEventSpy(new TabletModeSwitchEventSpy(this));
} else {
hasTabletModeInputChanged(false);
}
}
KSharedConfig::Ptr kwinSettings = kwinApp()->config();
m_settingsWatcher = KConfigWatcher::create(kwinSettings);
connect(m_settingsWatcher.data(), &KConfigWatcher::configChanged, this, &KWin::TabletModeManager::refreshSettings);
@@ -125,9 +31,8 @@ TabletModeManager::TabletModeManager()
// NOTE: slots must be exported for properties to work correctly
QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSignals | QDBusConnection::ExportAllSlots);
if (waylandServer()) {
connect(input(), &InputRedirection::hasTabletModeSwitchChanged, this, &TabletModeManager::hasTabletModeInputChanged);
}
setTabletModeAvailable(false);
setIsTablet(false);
}
void KWin::TabletModeManager::refreshSettings()
@@ -153,17 +58,9 @@ void KWin::TabletModeManager::refreshSettings()
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();
}
});
}
Q_UNUSED(set)
setTabletModeAvailable(false);
setIsTablet(false);
}
bool TabletModeManager::isTabletModeAvailable() const