Compare commits
12 Commits
wip/smcv/t
...
wip/sessio
Author | SHA1 | Date | |
---|---|---|---|
|
fbd5da7302 | ||
|
0b8a9503df | ||
|
fb1ece0b05 | ||
|
e2ff30a8dd | ||
|
a4ae4e3c64 | ||
|
2b59509ff2 | ||
|
a4ad19c934 | ||
|
f79c181c56 | ||
|
adfc69d501 | ||
|
a06c412f5f | ||
|
27894be982 | ||
|
96346f1050 |
@@ -17,11 +17,6 @@ typedef struct {
|
||||
GtkWidget *menubutton;
|
||||
GMenuModel *toolmenu;
|
||||
GtkTextBuffer *buffer;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
gboolean maximized;
|
||||
gboolean fullscreen;
|
||||
} DemoApplicationWindow;
|
||||
typedef GtkApplicationWindowClass DemoApplicationWindowClass;
|
||||
|
||||
@@ -337,6 +332,7 @@ static void
|
||||
startup (GApplication *app)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
const char *session_id;
|
||||
|
||||
G_APPLICATION_CLASS (demo_application_parent_class)->startup (app);
|
||||
|
||||
@@ -347,6 +343,17 @@ startup (GApplication *app)
|
||||
G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")));
|
||||
|
||||
g_object_unref (builder);
|
||||
|
||||
session_id = gtk_application_get_current_session_id (GTK_APPLICATION (app));
|
||||
|
||||
if (session_id)
|
||||
{
|
||||
GSettings *settings = g_settings_new ("org.gtk.Demo4.Application");
|
||||
|
||||
g_settings_set_string (settings, "session-id", session_id);
|
||||
|
||||
g_object_unref (settings);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -377,7 +384,7 @@ demo_application_init (DemoApplication *app)
|
||||
GSettings *settings;
|
||||
GAction *action;
|
||||
|
||||
settings = g_settings_new ("org.gtk.Demo4");
|
||||
settings = g_settings_new ("org.gtk.Demo4.Application");
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||
app_entries, G_N_ELEMENTS (app_entries),
|
||||
@@ -399,40 +406,11 @@ demo_application_class_init (DemoApplicationClass *class)
|
||||
app_class->activate = activate;
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_store_state (DemoApplicationWindow *win)
|
||||
{
|
||||
GSettings *settings;
|
||||
|
||||
settings = g_settings_new ("org.gtk.Demo4");
|
||||
g_settings_set (settings, "window-size", "(ii)", win->width, win->height);
|
||||
g_settings_set_boolean (settings, "maximized", win->maximized);
|
||||
g_settings_set_boolean (settings, "fullscreen", win->fullscreen);
|
||||
g_object_unref (settings);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_load_state (DemoApplicationWindow *win)
|
||||
{
|
||||
GSettings *settings;
|
||||
|
||||
settings = g_settings_new ("org.gtk.Demo4");
|
||||
g_settings_get (settings, "window-size", "(ii)", &win->width, &win->height);
|
||||
win->maximized = g_settings_get_boolean (settings, "maximized");
|
||||
win->fullscreen = g_settings_get_boolean (settings, "fullscreen");
|
||||
g_object_unref (settings);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_init (DemoApplicationWindow *window)
|
||||
{
|
||||
GtkWidget *popover;
|
||||
|
||||
window->width = -1;
|
||||
window->height = -1;
|
||||
window->maximized = FALSE;
|
||||
window->fullscreen = FALSE;
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (window));
|
||||
|
||||
popover = gtk_popover_menu_new_from_model (window->toolmenu);
|
||||
@@ -443,77 +421,11 @@ demo_application_window_init (DemoApplicationWindow *window)
|
||||
window);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_constructed (GObject *object)
|
||||
{
|
||||
DemoApplicationWindow *window = (DemoApplicationWindow *)object;
|
||||
|
||||
demo_application_window_load_state (window);
|
||||
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), window->width, window->height);
|
||||
|
||||
if (window->maximized)
|
||||
gtk_window_maximize (GTK_WINDOW (window));
|
||||
|
||||
if (window->fullscreen)
|
||||
gtk_window_fullscreen (GTK_WINDOW (window));
|
||||
|
||||
G_OBJECT_CLASS (demo_application_window_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
|
||||
|
||||
GTK_WIDGET_CLASS (demo_application_window_parent_class)->size_allocate (widget,
|
||||
width,
|
||||
height,
|
||||
baseline);
|
||||
|
||||
if (!window->maximized && !window->fullscreen)
|
||||
gtk_window_get_default_size (GTK_WINDOW (window), &window->width, &window->height);
|
||||
}
|
||||
|
||||
static void
|
||||
surface_state_changed (GtkWidget *widget)
|
||||
{
|
||||
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
|
||||
GdkToplevelState new_state;
|
||||
|
||||
new_state = gdk_toplevel_get_state (GDK_TOPLEVEL (gtk_native_get_surface (GTK_NATIVE (widget))));
|
||||
window->maximized = (new_state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0;
|
||||
window->fullscreen = (new_state & GDK_TOPLEVEL_STATE_FULLSCREEN) != 0;
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_realize (GtkWidget *widget)
|
||||
{
|
||||
GTK_WIDGET_CLASS (demo_application_window_parent_class)->realize (widget);
|
||||
|
||||
g_signal_connect_swapped (gtk_native_get_surface (GTK_NATIVE (widget)), "notify::state",
|
||||
G_CALLBACK (surface_state_changed), widget);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_unrealize (GtkWidget *widget)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (gtk_native_get_surface (GTK_NATIVE (widget)),
|
||||
surface_state_changed, widget);
|
||||
|
||||
GTK_WIDGET_CLASS (demo_application_window_parent_class)->unrealize (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_dispose (GObject *object)
|
||||
{
|
||||
DemoApplicationWindow *window = (DemoApplicationWindow *)object;
|
||||
|
||||
demo_application_window_store_state (window);
|
||||
|
||||
gtk_widget_dispose_template (GTK_WIDGET (window), demo_application_window_get_type ());
|
||||
|
||||
G_OBJECT_CLASS (demo_application_window_parent_class)->dispose (object);
|
||||
@@ -525,13 +437,8 @@ demo_application_window_class_init (DemoApplicationWindowClass *class)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->constructed = demo_application_window_constructed;
|
||||
object_class->dispose = demo_application_window_dispose;
|
||||
|
||||
widget_class->size_allocate = demo_application_window_size_allocate;
|
||||
widget_class->realize = demo_application_window_realize;
|
||||
widget_class->unrealize = demo_application_window_unrealize;
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/application_demo/application.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, message);
|
||||
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, infobar);
|
||||
@@ -548,11 +455,19 @@ int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GtkApplication *app;
|
||||
GSettings *settings;
|
||||
char *session_id;
|
||||
|
||||
app = GTK_APPLICATION (g_object_new (demo_application_get_type (),
|
||||
"application-id", "org.gtk.Demo4.App",
|
||||
"flags", G_APPLICATION_HANDLES_OPEN,
|
||||
NULL));
|
||||
|
||||
settings = g_settings_new ("org.gtk.Demo4.Application");
|
||||
session_id = g_settings_get_string (settings, "session-id");
|
||||
gtk_application_set_session_id (app, session_id);
|
||||
g_free (session_id);
|
||||
g_object_unref (settings);
|
||||
|
||||
return g_application_run (G_APPLICATION (app), 0, NULL);
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@
|
||||
<property name="default-width">200</property>
|
||||
<property name="default-height">200</property>
|
||||
<property name="icon-name">document-open</property>
|
||||
<property name="session-id">application-main</property>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<child>
|
||||
|
@@ -1140,6 +1140,19 @@ local_options (GApplication *app,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
startup (GApplication *app,
|
||||
gpointer data)
|
||||
{
|
||||
GSettings *settings = data;
|
||||
const char *session_id;
|
||||
|
||||
session_id = gtk_application_get_current_session_id (GTK_APPLICATION (app));
|
||||
|
||||
if (session_id)
|
||||
g_settings_set_string (settings, "session-id", session_id);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -1156,6 +1169,8 @@ main (int argc, char **argv)
|
||||
{ "app.about", { "F1", NULL } },
|
||||
{ "app.quit", { "<Control>q", NULL } },
|
||||
};
|
||||
GSettings *settings;
|
||||
char *session_id;
|
||||
int i;
|
||||
|
||||
app = gtk_application_new ("org.gtk.Demo4", G_APPLICATION_NON_UNIQUE|G_APPLICATION_HANDLES_COMMAND_LINE);
|
||||
@@ -1164,6 +1179,11 @@ main (int argc, char **argv)
|
||||
app_entries, G_N_ELEMENTS (app_entries),
|
||||
app);
|
||||
|
||||
settings = g_settings_new ("org.gtk.Demo4");
|
||||
session_id = g_settings_get_string (settings, "session-id");
|
||||
gtk_application_set_session_id (app, session_id);
|
||||
g_free (session_id);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (accels); i++)
|
||||
gtk_application_set_accels_for_action (app, accels[i].action_and_target, accels[i].accelerators);
|
||||
|
||||
@@ -1175,8 +1195,11 @@ main (int argc, char **argv)
|
||||
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
|
||||
g_signal_connect (app, "command-line", G_CALLBACK (command_line), NULL);
|
||||
g_signal_connect (app, "handle-local-options", G_CALLBACK (local_options), NULL);
|
||||
g_signal_connect (app, "startup", G_CALLBACK (startup), settings);
|
||||
|
||||
g_application_run (G_APPLICATION (app), argc, argv);
|
||||
|
||||
g_object_unref (settings);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@
|
||||
<object class="GtkApplicationWindow" id="window">
|
||||
<property name="default-width">800</property>
|
||||
<property name="default-height">600</property>
|
||||
<property name="session-id">main-window</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="headerbar">
|
||||
<child>
|
||||
|
@@ -2,24 +2,25 @@
|
||||
|
||||
<schemalist>
|
||||
|
||||
<enum id='org.gtk.Demo4.Color'>
|
||||
<enum id='org.gtk.Demo4.Application.Color'>
|
||||
<value nick='red' value='0'/>
|
||||
<value nick='green' value='1'/>
|
||||
<value nick='blue' value='2'/>
|
||||
</enum>
|
||||
|
||||
<schema id='org.gtk.Demo4' path='/org/gtk/Demo4/'>
|
||||
<key name='color' enum='org.gtk.Demo4.Color'>
|
||||
<key name='session-id' type='s'>
|
||||
<default>''</default>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id='org.gtk.Demo4.Application' path='/org/gtk/Demo4/Application/'>
|
||||
<key name='color' enum='org.gtk.Demo4.Application.Color'>
|
||||
<default>'red'</default>
|
||||
</key>
|
||||
<key name='window-size' type='(ii)'>
|
||||
<default>(-1, -1)</default>
|
||||
</key>
|
||||
<key name='maximized' type='b'>
|
||||
<default>false</default>
|
||||
</key>
|
||||
<key name='fullscreen' type='b'>
|
||||
<default>false</default>
|
||||
|
||||
<key name='session-id' type='s'>
|
||||
<default>''</default>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
|
@@ -30,6 +30,9 @@ endforeach
|
||||
# desktop file
|
||||
install_data('org.gtk.gtk4.NodeEditor.desktop', install_dir: gtk_applicationsdir)
|
||||
|
||||
install_data('org.gtk.NodeEditor4.gschema.xml', install_dir: gtk_schemasdir)
|
||||
gnome.compile_schemas()
|
||||
|
||||
# appdata
|
||||
configure_file(
|
||||
input: 'org.gtk.gtk4.NodeEditor.appdata.xml.in',
|
||||
|
@@ -191,6 +191,16 @@ node_editor_application_startup (GApplication *app)
|
||||
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
|
||||
const char *open_accels[2] = { "<Ctrl>O", NULL };
|
||||
GtkCssProvider *provider;
|
||||
GSettings *settings;
|
||||
gchar *session_id;
|
||||
|
||||
settings = g_settings_new ("org.gtk.NodeEditor4");
|
||||
session_id = g_settings_get_string (settings, "session-id");
|
||||
if (session_id)
|
||||
{
|
||||
gtk_application_set_session_id (GTK_APPLICATION (app), session_id);
|
||||
g_free (session_id);
|
||||
}
|
||||
|
||||
G_APPLICATION_CLASS (node_editor_application_parent_class)->startup (app);
|
||||
|
||||
@@ -207,6 +217,9 @@ node_editor_application_startup (GApplication *app)
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
g_settings_set_string (settings, "session-id",
|
||||
gtk_application_get_current_session_id (GTK_APPLICATION (app)));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -109,6 +109,7 @@
|
||||
<property name="default-width">1024</property>
|
||||
<property name="default-height">768</property>
|
||||
<property name="focus-widget">text_view</property>
|
||||
<property name="session-id">main-window</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<child type="start">
|
||||
|
11
demos/node-editor/org.gtk.NodeEditor4.gschema.xml
Normal file
11
demos/node-editor/org.gtk.NodeEditor4.gschema.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<schemalist>
|
||||
|
||||
<schema id='org.gtk.NodeEditor4' path='/org/gtk/NodeEditor4/'>
|
||||
<key name='session-id' type='s'>
|
||||
<default>''</default>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
</schemalist>
|
@@ -358,6 +358,9 @@ disable certain features.
|
||||
`color-mgmt`
|
||||
: Disable color management
|
||||
|
||||
`session-mgmt`
|
||||
: Disable session management
|
||||
|
||||
### `GDK_GL_DISABLE`
|
||||
|
||||
This variable can be set to a list of values, which cause GDK to
|
||||
|
21
gdk/gdk.c
21
gdk/gdk.c
@@ -142,16 +142,17 @@ static const GdkDebugKey gdk_debug_keys[] = {
|
||||
};
|
||||
|
||||
static const GdkDebugKey gdk_feature_keys[] = {
|
||||
{ "gl", GDK_FEATURE_OPENGL, "Disable OpenGL support" },
|
||||
{ "gl-api", GDK_FEATURE_GL_API, "Disable non-GLES GL API" },
|
||||
{ "gles-api", GDK_FEATURE_GLES_API, "Disable GLES GL API" },
|
||||
{ "egl", GDK_FEATURE_EGL, "Disable EGL" },
|
||||
{ "glx", GDK_FEATURE_GLX, "Disable GLX" },
|
||||
{ "wgl", GDK_FEATURE_WGL, "Disable WGL" },
|
||||
{ "vulkan", GDK_FEATURE_VULKAN, "Disable Vulkan support" },
|
||||
{ "dmabuf", GDK_FEATURE_DMABUF, "Disable dmabuf support" },
|
||||
{ "offload", GDK_FEATURE_OFFLOAD, "Disable graphics offload" },
|
||||
{ "color-mgmt", GDK_FEATURE_COLOR_MANAGEMENT, "Disable color management" },
|
||||
{ "gl", GDK_FEATURE_OPENGL, "Disable OpenGL support" },
|
||||
{ "gl-api", GDK_FEATURE_GL_API, "Disable non-GLES GL API" },
|
||||
{ "gles-api", GDK_FEATURE_GLES_API, "Disable GLES GL API" },
|
||||
{ "egl", GDK_FEATURE_EGL, "Disable EGL" },
|
||||
{ "glx", GDK_FEATURE_GLX, "Disable GLX" },
|
||||
{ "wgl", GDK_FEATURE_WGL, "Disable WGL" },
|
||||
{ "vulkan", GDK_FEATURE_VULKAN, "Disable Vulkan support" },
|
||||
{ "dmabuf", GDK_FEATURE_DMABUF, "Disable dmabuf support" },
|
||||
{ "offload", GDK_FEATURE_OFFLOAD, "Disable graphics offload" },
|
||||
{ "color-mgmt", GDK_FEATURE_COLOR_MANAGEMENT, "Disable color management" },
|
||||
{ "session-mgmt", GDK_FEATURE_SESSION_MANAGEMENT, "Disable session management" },
|
||||
};
|
||||
|
||||
|
||||
|
@@ -54,19 +54,20 @@ typedef enum {
|
||||
} GdkDebugFlags;
|
||||
|
||||
typedef enum {
|
||||
GDK_FEATURE_OPENGL = 1 << 0,
|
||||
GDK_FEATURE_GL_API = 1 << 1,
|
||||
GDK_FEATURE_GLES_API = 1 << 2,
|
||||
GDK_FEATURE_EGL = 1 << 3,
|
||||
GDK_FEATURE_GLX = 1 << 4,
|
||||
GDK_FEATURE_WGL = 1 << 5,
|
||||
GDK_FEATURE_VULKAN = 1 << 6,
|
||||
GDK_FEATURE_DMABUF = 1 << 7,
|
||||
GDK_FEATURE_OFFLOAD = 1 << 8,
|
||||
GDK_FEATURE_COLOR_MANAGEMENT = 1 << 9,
|
||||
GDK_FEATURE_OPENGL = 1 << 0,
|
||||
GDK_FEATURE_GL_API = 1 << 1,
|
||||
GDK_FEATURE_GLES_API = 1 << 2,
|
||||
GDK_FEATURE_EGL = 1 << 3,
|
||||
GDK_FEATURE_GLX = 1 << 4,
|
||||
GDK_FEATURE_WGL = 1 << 5,
|
||||
GDK_FEATURE_VULKAN = 1 << 6,
|
||||
GDK_FEATURE_DMABUF = 1 << 7,
|
||||
GDK_FEATURE_OFFLOAD = 1 << 8,
|
||||
GDK_FEATURE_COLOR_MANAGEMENT = 1 << 9,
|
||||
GDK_FEATURE_SESSION_MANAGEMENT = 1 << 10,
|
||||
} GdkFeatures;
|
||||
|
||||
#define GDK_ALL_FEATURES ((1 << 10) - 1)
|
||||
#define GDK_ALL_FEATURES ((1 << 11) - 1)
|
||||
|
||||
extern guint _gdk_debug_flags;
|
||||
|
||||
|
@@ -62,6 +62,7 @@
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
#include "presentation-time-client-protocol.h"
|
||||
#include "xx-color-management-v4-client-protocol.h"
|
||||
#include "xx-session-management-v1-client-protocol.h"
|
||||
|
||||
#include "wm-button-layout-translation.h"
|
||||
|
||||
@@ -101,6 +102,7 @@
|
||||
#define NO_XDG_OUTPUT_DONE_SINCE_VERSION 3
|
||||
#define OUTPUT_VERSION 3
|
||||
#define XDG_WM_DIALOG_VERSION 1
|
||||
#define XX_SESSION_MANAGEMENT_VERSION 1
|
||||
|
||||
#ifdef HAVE_TOPLEVEL_STATE_SUSPENDED
|
||||
#define XDG_WM_BASE_VERSION 6
|
||||
@@ -311,6 +313,46 @@ static const struct org_kde_kwin_server_decoration_manager_listener server_decor
|
||||
.default_mode = server_decoration_manager_default_mode
|
||||
};
|
||||
|
||||
static void
|
||||
session_listener_created (void *data,
|
||||
struct xx_session_v1 *xdg_session_v1,
|
||||
const char *id)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = data;
|
||||
|
||||
GDK_DEBUG (MISC, "session created: %s", id);
|
||||
|
||||
if (g_strcmp0 (display_wayland->session_id, id) != 0)
|
||||
{
|
||||
g_clear_pointer (&display_wayland->session_id, g_free);
|
||||
display_wayland->session_id = g_strdup (id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
session_listener_restored (void *data,
|
||||
struct xx_session_v1 *xdg_session_v1)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = data;
|
||||
|
||||
GDK_DEBUG (MISC, "session restored: %s", display_wayland->session_id);
|
||||
}
|
||||
|
||||
static void
|
||||
session_listener_replaced (void *data,
|
||||
struct xx_session_v1 *xdg_session_v1)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = data;
|
||||
|
||||
GDK_DEBUG (MISC, "session replaced: %s", display_wayland->session_id);
|
||||
}
|
||||
|
||||
static const struct xx_session_v1_listener xdg_session_listener = {
|
||||
.created = session_listener_created,
|
||||
.restored = session_listener_restored,
|
||||
.replaced = session_listener_replaced,
|
||||
};
|
||||
|
||||
/*
|
||||
* gdk_wayland_display_prefers_ssd:
|
||||
* @display: (type GdkWaylandDisplay): a `GdkDisplay`
|
||||
@@ -393,6 +435,14 @@ gdk_registry_handle_global (void *data,
|
||||
&xdg_wm_dialog_v1_interface,
|
||||
MIN (version, XDG_WM_DIALOG_VERSION));
|
||||
}
|
||||
else if (strcmp (interface, xx_session_manager_v1_interface.name) == 0 &&
|
||||
gdk_has_feature (GDK_FEATURE_SESSION_MANAGEMENT))
|
||||
{
|
||||
display_wayland->xdg_session_manager =
|
||||
wl_registry_bind (display_wayland->wl_registry, id,
|
||||
&xx_session_manager_v1_interface,
|
||||
MIN (version, XX_SESSION_MANAGEMENT_VERSION));
|
||||
}
|
||||
else if (strcmp (interface, gtk_shell1_interface.name) == 0)
|
||||
{
|
||||
display_wayland->gtk_shell =
|
||||
@@ -767,6 +817,8 @@ gdk_wayland_display_dispose (GObject *object)
|
||||
g_clear_pointer (&display_wayland->linux_dmabuf, zwp_linux_dmabuf_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->dmabuf_formats_info, dmabuf_formats_info_free);
|
||||
g_clear_pointer (&display_wayland->color, gdk_wayland_color_free);
|
||||
g_clear_pointer (&display_wayland->xdg_session, xx_session_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->xdg_session_manager, xx_session_manager_v1_destroy);
|
||||
|
||||
g_clear_pointer (&display_wayland->shm, wl_shm_destroy);
|
||||
g_clear_pointer (&display_wayland->wl_registry, wl_registry_destroy);
|
||||
@@ -2809,3 +2861,51 @@ gdk_wayland_display_dispatch_queue (GdkDisplay *display,
|
||||
_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_display_register_session (GdkDisplay *display,
|
||||
const char *name)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
|
||||
GDK_DEBUG (MISC, "register session %s", name);
|
||||
|
||||
if (!display_wayland->xdg_session_manager)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&display_wayland->session_id, g_free);
|
||||
display_wayland->session_id = g_strdup (name);
|
||||
|
||||
display_wayland->xdg_session =
|
||||
xx_session_manager_v1_get_session (display_wayland->xdg_session_manager,
|
||||
XX_SESSION_MANAGER_V1_REASON_LAUNCH,
|
||||
name);
|
||||
xx_session_v1_add_listener (display_wayland->xdg_session,
|
||||
&xdg_session_listener,
|
||||
display_wayland);
|
||||
|
||||
wl_display_roundtrip (display_wayland->wl_display);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_display_unregister_session (GdkDisplay *display)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
|
||||
if (!display_wayland->xdg_session_manager)
|
||||
return;
|
||||
|
||||
if (display_wayland->xdg_session)
|
||||
xx_session_v1_remove (display_wayland->xdg_session);
|
||||
|
||||
g_clear_pointer (&display_wayland->session_id, g_free);
|
||||
g_clear_pointer (&display_wayland->xdg_session, xx_session_v1_destroy);
|
||||
}
|
||||
|
||||
const char *
|
||||
gdk_wayland_display_get_current_session_id (GdkDisplay *display)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
|
||||
return display_wayland->session_id;
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@
|
||||
#include <gdk/wayland/presentation-time-client-protocol.h>
|
||||
#include <gdk/wayland/single-pixel-buffer-v1-client-protocol.h>
|
||||
#include <gdk/wayland/xdg-dialog-v1-client-protocol.h>
|
||||
#include <gdk/wayland/xx-session-management-v1-client-protocol.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gdk/gdkkeys.h>
|
||||
@@ -124,6 +125,8 @@ struct _GdkWaylandDisplay
|
||||
struct wp_viewporter *viewporter;
|
||||
struct wp_presentation *presentation;
|
||||
struct wp_single_pixel_buffer_manager_v1 *single_pixel_buffer;
|
||||
struct xx_session_manager_v1 *xdg_session_manager;
|
||||
struct xx_session_v1 *xdg_session;
|
||||
GdkWaylandColor *color;
|
||||
|
||||
GList *async_roundtrips;
|
||||
@@ -153,6 +156,8 @@ struct _GdkWaylandDisplay
|
||||
|
||||
GListStore *monitors;
|
||||
|
||||
char *session_id;
|
||||
|
||||
gint64 last_bell_time_ms;
|
||||
};
|
||||
|
||||
|
@@ -38,6 +38,7 @@
|
||||
#include <wayland/xdg-shell-unstable-v6-client-protocol.h>
|
||||
#include <wayland/xdg-foreign-unstable-v2-client-protocol.h>
|
||||
#include <wayland/xdg-dialog-v1-client-protocol.h>
|
||||
#include <wayland/xx-session-management-v1-client-protocol.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -126,6 +127,7 @@ struct _GdkWaylandToplevel
|
||||
struct wl_output *initial_fullscreen_output;
|
||||
|
||||
struct wp_presentation_feedback *feedback;
|
||||
struct xx_toplevel_session_v1 *toplevel_session;
|
||||
|
||||
struct {
|
||||
GdkToplevelState unset_flags;
|
||||
@@ -142,6 +144,7 @@ struct _GdkWaylandToplevel
|
||||
|
||||
char *title;
|
||||
gboolean decorated;
|
||||
char *session_id;
|
||||
|
||||
GdkGeometry geometry_hints;
|
||||
GdkSurfaceHints geometry_mask;
|
||||
@@ -819,6 +822,23 @@ create_zxdg_toplevel_v6_resources (GdkWaylandToplevel *toplevel)
|
||||
toplevel);
|
||||
}
|
||||
|
||||
static void
|
||||
attempt_restore_toplevel (GdkWaylandToplevel *wayland_toplevel)
|
||||
{
|
||||
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (wayland_toplevel));
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
|
||||
if (display_wayland->xdg_session &&
|
||||
wayland_toplevel->session_id &&
|
||||
wayland_toplevel->display_server.xdg_toplevel)
|
||||
{
|
||||
wayland_toplevel->toplevel_session =
|
||||
xx_session_v1_restore_toplevel (display_wayland->xdg_session,
|
||||
wayland_toplevel->display_server.xdg_toplevel,
|
||||
wayland_toplevel->session_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_create_xdg_toplevel (GdkWaylandToplevel *wayland_toplevel)
|
||||
{
|
||||
@@ -885,6 +905,8 @@ gdk_wayland_surface_create_xdg_toplevel (GdkWaylandToplevel *wayland_toplevel)
|
||||
if (!maybe_set_xdg_dialog_modal (wayland_toplevel))
|
||||
maybe_set_gtk_surface_modal (wayland_toplevel);
|
||||
|
||||
attempt_restore_toplevel (wayland_toplevel);
|
||||
|
||||
gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "Wayland surface commit", NULL);
|
||||
wl_surface_commit (wayland_surface->display_server.wl_surface);
|
||||
}
|
||||
@@ -1409,6 +1431,9 @@ gdk_wayland_toplevel_finalize (GObject *object)
|
||||
g_free (self->application.application_object_path);
|
||||
g_free (self->application.unique_bus_name);
|
||||
|
||||
g_free (self->session_id);
|
||||
g_clear_pointer (&self->toplevel_session, xx_toplevel_session_v1_destroy);
|
||||
|
||||
g_free (self->title);
|
||||
g_clear_pointer (&self->shortcuts_inhibitors, g_hash_table_unref);
|
||||
|
||||
@@ -2764,5 +2789,45 @@ gdk_wayland_toplevel_set_transient_for_exported (GdkToplevel *toplevel,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_toplevel_set_session_id (GdkToplevel *toplevel,
|
||||
const char *session_id)
|
||||
{
|
||||
GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
|
||||
g_clear_pointer (&wayland_toplevel->session_id, g_free);
|
||||
wayland_toplevel->session_id = g_strdup (session_id);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_toplevel_restore_from_session (GdkToplevel *toplevel)
|
||||
{
|
||||
GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel));
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
|
||||
if (display_wayland->xdg_session && wayland_toplevel->display_server.xdg_toplevel)
|
||||
{
|
||||
wayland_toplevel->toplevel_session =
|
||||
xx_session_v1_restore_toplevel (display_wayland->xdg_session,
|
||||
wayland_toplevel->display_server.xdg_toplevel,
|
||||
wayland_toplevel->session_id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_toplevel_remove_from_session (GdkToplevel *toplevel)
|
||||
{
|
||||
GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
|
||||
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel));
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
|
||||
if (display_wayland->xdg_session && wayland_toplevel->toplevel_session)
|
||||
{
|
||||
xx_toplevel_session_v1_remove (wayland_toplevel->toplevel_session);
|
||||
wayland_toplevel->toplevel_session = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* vim:set foldmethod=marker expandtab: */
|
||||
|
@@ -65,5 +65,12 @@ gboolean gdk_wayland_display_query_registry (GdkDisplay *di
|
||||
GDK_AVAILABLE_IN_4_4
|
||||
gpointer gdk_wayland_display_get_egl_display (GdkDisplay *display);
|
||||
|
||||
void gdk_wayland_display_register_session (GdkDisplay *display,
|
||||
const char *name);
|
||||
|
||||
void gdk_wayland_display_unregister_session (GdkDisplay *display);
|
||||
|
||||
const char * gdk_wayland_display_get_current_session_id (GdkDisplay *display);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@@ -67,4 +67,11 @@ GDK_AVAILABLE_IN_ALL
|
||||
void gdk_wayland_toplevel_set_application_id (GdkToplevel *toplevel,
|
||||
const char *application_id);
|
||||
|
||||
void gdk_wayland_toplevel_set_session_id (GdkToplevel *toplevel,
|
||||
const char *session_id);
|
||||
|
||||
void gdk_wayland_toplevel_restore_from_session (GdkToplevel *toplevel);
|
||||
|
||||
void gdk_wayland_toplevel_remove_from_session (GdkToplevel *toplevel);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -151,6 +151,11 @@ proto_sources = [
|
||||
'stability': 'private',
|
||||
'version': 4,
|
||||
},
|
||||
{
|
||||
'name': 'xx-session-management',
|
||||
'stability': 'private',
|
||||
'version': 1,
|
||||
},
|
||||
]
|
||||
|
||||
gdk_wayland_gen_headers = []
|
||||
|
264
gdk/wayland/protocol/xx-session-management-v1.xml
Normal file
264
gdk/wayland/protocol/xx-session-management-v1.xml
Normal file
@@ -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 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.
|
||||
</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>
|
@@ -77,6 +77,7 @@ gtk_application_impl_wayland_handle_window_realize (GtkApplicationImpl *impl,
|
||||
GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
|
||||
GdkSurface *gdk_surface;
|
||||
char *window_path;
|
||||
const char *session_id;
|
||||
|
||||
gdk_surface = gtk_native_get_surface (GTK_NATIVE (window));
|
||||
|
||||
@@ -95,6 +96,14 @@ gtk_application_impl_wayland_handle_window_realize (GtkApplicationImpl *impl,
|
||||
|
||||
g_free (window_path);
|
||||
|
||||
session_id = gtk_window_get_session_id (window);
|
||||
if (session_id)
|
||||
{
|
||||
gdk_wayland_toplevel_set_session_id (GDK_TOPLEVEL (gdk_surface),
|
||||
session_id);
|
||||
gdk_wayland_toplevel_restore_from_session (GDK_TOPLEVEL (gdk_surface));
|
||||
}
|
||||
|
||||
impl_class->handle_window_realize (impl, window);
|
||||
}
|
||||
|
||||
@@ -178,6 +187,38 @@ gtk_application_impl_wayland_uninhibit (GtkApplicationImpl *impl,
|
||||
g_warning ("Invalid inhibitor cookie");
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_application_impl_wayland_startup (GtkApplicationImpl *impl,
|
||||
gboolean register_session)
|
||||
{
|
||||
const char *session_id;
|
||||
|
||||
GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class)->startup (impl, register_session);
|
||||
|
||||
/* Note: This is independent of the register_session argument */
|
||||
session_id = gtk_application_get_session_id (impl->application);
|
||||
gdk_wayland_display_register_session (gdk_display_get_default (), session_id);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_application_impl_wayland_window_removed (GtkApplicationImpl *impl,
|
||||
GtkWindow *window)
|
||||
{
|
||||
GdkSurface *gdk_surface;
|
||||
|
||||
if (!gtk_window_get_hide_on_close (window))
|
||||
{
|
||||
gdk_surface = gtk_native_get_surface (GTK_NATIVE (window));
|
||||
gdk_wayland_toplevel_remove_from_session (GDK_TOPLEVEL (gdk_surface));
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
gtk_application_impl_wayland_get_current_session_id (GtkApplicationImpl *impl)
|
||||
{
|
||||
return gdk_wayland_display_get_current_session_id (gdk_display_get_default ());
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_application_impl_wayland_init (GtkApplicationImplWayland *wayland)
|
||||
{
|
||||
@@ -191,6 +232,8 @@ gtk_application_impl_wayland_class_init (GtkApplicationImplWaylandClass *class)
|
||||
class->dbus_inhibit = impl_class->inhibit;
|
||||
class->dbus_uninhibit = impl_class->uninhibit;
|
||||
|
||||
impl_class->startup =
|
||||
gtk_application_impl_wayland_startup;
|
||||
impl_class->handle_window_realize =
|
||||
gtk_application_impl_wayland_handle_window_realize;
|
||||
impl_class->before_emit =
|
||||
@@ -199,4 +242,8 @@ gtk_application_impl_wayland_class_init (GtkApplicationImplWaylandClass *class)
|
||||
gtk_application_impl_wayland_inhibit;
|
||||
impl_class->uninhibit =
|
||||
gtk_application_impl_wayland_uninhibit;
|
||||
impl_class->window_removed =
|
||||
gtk_application_impl_wayland_window_removed;
|
||||
impl_class->get_current_session_id =
|
||||
gtk_application_impl_wayland_get_current_session_id;
|
||||
}
|
||||
|
@@ -106,6 +106,34 @@
|
||||
* inform the user about the negative consequences of ending the
|
||||
* session while inhibitors are present.
|
||||
*
|
||||
* ## Restoring window state
|
||||
*
|
||||
* In windowing environments that support it, `GtkApplication` supports
|
||||
* restoring window state (this is up to the environment, but typically
|
||||
* includes the position, size, and states such as maximized or fullscreen).
|
||||
*
|
||||
* In order to restore state from a previous execution, the application needs
|
||||
* to specify a session identifier through [method@Gtk.Application.set_session_id]
|
||||
* obtained from a previous session. In order to start a new session, %NULL
|
||||
* should be used.
|
||||
*
|
||||
* The session will be registered during [signal@Gio.Application.startup],
|
||||
* at which point [method@Gtk.Application.get_current_session_id] will return
|
||||
* the session identifier for the current session. This is the session identifier
|
||||
* that needs to be preserved for future runs. If the session is being restored
|
||||
* from a prior run, this identifier will match the one given through
|
||||
* [method@Gtk.Application.set_session_id], otherwise it will be a new identifier.
|
||||
*
|
||||
* Individual windows are identified through [method@Gtk.Window.set_session_id],
|
||||
* so application toplevel windows can be matched with the previously saved
|
||||
* session state. Windows that whose state was saved will be restored to their
|
||||
* previous position when mapped.
|
||||
*
|
||||
* The window state is saved automatically in the background, thus no explicit
|
||||
* save() call is necessary. Other state, such as the active tab in a notebook
|
||||
* or scroll positions, is not preserved automatically and needs to be saved by
|
||||
* the application, if that is desired.
|
||||
*
|
||||
* ## See Also
|
||||
*
|
||||
* - [Using GtkApplication](https://developer.gnome.org/documentation/tutorials/application.html)
|
||||
@@ -127,6 +155,7 @@ enum {
|
||||
PROP_SCREENSAVER_ACTIVE,
|
||||
PROP_MENUBAR,
|
||||
PROP_ACTIVE_WINDOW,
|
||||
PROP_SESSION_ID,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
@@ -147,6 +176,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 +480,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 +509,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 +673,21 @@ 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.
|
||||
*
|
||||
* This property should be set to the ID of a previously saved session
|
||||
* before ::startup (if available).
|
||||
*
|
||||
* 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 +1276,102 @@ 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.
|
||||
*
|
||||
* Since: 4.16
|
||||
*/
|
||||
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
|
||||
*
|
||||
* Since: 4.16
|
||||
*/
|
||||
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
|
||||
*
|
||||
* Since: 4.16
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -284,6 +284,8 @@ typedef struct
|
||||
|
||||
GdkCursor *resize_cursor;
|
||||
|
||||
char *session_id;
|
||||
|
||||
GtkEventController *menubar_controller;
|
||||
} GtkWindowPrivate;
|
||||
|
||||
@@ -333,6 +335,8 @@ enum {
|
||||
PROP_MAXIMIZED,
|
||||
PROP_FULLSCREENED,
|
||||
|
||||
PROP_SESSION_ID,
|
||||
|
||||
LAST_ARG
|
||||
};
|
||||
|
||||
@@ -1076,6 +1080,24 @@ gtk_window_class_init (GtkWindowClass *klass)
|
||||
TRUE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkWindow:session-id: (attributes org.gtk.Property.get=gtk_window_get_session_id org.gtk.Property.set=gtk_window_set_session_id)
|
||||
*
|
||||
* The identifier of this toplevel in the session.
|
||||
*
|
||||
* In windowing environments that allow it, this identifier will be
|
||||
* used to identify windows in a persistent manner across runs, and
|
||||
* restore window state (e.g. position, size) for them.
|
||||
*
|
||||
* Currently, this is only implemented for the Wayland backend.
|
||||
*
|
||||
* Since: 4.16
|
||||
*/
|
||||
window_props[PROP_SESSION_ID] =
|
||||
g_param_spec_string ("session-id", NULL, NULL,
|
||||
NULL,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, LAST_ARG, window_props);
|
||||
|
||||
/**
|
||||
@@ -1895,6 +1917,9 @@ gtk_window_set_property (GObject *object,
|
||||
case PROP_HANDLE_MENUBAR_ACCEL:
|
||||
gtk_window_set_handle_menubar_accel (window, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_SESSION_ID:
|
||||
gtk_window_set_session_id (window, g_value_get_string (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -1984,6 +2009,9 @@ gtk_window_get_property (GObject *object,
|
||||
case PROP_HANDLE_MENUBAR_ACCEL:
|
||||
g_value_set_boolean (value, gtk_window_get_handle_menubar_accel (window));
|
||||
break;
|
||||
case PROP_SESSION_ID:
|
||||
g_value_set_string (value, gtk_window_get_session_id (window));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -6987,3 +7015,52 @@ gtk_window_get_handle_menubar_accel (GtkWindow *window)
|
||||
|
||||
return phase == GTK_PHASE_CAPTURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_window_set_session_id:
|
||||
* @window: a `GtkWindow`
|
||||
* @session_id: (nullable): A persistent identifier for this window
|
||||
*
|
||||
* Sets the identifier to be used for session management purposes.
|
||||
*
|
||||
* State of this window may be restored from prior executions, by using this
|
||||
* identifier to match the related state. This identifier should be constant,
|
||||
* or at least stable between executions, and unique among the windows of the
|
||||
* application.
|
||||
*
|
||||
* Different backends may have different requirements for this string, therefore
|
||||
* it is best to be conservative and keep the string relatively short and stick
|
||||
* to ASCII without leading or trailing whitespace.
|
||||
*
|
||||
* Since: 4.16
|
||||
**/
|
||||
void
|
||||
gtk_window_set_session_id (GtkWindow *window,
|
||||
const char *session_id)
|
||||
{
|
||||
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
|
||||
|
||||
if (g_set_str (&priv->session_id, session_id))
|
||||
g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_SESSION_ID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_window_get_session_id:
|
||||
* @window: a `GtkWindow`
|
||||
*
|
||||
* Gets the window identifier to be used for session management purposes.
|
||||
*
|
||||
* See [method@Gtk.Window.set_session_id] for more details about window
|
||||
* identifiers for session management.
|
||||
*
|
||||
* Returns: (nullable): the session identifier
|
||||
*
|
||||
* Since: 4.16
|
||||
*/
|
||||
const char *
|
||||
gtk_window_get_session_id (GtkWindow *window)
|
||||
{
|
||||
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
|
||||
|
||||
return priv->session_id;
|
||||
}
|
||||
|
@@ -259,6 +259,13 @@ void gtk_window_set_handle_menubar_accel (GtkWindow *window,
|
||||
GDK_AVAILABLE_IN_4_2
|
||||
gboolean gtk_window_get_handle_menubar_accel (GtkWindow *window);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
void gtk_window_set_session_id (GtkWindow *window,
|
||||
const char *session_id);
|
||||
|
||||
GDK_AVAILABLE_IN_4_16
|
||||
const char * gtk_window_get_session_id (GtkWindow *window);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkWindow, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkWindowGroup, g_object_unref)
|
||||
|
||||
|
@@ -700,6 +700,7 @@ add_wayland_protocols (GdkDisplay *display,
|
||||
append_wayland_protocol_row (gen, (struct wl_proxy *)d->single_pixel_buffer);
|
||||
if (d->color)
|
||||
append_wayland_protocol_row (gen, gdk_wayland_color_get_color_manager (d->color));
|
||||
append_wayland_protocol_row (gen, (struct wl_proxy *)d->xdg_session_manager);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user