diff options
author | Johan Klokkhammer Helsing <johan.helsing@qt.io> | 2017-08-17 13:20:04 +0200 |
---|---|---|
committer | Johan Helsing <johan.helsing@qt.io> | 2017-09-11 13:49:48 +0000 |
commit | 8828bf4dbeb90e479b3b461905f974774d6e20a4 (patch) | |
tree | 457b1904b1de1bd57b2d83a4da5006836725a2e4 | |
parent | 3f400e31fecd1c0436ad17d1be1dae7745c6a4f5 (diff) | |
download | qtwayland-8828bf4dbeb90e479b3b461905f974774d6e20a4.tar.gz |
Set window screen from wl_surface.enter and leave events
Removes the pointer mScreen, which would previously cause a crash if the screen
was removed.
Ensures that QWindow::screen() is correct, except in the cases where:
- The compositor has not yet sent enter and leave events (in which case the
primary output is returned).
- The compositor is not sending enter and leave events (although this is
mandatory, some compositors don't do this).
- The application developer has tried to move the window with
QWindow::setScreen(QScreen *). Since there is no way for a client to ask to
be moved to a specific monitor in windowed mode, we return the requested
screen until a new enter or leave event is received.
This will also be useful when implementing/fixing features where the current
screen matters. Examples are QT_AUTO_SCREEN_SCALE_FACTOR and the optional
output parameter to wl_shell_surface.set_fullscreen.
Task-number: QTBUG-62044
Change-Id: Iafde2e278fbc8876e8dafe5b2a4d2482fdc7961a
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
-rw-r--r-- | src/client/qwaylandscreen.cpp | 6 | ||||
-rw-r--r-- | src/client/qwaylandscreen_p.h | 1 | ||||
-rw-r--r-- | src/client/qwaylandwindow.cpp | 65 | ||||
-rw-r--r-- | src/client/qwaylandwindow_p.h | 11 |
4 files changed, 78 insertions, 5 deletions
diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp index ac595457..334e0ec4 100644 --- a/src/client/qwaylandscreen.cpp +++ b/src/client/qwaylandscreen.cpp @@ -175,6 +175,12 @@ QWaylandScreen * QWaylandScreen::waylandScreenFromWindow(QWindow *window) return static_cast<QWaylandScreen *>(platformScreen); } +QWaylandScreen *QWaylandScreen::fromWlOutput(::wl_output *output) +{ + auto wlOutput = static_cast<QtWayland::wl_output *>(wl_output_get_user_data(output)); + return static_cast<QWaylandScreen *>(wlOutput); +} + void QWaylandScreen::output_mode(uint32_t flags, int width, int height, int refresh) { if (!(flags & WL_OUTPUT_MODE_CURRENT)) diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h index b2900a96..3d4df6e6 100644 --- a/src/client/qwaylandscreen_p.h +++ b/src/client/qwaylandscreen_p.h @@ -99,6 +99,7 @@ public: ::wl_output *output() { return object(); } static QWaylandScreen *waylandScreenFromWindow(QWindow *window); + static QWaylandScreen *fromWlOutput(::wl_output *output); private: void output_mode(uint32_t flags, int width, int height, int refresh) override; diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 6649493b..e5edd0e5 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -69,6 +69,8 @@ #include <QtCore/QDebug> +#include <wayland-client-core.h> + QT_BEGIN_NAMESPACE namespace QtWaylandClient { @@ -78,8 +80,7 @@ QWaylandWindow *QWaylandWindow::mMouseGrab = 0; QWaylandWindow::QWaylandWindow(QWindow *window) : QObject() , QPlatformWindow(window) - , mScreen(QWaylandScreen::waylandScreenFromWindow(window)) - , mDisplay(mScreen->display()) + , mDisplay(screen()->display()) , mShellSurface(0) , mSubSurfaceWindow(0) , mWindowDecoration(0) @@ -99,6 +100,7 @@ QWaylandWindow::QWaylandWindow(QWindow *window) { static WId id = 1; mWindowId = id++; + connect(qApp, &QGuiApplication::screenRemoved, this, &QWaylandWindow::handleScreenRemoved); initializeWlSurface(); } @@ -356,6 +358,11 @@ void QWaylandWindow::closePopups(QWaylandWindow *parent) } } +QWaylandScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const +{ + return mScreens.isEmpty() ? screen() : mScreens.first(); +} + void QWaylandWindow::setVisible(bool visible) { if (visible) { @@ -491,6 +498,53 @@ void QWaylandWindow::requestResize() QWindowSystemInterface::flushWindowSystemEvents(); } +void QWaylandWindow::surface_enter(wl_output *output) +{ + QWaylandScreen *oldScreen = calculateScreenFromSurfaceEvents(); + auto addedScreen = QWaylandScreen::fromWlOutput(output); + + if (mScreens.contains(addedScreen)) { + qWarning() << "Unexpected wl_surface.enter received for output with id:" + << wl_proxy_get_id(reinterpret_cast<wl_proxy *>(output)) + << "screen name:" << addedScreen->name() << "screen model:" << addedScreen->model(); + return; + } + + mScreens.append(addedScreen); + + QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents(); + if (oldScreen != newScreen) //currently this will only happen if the first wl_surface.enter is for a non-primary screen + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); +} + +void QWaylandWindow::surface_leave(wl_output *output) +{ + QWaylandScreen *oldScreen = calculateScreenFromSurfaceEvents(); + auto *removedScreen = QWaylandScreen::fromWlOutput(output); + bool wasRemoved = mScreens.removeOne(removedScreen); + if (!wasRemoved) { + qWarning() << "Unexpected wl_surface.leave received for output with id:" + << wl_proxy_get_id(reinterpret_cast<wl_proxy *>(output)) + << "screen name:" << removedScreen->name() << "screen model:" << removedScreen->model(); + return; + } + + QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents(); + if (oldScreen != newScreen) + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); +} + +void QWaylandWindow::handleScreenRemoved(QScreen *qScreen) +{ + QWaylandScreen *oldScreen = calculateScreenFromSurfaceEvents(); + bool wasRemoved = mScreens.removeOne(static_cast<QWaylandScreen *>(qScreen->handle())); + if (wasRemoved) { + QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents(); + if (oldScreen != newScreen) + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); + } +} + void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y) { if (mFrameCallback) { @@ -579,6 +633,11 @@ QWaylandSubSurface *QWaylandWindow::subSurfaceWindow() const return mSubSurfaceWindow; } +QWaylandScreen *QWaylandWindow::screen() const +{ + return static_cast<QWaylandScreen *>(QPlatformWindow::screen()); +} + void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation) { if (mDisplay->compositorVersion() < 2) @@ -843,7 +902,7 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe #if QT_CONFIG(cursor) void QWaylandWindow::setMouseCursor(QWaylandInputDevice *device, const QCursor &cursor) { - device->setCursor(cursor, mScreen); + device->setCursor(cursor, screen()); } void QWaylandWindow::restoreMouseCursor(QWaylandInputDevice *device) diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index e7b9e3d3..bd4a3590 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -142,7 +142,7 @@ public: QWaylandDisplay *display() const { return mDisplay; } QWaylandShellSurface *shellSurface() const; QWaylandSubSurface *subSurfaceWindow() const; - QWaylandScreen *screen() const { return mScreen; } + QWaylandScreen *screen() const; void handleContentOrientationChange(Qt::ScreenOrientation orientation) override; void setOrientationMask(Qt::ScreenOrientations mask); @@ -209,7 +209,10 @@ public slots: void requestResize(); protected: - QWaylandScreen *mScreen; + void surface_enter(struct ::wl_output *output) override; + void surface_leave(struct ::wl_output *output) override; + + QVector<QWaylandScreen *> mScreens; //As seen by wl_surface.enter/leave events. Chronological order. QWaylandDisplay *mDisplay; QWaylandShellSurface *mShellSurface; QWaylandSubSurface *mSubSurfaceWindow; @@ -244,6 +247,9 @@ protected: QWaylandShmBackingStore *mBackingStore; +private slots: + void handleScreenRemoved(QScreen *qScreen); + private: bool setWindowStateInternal(Qt::WindowState flags); void setGeometry_helper(const QRect &rect); @@ -254,6 +260,7 @@ private: void reset(); void sendExposeEvent(const QRect &rect); static void closePopups(QWaylandWindow *parent); + QWaylandScreen *calculateScreenFromSurfaceEvents() const; void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e); |