summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/3rdparty/wayland/protocols/session-management/REUSE.toml12
-rw-r--r--src/3rdparty/wayland/protocols/session-management/qt_attribution.json17
-rw-r--r--src/3rdparty/wayland/protocols/session-management/xx-session-management-v1.xml264
-rw-r--r--src/gui/kernel/qplatformwindow_p.h1
-rw-r--r--src/plugins/platforms/wayland/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp17
-rw-r--r--src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h6
-rw-r--r--src/plugins/platforms/wayland/qwaylanddisplay.cpp9
-rw-r--r--src/plugins/platforms/wayland/qwaylanddisplay_p.h7
-rw-r--r--src/plugins/platforms/wayland/qwaylandintegration.cpp7
-rw-r--r--src/plugins/platforms/wayland/qwaylandintegration_p.h2
-rw-r--r--src/plugins/platforms/wayland/qwaylandsessionmanager.cpp91
-rw-r--r--src/plugins/platforms/wayland/qwaylandsessionmanager_p.h71
-rw-r--r--src/plugins/platforms/wayland/qwaylandwindow.cpp11
-rw-r--r--src/plugins/platforms/wayland/qwaylandwindow_p.h3
-rw-r--r--src/widgets/kernel/qwidget.cpp21
16 files changed, 539 insertions, 4 deletions
diff --git a/src/3rdparty/wayland/protocols/session-management/REUSE.toml b/src/3rdparty/wayland/protocols/session-management/REUSE.toml
new file mode 100644
index 00000000000..585706d8fcd
--- /dev/null
+++ b/src/3rdparty/wayland/protocols/session-management/REUSE.toml
@@ -0,0 +1,12 @@
+version = 1
+
+[[annotations]]
+path = "xx-session-management-v1.xml"
+precedence = "closest"
+SPDX-FileCopyrightText = [
+ "Copyright 2018 Mike Blumenkrantz",
+ "Copyright 2018 Samsung Electronics Co., Ltd",
+ "Copyright 2018 Red Hat Inc."
+]
+
+SPDX-License-Identifier = "MIT"
diff --git a/src/3rdparty/wayland/protocols/session-management/qt_attribution.json b/src/3rdparty/wayland/protocols/session-management/qt_attribution.json
new file mode 100644
index 00000000000..8539749f112
--- /dev/null
+++ b/src/3rdparty/wayland/protocols/session-management/qt_attribution.json
@@ -0,0 +1,17 @@
+[
+ {
+ "Id": "wayland-session-management-protocol",
+ "Name": "Wayland Session Management Protocol",
+ "QDocModule": "qtwaylandcompositor",
+ "QtUsage": "Used in the Qt Wayland platform plugin.",
+ "Files": "xx-session-management-v1.xml",
+ "Description": "An extension to restore window positions",
+ "Homepage": "https://wayland.freedesktop.org",
+ "Version": "experimental V1",
+ "DownloadLocation": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/experimental/xx-session-management/xx-session-management-v1.xml?ref_type=heads",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "../MIT_LICENSE.txt",
+ "Copyright": "Copyright 2018 Mike Blumenkrantz\nCopyright 2018 Samsung Electronics Co., Ltd\nCopyright 2018 Red Hat Inc."
+ }
+]
diff --git a/src/3rdparty/wayland/protocols/session-management/xx-session-management-v1.xml b/src/3rdparty/wayland/protocols/session-management/xx-session-management-v1.xml
new file mode 100644
index 00000000000..42458d9291a
--- /dev/null
+++ b/src/3rdparty/wayland/protocols/session-management/xx-session-management-v1.xml
@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xx_session_management_v1">
+ <copyright>
+ Copyright 2018 Mike Blumenkrantz
+ Copyright 2018 Samsung Electronics Co., Ltd
+ Copyright 2018 Red Hat Inc.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <description summary="Protocol for managing application sessions">
+ This description provides a high-level overview of the interplay between
+ the interfaces defined this protocol. For details, see the protocol
+ specification.
+
+ The xx_session_manager protocol declares interfaces necessary to
+ allow clients to restore toplevel state from previous executions. The
+ xx_session_manager_v1.get_session request can be used to obtain a
+ xx_session_v1 resource representing the state of a set of toplevels.
+
+ Clients may obtain the session string to use in future calls through
+ the xx_session_v1.created event. Compositors will use this string
+ as an identifiable token for future runs, possibly storing data about
+ the related toplevels in persistent storage.
+
+ Toplevels are managed through the xx_session_v1.add_toplevel and
+ xx_session_toplevel_v1.remove pair of requests. Clients will explicitly
+ request a toplevel to be restored according to prior state through the
+ xx_session_v1.restore_toplevel request before the toplevel is mapped.
+
+ Warning! The protocol described in this file is currently in the
+ experimental phase. Backwards incompatible major versions of the
+ protocol are to be expected. Exposing this protocol without an opt-in
+ mechanism is discouraged.
+ </description>
+
+ <interface name="xx_session_manager_v1" version="1">
+ <description summary="manage sessions for applications">
+ The xx_session_manager interface defines base requests for creating and
+ managing a session for an application. Sessions persist across application
+ and compositor restarts unless explicitly destroyed. A session is created
+ for the purpose of maintaining an application's xdg_toplevel surfaces
+ across compositor or application restarts. The compositor should remember
+ as many states as possible for surfaces in a given session, but there is
+ no requirement for which states must be remembered.
+ </description>
+
+ <enum name="error">
+ <entry name="in_use" summary="a requested session is already in use"
+ value="1"/>
+ </enum>
+
+ <enum name="reason">
+ <description summary="reason for getting a session">
+ The reason may determine in what way a session restores the window
+ management state of associated toplevels.
+
+ For example newly launched applications might be launched on the active
+ workspace with restored size and position, while a recovered
+ applications might restore additional state such as active workspace and
+ stacking order.
+ </description>
+ <entry name="launch" value="1">
+ <description summary="an app is newly launched">
+ A new app instance is launched, for example from an app launcher.
+ </description>
+ </entry>
+ <entry name="recover" value="2">
+ <description summary="an app recovered">
+ A app instance is recovering from for example a compositor or app crash.
+ </description>
+ </entry>
+ <entry name="session_restore" value="3">
+ <description summary="an app restored">
+ A app instance is restored, for example part of a restored session, or
+ restored from having been temporarily terminated due to resource
+ constraints.
+ </description>
+ </entry>
+ </enum>
+
+ <request name="destroy" type="destructor">
+ <description summary="Destroy this object">
+ This has no effect other than to destroy the xx_session_manager object.
+ </description>
+ </request>
+
+ <request name="get_session">
+ <description summary="create or restore a session">
+ Create a session object corresponding to either an existing session
+ identified by the given session identifier string or a new session.
+ While the session object exists, the session is considered to be "in
+ use".
+
+ If a identifier string represents a session that is currently actively
+ in use by the the same client, an 'in_use' error is raised. If some
+ other client is currently using the same session, the new session will
+ replace managing the associated state.
+
+ NULL is passed to initiate a new session. If an id is passed which does
+ not represent a valid session, the compositor treats it as if NULL had
+ been passed.
+
+ A client is allowed to have any number of in use sessions at the same
+ time.
+ </description>
+ <arg name="id" type="new_id" interface="xx_session_v1"/>
+ <arg name="reason" type="uint" enum="reason"
+ summary="reason for session"/>
+ <arg name="session" type="string"
+ summary="the session to restore"
+ allow-null="true"/>
+ </request>
+ </interface>
+
+ <interface name="xx_session_v1" version="1">
+ <description summary="A session for an application">
+ A xx_session_v1 object represents a session for an application. While the
+ object exists, all surfaces which have been added to the session will
+ have states stored by the compositor which can be reapplied at a later
+ time. Two sessions cannot exist for the same identifier string.
+
+ States for surfaces added to a session are automatically updated by the
+ compositor when they are changed.
+
+ Surfaces which have been added to a session are automatically removed from
+ the session if xdg_toplevel.destroy is called for the surface.
+ </description>
+
+ <enum name="error">
+ <entry name="invalid_restore"
+ summary="restore cannot be performed after initial toplevel commit"
+ value="1"/>
+ <entry name="name_in_use"
+ summary="toplevel name is already in used"
+ value="2"/>
+ <entry name="already_mapped"
+ summary="toplevel was already mapped when restored"
+ value="3"/>
+ </enum>
+
+ <request name="destroy" type="destructor">
+ <description summary="Destroy the session">
+ Destroy a session object, preserving the current state but not continuing
+ to make further updates if state changes occur. This makes the associated
+ xx_toplevel_session_v1 objects inert.
+ </description>
+ </request>
+
+ <request name="remove" type="destructor">
+ <description summary="Remove the session">
+ Remove the session, making it no longer available for restoration. A
+ compositor should in response to this request remove the data related to
+ this session from its storage.
+ </description>
+ </request>
+
+ <request name="add_toplevel">
+ <description summary="add a new surface to the session">
+ Attempt to add a given surface to the session. The passed name is used
+ to identify what window is being restored, and may be used store window
+ specific state within the session.
+
+ Calling this with a toplevel that is already managed by the session with
+ the same associated will raise an in_use error.
+ </description>
+ <arg name="id" type="new_id" interface="xx_toplevel_session_v1"/>
+ <arg name="toplevel" type="object" interface="xdg_toplevel"/>
+ <arg name="name" type="string"/>
+ </request>
+
+ <request name="restore_toplevel">
+ <description summary="restore a surface state">
+ Inform the compositor that the toplevel associated with the passed name
+ should have its window management state restored.
+
+ Calling this with a toplevel that is already managed by the session with
+ the same associated will raise an in_use error.
+
+ This request must be called prior to the first commit on the associated
+ wl_surface, otherwise an already_mapped error is raised.
+
+ As part of the initial configure sequence, if the toplevel was
+ successfully restored, a xx_toplevel_session_v1.restored event is
+ emitted. See the xx_toplevel_session_v1.restored event for further
+ details.
+ </description>
+ <arg name="id" type="new_id" interface="xx_toplevel_session_v1"/>
+ <arg name="toplevel" type="object" interface="xdg_toplevel"/>
+ <arg name="name" type="string"/>
+ </request>
+
+ <event name="created">
+ <description summary="newly-created session id">
+ Emitted at most once some time after getting a new session object. It
+ means that no previous state was restored, and a new session was created.
+ The passed id can be used to restore previous sessions.
+ </description>
+ <arg name="id" type="string"/>
+ </event>
+
+ <event name="restored">
+ <description summary="the session has been restored">
+ Emitted at most once some time after getting a new session object. It
+ means that previous state was at least partially restored. The same id
+ can again be used to restore previous sessions.
+ </description>
+ </event>
+
+ <event name="replaced">
+ <description summary="the session has been restored">
+ Emitted at most once, if the session was taken over by some other
+ client. When this happens, the session and all its toplevel session
+ objects become inert, and should be destroyed.
+ </description>
+ </event>
+ </interface>
+
+ <interface name="xx_toplevel_session_v1" version="1">
+ <request name="destroy" type="destructor">
+ <description summary="Destroy the object">
+ Destroy the object. This has no effect window management of the
+ associated toplevel.
+ </description>
+ </request>
+
+ <request name="remove" type="destructor">
+ <description summary="remove a surface from the session">
+ Remove a specified surface from the session and render any corresponding
+ xx_toplevel_session_v1 object inert. The compositor should remove any
+ data related to the toplevel in the corresponding session from its internal
+ storage.
+ </description>
+ </request>
+
+ <event name="restored">
+ <description summary="a toplevel's session has been restored">
+ The "restored" event is emitted prior to the first
+ xdg_toplevel.configure for the toplevel. It will only be emitted after
+ xx_session_v1.restore_toplevel, and the initial empty surface state has
+ been applied, and it indicates that the surface's session is being
+ restored with this configure event.
+ </description>
+ <arg name="surface" type="object" interface="xdg_toplevel"/>
+ </event>
+ </interface>
+</protocol>
diff --git a/src/gui/kernel/qplatformwindow_p.h b/src/gui/kernel/qplatformwindow_p.h
index 5ee14c90e8a..c446ac760c0 100644
--- a/src/gui/kernel/qplatformwindow_p.h
+++ b/src/gui/kernel/qplatformwindow_p.h
@@ -135,6 +135,7 @@ public:
auto role = std::any_cast<T *>(&anyRole);
return role ? *role : nullptr;
}
+ virtual void setSessionRestoreId(const QString &role) = 0;
Q_SIGNALS:
void surfaceCreated();
void surfaceDestroyed();
diff --git a/src/plugins/platforms/wayland/CMakeLists.txt b/src/plugins/platforms/wayland/CMakeLists.txt
index 32a4ae34228..254a43c0dc6 100644
--- a/src/plugins/platforms/wayland/CMakeLists.txt
+++ b/src/plugins/platforms/wayland/CMakeLists.txt
@@ -77,6 +77,7 @@ qt_internal_add_module(WaylandClient
qwaylandplatformservices.cpp qwaylandplatformservices_p.h
qwaylandpointergestures.cpp qwaylandpointergestures_p.h
qwaylandscreen.cpp qwaylandscreen_p.h
+ qwaylandsessionmanager.cpp qwaylandsessionmanager_p.h
qwaylandshellsurface.cpp qwaylandshellsurface_p.h
qwaylandshm.cpp qwaylandshm_p.h
qwaylandshmbackingstore.cpp qwaylandshmbackingstore_p.h
@@ -124,6 +125,8 @@ qt_internal_add_module(WaylandClient
../../../3rdparty/wayland/protocols/viewporter
../../../3rdparty/wayland/protocols/xdg-shell
../../../3rdparty/wayland/protocols/wlr-data-control
+ ../../../3rdparty/wayland/protocols/session-management
+
)
qt_internal_add_plugin(QWaylandIntegrationPlugin
@@ -164,6 +167,7 @@ qt6_generate_wayland_protocol_client_sources(WaylandClient
${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/wayland/extensions/server-buffer-extension.xml
${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/wayland/protocols/color-management/xx-color-management-v4.xml
${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/wayland/protocols/pointer-warp/pointer-warp-v1.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/wayland/protocols/session-management/xx-session-management-v1.xml
)
#### Keys ignored in scope 1:.:.:client.pro:<TRUE>:
diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
index 1356d93abab..9c40103d1e5 100644
--- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
+++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
@@ -8,6 +8,7 @@
#include "qwaylandxdgexporterv2_p.h"
#include "qwaylandxdgdialogv1_p.h"
#include "qwaylandxdgtopleveliconv1_p.h"
+#include "qwaylandsessionmanager_p.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
@@ -23,6 +24,16 @@ QT_BEGIN_NAMESPACE
namespace QtWaylandClient {
+template <typename T, auto f>
+struct WithDestructor : public T
+{
+ using T::T;
+ ~WithDestructor()
+ {
+ f(this->object());
+ }
+};
+
QWaylandXdgSurface::Toplevel::Toplevel(QWaylandXdgSurface *xdgSurface)
: QtWayland::xdg_toplevel(xdgSurface->get_toplevel())
, m_xdgSurface(xdgSurface)
@@ -45,6 +56,12 @@ QWaylandXdgSurface::Toplevel::Toplevel(QWaylandXdgSurface *xdgSurface)
m_xdgDialog.reset(m_xdgSurface->m_shell->m_xdgDialogWm->getDialog(object()));
m_xdgDialog->set_modal();
}
+
+#ifndef QT_NO_SESSIONMANAGER
+ const QString sessionRestoreId = xdgSurface->window()->sessionRestoreId();
+ if (!sessionRestoreId.isEmpty() && QWaylandSessionManager::instance()->session())
+ m_session.reset(new WithDestructor<QtWayland::xx_toplevel_session_v1, xx_toplevel_session_v1_destroy>(QWaylandSessionManager::instance()->session()->restore_toplevel(object(), sessionRestoreId)));
+#endif
}
QWaylandXdgSurface::Toplevel::~Toplevel()
diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
index 236d34c351c..4595940508c 100644
--- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
+++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
@@ -30,6 +30,10 @@
QT_BEGIN_NAMESPACE
+namespace QtWayland {
+ class xx_toplevel_session_v1;
+}
+
namespace QtWaylandClient {
class QWaylandDisplay;
@@ -41,6 +45,7 @@ class QWaylandXdgExporterV2;
class QWaylandXdgDialogWmV1;
class QWaylandXdgDialogV1;
class QWaylandXdgToplevelIconManagerV1;
+class QWaylandTopLevelSession;
class Q_WAYLANDCLIENT_EXPORT QWaylandXdgSurface : public QWaylandShellSurface, public QtWayland::xdg_surface
{
@@ -114,6 +119,7 @@ private:
QWaylandXdgToplevelDecorationV1 *m_decoration = nullptr;
QScopedPointer<QWaylandXdgExportedV2> m_exported;
QScopedPointer<QWaylandXdgDialogV1> m_xdgDialog;
+ QScopedPointer<QtWayland::xx_toplevel_session_v1> m_session;
};
class Positioner : public QtWayland::xdg_positioner {
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp
index 071ad78f91c..d853fc673e5 100644
--- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp
+++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp
@@ -53,6 +53,7 @@
#include <QtWaylandClient/private/qwayland-fractional-scale-v1.h>
#include <QtWaylandClient/private/qwayland-viewporter.h>
#include <QtWaylandClient/private/qwayland-cursor-shape-v1.h>
+#include <QtWaylandClient/private/qwayland-xx-session-management-v1.h>
#include <QtWaylandClient/private/qwayland-xdg-system-bell-v1.h>
#include <QtWaylandClient/private/qwayland-xdg-toplevel-drag-v1.h>
#include <QtWaylandClient/private/qwayland-wlr-data-control-unstable-v1.h>
@@ -803,6 +804,14 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
mGlobals.pointerWarp.reset(new WithDestructor<QtWayland::wp_pointer_warp_v1, wp_pointer_warp_v1_destroy>(
registry, id, 1));
}
+#ifndef QT_NO_SESSIONMANAGER
+ else if (interface == QLatin1String(QtWayland::xx_session_manager_v1::interface()->name)
+ && qEnvironmentVariableIntValue("QT_WAYLAND_ENABLE_XX_SESSION_MANAGER") > 0) {
+ mGlobals.xxSessionManager.reset(
+ new WithDestructor<QtWayland::xx_session_manager_v1, xx_session_manager_v1_destroy>(
+ registry, id, 1));
+ }
+#endif
mRegistryGlobals.append(RegistryGlobal(id, interface, version, registry));
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay_p.h b/src/plugins/platforms/wayland/qwaylanddisplay_p.h
index 29952886421..91d3497fe51 100644
--- a/src/plugins/platforms/wayland/qwaylanddisplay_p.h
+++ b/src/plugins/platforms/wayland/qwaylanddisplay_p.h
@@ -56,6 +56,7 @@ namespace QtWayland {
class wp_cursor_shape_manager_v1;
class wp_fractional_scale_manager_v1;
class wp_viewporter;
+ class xx_session_manager_v1;
class xdg_system_bell_v1;
class xdg_toplevel_drag_manager_v1;
class wp_pointer_warp_v1;
@@ -86,6 +87,7 @@ class QWaylandPointerGestures;
class QWaylandWindow;
class QWaylandIntegration;
class QWaylandHardwareIntegration;
+class QWaylandSessionManager;
class QWaylandSurface;
class QWaylandShellIntegration;
class QWaylandCursor;
@@ -214,6 +216,10 @@ public:
{
return mGlobals.xdgToplevelDragManager.get();
}
+ QtWayland::xx_session_manager_v1 *xxSessionManager() const
+ {
+ return mGlobals.xxSessionManager.get();
+ }
QtWayland::xdg_system_bell_v1 *systemBell() const
{
return mGlobals.systemBell.get();
@@ -360,6 +366,7 @@ private:
std::unique_ptr<QtWayland::wp_viewporter> viewporter;
std::unique_ptr<QtWayland::wp_fractional_scale_manager_v1> fractionalScaleManager;
std::unique_ptr<QtWayland::wp_cursor_shape_manager_v1> cursorShapeManager;
+ std::unique_ptr<QtWayland::xx_session_manager_v1> xxSessionManager;
std::unique_ptr<QtWayland::xdg_system_bell_v1> systemBell;
std::unique_ptr<QtWayland::xdg_toplevel_drag_manager_v1> xdgToplevelDragManager;
std::unique_ptr<QWaylandWindowManagerIntegration> windowManagerIntegration;
diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp
index 9158013fe78..d66710f4e55 100644
--- a/src/plugins/platforms/wayland/qwaylandintegration.cpp
+++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp
@@ -56,6 +56,7 @@
#include "qwaylandinputdeviceintegration_p.h"
#include "qwaylandinputdeviceintegrationfactory_p.h"
#include "qwaylandwindow_p.h"
+#include "qwaylandsessionmanager_p.h"
#include <QtWaylandClient/private/qwayland-xdg-system-bell-v1.h>
@@ -529,6 +530,12 @@ QWaylandShellIntegration *QWaylandIntegration::createShellIntegration(const QStr
}
}
+QPlatformSessionManager *QWaylandIntegration::createPlatformSessionManager(const QString &id, const QString &key) const
+{
+ Q_UNUSED(key);
+ return new QWaylandSessionManager(mDisplay.data(), id);
+}
+
void QWaylandIntegration::reset()
{
mServerBufferIntegration.reset();
diff --git a/src/plugins/platforms/wayland/qwaylandintegration_p.h b/src/plugins/platforms/wayland/qwaylandintegration_p.h
index d799555570d..04a0787d1ef 100644
--- a/src/plugins/platforms/wayland/qwaylandintegration_p.h
+++ b/src/plugins/platforms/wayland/qwaylandintegration_p.h
@@ -36,6 +36,7 @@ class QWaylandInputDevice;
class QWaylandScreen;
class QWaylandCursor;
class QWaylandPlatformServices;
+class QWaylandSessionManager;
class Q_WAYLANDCLIENT_EXPORT QWaylandIntegration : public QPlatformIntegration
#if QT_CONFIG(opengl)
@@ -131,6 +132,7 @@ private:
void initializeShellIntegration();
void initializeInputDeviceIntegration();
QWaylandShellIntegration *createShellIntegration(const QString& interfaceName);
+ QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const override;
const QString mPlatformName;
QScopedPointer<QPlatformFontDatabase> mFontDb;
diff --git a/src/plugins/platforms/wayland/qwaylandsessionmanager.cpp b/src/plugins/platforms/wayland/qwaylandsessionmanager.cpp
new file mode 100644
index 00000000000..9539bb15221
--- /dev/null
+++ b/src/plugins/platforms/wayland/qwaylandsessionmanager.cpp
@@ -0,0 +1,91 @@
+// Copyright (C) 2024 David Edmundson <[email protected]>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwaylandsessionmanager_p.h"
+
+#ifndef QT_NO_SESSIONMANAGER
+
+#include "qwaylanddisplay_p.h"
+#include "qwaylandwindow_p.h"
+
+#include <private/qsessionmanager_p.h>
+#include <private/qguiapplication_p.h>
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+QWaylandSessionManager::QWaylandSessionManager(QWaylandDisplay *display, const QString &id)
+ : QObject(nullptr)
+ , QPlatformSessionManager(id, QString())
+ , mDisplay(display)
+{
+ if (!display->xxSessionManager())
+ return;
+
+ // The protocol also exposes a way of supporting crash handling to expose later
+ startSession();
+}
+
+QWaylandSession *QWaylandSessionManager::session() const
+{
+ return mSession.data();
+}
+
+QWaylandSessionManager *QWaylandSessionManager::instance()
+{
+ auto *qGuiAppPriv = QGuiApplicationPrivate::instance();
+ auto *managerPrivate = static_cast<QSessionManagerPrivate*>(QObjectPrivate::get(qGuiAppPriv->session_manager));
+ return static_cast<QWaylandSessionManager *>(managerPrivate->platformSessionManager);
+}
+
+void QWaylandSessionManager::setSessionId(const QString &id)
+{
+ m_sessionId = id;
+}
+
+void QWaylandSessionManager::startSession()
+{
+ QtWayland::xx_session_manager_v1::reason restoreReason = QtWayland::xx_session_manager_v1::reason_launch;
+ if (!sessionId().isEmpty()) {
+ restoreReason = QtWayland::xx_session_manager_v1::reason_session_restore;
+ }
+ mSession.reset(new QWaylandSession(this));
+ mSession->init(mDisplay->xxSessionManager()->get_session(restoreReason, sessionId()));
+ mDisplay->forceRoundTrip();
+}
+
+QWaylandSession::QWaylandSession(QWaylandSessionManager *sessionManager)
+ : mSessionManager(sessionManager)
+{
+}
+
+QWaylandSession::~QWaylandSession() {
+ // There's also remove which is another dtor
+ // depending on whether we're meant to clean up server side or not
+ // we might need to expose that later
+ destroy();
+}
+
+void QWaylandSession::xx_session_v1_created(const QString &id) {
+ qCDebug(lcQpaWayland) << "Session created" << id;
+ mSessionManager->setSessionId(id);
+}
+
+void QWaylandSession::xx_session_v1_restored() {
+ qCDebug(lcQpaWayland) << "Session restored";
+ // session Id won't have change, do nothing
+}
+
+void QWaylandSession::xx_session_v1_replaced() {
+ qCDebug(lcQpaWayland) << "Session replaced";
+ mSessionManager->setSessionId(QString());
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/wayland/qwaylandsessionmanager_p.h b/src/plugins/platforms/wayland/qwaylandsessionmanager_p.h
new file mode 100644
index 00000000000..aa9e0eec001
--- /dev/null
+++ b/src/plugins/platforms/wayland/qwaylandsessionmanager_p.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2024 David Edmundson <[email protected]>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWAYLANDSESSIONMANAGER_H
+#define QWAYLANDSESSIONMANAGER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QT_NO_SESSIONMANAGER
+
+#include <QtGui/qpa/qplatformsessionmanager.h>
+#include <QtWaylandClient/qtwaylandclientglobal.h>
+#include <QtWaylandClient/private/qwayland-xx-session-management-v1.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWaylandClient {
+
+class QWaylandDisplay;
+class QWaylandWindow;
+class QWaylandSession;
+class QWaylandSessionManager;
+
+
+class Q_WAYLANDCLIENT_EXPORT QWaylandSession : public QObject, public QtWayland::xx_session_v1
+{
+ Q_OBJECT
+public:
+ QWaylandSession(QWaylandSessionManager *sessionManager);
+ ~QWaylandSession();
+
+protected:
+ void xx_session_v1_created(const QString &id) override;
+ void xx_session_v1_restored() override;
+ void xx_session_v1_replaced() override;
+private:
+ QWaylandSessionManager *mSessionManager;
+};
+
+class Q_WAYLANDCLIENT_EXPORT QWaylandSessionManager : public QObject, public QPlatformSessionManager
+{
+ Q_OBJECT
+public:
+ static QWaylandSessionManager *instance();
+ QWaylandSessionManager(QWaylandDisplay *display, const QString &id);
+
+ QWaylandSession* session() const;
+private:
+ void setSessionId(const QString &id);
+ void startSession();
+
+ QWaylandDisplay *mDisplay = nullptr;
+ QScopedPointer<QWaylandSession> mSession;
+ friend class QWaylandSession;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
+#endif
diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp
index 73d90b6c321..cfbc392c319 100644
--- a/src/plugins/platforms/wayland/qwaylandwindow.cpp
+++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp
@@ -1,6 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qwaylandsessionmanager_p.h"
#include "qwaylandwindow_p.h"
#include "qwaylandbuffer_p.h"
@@ -1934,6 +1935,16 @@ QSurfaceFormat QWaylandWindow::format() const
return mSurfaceFormat;
}
+void QWaylandWindow::setSessionRestoreId(const QString &role)
+{
+ mSessionRestoreId = role;
+}
+
+QString QWaylandWindow::sessionRestoreId() const
+{
+ return mSessionRestoreId;
+}
+
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wayland/qwaylandwindow_p.h b/src/plugins/platforms/wayland/qwaylandwindow_p.h
index 5ad826018bb..23c5ed04b8f 100644
--- a/src/plugins/platforms/wayland/qwaylandwindow_p.h
+++ b/src/plugins/platforms/wayland/qwaylandwindow_p.h
@@ -252,6 +252,8 @@ public:
bool windowEvent(QEvent *event) override;
QSurfaceFormat format() const override;
+ void setSessionRestoreId(const QString &role) override;
+ QString sessionRestoreId() const;
public Q_SLOTS:
void applyConfigure();
@@ -346,6 +348,7 @@ protected:
QWaylandShmBackingStore *mBackingStore = nullptr;
QMargins mCustomMargins;
+ QString mSessionRestoreId;
QPointer<QWaylandWindow> mTransientParent;
QList<QPointer<QWaylandWindow>> mChildPopups;
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 1155172a0a8..22ca1d238fe 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1360,6 +1360,12 @@ void QWidgetPrivate::create()
xcbWindow->setWindowRole(topData()->role);
}
#endif
+#if QT_CONFIG(wayland)
+ if (!topData()->role.isNull()) {
+ if (auto *waylandWindow = dynamic_cast<QWaylandWindow*>(win->handle()))
+ waylandWindow->setSessionRestoreId(topData()->role);
+ }
+#endif
QBackingStore *store = q->backingStore();
usesRhiFlush = false;
@@ -6359,17 +6365,24 @@ QString QWidget::windowRole() const
*/
void QWidget::setWindowRole(const QString &role)
{
-#if QT_CONFIG(xcb)
+#if QT_CONFIG(xcb) || QT_CONFIG(wayland)
Q_D(QWidget);
d->createTLExtra();
d->topData()->role = role;
+#else
+ Q_UNUSED(role);
+#endif
+
if (windowHandle()) {
+#if QT_CONFIG(xcb)
if (auto *xcbWindow = dynamic_cast<QXcbWindow*>(windowHandle()->handle()))
xcbWindow->setWindowRole(role);
- }
-#else
- Q_UNUSED(role);
#endif
+#if QT_CONFIG(wayland)
+ if (auto *waylandWindow = dynamic_cast<QWaylandWindow*>(windowHandle()->handle()))
+ waylandWindow->setSessionRestoreId(role);
+#endif
+ }
}
/*!