diff --git a/autotests/kded/tablethandler/testtablethandler.cpp b/autotests/kded/tablethandler/testtablethandler.cpp --- a/autotests/kded/tablethandler/testtablethandler.cpp +++ b/autotests/kded/tablethandler/testtablethandler.cpp @@ -91,6 +91,8 @@ void TestTabletHandler::onProfileChanged(const QString& tabletID, const QString& profile) { + Q_UNUSED(tabletID) + m_profileChanged = profile; } @@ -107,6 +109,8 @@ void TestTabletHandler::onTabletRemoved(const QString &tabletID) { + Q_UNUSED(tabletID) + m_tabletAdded = false; m_tabletRemoved = true; } @@ -189,7 +193,7 @@ QCOMPARE(m_tabletHandler->getProperty(QLatin1String("4321"), DeviceType::Touch, Property::Rotate), ScreenRotation::NONE.key()); // rotate screen - m_tabletHandler->onScreenRotated(ScreenRotation::HALF); + m_tabletHandler->onScreenRotated(Qt::InvertedLandscapeOrientation); // validate result QCOMPARE(m_tabletHandler->getProperty(QLatin1String("4321"), DeviceType::Eraser, Property::Rotate), ScreenRotation::HALF.key()); diff --git a/src/common/profilemanagement.cpp b/src/common/profilemanagement.cpp --- a/src/common/profilemanagement.cpp +++ b/src/common/profilemanagement.cpp @@ -34,8 +34,6 @@ #include #include -#include - using namespace Wacom; ProfileManagement::ProfileManagement() diff --git a/src/kcmodule/generalpagewidget.cpp b/src/kcmodule/generalpagewidget.cpp --- a/src/kcmodule/generalpagewidget.cpp +++ b/src/kcmodule/generalpagewidget.cpp @@ -43,8 +43,6 @@ #include #include -#include - using namespace Wacom; namespace Wacom { diff --git a/src/kded/tabletdaemon.h b/src/kded/tabletdaemon.h --- a/src/kded/tabletdaemon.h +++ b/src/kded/tabletdaemon.h @@ -23,6 +23,8 @@ #include #include +class QScreen; + /** * The wacom namespace holds all classes regarding the tablet daemon / kcmodule and applet. */ @@ -107,6 +109,23 @@ */ void setupEventNotifier(); + /** + * Helper function that sets up signals + * monitoring screen rotations and geometry changes + * for every existing and future screens. + */ + void monitorAllScreensGeometry(); + +private Q_SLOTS: + /** + * Sets up signals for rotation and geometry changes + * for a specific screen + * @param screen Screen to monitor + */ + void monitorScreenGeometry(QScreen *screen); + +private: + Q_DECLARE_PRIVATE(TabletDaemon) TabletDaemonPrivate *const d_ptr; /**< d-pointer for this class */ diff --git a/src/kded/tabletdaemon.cpp b/src/kded/tabletdaemon.cpp --- a/src/kded/tabletdaemon.cpp +++ b/src/kded/tabletdaemon.cpp @@ -38,9 +38,8 @@ #include #include #include -#include -#include -#include +#include +#include using namespace Wacom; @@ -150,8 +149,6 @@ void TabletDaemon::setupApplication() { - Q_D( TabletDaemon ); - static AboutData about( QLatin1Literal("wacomtablet"), i18n( "Graphic Tablet Configuration daemon" ), QLatin1String(kded_version), i18n( "A Wacom tablet control daemon" ) ); @@ -181,14 +178,53 @@ { Q_D( TabletDaemon ); - connect( &X11EventNotifier::instance(), SIGNAL(screenRotated(ScreenRotation)), &(d->tabletHandler), SLOT(onScreenRotated(ScreenRotation))); - connect( &X11EventNotifier::instance(), SIGNAL(tabletAdded(int)), &TabletFinder::instance(), SLOT(onX11TabletAdded(int))); - connect( &X11EventNotifier::instance(), SIGNAL(tabletRemoved(int)), &TabletFinder::instance(), SLOT(onX11TabletRemoved(int))); + // Set up monitoring for individual screen geometry changes + monitorAllScreensGeometry(); + + // Set up monitoring for screens being added, removed or reordered + connect(qApp, &QGuiApplication::primaryScreenChanged, &(d->tabletHandler), &TabletHandler::onScreenAddedRemoved); + connect(qApp, &QGuiApplication::screenAdded, &(d->tabletHandler), &TabletHandler::onScreenAddedRemoved); + connect(qApp, &QGuiApplication::screenRemoved, &(d->tabletHandler), &TabletHandler::onScreenAddedRemoved); + + // Set up tablet connected/disconnected signals + connect( &X11EventNotifier::instance(), &X11EventNotifier::tabletAdded, &TabletFinder::instance(), &TabletFinder::onX11TabletAdded); + connect( &X11EventNotifier::instance(), &X11EventNotifier::tabletRemoved, &TabletFinder::instance(), &TabletFinder::onX11TabletRemoved); - connect( &TabletFinder::instance(), SIGNAL(tabletAdded(TabletInformation)), &(d->tabletHandler), SLOT(onTabletAdded(TabletInformation))); - connect( &TabletFinder::instance(), SIGNAL(tabletRemoved(TabletInformation)), &(d->tabletHandler), SLOT(onTabletRemoved(TabletInformation))); + connect( &TabletFinder::instance(), &TabletFinder::tabletAdded, &(d->tabletHandler), &TabletHandler::onTabletAdded); + connect( &TabletFinder::instance(), &TabletFinder::tabletRemoved, &(d->tabletHandler), &TabletHandler::onTabletRemoved); X11EventNotifier::instance().start(); } +void TabletDaemon::monitorAllScreensGeometry() +{ + // FIXME: Should be duplicating old, buggy behaviour: + // rotation changes monitored for all screens, which causes + // unwanted rotation in a multi-screen setup + + // Add existing screens + for (const auto &screen : QGuiApplication::screens()) + { + monitorScreenGeometry(screen); + } + + // Monitor future screens + connect(qApp, &QGuiApplication::screenAdded, this, &TabletDaemon::monitorScreenGeometry); +} + +void TabletDaemon::monitorScreenGeometry(QScreen *screen) +{ + Q_D( TabletDaemon ); + + auto tabletHandler = &(d->tabletHandler); + + connect(screen, &QScreen::orientationChanged, tabletHandler, &TabletHandler::onScreenRotated); + screen->setOrientationUpdateMask(Qt::LandscapeOrientation | + Qt::PortraitOrientation | + Qt::InvertedLandscapeOrientation | + Qt::InvertedPortraitOrientation); + + connect(screen, &QScreen::geometryChanged, &(d->tabletHandler), &TabletHandler::onScreenGeometryChanged); +} + #include "tabletdaemon.moc" diff --git a/src/kded/tabletfinder.cpp b/src/kded/tabletfinder.cpp --- a/src/kded/tabletfinder.cpp +++ b/src/kded/tabletfinder.cpp @@ -95,7 +95,7 @@ continue; } - qDebug() << QString::fromLatin1("Tablet '%1' (%2) found.").arg(iter->get(TabletInfo::TabletName)).arg(iter->get(TabletInfo::TabletId)); + dbgWacom << QString::fromLatin1("Tablet '%1' (%2) found.").arg(iter->get(TabletInfo::TabletName)).arg(iter->get(TabletInfo::TabletId)); // emit tablet added signal emit tabletAdded(*iter); @@ -142,7 +142,7 @@ continue; } - qDebug() << QString::fromLatin1("Tablet '%1' (%2) added.").arg(tabletInfo.get(TabletInfo::TabletName)).arg(tabletInfo.get(TabletInfo::TabletId)); + dbgWacom << QString::fromLatin1("Tablet '%1' (%2) added.").arg(tabletInfo.get(TabletInfo::TabletName)).arg(tabletInfo.get(TabletInfo::TabletId)); // add tablet to the list of known tablets and emit added signal d->tabletList.append(tabletInfo); @@ -165,7 +165,7 @@ if (iter->hasDevice(deviceId)) { TabletInformation info = *iter; d->tabletList.erase(iter); - qDebug() << QString::fromLatin1("Removed tablet '%1' (%2).").arg(info.get(TabletInfo::TabletName)).arg(info.get(TabletInfo::TabletId)); + dbgWacom << QString::fromLatin1("Removed tablet '%1' (%2).").arg(info.get(TabletInfo::TabletName)).arg(info.get(TabletInfo::TabletId)); emit tabletRemoved(info); return; } @@ -178,12 +178,11 @@ { // lookup information from our tablet database if (!TabletDatabase::instance().lookupTablet(info.get (TabletInfo::TabletId), info)) { - qDebug() << QString::fromLatin1("Could not find tablet with id '%1' in database.").arg(info.get (TabletInfo::TabletId)); + dbgWacom << QString::fromLatin1("Could not find tablet with id '%1' in database.").arg(info.get (TabletInfo::TabletId)); return false; } // TODO use libwacom to get more tablet information return true; } - diff --git a/src/kded/tablethandler.h b/src/kded/tablethandler.h --- a/src/kded/tablethandler.h +++ b/src/kded/tablethandler.h @@ -29,6 +29,8 @@ #include #include +class QScreen; + namespace Wacom { class ScreenSpace; @@ -133,7 +135,18 @@ * * @param screenRotation The screen rotation. */ - void onScreenRotated(const ScreenRotation& screenRotation); + void onScreenRotated(const Qt::ScreenOrientation &newScreenRotation); + + /** + * @brief Handles screens being connected and disconnected + * @param screen Screen being connected or disconnected + */ + void onScreenAddedRemoved(QScreen *screen); + + /** + * @brief Handles changes in existing screen's geometry + */ + void onScreenGeometryChanged(); /** * Toggles the stylus/eraser to absolute/relative mode diff --git a/src/kded/tablethandler.cpp b/src/kded/tablethandler.cpp --- a/src/kded/tablethandler.cpp +++ b/src/kded/tablethandler.cpp @@ -178,14 +178,34 @@ -void TabletHandler::onScreenRotated( const ScreenRotation& screenRotation ) +void TabletHandler::onScreenRotated( const Qt::ScreenOrientation &newScreenRotation ) { Q_D( TabletHandler ); + dbgWacom << "Screen rotation changed: " << newScreenRotation; + //for each connected tablet, do the rotation foreach(const QString &tabletId, d->tabletInformationList.keys()) { QString curProfile = d->currentProfileList.value(tabletId); TabletProfile tabletProfile = d->profileManagerList.value(tabletId)->loadProfile(curProfile); + ScreenRotation screenRotation = ScreenRotation::NONE; + + switch (newScreenRotation) + { + case Qt::PrimaryOrientation: + case Qt::LandscapeOrientation: + screenRotation = ScreenRotation::NONE; + break; + case Qt::PortraitOrientation: + screenRotation = ScreenRotation::CW; + break; + case Qt::InvertedLandscapeOrientation: + screenRotation = ScreenRotation::HALF; + break; + case Qt::InvertedPortraitOrientation: + screenRotation = ScreenRotation::CCW; + break; + } // rotation has to be applied before screen mapping autoRotateTablet(tabletId, screenRotation, tabletProfile); @@ -195,6 +215,35 @@ } } +void TabletHandler::onScreenAddedRemoved(QScreen *screen) +{ + Q_D( TabletHandler ); + + Q_UNUSED(screen) + dbgWacom << "Number of screens has changed"; + + foreach(const QString &tabletId, d->tabletInformationList.keys()) { + QString curProfile = d->currentProfileList.value(tabletId); + TabletProfile tabletProfile = d->profileManagerList.value(tabletId)->loadProfile(curProfile); + + mapTabletToCurrentScreenSpace(tabletId, tabletProfile); + } +} + +void TabletHandler::onScreenGeometryChanged() +{ + Q_D( TabletHandler ); + + dbgWacom << "Screen geometry has changed"; + + foreach(const QString &tabletId, d->tabletInformationList.keys()) { + QString curProfile = d->currentProfileList.value(tabletId); + TabletProfile tabletProfile = d->profileManagerList.value(tabletId)->loadProfile(curProfile); + + mapTabletToCurrentScreenSpace(tabletId, tabletProfile); + } +} + void TabletHandler::onTogglePenMode() { diff --git a/src/kded/x11eventnotifier-xcb.cpp b/src/kded/x11eventnotifier-xcb.cpp --- a/src/kded/x11eventnotifier-xcb.cpp +++ b/src/kded/x11eventnotifier-xcb.cpp @@ -30,14 +30,12 @@ #include #include -#include namespace Wacom { class X11EventNotifierPrivate { public: - xcb_randr_rotation_t currentRotation; bool isStarted; }; } @@ -48,16 +46,14 @@ : EventNotifier(NULL), QAbstractNativeEventFilter(), d_ptr(new X11EventNotifierPrivate) { Q_D( X11EventNotifier ); - d->currentRotation = XCB_RANDR_ROTATION_ROTATE_0; d->isStarted = false; } X11EventNotifier::X11EventNotifier(const X11EventNotifier& notifier) : EventNotifier(NULL), QAbstractNativeEventFilter(), d_ptr(new X11EventNotifierPrivate) { Q_UNUSED(notifier); Q_D( X11EventNotifier ); - d->currentRotation = XCB_RANDR_ROTATION_ROTATE_0; d->isStarted = false; } @@ -123,9 +119,6 @@ if (event->response_type == XCB_GE_GENERIC && cookie->event_type == XCB_INPUT_HIERARCHY) { handleX11InputEvent(cookie); - - } else { - handleX11ScreenEvent(event); } // return QWidget::x11Event(event); @@ -145,64 +138,24 @@ for (; iter.rem; xcb_input_hierarchy_info_next(&iter)) { if (iter.data->flags & XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED) { - qDebug() << QString::fromLatin1("X11 device with id '%1' removed.").arg(iter.data->deviceid); + dbgWacom << QString::fromLatin1("X11 device with id '%1' removed.").arg(iter.data->deviceid); emit tabletRemoved(iter.data->deviceid); } else if (iter.data->flags & XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED) { - qDebug() << QString::fromLatin1("X11 device with id '%1' added.").arg(iter.data->deviceid); + dbgWacom << QString::fromLatin1("X11 device with id '%1' added.").arg(iter.data->deviceid); X11InputDevice device (iter.data->deviceid, QLatin1String("Unknown X11 Device")); if (device.isOpen() && device.isTabletDevice()) { - qDebug() << QString::fromLatin1("Wacom tablet device with X11 id '%1' added.").arg(iter.data->deviceid); + dbgWacom << QString::fromLatin1("Wacom tablet device with X11 id '%1' added.").arg(iter.data->deviceid); emit tabletAdded(iter.data->deviceid); } } } } -void X11EventNotifier::handleX11ScreenEvent(xcb_generic_event_t* event) -{ - Q_D( X11EventNotifier ); - - const xcb_query_extension_reply_t* reply = xcb_get_extension_data(QX11Info::connection(), &xcb_randr_id); - - if (event->response_type == reply->first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { - xcb_randr_screen_change_notify_event_t* ev = reinterpret_cast(event); - auto old_r = d->currentRotation; - d->currentRotation = static_cast(ev->rotation); - - if (old_r != d->currentRotation) { - ScreenRotation newRotation = ScreenRotation::NONE; - - switch (d->currentRotation) { - case XCB_RANDR_ROTATION_ROTATE_0: - newRotation = ScreenRotation::NONE; - break; - case XCB_RANDR_ROTATION_ROTATE_90: - newRotation = ScreenRotation::CCW; - break; - case XCB_RANDR_ROTATION_ROTATE_180: - newRotation = ScreenRotation::HALF; - break; - case XCB_RANDR_ROTATION_ROTATE_270: - newRotation = ScreenRotation::CW; - break; - default: - errWacom << QString::fromLatin1("FIXME: Unsupported screen rotation '%1'.").arg(d->currentRotation); - return; - } - - qDebug() << QString::fromLatin1("XRandr screen rotation detected: '%1'.").arg(newRotation.key()); - emit screenRotated(newRotation); - } - } -} - - - int X11EventNotifier::registerForNewDeviceEvent(xcb_connection_t* conn) { char buf[sizeof(xcb_input_event_mask_t) + sizeof(uint32_t)]; diff --git a/src/kded/x11eventnotifier-xlib.cpp b/src/kded/x11eventnotifier-xlib.cpp --- a/src/kded/x11eventnotifier-xlib.cpp +++ b/src/kded/x11eventnotifier-xlib.cpp @@ -42,7 +42,6 @@ class X11EventNotifierPrivate { public: - xcb_randr_rotation_t currentRotation; bool isStarted; }; } @@ -53,16 +52,14 @@ : EventNotifier(NULL), QAbstractNativeEventFilter(), d_ptr(new X11EventNotifierPrivate) { Q_D( X11EventNotifier ); - d->currentRotation = XCB_RANDR_ROTATION_ROTATE_0; d->isStarted = false; } X11EventNotifier::X11EventNotifier(const X11EventNotifier& notifier) : EventNotifier(NULL), QAbstractNativeEventFilter(), d_ptr(new X11EventNotifierPrivate) { Q_UNUSED(notifier); Q_D( X11EventNotifier ); - d->currentRotation = XCB_RANDR_ROTATION_ROTATE_0; d->isStarted = false; } @@ -130,7 +127,7 @@ if (event->response_type == XCB_GE_GENERIC && cookie->event_type == XI_HierarchyChanged) { // handleX11InputEvent(cookie); } else { - handleX11ScreenEvent(event); + // handleX11ScreenEvent(event); } // return QWidget::x11Event(event); @@ -148,46 +145,6 @@ -void X11EventNotifier::handleX11ScreenEvent(xcb_generic_event_t* event) -{ - Q_D( X11EventNotifier ); - - const xcb_query_extension_reply_t* reply = xcb_get_extension_data(QX11Info::connection(), &xcb_randr_id); - - if (event->response_type == reply->first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { - xcb_randr_screen_change_notify_event_t* ev = reinterpret_cast(event); - auto old_r = d->currentRotation; - d->currentRotation = static_cast(ev->rotation); - - if (old_r != d->currentRotation) { - ScreenRotation newRotation = ScreenRotation::NONE; - - switch (d->currentRotation) { - case XCB_RANDR_ROTATION_ROTATE_0: - newRotation = ScreenRotation::NONE; - break; - case XCB_RANDR_ROTATION_ROTATE_90: - newRotation = ScreenRotation::CCW; - break; - case XCB_RANDR_ROTATION_ROTATE_180: - newRotation = ScreenRotation::HALF; - break; - case XCB_RANDR_ROTATION_ROTATE_270: - newRotation = ScreenRotation::CW; - break; - default: - errWacom << QString::fromLatin1("FIXME: Unsupported screen rotation '%1'.").arg(d->currentRotation); - return; - } - - qDebug() << QString::fromLatin1("XRandr screen rotation detected: '%1'.").arg(newRotation.key()); - emit screenRotated(newRotation); - } - } -} - - - int X11EventNotifier::registerForNewDeviceEvent(xcb_connection_t* conn) { // This is already done by xcb plugin with more flags, doing this ourselves diff --git a/src/kded/xinputadaptor.cpp b/src/kded/xinputadaptor.cpp --- a/src/kded/xinputadaptor.cpp +++ b/src/kded/xinputadaptor.cpp @@ -188,6 +188,8 @@ // | 0 h offsetY | // | 0 0 1 | + dbgWacom << "Mapping to area: " << screenArea; + if (screenArea.isEmpty()) { return false; // nothing to do } @@ -199,6 +201,7 @@ if (screenSpace.isDesktop()) { // full screen area selected + dbgWacom << "Full screen area selected: " << fullScreenGeometry; screenAreaGeometry = fullScreenGeometry; } else if (screenSpace.isMonitor()) { @@ -208,15 +211,18 @@ if (screenNum >= screenList.count()) { // the selected monitor is no longer connected - use full screen + dbgWacom << "Selected monitor no longer connected - using full screen: " << fullScreenGeometry; screenAreaGeometry = fullScreenGeometry; } else { // use the given monitor geometry + dbgWacom << "Use monitor geometry for screen " << screenNum << ": " << screenList.at(screenNum); screenAreaGeometry = screenList.at(screenNum); } } else { // geometry selected + dbgWacom << "Geometry selected: " << StringUtils::toQRect(screenArea, true); screenAreaGeometry = StringUtils::toQRect(screenArea, true); if (screenAreaGeometry.isEmpty()) { @@ -232,11 +238,11 @@ int screenW = screenAreaGeometry.width(); int screenH = screenAreaGeometry.height(); - qreal w = ( qreal )screenW / ( qreal )fullScreenGeometry.width(); - qreal h = ( qreal )screenH / ( qreal )fullScreenGeometry.height(); + qreal w = static_cast(screenW) / fullScreenGeometry.width(); + qreal h = static_cast(screenH) / fullScreenGeometry.height(); - qreal offsetX = ( qreal )screenX / ( qreal )fullScreenGeometry.width(); - qreal offsetY = ( qreal )screenY / ( qreal )fullScreenGeometry.height(); + qreal offsetX = static_cast(screenX) / fullScreenGeometry.width(); + qreal offsetY = static_cast(screenY) / fullScreenGeometry.height(); dbgWacom << "Apply Coordinate Transformation Matrix"; dbgWacom << w << "0" << offsetX;