diff --git a/docs/README-wayland.md b/docs/README-wayland.md index d9cd6046f9813..1349bfae441c9 100644 --- a/docs/README-wayland.md +++ b/docs/README-wayland.md @@ -38,6 +38,14 @@ encounter limitations or behavior that is different from other windowing systems - Wayland does not allow toplevel windows to position themselves programmatically. +### How do I save and restore window layout and state between runs? + +- To preserve the state of toplevel windows across runs, assign the window a stable ID string with the + `SDL_PROP_WINDOW_CREATE_WAYLAND_WINDOW_ID_STRING` property at creation time, and serialize the global session property + string `SDL_PROP_GLOBAL_VIDEO_WAYLAND_SESSION_ID_STRING` before shutting down. On subsequent runs, restore the session + ID string property to the previously serialized value before window creation. This functionality requires that the + compositor supports the `xdg_session_management_v1` protocol. + ### Retrieving the global mouse cursor position when the cursor is outside a window doesn't work - Wayland only provides applications with the cursor position within the borders of the application windows. Querying diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h index 6117eceaf909d..b8ef11076ae76 100644 --- a/include/SDL3/SDL_video.h +++ b/include/SDL3/SDL_video.h @@ -102,6 +102,32 @@ typedef Uint32 SDL_WindowID; */ #define SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER "SDL.video.wayland.wl_display" +/** + * The session ID string used for saving and restoring window state across runs. + * + * To save the current state of Wayland toplevel windows, serialize this value before + * shutting down. To restore the previous state, set this property to the previously + * serialized value before window creation begins. + * + * This can be set at any time before the first call to a window creation function. Reading + * should be deferred until serialization time, as compositors may not set the session + * identifier string immediately. + * + * Setting this to an empty string ("") will cause a new session to be created. + * + * Setting this to null or an empty string before shutting down will cause the existing session + * to be removed. + * + * Note that for windows to be saved/restored by the session, they also need a stable, unique + * identifier string set via the `SDL_PROP_WINDOW_CREATE_WAYLAND_WINDOW_ID_STRING` property at + * creation time. + * + * \since This property is available since SDL 3.6.0. + * + * \sa SDL_CreateWindowWithProperties + */ +#define SDL_PROP_GLOBAL_VIDEO_WAYLAND_SESSION_ID_STRING "SDL.video.wayland.session_id" + /** * System theme. * @@ -1349,6 +1375,9 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren * application wants an associated `wl_egl_window` object to be created and * attached to the window, even if the window does not have the OpenGL * property or `SDL_WINDOW_OPENGL` flag set. + * - `SDL_PROP_WINDOW_CREATE_WAYLAND_WINDOW_ID_STRING` - a string used as + * a stable identifier for toplevel windows for the purpose of allowing + * the compositor to save/restore their state between runs. * - `SDL_PROP_WINDOW_CREATE_WAYLAND_WL_SURFACE_POINTER` - the wl_surface * associated with the window, if you want to wrap an existing window. See * [README-wayland](README-wayland) for more information. @@ -1440,6 +1469,7 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowWithProperties(SDL_Prop #define SDL_PROP_WINDOW_CREATE_WINDOWSCENE_POINTER "SDL.window.create.uikit.windowscene" #define SDL_PROP_WINDOW_CREATE_WAYLAND_SURFACE_ROLE_CUSTOM_BOOLEAN "SDL.window.create.wayland.surface_role_custom" #define SDL_PROP_WINDOW_CREATE_WAYLAND_CREATE_EGL_WINDOW_BOOLEAN "SDL.window.create.wayland.create_egl_window" +#define SDL_PROP_WINDOW_CREATE_WAYLAND_WINDOW_ID_STRING "SDL.window.create.wayland.window_id" #define SDL_PROP_WINDOW_CREATE_WAYLAND_WL_SURFACE_POINTER "SDL.window.create.wayland.wl_surface" #define SDL_PROP_WINDOW_CREATE_WIN32_HWND_POINTER "SDL.window.create.win32.hwnd" #define SDL_PROP_WINDOW_CREATE_WIN32_PIXEL_FORMAT_HWND_POINTER "SDL.window.create.win32.pixel_format_hwnd" @@ -1597,6 +1627,11 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetWindowParent(SDL_Window *window) * with the window * - `SDL_PROP_WINDOW_WAYLAND_EGL_WINDOW_POINTER`: the wl_egl_window * associated with the window + * - `SDL_PROP_WINDOW_WAYLAND_WINDOW_ID_STRING`: the window identification string, + * initially set with SDL_PROP_WINDOW_CREATE_WAYLAND_WINDOW_ID_STRING. and used + * as an identifier for session management. Setting this to null before + * destroying the window will cause any session information related to the + * window to be removed. * - `SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER`: the xdg_surface associated * with the window * - `SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER`: the xdg_toplevel role @@ -1663,6 +1698,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetWindowProperties(SDL_Window #define SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER "SDL.window.wayland.surface" #define SDL_PROP_WINDOW_WAYLAND_VIEWPORT_POINTER "SDL.window.wayland.viewport" #define SDL_PROP_WINDOW_WAYLAND_EGL_WINDOW_POINTER "SDL.window.wayland.egl_window" +#define SDL_PROP_WINDOW_WAYLAND_WINDOW_ID_STRING "SDL.window.wayland.window_id" #define SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER "SDL.window.wayland.xdg_surface" #define SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER "SDL.window.wayland.xdg_toplevel" #define SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_EXPORT_HANDLE_STRING "SDL.window.wayland.xdg_toplevel_export_handle" diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 9474cacc61fb8..401efec77bbdb 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -71,6 +71,7 @@ #include "pointer-warp-v1-client-protocol.h" #include "pointer-gestures-unstable-v1-client-protocol.h" #include "single-pixel-buffer-v1-client-protocol.h" +#include "xdg-session-management-v1-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -1326,6 +1327,60 @@ static void Wayland_InitColorManager(SDL_VideoData *d) } } +static void handle_xdg_session_created(void *data, struct xdg_session_v1 *xdg_session_v1, const char *id) +{ + SDL_SetStringProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_SESSION_ID_STRING, id); +} + +static void handle_xdg_session_restored(void *data, struct xdg_session_v1 *xdg_session_v1) +{ + // NOP +} + +static void handle_xdg_session_replaced(void *data, struct xdg_session_v1 *xdg_session_v1) +{ + SDL_SetStringProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_SESSION_ID_STRING, NULL); +} + +static const struct xdg_session_v1_listener xdg_session_listener = { + .created = handle_xdg_session_created, + .restored = handle_xdg_session_restored, + .replaced = handle_xdg_session_replaced +}; + +void Wayland_SessionCreate(SDL_VideoData *viddata) +{ + if (!viddata->xdg_session_manager) { + return; + } + + // Register a new session, if one does not yet exist. + if (!viddata->xdg_session) { + const char *session_id = SDL_GetStringProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_SESSION_ID_STRING, NULL); + if (session_id) { + if (*session_id == '\0') { + // Create a new session if the ID string is empty. + session_id = NULL; + } + + viddata->xdg_session = xdg_session_manager_v1_get_session(viddata->xdg_session_manager, XDG_SESSION_MANAGER_V1_REASON_LAUNCH, session_id); + xdg_session_v1_add_listener(viddata->xdg_session, &xdg_session_listener, viddata); + } + } +} + +static void Wayland_MaybeRemoveSession(SDL_VideoData *viddata) +{ + // If the session string was cleared, remove the session. + if (viddata->xdg_session) { + const char *session_id = SDL_GetStringProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_SESSION_ID_STRING, NULL); + if (!session_id || *session_id == '\0') { + xdg_session_v1_remove(viddata->xdg_session); + WAYLAND_wl_display_roundtrip(viddata->display); + } + } +} + static void handle_xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg, uint32_t serial) { xdg_wm_base_pong(xdg, serial); @@ -1425,6 +1480,8 @@ static void handle_registry_global(void *data, struct wl_registry *registry, uin Wayland_DisplayInitPointerGestureManager(d); } else if (SDL_strcmp(interface, wp_single_pixel_buffer_manager_v1_interface.name) == 0) { d->single_pixel_buffer_manager = wl_registry_bind(d->registry, id, &wp_single_pixel_buffer_manager_v1_interface, 1); + } else if (SDL_strcmp(interface, xdg_session_manager_v1_interface.name) == 0) { + d->xdg_session_manager = wl_registry_bind(d->registry, id, &xdg_session_manager_v1_interface, 1); } #ifdef SDL_WL_FIXES_VERSION else if (SDL_strcmp(interface, wl_fixes_interface.name) == 0) { @@ -1622,6 +1679,8 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this) SDL_VideoData *data = _this->internal; SDL_WaylandSeat *seat, *tmp; + Wayland_MaybeRemoveSession(data); + for (int i = _this->num_displays - 1; i >= 0; --i) { SDL_VideoDisplay *display = _this->displays[i]; Wayland_free_display(display, false); @@ -1779,6 +1838,16 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this) data->single_pixel_buffer_manager = NULL; } + if (data->xdg_session) { + xdg_session_v1_destroy(data->xdg_session); + data->xdg_session = NULL; + } + + if (data->xdg_session_manager) { + xdg_session_manager_v1_destroy(data->xdg_session_manager); + data->xdg_session_manager = NULL; + } + if (data->subcompositor) { wl_subcompositor_destroy(data->subcompositor); data->subcompositor = NULL; diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index e4247e671cfb2..71bf372b859ba 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -87,7 +87,9 @@ struct SDL_VideoData struct wl_fixes *wl_fixes; struct zwp_pointer_gestures_v1 *zwp_pointer_gestures; struct wp_single_pixel_buffer_manager_v1 *single_pixel_buffer_manager; + struct xdg_session_manager_v1 *xdg_session_manager; + struct xdg_session_v1 *xdg_session; struct xkb_context *xkb_context; struct wl_list seat_list; @@ -103,6 +105,7 @@ struct SDL_VideoData bool display_disconnected; bool display_externally_owned; bool scale_to_display_enabled; + bool session_ready; }; struct SDL_DisplayData @@ -162,9 +165,12 @@ extern bool SDL_WAYLAND_own_surface(struct wl_surface *surface); extern bool SDL_WAYLAND_own_output(struct wl_output *output); extern SDL_WindowData *Wayland_GetWindowDataForOwnedSurface(struct wl_surface *surface); -void Wayland_AddWindowDataToExternalList(SDL_WindowData *data); -void Wayland_RemoveWindowDataFromExternalList(SDL_WindowData *data); -struct wl_event_queue *Wayland_DisplayCreateQueue(struct wl_display *display, const char *name); +extern void Wayland_AddWindowDataToExternalList(SDL_WindowData *data); +extern void Wayland_RemoveWindowDataFromExternalList(SDL_WindowData *data); + +extern void Wayland_SessionCreate(SDL_VideoData *data); + +extern struct wl_event_queue *Wayland_DisplayCreateQueue(struct wl_display *display, const char *name); extern bool Wayland_LoadLibdecor(SDL_VideoData *data, bool ignore_xdg); diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 20da36b6339ed..f2a7d85be6457 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -48,6 +48,7 @@ #include "frog-color-management-v1-client-protocol.h" #include "xdg-toplevel-icon-v1-client-protocol.h" #include "color-management-v1-client-protocol.h" +#include "xdg-session-management-v1-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -2018,6 +2019,38 @@ bool Wayland_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool mod return true; } +static void Wayland_RegisterToplevelForSession(SDL_WindowData *data) +{ + SDL_VideoData *viddata = data->waylandData; + + if (viddata->xdg_session_manager) { + const char *id = SDL_GetStringProperty(data->sdlwindow->props, SDL_PROP_WINDOW_WAYLAND_WINDOW_ID_STRING, NULL); + if (id && *id != '\0') { + Wayland_SessionCreate(viddata); + data->xdg_toplevel_session = xdg_session_v1_restore_toplevel(viddata->xdg_session, GetToplevelForWindow(data), id); + data->session_id = SDL_strdup(id); + } + } +} + +static void Wayland_DestroyToplevelSession(SDL_WindowData *data) +{ + SDL_VideoData *viddata = data->waylandData; + + if (data->xdg_toplevel_session) { + const char *id = SDL_GetStringProperty(data->sdlwindow->props, SDL_PROP_WINDOW_WAYLAND_WINDOW_ID_STRING, NULL); + if (!id || SDL_strcmp(data->session_id, id) != 0) { + xdg_session_v1_remove_toplevel(viddata->xdg_session, data->session_id); + } + + xdg_toplevel_session_v1_destroy(data->xdg_toplevel_session); + data->xdg_toplevel_session = NULL; + + SDL_free(data->session_id); + data->session_id = NULL; + } +} + static void show_hide_sync_handler(void *data, struct wl_callback *callback, uint32_t callback_data) { // Get the window from the ID as it may have been destroyed @@ -2224,6 +2257,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) } // Restore state that was set prior to this call + Wayland_RegisterToplevelForSession(data); Wayland_SetWindowParent(_this, window, window->parent); if (window->flags & SDL_WINDOW_MODAL) { @@ -2384,6 +2418,8 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_HIDDEN; + Wayland_DestroyToplevelSession(wind); + if (wind->server_decoration) { zxdg_toplevel_decoration_v1_destroy(wind->server_decoration); wind->server_decoration = NULL; @@ -3021,6 +3057,12 @@ bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, data->surface); SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_VIEWPORT_POINTER, data->viewport); SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_EGL_WINDOW_POINTER, data->egl_window); + if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL || data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { + const char *window_id = SDL_GetStringProperty(create_props, SDL_PROP_WINDOW_CREATE_WAYLAND_WINDOW_ID_STRING, NULL); + if (window_id && *window_id != '\0') { + SDL_SetStringProperty(props, SDL_PROP_WINDOW_WAYLAND_WINDOW_ID_STRING, window_id); + } + } data->hit_test_result = SDL_HITTEST_NORMAL; @@ -3553,6 +3595,7 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) SDL_free(wind->outputs); SDL_free(wind->app_id); + SDL_free(wind->session_id); if (wind->gles_swap_frame_callback) { wl_callback_destroy(wind->gles_swap_frame_callback); diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index e0618553526b1..55d17d7aabb88 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -118,6 +118,7 @@ struct SDL_WindowData struct xdg_toplevel_icon_v1 *xdg_toplevel_icon_v1; struct frog_color_managed_surface *frog_color_managed_surface; struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback; + struct xdg_toplevel_session_v1 *xdg_toplevel_session; struct Wayland_ColorInfoState *color_info_state; @@ -127,6 +128,7 @@ struct SDL_WindowData int num_outputs; char *app_id; + char *session_id; double scale_factor; struct wl_buffer **icon_buffers; diff --git a/wayland-protocols/xdg-session-management-v1.xml b/wayland-protocols/xdg-session-management-v1.xml new file mode 100644 index 0000000000000..955be45fbb6ca --- /dev/null +++ b/wayland-protocols/xdg-session-management-v1.xml @@ -0,0 +1,317 @@ + + + + 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. + + + + This description provides a high-level overview of the interplay between + the interfaces defined this protocol. For details, see the protocol + specification. + + The xdg_session_manager protocol declares interfaces necessary to + allow clients to restore toplevel state from previous executions. The + xdg_session_manager_v1.get_session request can be used to obtain a + xdg_session_v1 resource representing the state of a set of toplevels. + + Clients may obtain the session string to use in future calls through + the xdg_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. Clients that wish to + track sessions in multiple environments may use the $XDG_CURRENT_DESKTOP + environment variable. + + Toplevels are managed through the xdg_session_v1.add_toplevel and + xdg_session_v1.remove_toplevel pair of requests. Clients will explicitly + request a toplevel to be restored according to prior state through the + xdg_session_v1.restore_toplevel request before the toplevel is mapped. + + Compositors may store session information up to any arbitrary level, and + apply any limits and policies to the amount of data stored and its lifetime. + Clients must account for missing sessions and partial session restoration. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + + + + + The xdg_session_manager_v1 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. + + Policies such as cache eviction are declared an implementation detail of + the compositor. Clients should account for no longer existing sessions. + + + + + + + + + + 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 + application might restore additional state such as active workspace and + stacking order. + + + + A new app instance is launched, for example from an app launcher. + + + + + A app instance is recovering from for example a compositor or app crash. + + + + + A app instance is restored, for example part of a restored session, or + restored from having been temporarily terminated due to resource + constraints. + + + + + + + This has no effect other than to destroy the xdg_session_manager object. + + + + + + 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 a session_id is passed + which does not represent a valid session, the compositor treats it as if + NULL had been passed. + + The session id string must be UTF-8 encoded. It is also limited by the + maximum length of wayland messages (around 4KB). The 'invalid_session_id' + protocol error will be raised if an invalid string is provided. + + A client is allowed to have any number of in use sessions at the same + time. + + + + + + + + + + A xdg_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. + + + + + + + + + + + Destroy a session object, preserving the current state but not continuing + to make further updates if state changes occur. This makes the associated + xdg_toplevel_session_v1 objects inert. + + + + + + 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. + + + + + + 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 to store + window specific state within the session. + + The name given to the toplevel must not correspond to any previously + existing toplevel names in the session. If the name matches an already + known toplevel name in the session, a 'name_in_use' protocol error will + be raised. + + This request will return a xdg_toplevel_session_v1 for later + manipulation. As this resource is created from an empty initial state, + compositors must not emit a xdg_toplevel_session_v1.restored event for + resources created through this request. + + The name string must be UTF-8 encoded. It is also limited by the maximum + length of wayland messages (around 4KB). The 'invalid_name' protocol + error will be raised if an invalid string is provided. + + + + + + + + + Inform the compositor that the toplevel associated with the passed name + should have its window management state restored. + + If the toplevel name was previously granted to another xdg_toplevel, + the 'name_in_use' protocol error will be raised. + + This request must be called prior to the first commit on the associated + wl_surface after creating the toplevel, otherwise an 'already_mapped' + error is raised. + + As part of the initial configure sequence, if the toplevel was + successfully restored, a xdg_toplevel_session_v1.restored event is + emitted. If the toplevel name was not known in the session, this request + will be equivalent to the xdg_toplevel_session_v1.add_toplevel request, + and no such event will be emitted. See the xdg_toplevel_session_v1.restored + event for further details. + + The name string must be UTF-8 encoded. It is also limited by the maximum + length of wayland messages (around 4KB). The 'invalid_name' protocol + error will be raised if an invalid string is provided. + + + + + + + + + Remove a specified surface from the session and render any related + xdg_toplevel_session_v1 object inert. The compositor should remove any + data related to the toplevel in the corresponding session from its internal + storage. + + The window is specified by its name in the session. The name string + must be encoded in UTF-8, and it is limited in size by the maximum + length of wayland messages (around 4KB). + + + + + + + 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 persistently stored and used to restore previous + sessions. + + + + + + + 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. + + + + + + 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. + + + + + + + A xdg_toplevel_session_v1 resource acts as a handle for the given + toplevel in the session. It allows for receiving events after a + toplevel state was restored, and has the requests to manage them. + + + + + Destroy the object. This has no effect over window management of the + associated toplevel. + + + + + + Renames the toplevel session. The new name can be used in subsequent requests + to identify this session object. The state associated with this toplevel + session will be preserved. + + If the xdg_session_v1 already contains a toplevel with the specified name, + the 'name_in_use' protocol error will be raised. + + + + + + + The "restored" event is emitted prior to the first + xdg_toplevel.configure for the toplevel. It will only be emitted after + xdg_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. + + + +