From a4ad19c934be3c9f883ab7a2cfb7f6bd1723f0f2 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 19 Jun 2024 14:00:37 +0200 Subject: [PATCH] gtk: Add GtkApplication property for session IDs This API has two "phases": - An initialization call, calling gtk_application_set_session_id() to set a session identifier from previous runs. - A post-initialization call, to retrieve the session identifier in use for this session. This may be the same identifier than previously specified, if the session could be recovered, or a brand new one if the session is created from scratch. The storage of this session identifier is left up to the applications, and could be material for later GNOME session integration with persistent save states. --- gtk/gtkapplication.c | 114 ++++++++++++++++++++++++++++++++++++ gtk/gtkapplication.h | 10 ++++ gtk/gtkapplicationimpl.c | 9 +++ gtk/gtkapplicationprivate.h | 4 +- 4 files changed, 136 insertions(+), 1 deletion(-) diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c index 4d81ef56db..94cff8f29a 100644 --- a/gtk/gtkapplication.c +++ b/gtk/gtkapplication.c @@ -127,6 +127,7 @@ enum { PROP_SCREENSAVER_ACTIVE, PROP_MENUBAR, PROP_ACTIVE_WINDOW, + PROP_SESSION_ID, NUM_PROPERTIES }; @@ -147,6 +148,7 @@ typedef struct GtkActionMuxer *muxer; GtkBuilder *menus_builder; char *help_overlay_path; + char *session_id; } GtkApplicationPrivate; G_DEFINE_TYPE_WITH_PRIVATE (GtkApplication, gtk_application, G_TYPE_APPLICATION) @@ -450,6 +452,10 @@ gtk_application_get_property (GObject *object, g_value_set_object (value, gtk_application_get_active_window (application)); break; + case PROP_SESSION_ID: + g_value_set_string (value, gtk_application_get_session_id (application)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -475,6 +481,10 @@ gtk_application_set_property (GObject *object, gtk_application_set_menubar (application, g_value_get_object (value)); break; + case PROP_SESSION_ID: + gtk_application_set_session_id (application, g_value_get_string (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -635,6 +645,18 @@ gtk_application_class_init (GtkApplicationClass *class) GTK_TYPE_WINDOW, G_PARAM_READABLE|G_PARAM_STATIC_STRINGS); + /** + * GtkApplication:session-id: (attributes org.gtk.Property.get=gtk_application_get_session_id org.gtk.Property.set=gtk_application_set_session_id) + * + * The identifier of the session used to restore window state. + * + * Since: 4.16 + */ + gtk_application_props[PROP_SESSION_ID] = + g_param_spec_string ("session-id", NULL, NULL, + NULL, + G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, NUM_PROPERTIES, gtk_application_props); } @@ -1223,3 +1245,95 @@ gtk_application_set_screensaver_active (GtkApplication *application, g_object_notify (G_OBJECT (application), "screensaver-active"); } } + +/** + * gtk_application_set_session_id: + * @application: a `GtkApplication` + * @session_id: (nullable): The identifier used for session management purposes + * + * Sets the identifier used for session management purposes. + * + * This identifier would have been typically retrieved in prior runs + * through [method@Gtk.Application.get_current_session_id]. + * + * This session identifier must be set before `GApplication::startup` happens, + * as it will be applied there. In the case %NULL was passed, or the request + * resulted in a new session being created from scratch, + * [method@Gtk.Application.get_current_session_id] may return a different + * identifier than the one passed here. + **/ +void +gtk_application_set_session_id (GtkApplication *application, + const char *session_id) +{ + GtkApplicationPrivate *priv = + gtk_application_get_instance_private (application); + + g_return_if_fail (GTK_IS_APPLICATION (application)); + + if (g_set_str (&priv->session_id, session_id)) + g_object_notify (G_OBJECT (application), "session-id"); +} + +/** + * gtk_application_get_session_id: + * @application: a `GtkApplication` + * + * Gets the session identifier that this `GtkApplication` will use + * for session management registration. + * + * See [method@Gtk.Application.set_session_id] for more information about + * session management. + * + * Returns: (nullable): The session management ID + **/ +const char * +gtk_application_get_session_id (GtkApplication *application) +{ + GtkApplicationPrivate *priv = + gtk_application_get_instance_private (application); + + return priv->session_id; +} + +/** + * gtk_application_get_current_session_id: + * @application: a `GtkApplication` + * + * Retrieves the session management identifier that the application + * is using during execution. + * + * This identifier may be saved for future executions of the application + * to have their window state recovered. + * + * This function may be used during or after [signal@Gio.Application.startup] + * to retrieve a session identifier string in environments where session + * management is supported. + * + * In order to restore window state in future runs of the same application, + * this string should be stored, so it can be passed through + * [method@Gtk.Application.set_session_id] in these future executions. + * + * Note that this identifier may end up being different from the one + * initially specified through [method@Gtk.Application.set_session_id], + * e.g. in the case the specified session ID could not be recovered and a + * new session was created. + * + * If called on an environment/backend that does not support session + * management, or prior to application startup, this method will return `NULL`. + * + * Currently, session management is only supported in the Wayland backend. + * + * Returns: (nullable): The session identifier to preserve for future runs + **/ +const char * +gtk_application_get_current_session_id (GtkApplication *application) +{ + GtkApplicationPrivate *priv = + gtk_application_get_instance_private (application); + + if (!priv->impl) + return NULL; + + return gtk_application_impl_get_current_session_id (priv->impl); +} diff --git a/gtk/gtkapplication.h b/gtk/gtkapplication.h index 7260de6dc7..0ca9bd2d05 100644 --- a/gtk/gtkapplication.h +++ b/gtk/gtkapplication.h @@ -134,6 +134,16 @@ GDK_AVAILABLE_IN_ALL GMenu * gtk_application_get_menu_by_id (GtkApplication *application, const char *id); +GDK_AVAILABLE_IN_4_16 +void gtk_application_set_session_id (GtkApplication *application, + const char *session_id); + +GDK_AVAILABLE_IN_4_16 +const char * gtk_application_get_session_id (GtkApplication *application); + +GDK_AVAILABLE_IN_4_16 +const char * gtk_application_get_current_session_id (GtkApplication *application); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkApplication, g_object_unref) G_END_DECLS diff --git a/gtk/gtkapplicationimpl.c b/gtk/gtkapplicationimpl.c index 6948fa11e0..1403625a3e 100644 --- a/gtk/gtkapplicationimpl.c +++ b/gtk/gtkapplicationimpl.c @@ -153,6 +153,15 @@ gtk_application_impl_prefers_app_menu (GtkApplicationImpl *impl) return GTK_APPLICATION_IMPL_GET_CLASS (impl)->prefers_app_menu (impl); } +const char * +gtk_application_impl_get_current_session_id (GtkApplicationImpl *impl) +{ + if (!GTK_APPLICATION_IMPL_GET_CLASS (impl)->get_current_session_id) + return NULL; + + return GTK_APPLICATION_IMPL_GET_CLASS (impl)->get_current_session_id (impl); +} + GtkApplicationImpl * gtk_application_impl_new (GtkApplication *application, GdkDisplay *display) diff --git a/gtk/gtkapplicationprivate.h b/gtk/gtkapplicationprivate.h index a6c56c89df..246ab8d654 100644 --- a/gtk/gtkapplicationprivate.h +++ b/gtk/gtkapplicationprivate.h @@ -100,7 +100,7 @@ typedef struct gboolean (* prefers_app_menu) (GtkApplicationImpl *impl); - + const char * (* get_current_session_id) (GtkApplicationImpl *impl); } GtkApplicationImplClass; #define GTK_TYPE_APPLICATION_IMPL_DBUS (gtk_application_impl_dbus_get_type ()) @@ -195,5 +195,7 @@ gboolean gtk_application_impl_prefers_app_menu (GtkAppl void gtk_application_impl_quartz_setup_menu (GMenuModel *model, GtkActionMuxer *muxer); +const char * gtk_application_impl_get_current_session_id (GtkApplicationImpl *impl); + G_END_DECLS