1
0
Fork 0

wayland: Implement the XDG session management protocol

The xdg_session_manager_v1 global interface is the generator
of xdg_session_v1 objects for clients. These will notify of an
unique ID that can be used for future instantiations.

Once a xdg_session_v1 object is obtained, toplevels can be added
to be managed by it, and clients may get a hint about whether the
toplevel was restored to a saved state.

Changes by Carlos Garnacho: Integrate with MetaSessionManager core
object. Flesh out event emission of xdg_session_v1 and
xdg_toplevel_session_v1 objects, handle sessions being
replaced/deleted.

Changes by Sebastian Wick:
* make lifetimes of xdg_sessions entirely determined by the wayland and
  handle its destruction via the signal
* fix session destruction vs deletion
* do not drop refcount of replaced session state temporarily to make
  sure the replacing session keeps the state
* disconnect signals of destroyed and replaced sessions
* disconnect window-unmanaging signal handler for
  MetaWaylandXdgToplevelSession
* call wl_resource_destroy in xdg_toplevel_session_remove to make it a
  destructor
* handle session being destroyed before topevel-sessions
* handle the toplevel going away before the topevel-sessions

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3825>
This commit is contained in:
Jonas Ådahl 2024-06-19 12:47:17 +02:00 committed by Marge Bot
parent 2074e4e146
commit 74ce36f323
8 changed files with 935 additions and 1 deletions

View file

@ -709,8 +709,12 @@ if have_wayland
'wayland/meta-wayland-xdg-foreign.c', 'wayland/meta-wayland-xdg-foreign.c',
'wayland/meta-wayland-xdg-foreign.h', 'wayland/meta-wayland-xdg-foreign.h',
'wayland/meta-wayland-xdg-foreign-private.h', 'wayland/meta-wayland-xdg-foreign-private.h',
'wayland/meta-wayland-xdg-session-manager.c',
'wayland/meta-wayland-xdg-session-manager.h',
'wayland/meta-wayland-xdg-session-state.c', 'wayland/meta-wayland-xdg-session-state.c',
'wayland/meta-wayland-xdg-session-state.h', 'wayland/meta-wayland-xdg-session-state.h',
'wayland/meta-wayland-xdg-session.c',
'wayland/meta-wayland-xdg-session.h',
'wayland/meta-wayland-xdg-shell.c', 'wayland/meta-wayland-xdg-shell.c',
'wayland/meta-wayland-xdg-shell.h', 'wayland/meta-wayland-xdg-shell.h',
'wayland/meta-wayland-xdg-dialog.c', 'wayland/meta-wayland-xdg-dialog.c',

View file

@ -103,6 +103,7 @@ struct _MetaWaylandCompositor
MetaWaylandTabletManager *tablet_manager; MetaWaylandTabletManager *tablet_manager;
MetaWaylandActivation *activation; MetaWaylandActivation *activation;
MetaWaylandXdgForeign *foreign; MetaWaylandXdgForeign *foreign;
MetaWaylandXdgSessionManager *session_manager;
GHashTable *scheduled_surface_associations; GHashTable *scheduled_surface_associations;

View file

@ -60,3 +60,4 @@
#define META_XX_COLOR_MANAGEMENT_VERSION 1 #define META_XX_COLOR_MANAGEMENT_VERSION 1
#define META_XDG_DIALOG_VERSION 1 #define META_XDG_DIALOG_VERSION 1
#define META_WP_DRM_LEASE_DEVICE_V1_VERSION 1 #define META_WP_DRM_LEASE_DEVICE_V1_VERSION 1
#define META_XDG_SESSION_MANAGER_V1_VERSION 1

View file

