summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Martin <notmart@gmail.com>2016-12-29 11:32:30 (GMT)
committerMarco Martin <notmart@gmail.com>2016-12-29 11:43:11 (GMT)
commit44c703dcb41c7b6af58a55151e9132c0dcf66763 (patch)
tree11b4bf8e09f563ace729b7e2656ee14dfe526ccf
parentc57ff94572bd22904f7790d9d555b7ce00c18309 (diff)
use a native event filter to notice the screen was swapped
Summary: this replaces the approach with the expose event in 20b439a4f4a by directly monitoring the xcb screen change notify native event Test Plan: attaching and detaching the external screen on a laptop configured to deactivate the internal screen upon connection same behavior as D3777 Reviewers: sebas, davidedmundson, #plasma Reviewed By: davidedmundson, #plasma Subscribers: pmuralidharan, plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D3822
-rw-r--r--CMakeLists.txt2
-rw-r--r--shell/CMakeLists.txt2
-rw-r--r--shell/autotests/CMakeLists.txt4
-rw-r--r--shell/desktopview.cpp13
-rw-r--r--shell/desktopview.h2
-rw-r--r--shell/screenpool.cpp43
-rw-r--r--shell/screenpool.h7
-rw-r--r--shell/shellcorona.cpp15
-rw-r--r--shell/shellcorona.h1
9 files changed, 58 insertions, 31 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ddcd819..0118135 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,7 +82,7 @@ set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries"
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
index 4450808..2689269 100644
--- a/shell/CMakeLists.txt
+++ b/shell/CMakeLists.txt
@@ -100,7 +100,7 @@ target_include_directories(plasmashell PRIVATE "${CMAKE_BINARY_DIR}")
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/autotests/CMakeLists.txt b/shell/autotests/CMakeLists.txt
index 16f1466..dfc8f0e 100644
--- a/shell/autotests/CMakeLists.txt
+++ b/shell/autotests/CMakeLists.txt
@@ -10,6 +10,10 @@ MACRO(PLASMASHELL_UNIT_TESTS)
Qt5::Gui
KF5::Service
)
+ if(HAVE_X11)
+ target_link_libraries(${_testname} ${X11_LIBRARIES} ${XCB_LIBRARIES} )
+ target_link_libraries(${_testname} Qt5::X11Extras)
+ endif()
if(QT_QTOPENGL_FOUND)
target_link_libraries(${_testname} Qt5::OpenGL)
endif()
diff --git a/shell/desktopview.cpp b/shell/desktopview.cpp
index 7391e2b..b91422a 100644
--- a/shell/desktopview.cpp
+++ b/shell/desktopview.cpp
@@ -85,7 +85,6 @@ void DesktopView::setScreenToFollow(QScreen *screen)
return;
}
- m_screenName = screen->name();
m_screenToFollow = screen;
setScreen(screen);
adaptToScreen();
@@ -199,17 +198,7 @@ DesktopView::SessionType DesktopView::sessionType() const
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<QKeyEvent *>(e);
if (KWindowSystem::showingDesktop() && ke->key() == Qt::Key_Escape) {
ShellCorona *c = qobject_cast<ShellCorona *>(corona());
diff --git a/shell/desktopview.h b/shell/desktopview.h
index 98dd47c..d0696df 100644
--- a/shell/desktopview.h
+++ b/shell/desktopview.h
@@ -88,14 +88,12 @@ private Q_SLOTS:
Q_SIGNALS:
void stayBehindChanged();
void windowTypeChanged();
- void screenRenamed();
private:
void coronaPackageChanged(const KPackage::Package &package);
void ensureWindowType();
void setupWaylandIntegration();
- QString m_screenName;
QPointer<PlasmaQuick::ConfigView> m_configView;
QPointer<QScreen> m_oldScreen;
QPointer<QScreen> m_screenToFollow;
diff --git a/shell/screenpool.cpp b/shell/screenpool.cpp
index b60cca1..97daff3 100644
--- a/shell/screenpool.cpp
+++ b/shell/screenpool.cpp
@@ -18,14 +18,24 @@
*/
#include "screenpool.h"
+#include <config-plasma.h>
#include <QGuiApplication>
#include <QScreen>
+#if HAVE_X11
+#include <QtX11Extras/QX11Info>
+#include <xcb/xcb.h>
+#include <xcb/randr.h>
+#include <xcb/xcb_event.h>
+#endif
+
ScreenPool::ScreenPool(KSharedConfig::Ptr config, QObject *parent)
: QObject(parent),
m_configGroup(KConfigGroup(config, QStringLiteral("ScreenConnectors")))
{
+ qApp->installNativeEventFilter(this);
+
m_configSaveTimer.setSingleShot(true);
connect(&m_configSaveTimer, &QTimer::timeout, this, [this](){
m_configGroup.sync();
@@ -159,5 +169,38 @@ QList <int> ScreenPool::knownIds() const
return m_connectorForId.keys();
}
+bool ScreenPool::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<xcb_generic_event_t *>(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() != primaryConnector()) {
+ //new screen?
+ if (id(qGuiApp->primaryScreen()->name()) < 0) {
+ insertScreenMapping(firstAvailableId(), qGuiApp->primaryScreen()->name());
+ }
+ //switch the primary screen in the pool
+ setPrimaryConnector(qGuiApp->primaryScreen()->name());
+ }
+ }
+#endif
+ return false;
+}
+
+
#include "moc_screenpool.cpp"
diff --git a/shell/screenpool.h b/shell/screenpool.h
index 9b3a9af..9baa90b 100644
--- a/shell/screenpool.h
+++ b/shell/screenpool.h
@@ -24,11 +24,13 @@
#include <QHash>
#include <QString>
#include <QTimer>
+#include <QAbstractNativeEventFilter>
#include <KConfigGroup>
#include <KSharedConfig>
-class ScreenPool : public QObject {
+class ScreenPool : public QObject, public QAbstractNativeEventFilter
+{
Q_OBJECT
public:
@@ -50,6 +52,9 @@ public:
//all ids that are known, included screens not enabled at the moment
QList <int> knownIds() const;
+protected:
+ bool nativeEventFilter(const QByteArray & eventType, void * message, long * result) Q_DECL_OVERRIDE;
+
private:
void save();
diff --git a/shell/shellcorona.cpp b/shell/shellcorona.cpp
index 4e7dd3e..dd281c9 100644
--- a/shell/shellcorona.cpp
+++ b/shell/shellcorona.cpp
@@ -80,6 +80,7 @@
#if HAVE_X11
#include <NETWM>
#include <QtX11Extras/QX11Info>
+#include <xcb/xcb.h>
#endif
@@ -1149,20 +1150,6 @@ void ShellCorona::addOutput(QScreen* screen)
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);
diff --git a/shell/shellcorona.h b/shell/shellcorona.h
index fbe21fd..3322000 100644
--- a/shell/shellcorona.h
+++ b/shell/shellcorona.h
@@ -242,6 +242,7 @@ private:
QSet<QScreen*> m_redundantOutputs;
QList<KDeclarative::QmlObject *> m_alternativesObjects;
KDeclarative::QmlObject *m_interactiveConsole;
+ int m_eventBase;
QTimer m_waitingPanelsTimer;
QTimer m_appConfigSyncTimer;