use a native event filter to notice the screen was swapped

Summary:
this replaces the approach with the expose event in
20b439a4f4 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
wilder-5.14
Marco Martin 9 years ago
parent c57ff94572
commit 44c703dcb4
  1. 2
      CMakeLists.txt
  2. 2
      shell/CMakeLists.txt
  3. 4
      shell/autotests/CMakeLists.txt
  4. 13
      shell/desktopview.cpp
  5. 2
      shell/desktopview.h
  6. 43
      shell/screenpool.cpp
  7. 7
      shell/screenpool.h
  8. 15
      shell/shellcorona.cpp
  9. 1
      shell/shellcorona.h

@ -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")

@ -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()

@ -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()

@ -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());

@ -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;

@ -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"

@ -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();

@ -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);

@ -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;

Loading…
Cancel
Save