diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,7 @@ PURPOSE "Required for building the X11 based workspace") if(X11_FOUND) - find_package(XCB MODULE REQUIRED COMPONENTS XCB) + find_package(XCB MODULE REQUIRED COMPONENTS XCB RANDR) set_package_properties(XCB PROPERTIES TYPE REQUIRED) if(NOT X11_SM_FOUND) message(FATAL_ERROR "\nThe X11 Session Management (SM) development package could not be found.\nPlease install libSM.\n") diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -99,7 +99,7 @@ target_compile_definitions(plasmashell PRIVATE -DPROJECT_VERSION="${PROJECT_VERSION}") if(HAVE_X11) - target_link_libraries(plasmashell ${X11_LIBRARIES} XCB::XCB ) + target_link_libraries(plasmashell ${X11_LIBRARIES} ${XCB_LIBRARIES} ) target_link_libraries(plasmashell Qt5::X11Extras) endif() diff --git a/shell/desktopview.h b/shell/desktopview.h --- a/shell/desktopview.h +++ b/shell/desktopview.h @@ -88,14 +88,12 @@ Q_SIGNALS: void stayBehindChanged(); void windowTypeChanged(); - void screenRenamed(); private: void coronaPackageChanged(const KPackage::Package &package); void ensureWindowType(); void setupWaylandIntegration(); - QString m_screenName; QPointer m_configView; QPointer m_oldScreen; QPointer m_screenToFollow; diff --git a/shell/desktopview.cpp b/shell/desktopview.cpp --- a/shell/desktopview.cpp +++ b/shell/desktopview.cpp @@ -85,7 +85,6 @@ return; } - m_screenName = screen->name(); m_screenToFollow = screen; setScreen(screen); adaptToScreen(); @@ -199,17 +198,7 @@ bool DesktopView::event(QEvent *e) { - //NOTE: we need this heuristic for the case when there is an - //internal laptop screen that gets disabled upon connection of an external one. the only QCreen * pointer gets recycled and there is no dedicated signal to discover this at all - //after being moved, the view will get an expose event, so we can check there if the screen has been renamed - //see https://bugs.kde.org/show_bug.cgi?id=373880 - //https://bugreports.qt.io/browse/QTBUG-57785 - if (e->type() == QEvent::Expose) { - if (m_screenToFollow && m_screenToFollow->name() != m_screenName) { - m_screenName = m_screenToFollow->name(); - emit screenRenamed(); - } - } else if (e->type() == QEvent::KeyRelease) { + if (e->type() == QEvent::KeyRelease) { QKeyEvent *ke = static_cast(e); if (KWindowSystem::showingDesktop() && ke->key() == Qt::Key_Escape) { ShellCorona *c = qobject_cast(corona()); diff --git a/shell/shellcorona.h b/shell/shellcorona.h --- a/shell/shellcorona.h +++ b/shell/shellcorona.h @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -65,7 +66,7 @@ } } -class ShellCorona : public Plasma::Corona, QDBusContext +class ShellCorona : public Plasma::Corona, QDBusContext, public QAbstractNativeEventFilter { Q_OBJECT Q_PROPERTY(QString shell READ shell WRITE setShell) @@ -113,6 +114,9 @@ QString defaultContainmentPlugin() const; +protected: + bool nativeEventFilter(const QByteArray & eventType, void * message, long * result) Q_DECL_OVERRIDE; + public Q_SLOTS: /** * Request saving applicationConfig on disk, it's event compressed, not immediate @@ -240,6 +244,7 @@ QSet m_redundantOutputs; QList m_alternativesObjects; KDeclarative::QmlObject *m_interactiveConsole; + int m_eventBase; QTimer m_waitingPanelsTimer; QTimer m_appConfigSyncTimer; diff --git a/shell/shellcorona.cpp b/shell/shellcorona.cpp --- a/shell/shellcorona.cpp +++ b/shell/shellcorona.cpp @@ -79,6 +79,9 @@ #if HAVE_X11 #include #include +#include +#include +#include #endif @@ -97,6 +100,8 @@ qmlRegisterUncreatableType("org.kde.plasma.shell", 2, 0, "Desktop", QStringLiteral("It is not possible to create objects of type Desktop")); qmlRegisterUncreatableType("org.kde.plasma.shell", 2, 0, "Panel", QStringLiteral("It is not possible to create objects of type Panel")); + qApp->installNativeEventFilter(this); + m_lookAndFeelPackage = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel")); KConfigGroup cg(KSharedConfig::openConfig(QStringLiteral("kdeglobals")), "KDE"); const QString packageName = cg.readEntry("LookAndFeelPackage", QString()); @@ -1144,20 +1149,6 @@ DesktopView *view = new DesktopView(this, screen); connect(view, &QQuickWindow::sceneGraphError, this, &ShellCorona::showOpenGLNotCompatibleWarning); - // a particular edge case: when we switch the only enabled screen - // we don't have any signal about it, the primary screen changes but we have the same old QScreen* getting recycled - // see https://bugs.kde.org/show_bug.cgi?id=373880 - // if this slot will be invoked many times, their//second time on will do nothing as name and primaryconnector will be the same by then - connect(view, &DesktopView::screenRenamed, this, [=](){ - if (qGuiApp->primaryScreen()->name() != m_screenPool->primaryConnector()) { - //new screen? - if (m_screenPool->id(qGuiApp->primaryScreen()->name()) < 0) { - m_screenPool->insertScreenMapping(m_screenPool->firstAvailableId(), qGuiApp->primaryScreen()->name()); - } - //switch the primary screen in the pool - m_screenPool->setPrimaryConnector(qGuiApp->primaryScreen()->name()); - } - }); Plasma::Containment *containment = createContainmentForActivity(m_activityController->currentActivity(), insertPosition); Q_ASSERT(containment); @@ -2005,6 +1996,38 @@ return plugin; } +bool ShellCorona::nativeEventFilter(const QByteArray& eventType, void* message, long int* result) +{ + Q_UNUSED(result); +#if HAVE_X11 + // a particular edge case: when we switch the only enabled screen + // we don't have any signal about it, the primary screen changes but we have the same old QScreen* getting recycled + // see https://bugs.kde.org/show_bug.cgi?id=373880 + // if this slot will be invoked many times, their//second time on will do nothing as name and primaryconnector will be the same by then + if (eventType != "xcb_generic_event_t") { + return false; + } + + xcb_generic_event_t *ev = static_cast(message); + + const auto responseType = XCB_EVENT_RESPONSE_TYPE(ev); + + const xcb_query_extension_reply_t* reply = xcb_get_extension_data(QX11Info::connection(), &xcb_randr_id); + + if (responseType == reply->first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { + if (qGuiApp->primaryScreen()->name() != m_screenPool->primaryConnector()) { + //new screen? + if (m_screenPool->id(qGuiApp->primaryScreen()->name()) < 0) { + m_screenPool->insertScreenMapping(m_screenPool->firstAvailableId(), qGuiApp->primaryScreen()->name()); + } + //switch the primary screen in the pool + m_screenPool->setPrimaryConnector(qGuiApp->primaryScreen()->name()); + } + } +#endif + return false; +} + void ShellCorona::updateStruts() { foreach(PanelView* view, m_panelViews) {