diff --git a/abstract_wayland_output.h b/abstract_wayland_output.h index c2d91508d..aa4023f93 100644 --- a/abstract_wayland_output.h +++ b/abstract_wayland_output.h @@ -1,191 +1,191 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright 2019 Roman Gilg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #ifndef KWIN_ABSTRACT_WAYLAND_OUTPUT_H #define KWIN_ABSTRACT_WAYLAND_OUTPUT_H #include "abstract_output.h" #include #include #include #include #include #include #include #include #include #include namespace KWayland { namespace Server { class OutputInterface; class OutputDeviceInterface; class OutputChangeSet; class OutputManagementInterface; class XdgOutputInterface; } } namespace KWin { /** * Generic output representation in a Wayland session */ class KWIN_EXPORT AbstractWaylandOutput : public AbstractOutput { Q_OBJECT public: enum class Transform { Normal, Rotated90, Rotated180, Rotated270, Flipped, Flipped90, Flipped180, Flipped270 }; explicit AbstractWaylandOutput(QObject *parent = nullptr); ~AbstractWaylandOutput() override; QString name() const override; QByteArray uuid() const override; QSize modeSize() const; // TODO: The name is ambiguous. Rename this function. QSize pixelSize() const; qreal scale() const override; /** * The geometry of this output in global compositor co-ordinates (i.e scaled) */ QRect geometry() const override; QSize physicalSize() const override; + /** + * Returns the orientation of this output. + * + * - Flipped along the vertical axis is landscape + inv. portrait. + * - Rotated 90° and flipped along the horizontal axis is portrait + inv. landscape + * - Rotated 180° and flipped along the vertical axis is inv. landscape + inv. portrait + * - Rotated 270° and flipped along the horizontal axis is inv. portrait + inv. landscape + + * portrait + */ + Transform transform() const; + /** * Current refresh rate in 1/ms. */ int refreshRate() const override; bool isInternal() const override { return m_internal; } void setGlobalPos(const QPoint &pos); void setScale(qreal scale); void applyChanges(const KWayland::Server::OutputChangeSet *changeSet) override; QPointer waylandOutput() const { return m_waylandOutput; } bool isEnabled() const; /** * Enable or disable the output. * * This differs from updateDpms as it also removes the wl_output. * The default is on. */ void setEnabled(bool enable) override; Q_SIGNALS: void modeChanged(); protected: void initInterfaces(const QString &model, const QString &manufacturer, const QByteArray &uuid, const QSize &physicalSize, const QVector &modes); QPointer xdgOutput() const { return m_xdgOutput; } QPointer waylandOutputDevice() const { return m_waylandOutputDevice; } QPoint globalPos() const; bool internal() const { return m_internal; } void setInternal(bool set) { m_internal = set; } void setDpmsSupported(bool set) { m_supportsDpms = set; } virtual void updateEnablement(bool enable) { Q_UNUSED(enable); } virtual void updateDpms(KWayland::Server::OutputInterface::DpmsMode mode) { Q_UNUSED(mode); } virtual void updateMode(int modeIndex) { Q_UNUSED(modeIndex); } virtual void updateTransform(Transform transform) { Q_UNUSED(transform); } void setWaylandMode(const QSize &size, int refreshRate); void setTransform(Transform transform); QSize orientateSize(const QSize &size) const; - /** - * Returns the orientation of this output. - * - * - Flipped along the vertical axis is landscape + inv. portrait. - * - Rotated 90° and flipped along the horizontal axis is portrait + inv. landscape - * - Rotated 180° and flipped along the vertical axis is inv. landscape + inv. portrait - * - Rotated 270° and flipped along the horizontal axis is inv. portrait + inv. landscape + - * portrait - */ - Transform transform() const; - private: void createWaylandOutput(); void createXdgOutput(); void setTransform(KWayland::Server::OutputDeviceInterface::Transform transform); QPointer m_waylandOutput; QPointer m_xdgOutput; QPointer m_waylandOutputDevice; KWayland::Server::OutputInterface::DpmsMode m_dpms = KWayland::Server::OutputInterface::DpmsMode::On; bool m_internal = false; bool m_supportsDpms = false; }; } #endif // KWIN_OUTPUT_H diff --git a/libinput/connection.cpp b/libinput/connection.cpp index ff1497b67..cc5628ea1 100644 --- a/libinput/connection.cpp +++ b/libinput/connection.cpp @@ -1,720 +1,765 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2014 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "connection.h" #include "context.h" #include "device.h" #include "events.h" + +// TODO: Make it compile also in testing environment #ifndef KWIN_BUILD_TESTING +#include "../abstract_wayland_output.h" +#include "../main.h" +#include "../platform.h" #include "../screens.h" #endif + #include "../logind.h" #include "../udev.h" #include "libinput_logging.h" #include #include #include #include #include #include #include #include namespace KWin { namespace LibInput { class ConnectionAdaptor : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.InputDeviceManager") Q_PROPERTY(QStringList devicesSysNames READ devicesSysNames CONSTANT) private: Connection *m_con; public: ConnectionAdaptor(Connection *con) : m_con(con) { connect(con, &Connection::deviceAddedSysName, this, &ConnectionAdaptor::deviceAdded, Qt::QueuedConnection); connect(con, &Connection::deviceRemovedSysName, this, &ConnectionAdaptor::deviceRemoved, Qt::QueuedConnection); QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin/InputDevice"), QStringLiteral("org.kde.KWin.InputDeviceManager"), this, QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSignals ); } ~ConnectionAdaptor() override { QDBusConnection::sessionBus().unregisterObject(QStringLiteral("/org/kde/KWin/InputDeviceManager")); } QStringList devicesSysNames() { // TODO: is this allowed? directly calling function of object in another thread!? // otherwise use signal-slot mechanism return m_con->devicesSysNames(); } Q_SIGNALS: void deviceAdded(QString sysName); void deviceRemoved(QString sysName); }; Connection *Connection::s_self = nullptr; QPointer Connection::s_thread; static ConnectionAdaptor *s_adaptor = nullptr; static Context *s_context = nullptr; static quint32 toLibinputLEDS(Xkb::LEDs leds) { quint32 libinputLeds = 0; if (leds.testFlag(Xkb::LED::NumLock)) { libinputLeds = libinputLeds | LIBINPUT_LED_NUM_LOCK; } if (leds.testFlag(Xkb::LED::CapsLock)) { libinputLeds = libinputLeds | LIBINPUT_LED_CAPS_LOCK; } if (leds.testFlag(Xkb::LED::ScrollLock)) { libinputLeds = libinputLeds | LIBINPUT_LED_SCROLL_LOCK; } return libinputLeds; } Connection::Connection(QObject *parent) : Connection(nullptr, parent) { // only here to fix build, using will crash, BUG 343529 } void Connection::createThread() { if (s_thread) { return; } s_thread = new QThread(); s_thread->setObjectName(QStringLiteral("libinput-connection")); s_thread->start(); } Connection *Connection::create(QObject *parent) { Q_ASSERT(!s_self); static Udev s_udev; if (!s_udev.isValid()) { qCWarning(KWIN_LIBINPUT) << "Failed to initialize udev"; return nullptr; } if (!s_context) { s_context = new Context(s_udev); if (!s_context->isValid()) { qCWarning(KWIN_LIBINPUT) << "Failed to create context from udev"; delete s_context; s_context = nullptr; return nullptr; } if (!s_context->assignSeat(LogindIntegration::self()->seat().toUtf8().constData())) { qCWarning(KWIN_LIBINPUT) << "Failed to assign seat" << LogindIntegration::self()->seat(); delete s_context; s_context = nullptr; return nullptr; } } Connection::createThread(); s_self = new Connection(s_context); s_self->moveToThread(s_thread); QObject::connect(s_thread, &QThread::finished, s_self, &QObject::deleteLater); QObject::connect(s_thread, &QThread::finished, s_thread, &QObject::deleteLater); QObject::connect(parent, &QObject::destroyed, s_thread, &QThread::quit); if (!s_adaptor) { s_adaptor = new ConnectionAdaptor(s_self); } return s_self; } Connection::Connection(Context *input, QObject *parent) : QObject(parent) , m_input(input) , m_notifier(nullptr) , m_mutex(QMutex::Recursive) , m_leds() { Q_ASSERT(m_input); // need to connect to KGlobalSettings as the mouse KCM does not emit a dedicated signal QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"), QStringLiteral("notifyChange"), this, SLOT(slotKGlobalSettingsNotifyChange(int,int))); } Connection::~Connection() { delete s_adaptor; s_adaptor = nullptr; s_self = nullptr; delete s_context; s_context = nullptr; } void Connection::setup() { QMetaObject::invokeMethod(this, "doSetup", Qt::QueuedConnection); } void Connection::doSetup() { connect(s_self, &Connection::deviceAdded, s_self, [](Device* device) { emit s_self->deviceAddedSysName(device->sysName()); }); connect(s_self, &Connection::deviceRemoved, s_self, [](Device* device) { emit s_self->deviceRemovedSysName(device->sysName()); }); Q_ASSERT(!m_notifier); m_notifier = new QSocketNotifier(m_input->fileDescriptor(), QSocketNotifier::Read, this); connect(m_notifier, &QSocketNotifier::activated, this, &Connection::handleEvent); LogindIntegration *logind = LogindIntegration::self(); connect(logind, &LogindIntegration::sessionActiveChanged, this, [this](bool active) { if (active) { if (!m_input->isSuspended()) { return; } m_input->resume(); wasSuspended = true; } else { deactivate(); } } ); handleEvent(); } void Connection::deactivate() { if (m_input->isSuspended()) { return; } m_keyboardBeforeSuspend = hasKeyboard(); m_alphaNumericKeyboardBeforeSuspend = hasAlphaNumericKeyboard(); m_pointerBeforeSuspend = hasPointer(); m_touchBeforeSuspend = hasTouch(); m_tabletModeSwitchBeforeSuspend = hasTabletModeSwitch(); m_input->suspend(); handleEvent(); } void Connection::handleEvent() { QMutexLocker locker(&m_mutex); const bool wasEmpty = m_eventQueue.isEmpty(); do { m_input->dispatch(); Event *event = m_input->event(); if (!event) { break; } m_eventQueue << event; } while (true); if (wasEmpty && !m_eventQueue.isEmpty()) { emit eventsRead(); } } +#ifndef KWIN_BUILD_TESTING +QPointF devicePointToGlobalPosition(const QPointF &devicePos, const AbstractWaylandOutput *output) +{ + using Transform = AbstractWaylandOutput::Transform; + + QPointF pos = devicePos; + // TODO: Do we need to handle the flipped cases differently? + switch (output->transform()) { + case Transform::Normal: + case Transform::Flipped: + break; + case Transform::Rotated90: + case Transform::Flipped90: + pos = QPointF(output->modeSize().height() - devicePos.y(), devicePos.x()); + break; + case Transform::Rotated180: + case Transform::Flipped180: + pos = QPointF(output->modeSize().width() - devicePos.x(), + output->modeSize().height() - devicePos.y()); + break; + case Transform::Rotated270: + case Transform::Flipped270: + pos = QPointF(devicePos.y(), output->modeSize().width() - devicePos.x()); + break; + default: + Q_UNREACHABLE(); + } + return output->geometry().topLeft() + pos / output->scale(); +} +#endif + void Connection::processEvents() { QMutexLocker locker(&m_mutex); while (!m_eventQueue.isEmpty()) { QScopedPointer event(m_eventQueue.takeFirst()); switch (event->type()) { case LIBINPUT_EVENT_DEVICE_ADDED: { auto device = new Device(event->nativeDevice()); device->moveToThread(s_thread); m_devices << device; if (device->isKeyboard()) { m_keyboard++; if (device->isAlphaNumericKeyboard()) { m_alphaNumericKeyboard++; if (m_alphaNumericKeyboard == 1) { emit hasAlphaNumericKeyboardChanged(true); } } if (m_keyboard == 1) { emit hasKeyboardChanged(true); } } if (device->isPointer()) { m_pointer++; if (m_pointer == 1) { emit hasPointerChanged(true); } } if (device->isTouch()) { m_touch++; if (m_touch == 1) { emit hasTouchChanged(true); } } if (device->isTabletModeSwitch()) { m_tabletModeSwitch++; if (m_tabletModeSwitch == 1) { emit hasTabletModeSwitchChanged(true); } } applyDeviceConfig(device); applyScreenToDevice(device); // enable possible leds libinput_device_led_update(device->device(), static_cast(toLibinputLEDS(m_leds))); emit deviceAdded(device); break; } case LIBINPUT_EVENT_DEVICE_REMOVED: { auto it = std::find_if(m_devices.begin(), m_devices.end(), [&event] (Device *d) { return event->device() == d; } ); if (it == m_devices.end()) { // we don't know this device break; } auto device = *it; m_devices.erase(it); emit deviceRemoved(device); if (device->isKeyboard()) { m_keyboard--; if (device->isAlphaNumericKeyboard()) { m_alphaNumericKeyboard--; if (m_alphaNumericKeyboard == 0) { emit hasAlphaNumericKeyboardChanged(false); } } if (m_keyboard == 0) { emit hasKeyboardChanged(false); } } if (device->isPointer()) { m_pointer--; if (m_pointer == 0) { emit hasPointerChanged(false); } } if (device->isTouch()) { m_touch--; if (m_touch == 0) { emit hasTouchChanged(false); } } if (device->isTabletModeSwitch()) { m_tabletModeSwitch--; if (m_tabletModeSwitch == 0) { emit hasTabletModeSwitchChanged(false); } } device->deleteLater(); break; } case LIBINPUT_EVENT_KEYBOARD_KEY: { KeyEvent *ke = static_cast(event.data()); emit keyChanged(ke->key(), ke->state(), ke->time(), ke->device()); break; } case LIBINPUT_EVENT_POINTER_AXIS: { PointerEvent *pe = static_cast(event.data()); const auto axes = pe->axis(); for (const InputRedirection::PointerAxis &axis : axes) { emit pointerAxisChanged(axis, pe->axisValue(axis), pe->discreteAxisValue(axis), pe->axisSource(), pe->time(), pe->device()); } break; } case LIBINPUT_EVENT_POINTER_BUTTON: { PointerEvent *pe = static_cast(event.data()); emit pointerButtonChanged(pe->button(), pe->buttonState(), pe->time(), pe->device()); break; } case LIBINPUT_EVENT_POINTER_MOTION: { PointerEvent *pe = static_cast(event.data()); auto delta = pe->delta(); auto deltaNonAccel = pe->deltaUnaccelerated(); quint32 latestTime = pe->time(); quint64 latestTimeUsec = pe->timeMicroseconds(); auto it = m_eventQueue.begin(); while (it != m_eventQueue.end()) { if ((*it)->type() == LIBINPUT_EVENT_POINTER_MOTION) { QScopedPointer p(static_cast(*it)); delta += p->delta(); deltaNonAccel += p->deltaUnaccelerated(); latestTime = p->time(); latestTimeUsec = p->timeMicroseconds(); it = m_eventQueue.erase(it); } else { break; } } emit pointerMotion(delta, deltaNonAccel, latestTime, latestTimeUsec, pe->device()); break; } case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: { PointerEvent *pe = static_cast(event.data()); emit pointerMotionAbsolute(pe->absolutePos(), pe->absolutePos(m_size), pe->time(), pe->device()); break; } case LIBINPUT_EVENT_TOUCH_DOWN: { #ifndef KWIN_BUILD_TESTING TouchEvent *te = static_cast(event.data()); - const auto &geo = screens()->geometry(te->device()->screenId()); - emit touchDown(te->id(), geo.topLeft() + te->absolutePos(geo.size()), te->time(), te->device()); + const auto *output = static_cast( + kwinApp()->platform()->enabledOutputs()[te->device()->screenId()]); + const QPointF globalPos = + devicePointToGlobalPosition(te->absolutePos(output->modeSize()), + output); + emit touchDown(te->id(), globalPos, te->time(), te->device()); break; #endif } case LIBINPUT_EVENT_TOUCH_UP: { TouchEvent *te = static_cast(event.data()); emit touchUp(te->id(), te->time(), te->device()); break; } case LIBINPUT_EVENT_TOUCH_MOTION: { #ifndef KWIN_BUILD_TESTING TouchEvent *te = static_cast(event.data()); - const auto &geo = screens()->geometry(te->device()->screenId()); - emit touchMotion(te->id(), geo.topLeft() + te->absolutePos(geo.size()), te->time(), te->device()); + const auto *output = static_cast( + kwinApp()->platform()->enabledOutputs()[te->device()->screenId()]); + const QPointF globalPos = + devicePointToGlobalPosition(te->absolutePos(output->modeSize()), + output); + emit touchMotion(te->id(), globalPos, te->time(), te->device()); break; #endif } case LIBINPUT_EVENT_TOUCH_CANCEL: { emit touchCanceled(event->device()); break; } case LIBINPUT_EVENT_TOUCH_FRAME: { emit touchFrame(event->device()); break; } case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: { PinchGestureEvent *pe = static_cast(event.data()); emit pinchGestureBegin(pe->fingerCount(), pe->time(), pe->device()); break; } case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: { PinchGestureEvent *pe = static_cast(event.data()); emit pinchGestureUpdate(pe->scale(), pe->angleDelta(), pe->delta(), pe->time(), pe->device()); break; } case LIBINPUT_EVENT_GESTURE_PINCH_END: { PinchGestureEvent *pe = static_cast(event.data()); if (pe->isCancelled()) { emit pinchGestureCancelled(pe->time(), pe->device()); } else { emit pinchGestureEnd(pe->time(), pe->device()); } break; } case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: { SwipeGestureEvent *se = static_cast(event.data()); emit swipeGestureBegin(se->fingerCount(), se->time(), se->device()); break; } case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: { SwipeGestureEvent *se = static_cast(event.data()); emit swipeGestureUpdate(se->delta(), se->time(), se->device()); break; } case LIBINPUT_EVENT_GESTURE_SWIPE_END: { SwipeGestureEvent *se = static_cast(event.data()); if (se->isCancelled()) { emit swipeGestureCancelled(se->time(), se->device()); } else { emit swipeGestureEnd(se->time(), se->device()); } break; } case LIBINPUT_EVENT_SWITCH_TOGGLE: { SwitchEvent *se = static_cast(event.data()); switch (se->state()) { case SwitchEvent::State::Off: emit switchToggledOff(se->time(), se->timeMicroseconds(), se->device()); break; case SwitchEvent::State::On: emit switchToggledOn(se->time(), se->timeMicroseconds(), se->device()); break; default: Q_UNREACHABLE(); } break; } case LIBINPUT_EVENT_TABLET_TOOL_AXIS: case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: case LIBINPUT_EVENT_TABLET_TOOL_TIP: { auto *tte = static_cast(event.data()); KWin::InputRedirection::TabletEventType tabletEventType; switch (event->type()) { case LIBINPUT_EVENT_TABLET_TOOL_AXIS: tabletEventType = KWin::InputRedirection::Axis; break; case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: tabletEventType = KWin::InputRedirection::Proximity; break; case LIBINPUT_EVENT_TABLET_TOOL_TIP: default: tabletEventType = KWin::InputRedirection::Tip; break; } auto serial = libinput_tablet_tool_get_serial(tte->tool()); auto toolId = libinput_tablet_tool_get_tool_id(tte->tool()); emit tabletToolEvent(tabletEventType, tte->transformedPosition(m_size), tte->pressure(), tte->xTilt(), tte->yTilt(), tte->rotation(), tte->isTipDown(), tte->isNearby(), serial, toolId, event->device()); break; } case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: { auto *tabletEvent = static_cast(event.data()); emit tabletToolButtonEvent(tabletEvent->buttonId(), tabletEvent->isButtonPressed()); break; } case LIBINPUT_EVENT_TABLET_PAD_BUTTON: { auto *tabletEvent = static_cast(event.data()); emit tabletPadButtonEvent(tabletEvent->buttonId(), tabletEvent->isButtonPressed()); break; } case LIBINPUT_EVENT_TABLET_PAD_RING: { auto *tabletEvent = static_cast(event.data()); emit tabletPadRingEvent(tabletEvent->number(), tabletEvent->position(), tabletEvent->source() == LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER); break; } case LIBINPUT_EVENT_TABLET_PAD_STRIP: { auto *tabletEvent = static_cast(event.data()); emit tabletPadStripEvent(tabletEvent->number(), tabletEvent->position(), tabletEvent->source() == LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER); break; } default: // nothing break; } } if (wasSuspended) { if (m_keyboardBeforeSuspend && !m_keyboard) { emit hasKeyboardChanged(false); } if (m_alphaNumericKeyboardBeforeSuspend && !m_alphaNumericKeyboard) { emit hasAlphaNumericKeyboardChanged(false); } if (m_pointerBeforeSuspend && !m_pointer) { emit hasPointerChanged(false); } if (m_touchBeforeSuspend && !m_touch) { emit hasTouchChanged(false); } if (m_tabletModeSwitchBeforeSuspend && !m_tabletModeSwitch) { emit hasTabletModeSwitchChanged(false); } wasSuspended = false; } } void Connection::setScreenSize(const QSize &size) { m_size = size; } void Connection::updateScreens() { QMutexLocker locker(&m_mutex); for (auto device: qAsConst(m_devices)) { applyScreenToDevice(device); } } void Connection::applyScreenToDevice(Device *device) { #ifndef KWIN_BUILD_TESTING QMutexLocker locker(&m_mutex); if (!device->isTouch()) { return; } int id = -1; // let's try to find a screen for it if (screens()->count() == 1) { id = 0; } if (id == -1 && !device->outputName().isEmpty()) { // we have an output name, try to find a screen with matching name for (int i = 0; i < screens()->count(); i++) { if (screens()->name(i) == device->outputName()) { id = i; break; } } } if (id == -1) { // do we have an internal screen? int internalId = -1; for (int i = 0; i < screens()->count(); i++) { if (screens()->isInternal(i)) { internalId = i; break; } } auto testScreenMatches = [device] (int id) { const auto &size = device->size(); const auto &screenSize = screens()->physicalSize(id); return std::round(size.width()) == std::round(screenSize.width()) && std::round(size.height()) == std::round(screenSize.height()); }; if (internalId != -1 && testScreenMatches(internalId)) { id = internalId; } // let's compare all screens for size for (int i = 0; i < screens()->count(); i++) { if (testScreenMatches(i)) { id = i; break; } } if (id == -1) { // still not found if (internalId != -1) { // we have an internal id, so let's use that id = internalId; } else { // just take first screen, we have no clue id = 0; } } } device->setScreenId(id); device->setOrientation(screens()->orientation(id)); #else Q_UNUSED(device) #endif } bool Connection::isSuspended() const { if (!s_context) { return false; } return s_context->isSuspended(); } void Connection::applyDeviceConfig(Device *device) { // pass configuration to Device device->setConfig(m_config->group("Libinput").group(QString::number(device->vendor())).group(QString::number(device->product())).group(device->name())); device->loadConfiguration(); } void Connection::slotKGlobalSettingsNotifyChange(int type, int arg) { if (type == 3 /**SettingsChanged**/ && arg == 0 /** SETTINGS_MOUSE */) { m_config->reparseConfiguration(); for (auto it = m_devices.constBegin(), end = m_devices.constEnd(); it != end; ++it) { if ((*it)->isPointer()) { applyDeviceConfig(*it); } } } } void Connection::toggleTouchpads() { bool changed = false; m_touchpadsEnabled = !m_touchpadsEnabled; for (auto it = m_devices.constBegin(); it != m_devices.constEnd(); ++it) { auto device = *it; if (!device->isTouchpad()) { continue; } const bool old = device->isEnabled(); device->setEnabled(m_touchpadsEnabled); if (old != device->isEnabled()) { changed = true; } } if (changed) { // send OSD message QDBusMessage msg = QDBusMessage::createMethodCall( QStringLiteral("org.kde.plasmashell"), QStringLiteral("/org/kde/osdService"), QStringLiteral("org.kde.osdService"), QStringLiteral("touchpadEnabledChanged") ); msg.setArguments({m_touchpadsEnabled}); QDBusConnection::sessionBus().asyncCall(msg); } } void Connection::enableTouchpads() { if (m_touchpadsEnabled) { return; } toggleTouchpads(); } void Connection::disableTouchpads() { if (!m_touchpadsEnabled) { return; } toggleTouchpads(); } void Connection::updateLEDs(Xkb::LEDs leds) { if (m_leds == leds) { return; } m_leds = leds; // update on devices const libinput_led l = static_cast(toLibinputLEDS(leds)); for (auto it = m_devices.constBegin(), end = m_devices.constEnd(); it != end; ++it) { libinput_device_led_update((*it)->device(), l); } } QStringList Connection::devicesSysNames() const { QStringList sl; foreach (Device *d, m_devices) { sl.append(d->sysName()); } return sl; } } } #include "connection.moc"