Client: Provide support for custom shells

Currently, an application can use only one shell surface protocol at a
time. However, there are applications that need to use more than one
shell surface protocol, e.g. xdg-shell + layer-shell. layer-shell can be
used for the desktop background window, and xdg-shell for popups, etc.

This change introduces an API in QWaylandWindow that allows specifying
the shell integration per window.

Custom shell code needs to call QWaylandWindow::setShellIntegration()
while the window is unmapped. By default, QWaylandWindow will use
QWaylandDisplay's shell integration plugin.

This change should be source compatible with existing shell integration
plugins deployed in the wild.

If the custom shell wants to track additional state for the window, it
should do it using its own means. Perhaps we could improve this in the
future releases of Qt.

[ChangeLog][QtWaylandClient] It is possible to run Qt applications using
more than one shell surface protocol, e.g. xdg-shell + layer-shell.

Change-Id: Id0458b32af623f114c06d51d0d21ad06efd69328
Reviewed-by: David Edmundson <davidedmundson@kde.org>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
Vlad Zahorodnii 2022-11-16 15:13:17 +02:00
parent 9e23cbc94c
commit 0052d0ed13
3 changed files with 22 additions and 5 deletions

View File

@ -148,8 +148,9 @@ void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourc
}
#endif
if (auto shellIntegration = m_integration->shellIntegration())
return shellIntegration->nativeResourceForWindow(resourceString, window);
QWaylandWindow *platformWindow = static_cast<QWaylandWindow *>(window->handle());
if (platformWindow && platformWindow->shellIntegration())
return platformWindow->shellIntegration()->nativeResourceForWindow(resourceString, window);
return nullptr;
}

View File

@ -45,6 +45,7 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
: QPlatformWindow(window)
, mDisplay(display)
, mSurfaceLock(QReadWriteLock::Recursive)
, mShellIntegration(display->shellIntegration())
, mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
{
{
@ -130,9 +131,9 @@ void QWaylandWindow::initWindow()
}
} else if (shouldCreateShellSurface()) {
Q_ASSERT(!mShellSurface);
Q_ASSERT(mDisplay->shellIntegration());
Q_ASSERT(mShellIntegration);
mShellSurface = mDisplay->shellIntegration()->createShellSurface(this);
mShellSurface = mShellIntegration->createShellSurface(this);
if (mShellSurface) {
// Set initial surface title
setWindowTitle(window()->title());
@ -216,9 +217,19 @@ void QWaylandWindow::initializeWlSurface()
emit wlSurfaceCreated();
}
void QWaylandWindow::setShellIntegration(QWaylandShellIntegration *shellIntegration)
{
Q_ASSERT(shellIntegration);
if (mShellSurface) {
qCWarning(lcQpaWayland) << "Cannot set shell integration while there's already a shell surface created";
return;
}
mShellIntegration = shellIntegration;
}
bool QWaylandWindow::shouldCreateShellSurface() const
{
if (!mDisplay->shellIntegration())
if (!shellIntegration())
return false;
if (shouldCreateSubSurface())

View File

@ -50,6 +50,7 @@ class QWaylandSubSurface;
class QWaylandAbstractDecoration;
class QWaylandInputDevice;
class QWaylandScreen;
class QWaylandShellIntegration;
class QWaylandShmBackingStore;
class QWaylandPointerEvent;
class QWaylandPointerGestureSwipeEvent;
@ -202,6 +203,9 @@ public:
void setBackingStore(QWaylandShmBackingStore *backingStore) { mBackingStore = backingStore; }
QWaylandShmBackingStore *backingStore() const { return mBackingStore; }
void setShellIntegration(QWaylandShellIntegration *shellIntegration);
QWaylandShellIntegration *shellIntegration() const { return mShellIntegration; }
bool setKeyboardGrabEnabled(bool) override { return false; }
void propagateSizeHints() override;
void addAttachOffset(const QPoint point);
@ -245,6 +249,7 @@ protected:
QScopedPointer<QWaylandFractionalScale> mFractionalScale;
QScopedPointer<QWaylandViewport> mViewport;
QWaylandShellIntegration *mShellIntegration = nullptr;
QWaylandShellSurface *mShellSurface = nullptr;
QWaylandSubSurface *mSubSurfaceWindow = nullptr;
QList<QWaylandSubSurface *> mChildren;