summaryrefslogtreecommitdiffstats
path: root/src/client/qwaylandwindow.cpp
diff options
context:
space:
mode:
authorGiulio Camuffo <giulio.camuffo@kdab.com>2016-07-02 10:46:58 +0200
committerPaul Olav Tvete <paul.tvete@qt.io>2016-11-17 15:28:24 +0000
commit5b807802866c8df00cb3340d4f9bcc343be5973a (patch)
tree0fe08bebff92ebc5cf708ce97ede8a4e422399af /src/client/qwaylandwindow.cpp
parent12f2e1e23fc1de16a42d3024561c0f839f9e96cd (diff)
Create and destroy the shell surface when showing and hiding
This changes the shell surface handling for windows, and instead of creating the shell surface at initialization time, and then attaching a null buffer to hide it, it creates the shell surface on setVisible(true), and destroys it on setVisible(false). This fixes hiding when using xdg_shell, as that interface defines that attaching a null buffer to an xdg_surface is an error. Also this should help with bugged EGL drivers which attach a buffer after eglSwapBuffers() returns, which used to cause a newly hidden window to get a new valid buffer after we attached a null one, showing it again. Task-number: QTBUG-47902 Change-Id: I8e0a0442319a98cc1361803ea7be1d079b36fc8c Reviewed-by: Johan Helsing <johan.helsing@qt.io> Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
Diffstat (limited to 'src/client/qwaylandwindow.cpp')
-rw-r--r--src/client/qwaylandwindow.cpp90
1 files changed, 43 insertions, 47 deletions
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index 6c3647d81..1ff6686f6 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -96,8 +96,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window)
{
static WId id = 1;
mWindowId = id++;
- if (window->type() != Qt::Desktop)
- initWindow();
}
QWaylandWindow::~QWaylandWindow()
@@ -126,18 +124,28 @@ QWaylandWindow::~QWaylandWindow()
void QWaylandWindow::initWindow()
{
- init(mDisplay->createSurface(static_cast<QtWayland::wl_surface *>(this)));
+ if (window()->type() == Qt::Desktop)
+ return;
+
+ if (!isInitialized())
+ init(mDisplay->createSurface(static_cast<QtWayland::wl_surface *>(this)));
if (shouldCreateSubSurface()) {
+ Q_ASSERT(!mSubSurfaceWindow);
+
QWaylandWindow *p = static_cast<QWaylandWindow *>(QPlatformWindow::parent());
if (::wl_subsurface *ss = mDisplay->createSubSurface(this, p)) {
mSubSurfaceWindow = new QWaylandSubSurface(this, p, ss);
}
} else if (shouldCreateShellSurface()) {
+ Q_ASSERT(!mShellSurface);
+
mShellSurface = mDisplay->createShellSurface(this);
- }
+ if (!mShellSurface)
+ qFatal("Could not create a shell surface object.");
+
+ mShellSurface->setType(window()->type(), transientParent());
- if (mShellSurface) {
// Set initial surface title
setWindowTitle(window()->title());
@@ -171,17 +179,6 @@ void QWaylandWindow::initWindow()
}
}
- if (mShellSurface) {
- if (window()->transientParent()) {
- if (window()->type() != Qt::Popup) {
- mShellSurface->updateTransientParent(window()->transientParent());
- }
- } else {
- if (window()->type() != Qt::ToolTip)
- mShellSurface->setTopLevel();
- }
- }
-
// Enable high-dpi rendering. Scale() returns the screen scale factor and will
// typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale()
// to inform the compositor that high-resolution buffers will be provided.
@@ -244,6 +241,9 @@ WId QWaylandWindow::winId() const
void QWaylandWindow::setParent(const QPlatformWindow *parent)
{
+ if (!window()->isVisible())
+ return;
+
QWaylandWindow *oldparent = mSubSurfaceWindow ? mSubSurfaceWindow->parent() : 0;
if (oldparent == parent)
return;
@@ -287,8 +287,7 @@ void QWaylandWindow::setGeometry_helper(const QRect &rect)
QMargins m = QPlatformWindow::parent()->frameMargins();
mSubSurfaceWindow->set_position(rect.x() + m.left(), rect.y() + m.top());
mSubSurfaceWindow->parent()->window()->requestUpdate();
- } else if (shellSurface() && window()->transientParent() && window()->type() != Qt::Popup)
- shellSurface()->updateTransientParent(window()->transientParent());
+ }
}
void QWaylandWindow::setGeometry(const QRect &rect)
@@ -313,20 +312,8 @@ void QWaylandWindow::setGeometry(const QRect &rect)
void QWaylandWindow::setVisible(bool visible)
{
if (visible) {
- if (mShellSurface) {
- if (window()->type() == Qt::Popup) {
- QWaylandWindow *parent = transientParent();
- if (parent) {
- QWaylandWlShellSurface *wlshellSurface = qobject_cast<QWaylandWlShellSurface*>(mShellSurface);
- if (wlshellSurface)
- wlshellSurface->setPopup(parent, mDisplay->lastInputDevice(), mDisplay->lastInputSerial());
- }
- } else if (window()->type() == Qt::ToolTip) {
- if (QWaylandWindow *parent = transientParent()) {
- mShellSurface->updateTransientParent(parent->window());
- }
- }
- }
+ initWindow();
+ mDisplay->flushRequests();
setGeometry(window()->geometry());
// Don't flush the events here, or else the newly visible window may start drawing, but since
@@ -338,10 +325,8 @@ void QWaylandWindow::setVisible(bool visible)
// case 'this' will be deleted. When that happens, we must abort right away.
QPointer<QWaylandWindow> deleteGuard(this);
QWindowSystemInterface::flushWindowSystemEvents();
- if (!deleteGuard.isNull()) {
- attach(static_cast<QWaylandBuffer *>(0), 0, 0);
- commit();
- }
+ if (!deleteGuard.isNull())
+ reset();
}
}
@@ -374,7 +359,7 @@ void QWaylandWindow::setMask(const QRegion &mask)
wl_region_destroy(region);
}
- commit();
+ wl_surface::commit();
}
void QWaylandWindow::configure(uint32_t edges, int32_t width, int32_t height)
@@ -461,6 +446,7 @@ void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
wl_callback_add_listener(callback, &QWaylandWindow::callbackListener, this);
mFrameCallback = callback;
mWaitingForFrameSync = true;
+ buffer->setBusy();
attach(buffer->buffer(), x, y);
} else {
@@ -479,6 +465,18 @@ void QWaylandWindow::damage(const QRect &rect)
damage(rect.x(), rect.y(), rect.width(), rect.height());
}
+void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
+{
+ if (!isInitialized())
+ return;
+
+ attachOffset(buffer);
+ const QVector<QRect> rects = damage.rects();
+ for (const QRect &rect: rects)
+ wl_surface::damage(rect.x(), rect.y(), rect.width(), rect.height());
+ wl_surface::commit();
+}
+
const wl_callback_listener QWaylandWindow::callbackListener = {
QWaylandWindow::frameCallback
};
@@ -555,7 +553,7 @@ void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orient
}
set_buffer_transform(transform);
// set_buffer_transform is double buffered, we need to commit.
- commit();
+ wl_surface::commit();
}
void QWaylandWindow::setOrientationMask(Qt::ScreenOrientations mask)
@@ -681,15 +679,13 @@ static QWindow *topLevelWindow(QWindow *window)
QWaylandWindow *QWaylandWindow::transientParent() const
{
- if (window()->transientParent()) {
- // Take the top level window here, since the transient parent may be a QWidgetWindow
- // or some other window without a shell surface, which is then not able to get mouse
- // events.
- return static_cast<QWaylandWindow *>(topLevelWindow(window()->transientParent())->handle());
- }
- // Try with the current focus window. It should be the right one and anyway
- // better than having no parent at all.
- return mDisplay->lastInputWindow();
+ // Take the top level window here, since the transient parent may be a QWidgetWindow
+ // or some other window without a shell surface, which is then not able to get mouse
+ // events.
+ if (auto transientParent = window()->transientParent())
+ return static_cast<QWaylandWindow *>(topLevelWindow(transientParent)->handle());
+
+ return nullptr;
}
void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e)