@ -0,0 +1,397 @@
/*
* Copyright (C) 2024 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include "wayland/meta-wayland-xdg-session-manager.h"
#include <glib.h>
#include "wayland/meta-wayland-xdg-shell.h"
#include "wayland/meta-wayland-xdg-session.h"
#include "wayland/meta-wayland-private.h"
#include "core/meta-debug-control-private.h"
#include "core/meta-session-manager.h"
#include "session-management-v1-server-protocol.h"
typedef struct _MetaWaylandXdgSessionManager
{
MetaWaylandCompositor *compositor;
struct wl_global *global;
GHashTable *sessions;
GHashTable *session_states;
} MetaWaylandXdgSessionManager;
static void xdg_session_manager_remove_session (MetaWaylandXdgSessionManager *session_manager,
MetaWaylandXdgSession *session);
static void
xdg_session_manager_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static gboolean
on_restore_toplevel (MetaWaylandXdgSession *session,
MetaWaylandXdgToplevel *xdg_toplevel,
const char *name,
MetaWaylandXdgSessionManager *xdg_session_manager)
{
MetaContext *context =
meta_wayland_compositor_get_context (xdg_session_manager->compositor);
MetaSessionManager *session_manager =
meta_context_get_session_manager (context);
MetaSessionState *session_state;
MetaWaylandSurface *surface;
MetaWindow *window;
session_state =
meta_session_manager_get_session (META_SESSION_MANAGER (session_manager),
META_TYPE_WAYLAND_XDG_SESSION_STATE,
meta_wayland_xdg_session_get_id (session));
surface =
meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (xdg_toplevel));
if (!surface)
return FALSE;
window = meta_wayland_surface_get_toplevel_window (surface);
if (!window)
return FALSE;
if (!meta_session_state_restore_window (session_state, name, window))
return FALSE;
meta_wayland_xdg_toplevel_set_hint_restored (xdg_toplevel);
return TRUE;
}
static void
on_save_toplevel (MetaWaylandXdgSession *session,
MetaWaylandXdgToplevel *xdg_toplevel,
const char *name,
MetaWindow *window,
MetaWaylandXdgSessionManager *xdg_session_manager)
{
MetaContext *context =
meta_wayland_compositor_get_context (xdg_session_manager->compositor);
MetaSessionManager *session_manager =
meta_context_get_session_manager (context);
MetaSessionState *session_state;
session_state =
meta_session_manager_get_session (META_SESSION_MANAGER (session_manager),
META_TYPE_WAYLAND_XDG_SESSION_STATE,
meta_wayland_xdg_session_get_id (session));
meta_session_state_save_window (session_state, name, window);
}
static void
on_remove_toplevel (MetaWaylandXdgSession *session,
const char *name,
MetaWaylandXdgSessionManager *xdg_session_manager)
{
MetaContext *context =
meta_wayland_compositor_get_context (xdg_session_manager->compositor);
MetaSessionManager *session_manager =
meta_context_get_session_manager (context);
MetaSessionState *session_state;
session_state =
meta_session_manager_get_session (session_manager,
META_TYPE_WAYLAND_XDG_SESSION_STATE,
meta_wayland_xdg_session_get_id (session));
meta_session_state_remove_window (session_state, name);
}
static void
on_session_destroyed (MetaWaylandXdgSession *session,
MetaWaylandXdgSessionManager *session_manager)
{
xdg_session_manager_remove_session (session_manager, session);
}
static void
on_session_delete (MetaWaylandXdgSession *xdg_session,
MetaWaylandXdgSessionManager *xdg_session_manager)
{
MetaContext *context =
meta_wayland_compositor_get_context (xdg_session_manager->compositor);
MetaSessionManager *session_manager =
meta_context_get_session_manager (context);
const char *session_id = meta_wayland_xdg_session_get_id (xdg_session);
g_hash_table_remove (xdg_session_manager->session_states, session_id);
meta_session_manager_delete_session (session_manager, session_id);
}
static void
xdg_session_manager_remove_session (MetaWaylandXdgSessionManager *session_manager,
MetaWaylandXdgSession *session)
{
const char *session_id = meta_wayland_xdg_session_get_id (session);
g_signal_handlers_disconnect_by_func (session,
on_session_destroyed,
session_manager);
g_signal_handlers_disconnect_by_func (session,
on_restore_toplevel,
session_manager);
g_signal_handlers_disconnect_by_func (session,
on_save_toplevel,
session_manager);
g_signal_handlers_disconnect_by_func (session,
on_remove_toplevel,
session_manager);
g_signal_handlers_disconnect_by_func (session,
on_session_delete,
session_manager);
g_hash_table_remove (session_manager->sessions, session_id);
}
static char *
generate_session_id (MetaWaylandXdgSessionManager *session_manager)
{
while (TRUE)
{
g_autofree char *id = NULL;
id = g_uuid_string_random ();
if (!g_hash_table_lookup (session_manager->sessions, id))
return g_steal_pointer (&id);
}
}
static void
xdg_session_manager_get_session (struct wl_client *client,
struct wl_resource *resource,
uint32_t id,
uint32_t reason_value,
const char *session_id)
{
MetaWaylandXdgSessionManager *xdg_session_manager =
wl_resource_get_user_data (resource);
MetaContext *context =
meta_wayland_compositor_get_context (xdg_session_manager->compositor);
MetaSessionManager *session_manager =
meta_context_get_session_manager (context);
g_autoptr (MetaSessionState) session_state = NULL;
g_autoptr (MetaWaylandXdgSession) session = NULL;
g_autofree char *name = NULL, *stolen_name = NULL;
gboolean created = FALSE;
/* Unknown session ID is the same as NULL */
if (session_id &&
!meta_session_manager_get_session_exists (session_manager, session_id))
session_id = NULL;
if (session_id)
{
MetaWaylandXdgSession *prev_session;
prev_session =
g_hash_table_lookup (xdg_session_manager->sessions, session_id);
if (prev_session)
{
if (meta_wayland_xdg_session_is_same_client (prev_session, client))
{
wl_resource_post_error (resource,
XX_SESSION_MANAGER_V1_ERROR_IN_USE,
"Session %s already in use",
session_id);
return;
}
/* Replace existing session */
meta_wayland_xdg_session_emit_replaced (prev_session);
xdg_session_manager_remove_session (xdg_session_manager,
prev_session);
}
name = g_strdup (session_id);
}
else
{
name = generate_session_id (xdg_session_manager);
created = TRUE;
}
if (!g_hash_table_steal_extended (xdg_session_manager->session_states,
name,
(gpointer *) &stolen_name,
(gpointer *) &session_state))
{
session_state =
meta_session_manager_get_session (session_manager,
META_TYPE_WAYLAND_XDG_SESSION_STATE,
name);
}
session = meta_wayland_xdg_session_new (META_WAYLAND_XDG_SESSION_STATE (session_state),
client,
wl_resource_get_version (resource),
id);
g_signal_connect (session, "destroyed",
G_CALLBACK (on_session_destroyed), xdg_session_manager);
g_signal_connect (session, "restore-toplevel",
G_CALLBACK (on_restore_toplevel), xdg_session_manager);
g_signal_connect (session, "save-toplevel",
G_CALLBACK (on_save_toplevel), xdg_session_manager);
g_signal_connect (session, "remove-toplevel",
G_CALLBACK (on_remove_toplevel), xdg_session_manager);
g_signal_connect (session, "delete",
G_CALLBACK (on_session_delete), xdg_session_manager);
if (created)
meta_wayland_xdg_session_emit_created (session);
else
meta_wayland_xdg_session_emit_restored (session);
g_hash_table_insert (xdg_session_manager->sessions,
g_strdup (name),
session);
g_hash_table_insert (xdg_session_manager->session_states,
g_strdup (name),
g_steal_pointer (&session_state));
}
static const struct xx_session_manager_v1_interface meta_xdg_session_manager_interface = {
xdg_session_manager_destroy,
xdg_session_manager_get_session,
};
static void
bind_session_manager (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
MetaWaylandXdgSessionManager *session_manager = data;
struct wl_resource *resource;
resource = wl_resource_create (client, &xx_session_manager_v1_interface,
version, id);
wl_resource_set_implementation (resource, &meta_xdg_session_manager_interface,
session_manager, NULL);
}
static void
update_enabled (MetaWaylandXdgSessionManager *session_manager)
{
MetaWaylandCompositor *compositor = session_manager->compositor;
MetaDebugControl *debug_control =
meta_context_get_debug_control (compositor->context);
gboolean is_enabled;
is_enabled =
meta_debug_control_is_session_management_protocol_enabled (debug_control);
if (is_enabled && !session_manager->global)
{
struct wl_display *wayland_display;
wayland_display =
meta_wayland_compositor_get_wayland_display (compositor);
session_manager->global =
wl_global_create (wayland_display,
&xx_session_manager_v1_interface,
META_XDG_SESSION_MANAGER_V1_VERSION,
session_manager, bind_session_manager);
if (!session_manager->global)
g_error ("Could not create session manager global");
}
else if (!is_enabled)
{
g_clear_pointer (&session_manager->global, wl_global_destroy);
}
}
static MetaWaylandXdgSessionManager *
meta_wayland_session_manager_new (MetaWaylandCompositor *compositor)
{
MetaWaylandXdgSessionManager *session_manager;
session_manager = g_new0 (MetaWaylandXdgSessionManager, 1);
session_manager->compositor = compositor;
session_manager->sessions =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
session_manager->session_states =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
return session_manager;
}
static void
meta_wayland_session_manager_free (MetaWaylandXdgSessionManager *session_manager)
{
g_clear_pointer (&session_manager->sessions, g_hash_table_unref);
g_clear_pointer (&session_manager->session_states, g_hash_table_unref);
g_free (session_manager);
}
static void
on_protocol_enabled_changed (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
MetaWaylandXdgSessionManager *session_manager = user_data;
update_enabled (session_manager);
}
void
meta_wayland_xdg_session_management_init (MetaWaylandCompositor *compositor)
{
MetaDebugControl *debug_control =
meta_context_get_debug_control (compositor->context);
compositor->session_manager = meta_wayland_session_manager_new (compositor);
g_signal_connect (debug_control, "notify::session-management-protocol",
G_CALLBACK (on_protocol_enabled_changed),
compositor->session_manager);
update_enabled (compositor->session_manager);
}
void
meta_wayland_xdg_session_management_finalize (MetaWaylandCompositor *compositor)
{
MetaDebugControl *debug_control =
meta_context_get_debug_control (compositor->context);
g_signal_handlers_disconnect_by_func (debug_control,
on_protocol_enabled_changed,
compositor->session_manager);
g_clear_pointer (&compositor->session_manager,
meta_wayland_session_manager_free);
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (C) 2024 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "wayland/meta-wayland-types.h"
void meta_wayland_xdg_session_management_init (MetaWaylandCompositor *compositor);
void meta_wayland_xdg_session_management_finalize (MetaWaylandCompositor *compositor);

View file

@ -0,0 +1,457 @@
/*
* Copyright (C) 2024 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include "wayland/meta-wayland-xdg-session.h"
#include <glib-object.h>
#include "wayland/meta-wayland-xdg-session-state.h"
#include "wayland/meta-wayland-xdg-shell.h"
#include "session-management-v1-server-protocol.h"
typedef struct _MetaWaylandXdgToplevelSession
{
grefcount ref_count;
MetaWaylandSurface *surface;
struct wl_resource *resource;
MetaWaylandXdgSession *session;
char *name;
} MetaWaylandXdgToplevelSession;
enum
{
DESTROYED,
RESTORE_TOPLEVEL,
SAVE_TOPLEVEL,
REMOVE_TOPLEVEL,
DELETE,
N_SIGNALS
};
static guint signals[N_SIGNALS];
struct _MetaWaylandXdgSession
{
GObject parent;
char *id;
struct wl_resource *resource;
GHashTable *toplevels; /* name -> MetaWaylandXdgToplevelSession */
};
G_DEFINE_FINAL_TYPE (MetaWaylandXdgSession,
meta_wayland_xdg_session,
G_TYPE_OBJECT)
static void on_window_unmanaging (MetaWindow *window,
MetaWaylandXdgToplevelSession *toplevel_session);
static MetaWaylandXdgToplevelSession *
meta_wayland_xdg_toplevel_session_ref (MetaWaylandXdgToplevelSession *toplevel_session)
{
g_ref_count_inc (&toplevel_session->ref_count);
return toplevel_session;
}
static void
meta_wayland_xdg_toplevel_session_unref (MetaWaylandXdgToplevelSession *toplevel_session)
{
if (g_ref_count_dec (&toplevel_session->ref_count))
{
MetaWindow *window = NULL;
MetaWaylandSurface *surface = toplevel_session->surface;
if (surface)
window = meta_wayland_surface_get_toplevel_window (surface);
if (window)
{
g_signal_handlers_disconnect_by_func (window,
on_window_unmanaging,
toplevel_session);
}
g_free (toplevel_session->name);
g_free (toplevel_session);
}
}
static void
xdg_toplevel_session_destroy (struct wl_client *wl_client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
xdg_toplevel_session_remove (struct wl_client *wl_client,
struct wl_resource *resource)
{
MetaWaylandXdgToplevelSession *toplevel_session =
wl_resource_get_user_data (resource);
MetaWaylandXdgSession *session = toplevel_session->session;
if (session)
{
g_signal_emit (session, signals[REMOVE_TOPLEVEL], 0, toplevel_session->name);
g_hash_table_remove (session->toplevels, toplevel_session->name);
}
wl_resource_destroy (resource);
}
static const struct xx_toplevel_session_v1_interface meta_xdg_toplevel_session_interface = {
xdg_toplevel_session_destroy,
xdg_toplevel_session_remove,
};
static void
xdg_toplevel_session_destructor (struct wl_resource *resource)
{
MetaWaylandXdgToplevelSession *toplevel_session =
wl_resource_get_user_data (resource);
meta_wayland_xdg_toplevel_session_unref (toplevel_session);
}
static MetaWaylandXdgToplevelSession *
meta_wayland_xdg_toplevel_session_new (MetaWaylandXdgSession *xdg_session,
MetaWaylandSurface *surface,
const char *name,
struct wl_client *wl_client,
uint32_t version,
uint32_t id)
{
MetaWaylandXdgToplevelSession *toplevel_session;
toplevel_session = g_new0 (MetaWaylandXdgToplevelSession, 1);
g_ref_count_init (&toplevel_session->ref_count);
toplevel_session->surface = surface;
toplevel_session->session = xdg_session;
toplevel_session->name = g_strdup (name);
toplevel_session->resource =
wl_resource_create (wl_client,
&xx_toplevel_session_v1_interface,
version, id);
wl_resource_set_implementation (toplevel_session->resource,
&meta_xdg_toplevel_session_interface,
meta_wayland_xdg_toplevel_session_ref (toplevel_session),
xdg_toplevel_session_destructor);
return toplevel_session;
}
static void
meta_wayland_xdg_toplevel_session_emit_restored (MetaWaylandXdgToplevelSession *toplevel_session)
{
MetaWaylandXdgToplevel *xdg_toplevel =
META_WAYLAND_XDG_TOPLEVEL (toplevel_session->surface->role);
struct wl_resource *xdg_toplevel_resource =
meta_wayland_xdg_toplevel_get_resource (xdg_toplevel);
xx_toplevel_session_v1_send_restored (toplevel_session->resource,
xdg_toplevel_resource);
}
static void
meta_wayland_xdg_session_dispose (GObject *object)
{
MetaWaylandXdgSession *session = META_WAYLAND_XDG_SESSION (object);
g_clear_pointer (&session->id, g_free);
g_clear_pointer (&session->toplevels, g_hash_table_unref);
G_OBJECT_CLASS (meta_wayland_xdg_session_parent_class)->dispose (object);
}
static void
meta_wayland_xdg_session_class_init (MetaWaylandXdgSessionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = meta_wayland_xdg_session_dispose;
signals[DESTROYED] =
g_signal_new ("destroyed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
NULL,
G_TYPE_NONE, 0);
signals[RESTORE_TOPLEVEL] =
g_signal_new ("restore-toplevel",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
g_signal_accumulator_true_handled,
NULL,
NULL,
G_TYPE_BOOLEAN, 2,
META_TYPE_WAYLAND_XDG_TOPLEVEL,
G_TYPE_STRING);
signals[SAVE_TOPLEVEL] =
g_signal_new ("save-toplevel",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 3,
META_TYPE_WAYLAND_XDG_TOPLEVEL,
G_TYPE_STRING,
META_TYPE_WINDOW);
signals[REMOVE_TOPLEVEL] =
g_signal_new ("remove-toplevel",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_STRING);
signals[DELETE] =
g_signal_new ("delete",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
meta_wayland_xdg_session_init (MetaWaylandXdgSession *session)
{
}
static void
xdg_session_destroy (struct wl_client *wl_client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
xdg_session_remove (struct wl_client *wl_client,
struct wl_resource *resource)
{
MetaWaylandXdgSession *session =
META_WAYLAND_XDG_SESSION (wl_resource_get_user_data (resource));
g_signal_emit (session, signals[DELETE], 0);
wl_resource_destroy (resource);
}
static void
on_window_unmanaging (MetaWindow *window,
MetaWaylandXdgToplevelSession *toplevel_session)
{
MetaWaylandXdgSession *session = toplevel_session->session;
if (session)
{
MetaWaylandXdgToplevel *xdg_toplevel =
META_WAYLAND_XDG_TOPLEVEL (toplevel_session->surface->role);
g_signal_emit (session, signals[SAVE_TOPLEVEL], 0,
xdg_toplevel, toplevel_session->name, window);
}
toplevel_session->surface = NULL;
}
static void
xdg_session_add_toplevel (struct wl_client *wl_client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *toplevel_resource,
const char *name)
{
MetaWaylandXdgSession *session =
META_WAYLAND_XDG_SESSION (wl_resource_get_user_data (resource));
MetaWaylandXdgToplevel *xdg_toplevel =
wl_resource_get_user_data (toplevel_resource);
MetaWaylandSurfaceRole *surface_role;
MetaWaylandSurface *surface;
MetaWaylandXdgToplevelSession *toplevel_session;
MetaWindow *window;
if (g_hash_table_lookup (session->toplevels, name))
{
wl_resource_post_error (resource, XX_SESSION_V1_ERROR_NAME_IN_USE,
"Name of toplevel was already in use");
return;
}
surface_role = META_WAYLAND_SURFACE_ROLE (xdg_toplevel);
surface = meta_wayland_surface_role_get_surface (surface_role);
toplevel_session =
meta_wayland_xdg_toplevel_session_new (session, surface, name,
wl_client,
wl_resource_get_version (resource),
id);
g_hash_table_insert (session->toplevels, g_strdup (name), toplevel_session);
window = meta_wayland_surface_get_toplevel_window (surface);
if (window)
{
g_signal_connect (window, "unmanaging",
G_CALLBACK (on_window_unmanaging), toplevel_session);
}
}
static void
xdg_session_restore_toplevel (struct wl_client *wl_client,
struct wl_resource *resource,
uint32_t id,
struct wl_resource *toplevel_resource,
const char *name)
{
MetaWaylandXdgSession *session =
META_WAYLAND_XDG_SESSION (wl_resource_get_user_data (resource));
MetaWaylandXdgToplevel *xdg_toplevel =
wl_resource_get_user_data (toplevel_resource);
MetaWaylandSurfaceRole *surface_role;
MetaWaylandSurface *surface;
MetaWaylandXdgToplevelSession *toplevel_session;
MetaWindow *window;
gboolean restored = FALSE;
if (g_hash_table_lookup (session->toplevels, name))
{
wl_resource_post_error (resource, XX_SESSION_V1_ERROR_NAME_IN_USE,
"Name of toplevel was already in use");
return;
}
surface_role = META_WAYLAND_SURFACE_ROLE (xdg_toplevel);
surface = meta_wayland_surface_role_get_surface (surface_role);
if (meta_wayland_surface_has_initial_commit (surface))
{
wl_resource_post_error (resource, XX_SESSION_V1_ERROR_ALREADY_MAPPED,
"Tried to restore an already mapped toplevel");
return;
}
toplevel_session =
meta_wayland_xdg_toplevel_session_new (session, surface, name,
wl_client,
wl_resource_get_version (resource),
id);
g_hash_table_insert (session->toplevels, g_strdup (name), toplevel_session);
window = meta_wayland_surface_get_toplevel_window (surface);
if (window)
{
g_signal_connect (window, "unmanaging",
G_CALLBACK (on_window_unmanaging), toplevel_session);
}
g_signal_emit (session,
signals[RESTORE_TOPLEVEL], 0,
xdg_toplevel, name, &restored);
if (restored)
meta_wayland_xdg_toplevel_session_emit_restored (toplevel_session);
}
static const struct xx_session_v1_interface meta_xdg_session_interface = {
xdg_session_destroy,
xdg_session_remove,
xdg_session_add_toplevel,
xdg_session_restore_toplevel,
};
static void
xdg_session_destructor (struct wl_resource *resource)
{
MetaWaylandXdgSession *session =
META_WAYLAND_XDG_SESSION (wl_resource_get_user_data (resource));
GHashTableIter iter;
gpointer value;
g_signal_emit (session, signals[DESTROYED], 0);
g_hash_table_iter_init (&iter, session->toplevels);
while (g_hash_table_iter_next (&iter, NULL, &value))
{
MetaWaylandXdgToplevelSession *toplevel_session = value;
toplevel_session->session = NULL;
}
g_object_unref (session);
}
MetaWaylandXdgSession *
meta_wayland_xdg_session_new (MetaWaylandXdgSessionState *session_state,
struct wl_client *wl_client,
uint32_t version,
uint32_t id)
{
g_autoptr (MetaWaylandXdgSession) session = NULL;
session = g_object_new (META_TYPE_WAYLAND_XDG_SESSION, NULL);
session->id =
g_strdup (meta_session_state_get_name (META_SESSION_STATE (session_state)));
session->toplevels =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) meta_wayland_xdg_toplevel_session_unref);
session->resource = wl_resource_create (wl_client,
&xx_session_v1_interface,
version, id);
wl_resource_set_implementation (session->resource,
&meta_xdg_session_interface,
g_object_ref (session),
xdg_session_destructor);
return g_steal_pointer (&session);
}
const char *
meta_wayland_xdg_session_get_id (MetaWaylandXdgSession *session)
{
return session->id;
}
void
meta_wayland_xdg_session_emit_created (MetaWaylandXdgSession *session)
{
xx_session_v1_send_created (session->resource, session->id);
}
void
meta_wayland_xdg_session_emit_replaced (MetaWaylandXdgSession *session)
{
xx_session_v1_send_replaced (session->resource);
}
void
meta_wayland_xdg_session_emit_restored (MetaWaylandXdgSession *session)
{
xx_session_v1_send_restored (session->resource);
}
gboolean
meta_wayland_xdg_session_is_same_client (MetaWaylandXdgSession *session,
struct wl_client *client)
{
return wl_resource_get_client (session->resource) == client;
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (C) 2024 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <wayland-server-core.h>
#include "wayland/meta-wayland-types.h"
#include "wayland/meta-wayland-xdg-session-state.h"
#define META_TYPE_WAYLAND_XDG_SESSION (meta_wayland_xdg_session_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandXdgSession,
meta_wayland_xdg_session,
META, WAYLAND_XDG_SESSION,
GObject)
MetaWaylandXdgSession * meta_wayland_xdg_session_new (MetaWaylandXdgSessionState *session_state,
struct wl_client *wl_client,
uint32_t version,
uint32_t id);
const char * meta_wayland_xdg_session_get_id (MetaWaylandXdgSession *session);
void meta_wayland_xdg_session_emit_created (MetaWaylandXdgSession *session);
void meta_wayland_xdg_session_emit_replaced (MetaWaylandXdgSession *session);
void meta_wayland_xdg_session_emit_restored (MetaWaylandXdgSession *session);
gboolean meta_wayland_xdg_session_is_same_client (MetaWaylandXdgSession *session,
struct wl_client *client);

View file

@ -48,6 +48,7 @@
#include "wayland/meta-wayland-inhibit-shortcuts-dialog.h" #include "wayland/meta-wayland-inhibit-shortcuts-dialog.h"
#include "wayland/meta-wayland-inhibit-shortcuts.h" #include "wayland/meta-wayland-inhibit-shortcuts.h"
#include "wayland/meta-wayland-legacy-xdg-foreign.h" #include "wayland/meta-wayland-legacy-xdg-foreign.h"
#include "wayland/meta-wayland-linux-drm-syncobj.h"
#include "wayland/meta-wayland-outputs.h" #include "wayland/meta-wayland-outputs.h"
#include "wayland/meta-wayland-presentation-time-private.h" #include "wayland/meta-wayland-presentation-time-private.h"
#include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-private.h"
@ -58,7 +59,7 @@
#include "wayland/meta-wayland-transaction.h" #include "wayland/meta-wayland-transaction.h"
#include "wayland/meta-wayland-xdg-dialog.h" #include "wayland/meta-wayland-xdg-dialog.h"
#include "wayland/meta-wayland-xdg-foreign.h" #include "wayland/meta-wayland-xdg-foreign.h"
#include "wayland/meta-wayland-linux-drm-syncobj.h" #include "wayland/meta-wayland-xdg-session-manager.h"
#ifdef HAVE_XWAYLAND #ifdef HAVE_XWAYLAND
#include "wayland/meta-wayland-x11-interop.h" #include "wayland/meta-wayland-x11-interop.h"
@ -690,6 +691,7 @@ meta_wayland_compositor_finalize (GObject *object)
MetaBackend *backend = meta_context_get_backend (compositor->context); MetaBackend *backend = meta_context_get_backend (compositor->context);
ClutterActor *stage = meta_backend_get_stage (backend); ClutterActor *stage = meta_backend_get_stage (backend);
meta_wayland_xdg_session_management_finalize (compositor);
meta_wayland_activation_finalize (compositor); meta_wayland_activation_finalize (compositor);
meta_wayland_outputs_finalize (compositor); meta_wayland_outputs_finalize (compositor);
meta_wayland_presentation_time_finalize (compositor); meta_wayland_presentation_time_finalize (compositor);
@ -892,6 +894,7 @@ meta_wayland_compositor_new (MetaContext *context)
meta_wayland_drm_syncobj_init (compositor); meta_wayland_drm_syncobj_init (compositor);
meta_wayland_init_xdg_wm_dialog (compositor); meta_wayland_init_xdg_wm_dialog (compositor);
meta_wayland_init_color_management (compositor); meta_wayland_init_color_management (compositor);
meta_wayland_xdg_session_management_init (compositor);
#ifdef HAVE_NATIVE_BACKEND #ifdef HAVE_NATIVE_BACKEND
meta_wayland_drm_lease_manager_init (compositor); meta_wayland_drm_lease_manager_init (compositor);