/*
* Copyright © 2010 Codethink Limited
* Copyright © 2013 Canonical Limited
* Copyright © 2020 Emmanuel Gil Peyrot
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2 of the licence , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see < http : //www.gnu.org/licenses/>.
*
* Author : Ryan Lortie < desrt @ desrt . ca >
*/
#include "config.h"
#include "gtkapplicationprivate.h"
#include "gtkapplicationwindowprivate.h"
#include "gtknative.h"
#include "gtkprivate.h"
#include <gdk/wayland/gdkwayland.h>
#include <gdk/wayland/gdktoplevel-wayland-private .h>
#include <gdk/wayland/gdkdisplay-wayland.h>
#include "a11y/gtkatspicontextprivate.h"
#include "gtkatcontextprivate.h"
typedef struct
{
GtkApplicationImplDBusClass parent_class;
} GtkApplicationImplWaylandClass;
typedef struct
{
guint cookie;
guint dbus_cookie;
GtkApplicationInhibitFlags flags;
GdkSurface *surface;
} GtkApplicationWaylandInhibitor;
static void
gtk_application_wayland_inhibitor_free (GtkApplicationWaylandInhibitor *inhibitor)
{
g_free (inhibitor);
}
typedef struct
{
GtkApplicationImplDBus dbus;
GSList *inhibitors;
guint next_cookie;
gboolean session_mgmt_supported;
} GtkApplicationImplWayland;
G_DEFINE_TYPE (GtkApplicationImplWayland, gtk_application_impl_wayland, GTK_TYPE_APPLICATION_IMPL_DBUS)
static void
restore_wayland_fallback_state (GtkWindow *window,
GVariant *state)
{
int width, height;
gboolean is_maximized = FALSE ;
gboolean is_fullscreen = FALSE ;
GTK_DEBUG (SESSION, "No Wayland session management state found! Restoring fallback state" );
if (g_variant_lookup (state, "size" , "(ii)" , &width, &height))
gtk_window_set_default_size (window, width, height);
g_variant_lookup (state, "is-maximized" , "b" , &is_maximized);
g_variant_lookup (state, "is-fullscreen" , "b" , &is_fullscreen);
g_object_set (window,
"maximized" , is_maximized,
"fullscreened" , is_fullscreen,
NULL);
}
static void
set_a11y_properties (GtkWindow *window)
{
GdkSurface *gdk_surface;
GtkATContext *at_context;
gdk_surface = gtk_native_get_surface (GTK_NATIVE (window));
at_context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (window));
if (GTK_IS_AT_SPI_CONTEXT (at_context))
{
const char *dbus_name = NULL, *object_path = NULL;
GVariant *ref_data;
gtk_at_context_realize (at_context);
ref_data = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (at_context));
g_variant_get (ref_data, "(&s&o)" , &dbus_name, &object_path);
gdk_wayland_toplevel_set_a11y_properties (GDK_TOPLEVEL (gdk_surface),
dbus_name, object_path);
g_variant_unref (ref_data);
}
g_clear_object (&at_context);
}
static void
gtk_application_impl_wayland_handle_window_realize (GtkApplicationImpl *impl,
GtkWindow *window)
{
GtkApplicationImplClass *impl_class =
GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class);
GtkApplicationImplDBus *dbus = (GtkApplicationImplDBus *) impl;
GdkSurface *gdk_surface;
char *window_path;
GVariant *state;
char *id = NULL;
GtkATContext *at_context = NULL;
GTK_DEBUG (SESSION, "Handle window realize" );
gdk_surface = gtk_native_get_surface (GTK_NATIVE (window));
if (!GDK_IS_WAYLAND_TOPLEVEL (gdk_surface))
return ;
window_path = gtk_application_impl_dbus_get_window_path (dbus, window);
gdk_wayland_toplevel_set_dbus_properties (GDK_TOPLEVEL (gdk_surface),
dbus->application_id,
dbus->app_menu_path,
dbus->menubar_path,
window_path,
dbus->object_path,
dbus->unique_name);
g_free (window_path);
state = gtk_application_impl_dbus_get_window_state (dbus, window);
if (state)
{
if (g_variant_lookup (state, "session-id" , "s" , &id))
GTK_DEBUG (SESSION, "Found saved session ID %s" , id);
else
restore_wayland_fallback_state (window, state);
}
if (!id)
{
id = g_uuid_string_random ();
GTK_DEBUG (SESSION, "No saved session ID, using %s" , id);
}
GTK_DEBUG (SESSION, "Set Wayland toplevel session ID: %s" , id);
gdk_wayland_toplevel_set_session_id (GDK_TOPLEVEL (gdk_surface), id);
gdk_wayland_toplevel_restore_from_session (GDK_TOPLEVEL (gdk_surface));
g_free (id);
at_context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (window));
if (at_context)
{
if (gtk_at_context_is_realized (at_context))
set_a11y_properties (window);
else
g_signal_connect_object (at_context, "notify::realized" , (GCallback) set_a11y_properties, window, G_CONNECT_SWAPPED);
g_clear_object (&at_context);
}
impl_class->handle_window_realize (impl, window);
}
static void
gtk_application_impl_wayland_before_emit (GtkApplicationImpl *impl,
GVariant *platform_data)
{
const char *startup_notification_id = NULL;
g_variant_lookup (platform_data, "activation-token" , "&s" , &startup_notification_id);
if (!startup_notification_id)
g_variant_lookup (platform_data, "desktop-startup-id" , "&s" , &startup_notification_id);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gdk_wayland_display_set_startup_notification_id (gdk_display_get_default (), startup_notification_id);
G_GNUC_END_IGNORE_DEPRECATIONS
}
static void
gtk_application_impl_wayland_window_removed (GtkApplicationImpl *impl,
GtkWindow *window)
{
GtkApplicationImplWayland *wayland = (GtkApplicationImplWayland *) impl;
GSList *iter = wayland->inhibitors;
GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class)->window_removed (impl, window);
while (iter)
{
GtkApplicationWaylandInhibitor *inhibitor = iter->data;
GSList *next = iter->next;
if (inhibitor->surface && inhibitor->surface == gtk_native_get_surface (GTK_NATIVE (window)))
{
inhibitor->surface = NULL;
if (!inhibitor->dbus_cookie)
{
gtk_application_wayland_inhibitor_free (inhibitor);
wayland->inhibitors = g_slist_delete_link (wayland->inhibitors, iter);
}
}
iter = next;
}
}
static void
gtk_application_impl_wayland_window_forget (GtkApplicationImpl *impl,
GtkWindow *window)
{
GdkSurface *surface;
GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class)->window_forget (impl, window);
surface = gtk_native_get_surface (GTK_NATIVE (window));
if (GDK_IS_WAYLAND_TOPLEVEL (surface))
{
GTK_DEBUG (SESSION, "Forgetting saved toplevel: %s" ,
gdk_wayland_toplevel_get_session_id (GDK_TOPLEVEL (surface)));
gdk_wayland_toplevel_remove_from_session (GDK_TOPLEVEL (surface));
}
}
static void
gtk_application_impl_wayland_window_forget_by_state (GtkApplicationImpl *impl,
GVariant *state)
{
GdkDisplay *display = gdk_display_get_default ();
char *id = NULL;
GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class)->window_forget_by_state (impl, state);
if (g_variant_lookup (state, "session-id" , "&s" , &id))
{
GTK_DEBUG (SESSION, "Forgetting saved toplevel (by ID): %s" , id);
gdk_wayland_display_remove_session_toplevel (display, id);
}
}
static void
gtk_application_impl_wayland_window_unforget (GtkApplicationImpl *impl,
GtkWindow *window)
{
GdkSurface *surface;
GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class)->window_unforget (impl, window);
surface = gtk_native_get_surface (GTK_NATIVE (window));
GTK_DEBUG (SESSION, "Adding toplevel back to session: %s" ,
gdk_wayland_toplevel_get_session_id (GDK_TOPLEVEL (surface)));
gdk_wayland_toplevel_ensure_in_session (GDK_TOPLEVEL (surface));
}
static guint
gtk_application_impl_wayland_inhibit (GtkApplicationImpl *impl,
GtkWindow *window,
GtkApplicationInhibitFlags flags,
const char *reason)
{
GtkApplicationImplWayland *wayland = (GtkApplicationImplWayland *) impl;
GdkSurface *surface;
GtkApplicationWaylandInhibitor *inhibitor;
gboolean success;
if (!flags)
return 0 ;
inhibitor = g_new0 (GtkApplicationWaylandInhibitor, 1 );
inhibitor->cookie = ++wayland->next_cookie;
inhibitor->flags = flags;
wayland->inhibitors = g_slist_prepend (wayland->inhibitors, inhibitor);
if (flags & GTK_APPLICATION_INHIBIT_IDLE && window && impl->application == gtk_window_get_application (window))
{
surface = gtk_native_get_surface (GTK_NATIVE (window));
if (GDK_IS_WAYLAND_TOPLEVEL (surface))
{
success = gdk_wayland_toplevel_inhibit_idle (GDK_TOPLEVEL (surface));
if (success)
{
flags &= ~GTK_APPLICATION_INHIBIT_IDLE;
inhibitor->surface = surface;
}
}
}
if (flags)
inhibitor->dbus_cookie = GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class)->inhibit (impl, window, flags, reason);
return inhibitor->cookie;
}
static void
gtk_application_impl_wayland_uninhibit (GtkApplicationImpl *impl,
guint cookie)
{
GtkApplicationImplWayland *wayland = (GtkApplicationImplWayland *) impl;
GSList *iter;
for (iter = wayland->inhibitors; iter; iter = iter->next)
{
GtkApplicationWaylandInhibitor *inhibitor = iter->data;
if (inhibitor->cookie == cookie)
{
if (inhibitor->dbus_cookie)
GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class)->uninhibit (impl, inhibitor->dbus_cookie);
if (inhibitor->surface)
gdk_wayland_toplevel_uninhibit_idle (GDK_TOPLEVEL (inhibitor->surface));
gtk_application_wayland_inhibitor_free (inhibitor);
wayland->inhibitors = g_slist_delete_link (wayland->inhibitors, iter);
return ;
}
}
g_warning ("Invalid inhibitor cookie" );
}
static void
gtk_application_impl_wayland_startup (GtkApplicationImpl *impl,
gboolean support_save)
{
GtkApplicationImplWayland *wayland = (GtkApplicationImplWayland *) impl;
GdkDisplay *display = gdk_display_get_default ();
enum xdg_session_manager_v1_reason wl_reason;
char *id = NULL;
GVariant *state;
GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class)->startup (impl, support_save);
if (!support_save)
return ;
state = gtk_application_impl_retrieve_state (impl);
if (state)
{
GVariant *global = g_variant_get_child_value (state, 0 );
g_variant_lookup (global, "wayland-session" , "s" , &id);
g_clear_pointer (&global, g_variant_unref);
g_clear_pointer (&state, g_variant_unref);
}
switch (wayland->dbus.reason)
{
case GTK_RESTORE_REASON_LAUNCH:
wl_reason = XDG_SESSION_MANAGER_V1_REASON_LAUNCH;
break ;
case GTK_RESTORE_REASON_RESTORE:
wl_reason = XDG_SESSION_MANAGER_V1_REASON_SESSION_RESTORE;
break ;
case GTK_RESTORE_REASON_RECOVER:
wl_reason = XDG_SESSION_MANAGER_V1_REASON_RECOVER;
break ;
case GTK_RESTORE_REASON_PRISTINE:
wl_reason = XDG_SESSION_MANAGER_V1_REASON_LAUNCH;
g_clear_pointer (&id, g_free);
break ;
default :
g_assert_not_reached ();
}
GTK_DEBUG (SESSION, "Wayland register session ID %s" , id);
wayland->session_mgmt_supported = gdk_wayland_display_register_session (display, wl_reason, id);
g_free (id);
}
static void
collect_wayland_fallback_state (GtkWindow *window,
GVariantBuilder *state)
{
int width, height;
gboolean is_maximized;
gboolean is_fullscreen;
GTK_DEBUG (SESSION, "Wayland compositor doesn't appear to support session management! Collecting fallback state" );
gtk_window_get_default_size (window, &width, &height);
g_variant_builder_add (state, "{sv}" , "size" , g_variant_new ("(ii)" , width, height));
is_maximized = gtk_window_is_maximized (window);
g_variant_builder_add (state, "{sv}" , "is-maximized" , g_variant_new_boolean (is_maximized));
is_fullscreen = gtk_window_is_fullscreen (window);
g_variant_builder_add (state, "{sv}" , "is-fullscreen" , g_variant_new_boolean (is_fullscreen));
}
static void
gtk_application_impl_wayland_collect_window_state (GtkApplicationImpl *impl,
GtkWindow *window,
GVariantBuilder *state)
{
GtkApplicationImplWayland *wayland = (GtkApplicationImplWayland*) impl;
GdkSurface *surface;
const char *session_id;
if (!wayland->session_mgmt_supported)
{
collect_wayland_fallback_state (window, state);
return ;
}
surface = gtk_native_get_surface (GTK_NATIVE (window));
session_id = gdk_wayland_toplevel_get_session_id (GDK_TOPLEVEL (surface));
if (session_id)
g_variant_builder_add (state, "{sv}" , "session-id" , g_variant_new_string (session_id));
}
static void
gtk_application_impl_wayland_collect_global_state (GtkApplicationImpl *impl,
GVariantBuilder *state)
{
GdkDisplay *display = gdk_display_get_default ();
const char *id;
GTK_APPLICATION_IMPL_CLASS (gtk_application_impl_wayland_parent_class)->collect_global_state (impl, state);
id = gdk_wayland_display_get_session_id (display);
if (id)
g_variant_builder_add (state, "{sv}" , "wayland-session" , g_variant_new_string (id));
}
static void
gtk_application_impl_wayland_init (GtkApplicationImplWayland *wayland)
{
}
static void
gtk_application_impl_wayland_class_init (GtkApplicationImplWaylandClass *class )
{
GtkApplicationImplClass *impl_class = GTK_APPLICATION_IMPL_CLASS (class );
impl_class->handle_window_realize = gtk_application_impl_wayland_handle_window_realize;
impl_class->before_emit = gtk_application_impl_wayland_before_emit;
impl_class->window_removed = gtk_application_impl_wayland_window_removed;
impl_class->window_forget = gtk_application_impl_wayland_window_forget;
impl_class->window_forget_by_state = gtk_application_impl_wayland_window_forget_by_state;
impl_class->window_unforget = gtk_application_impl_wayland_window_unforget;
impl_class->inhibit = gtk_application_impl_wayland_inhibit;
impl_class->uninhibit = gtk_application_impl_wayland_uninhibit;
impl_class->startup = gtk_application_impl_wayland_startup;
impl_class->collect_window_state = gtk_application_impl_wayland_collect_window_state;
impl_class->collect_global_state = gtk_application_impl_wayland_collect_global_state;
}
Messung V0.5 in Prozent C=98 H=95 G=96
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-07-02)
¤
*© Formatika GbR, Deutschland