Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gdkdisplay-wayland.c

  Sprache: C
 

/*
 * Copyright © 2010 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */


#include "config.h"

#define VK_USE_PLATFORM_WAYLAND_KHR

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif

#include <glib.h>
#include <gio/gio.h>
#include "gdkwayland.h"
#include "gdkdisplay.h"
#include "gdkdisplay-wayland.h"
#include "gdkmonitor-wayland.h"
#include "gdkseat-wayland.h"
#include "gdksurfaceprivate.h"
#include "gdkdeviceprivate.h"
#include "gdkdevice-wayland-private.h"
#include "gdksurface-wayland-private.h"
#include "gdkkeymap-wayland.h"
#include "gdkcairocontext-wayland.h"
#include "gdkglcontext-wayland.h"
#include "gdkvulkancontext-wayland.h"
#include "gdkwaylandmonitor.h"
#include "gdkprofilerprivate.h"
#include "gdktoplevel-wayland-private.h"
#include "gdkwaylandcolor-private.h"
#include "gdkshm-private.h"
#include "gdksettings-wayland.h"
#include "gdkapplaunchcontext-wayland.h"
#include "gdkeventsourceprivate.h"
#include "gdkwaylandprivate.h"

#include <wayland/pointer-gestures-unstable-v1-client-protocol.h>
#include "tablet-v2-client-protocol.h"
#include <wayland/xdg-shell-unstable-v6-client-protocol.h>
#include <wayland/xdg-foreign-unstable-v1-client-protocol.h>
#include <wayland/xdg-foreign-unstable-v2-client-protocol.h>
#include <wayland/server-decoration-client-protocol.h>
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "presentation-time-client-protocol.h"
#include "color-management-v1-client-protocol.h"
#include "color-representation-v1-client-protocol.h"
#include "xdg-session-management-v1-client-protocol.h"

#include "gdk/gdkprivate.h"

/* Keep g_assert() defined even if we disable it globally,
 * as we use it in many places as a handy mechanism to check
 * for non-NULL
 */

#ifdef G_DISABLE_ASSERT
undef g_assert
define g_assert(expr)                  G_STMT_START { \
                                           if G_LIKELY (expr) ; else \
                                             g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
                                                                       #expr); \
                                         } G_STMT_END
#endif

/**
 * GdkWaylandDisplay:
 *
 * The Wayland implementation of `GdkDisplay`.
 *
 * Beyond the regular [class@Gdk.Display] API, the Wayland implementation
 * provides access to Wayland objects such as the `wl_display` with
 * [method@GdkWayland.WaylandDisplay.get_wl_display], the `wl_compositor` with
 * [method@GdkWayland.WaylandDisplay.get_wl_compositor].
 *
 * You can find out what Wayland globals are supported by a display
 * with [method@GdkWayland.WaylandDisplay.query_registry].
 */


#define MIN_SYSTEM_BELL_DELAY_MS 20

#define COMPOSITOR_VERSION              6
#define SHM_VERSION                     1
#define LINUX_DMABUF_MIN_VERSION        4
#define LINUX_DMABUF_VERSION            5
#define DATA_DEVICE_MANAGER_VERSION     3
#define SUBCOMPOSITOR_VERSION           1
#define SEAT_VERSION                    10
#define POINTER_GESTURES_VERSION        3
#define PRIMARY_SELECTION_VERSION       1
#define OUTPUT_MIN_VERSION              2
#define OUTPUT_VERSION                  4
#define XDG_OUTPUT_MIN_VERSION          3
#define XDG_OUTPUT_VERSION              3
#define TABLET_VERSION                  2
#define EXPORTER_V1_VERSION             1
#define EXPORTER_V2_VERSION             1
#define IMPORTER_V1_VERSION             1
#define IMPORTER_V2_VERSION             1
#define SHORTCUTS_INHIBIT_VERSION       1
#define SERVER_DECORATION_VERSION       1
#define XDG_OUTPUT_VERSION              3
#define IDLE_INHIBIT_VERSION            1
#define ACTIVATION_VERSION              1
#define FRACTIONAL_SCALE_VERSION        1
#define VIEWPORTER_VERSION              1
#define PRESENTATION_VERSION            1
#define SINGLE_PIXEL_BUFFER_VERSION     1
#define SYSTEM_BELL_VERSION             1
#define CURSOR_SHAPE_VERSION            2
#define GTK_SHELL1_VERSION              7
#define XDG_WM_DIALOG_VERSION           1
#define XDG_TOPLEVEL_ICON_VERSION       1
#define XDG_WM_BASE_VERSION             7

G_DEFINE_TYPE (GdkWaylandDisplay, gdk_wayland_display, GDK_TYPE_DISPLAY)

G_GNUC_PRINTF (10)
static void
log_handler (const char *format, va_list args)
{
  g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args);
}

/* {{{ GDK_WAYLAND_DISABLE filtering */

static void
init_skip_protocols (GdkWaylandDisplay *display_wayland)
{
  const char *variable, *string, *p, *q;
  gboolean help;
  GStrvBuilder *strv;

  variable = "GDK_WAYLAND_DISABLE";
  string = g_getenv (variable);

  help = FALSE;

  if (string == NULL)
    string = "";

  strv = g_strv_builder_new ();

  p = string;
  while (*p)
    {
      q = strpbrk (p, ":;, \t");
      if (!q)
        q = p + strlen (p);

      if (g_ascii_strncasecmp ("help", p, q - p) == 0)
        help = TRUE;
      else
        g_strv_builder_take (strv, g_strndup (p, q - p));

      p = q;
      if (*p)
        p++;
    }

  if (!GDK_DISPLAY_DEBUG_CHECK (GDK_DISPLAY (display_wayland), COLOR_MANAGEMENT))
    g_strv_builder_add (strv, wp_color_manager_v1_interface.name);

  if (help)
    {
      gdk_help_message ("%s can be set to a list of Wayland interfaces to disable.\n", variable);
      if (!GDK_DISPLAY_DEBUG_CHECK (GDK_DISPLAY (display_wayland), MISC))
        {
          gdk_help_message ("Supported %s values:", variable);
          display_wayland->list_protocols = TRUE;
        }
    }

  display_wayland->skip_protocols = g_strv_builder_unref_to_strv (strv);
}

static gboolean
match_global (GdkWaylandDisplay *display_wayland,
              const char        *interface,
              uint32_t           version,
              const char        *name,
              uint32_t           min_version)
{
  if (strcmp (interface, name) != 0)
    return FALSE;

  if (version < min_version)
    {
      GDK_DISPLAY_DEBUG (GDK_DISPLAY (display_wayland), MISC,
                         "Not using %s, too old (%u < %u)",
                         interface, version, min_version);
      return FALSE;
    }

  if (g_strv_contains ((const char * const *) display_wayland->skip_protocols, name))
    {
      GDK_DISPLAY_DEBUG (GDK_DISPLAY (display_wayland), MISC,
                         "Not using %s, disabled",
                         interface);
      return FALSE;
    }

  return TRUE;
}

/* }}} */
/* {{{ Async roundtrips */

static void
async_roundtrip_callback (void               *data,
                          struct wl_callback *callback,
                          uint32_t            time)
{
  GdkWaylandDisplay *display_wayland = data;

  display_wayland->async_roundtrips =
    g_list_remove (display_wayland->async_roundtrips, callback);
  wl_callback_destroy (callback);
}

static const struct wl_callback_listener async_roundtrip_listener = {
  async_roundtrip_callback
};

static void
_gdk_wayland_display_async_roundtrip (GdkWaylandDisplay *display_wayland)
{
  struct wl_callback *callback;

  callback = wl_display_sync (display_wayland->wl_display);
  wl_callback_add_listener (callback,
                            &async_roundtrip_listener,
                            display_wayland);
  display_wayland->async_roundtrips =
    g_list_append (display_wayland->async_roundtrips, callback);
}

/* }}} */
/* {{{ Global dependency handling */

static gboolean
is_known_global (gpointer key, gpointer value, gpointer user_data)
{
  const char *required_global = user_data;
  const char *known_global = value;

  return g_strcmp0 (required_global, known_global) == 0;
}

static gboolean
has_required_globals (GdkWaylandDisplay *display_wayland,
                      const char *required_globals[])
{
  int i = 0;

  while (required_globals[i])
    {
      if (g_hash_table_find (display_wayland->known_globals,
                             is_known_global,
                             (gpointer)required_globals[i]) == NULL)
        return FALSE;

      i++;
    }

  return TRUE;
}

typedef struct _OnHasGlobalsClosure OnHasGlobalsClosure;

typedef void (*HasGlobalsCallback) (GdkWaylandDisplay *display_wayland,
                                    OnHasGlobalsClosure *closure);

struct _OnHasGlobalsClosure
{
  HasGlobalsCallback handler;
  const char **required_globals;
};

static void
process_on_globals_closures (GdkWaylandDisplay *display_wayland)
{
  GList *iter;

  iter = display_wayland->on_has_globals_closures;
  while (iter != NULL)
    {
      GList *next = iter->next;
      OnHasGlobalsClosure *closure = iter->data;

      if (has_required_globals (display_wayland,
                                closure->required_globals))
        {
          closure->handler (display_wayland, closure);
          g_free (closure);
          display_wayland->on_has_globals_closures =
            g_list_delete_link (display_wayland->on_has_globals_closures, iter);
        }

      iter = next;
    }
}

typedef struct
{
  OnHasGlobalsClosure base;
  uint32_t id;
  uint32_t version;
} SeatAddedClosure;

static void
gdk_wayland_display_add_seat (GdkWaylandDisplay *display_wayland,
                              uint32_t id,
                              uint32_t version)
{
  struct wl_seat *seat;

  seat = wl_registry_bind (display_wayland->wl_registry,
                           id, &wl_seat_interface,
                           MIN (version, SEAT_VERSION));
  gdk_wayland_display_create_seat (display_wayland, id, seat);
  _gdk_wayland_display_async_roundtrip (display_wayland);
}

static void
seat_added_closure_run (GdkWaylandDisplay *display_wayland,
                        OnHasGlobalsClosure *closure)
{
  SeatAddedClosure *seat_added_closure = (SeatAddedClosure*)closure;

  gdk_wayland_display_add_seat (display_wayland,
                                seat_added_closure->id,
                                seat_added_closure->version);
}

static void
postpone_on_globals_closure (GdkWaylandDisplay *display_wayland,
                             OnHasGlobalsClosure *closure)
{
  display_wayland->on_has_globals_closures =
    g_list_append (display_wayland->on_has_globals_closures, closure);
}

/* }}} */
/* {{{ gtk_shell listener */

static void
gtk_shell_handle_capabilities (void              *data,
                               struct gtk_shell1 *shell,
                               uint32_t           capabilities)
{
  GdkDisplay *display = data;
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (data);

  display_wayland->shell_capabilities = capabilities;

  gdk_display_setting_changed (display, "gtk-shell-shows-app-menu");
  gdk_display_setting_changed (display, "gtk-shell-shows-menubar");
  gdk_display_setting_changed (display, "gtk-shell-shows-desktop");
}

struct gtk_shell1_listener gdk_display_gtk_shell_listener = {
  gtk_shell_handle_capabilities
};

/* }}} */
/* {{{ xdg_wm_base listener */

static void
xdg_wm_base_ping (void               *data,
                  struct xdg_wm_base *xdg_wm_base,
                  uint32_t            serial)
{
  GDK_DEBUG (EVENTS, "ping, shell %p, serial %u", xdg_wm_base, serial);

  xdg_wm_base_pong (xdg_wm_base, serial);
}

static const struct xdg_wm_base_listener xdg_wm_base_listener = {
  xdg_wm_base_ping,
};

/* }}} */
/* {{{ zxdg_shell_v6 listener */

static void
zxdg_shell_v6_ping (void                 *data,
                    struct zxdg_shell_v6 *xdg_shell,
                    uint32_t              serial)
{
  GDK_DISPLAY_DEBUG (GDK_DISPLAY (data), EVENTS,
                     "ping, shell %p, serial %u", xdg_shell, serial);

  zxdg_shell_v6_pong (xdg_shell, serial);
}

static const struct zxdg_shell_v6_listener zxdg_shell_v6_listener = {
  zxdg_shell_v6_ping,
};

/* }}} */
/* {{{ wl_shm listener */

static void
wl_shm_format (void          *data,
               struct wl_shm *wl_shm,
               uint32_t       format)
{
  GDK_DEBUG (MISC, "supported shm pixel format %.4s (0x%X)",
             format == 0 ? "ARGB8888"
               : (format == 1 ? "XRGB8888"
               : (char *) &format), format);
}

static const struct wl_shm_listener wl_shm_listener = {
  wl_shm_format
};

 /* }}} */
/* {{{ server_decoration listener */

static void
server_decoration_manager_default_mode (void                                          *data,
                                        struct org_kde_kwin_server_decoration_manager *manager,
                                        uint32_t                                       mode)
{
  g_assert (mode <= ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER);
  const char *modes[] = {
    [ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE]   = "none",
    [ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT] = "client",
    [ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER] = "server",
  };
  GdkWaylandDisplay *display_wayland = data;
  GDK_DISPLAY_DEBUG (GDK_DISPLAY (data), MISC, "Compositor prefers decoration mode '%s'", modes[mode]);
  display_wayland->server_decoration_mode = mode;
}

static const struct org_kde_kwin_server_decoration_manager_listener server_decoration_listener = {
  .default_mode = server_decoration_manager_default_mode
};

/* }}} */
/* {{{ session listener */

static void
session_listener_created (void                  *data,
                          struct xdg_session_v1 *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 xdg_session_v1 *session_v1)
{
  GdkWaylandDisplay *display_wayland = data;

  GDK_DEBUG (MISC, "session restored: %s", display_wayland->session_id);
}

static void
session_listener_replaced (void                  *data,
                           struct xdg_session_v1 *session_v1)
{
  GdkWaylandDisplay *display_wayland = data;

  GDK_DEBUG (MISC, "session replaced: %s", display_wayland->session_id);
}

static const struct xdg_session_v1_listener session_listener = {
  .created = session_listener_created,
  .restored = session_listener_restored,
  .replaced = session_listener_replaced,
};

/* }}} */
/* {{{ wl_registry listener */

static void
gdk_registry_handle_global (void               *data,
                            struct wl_registry *registry,
                            uint32_t            id,
                            const char         *interface,
                            uint32_t            version)
{
  GdkWaylandDisplay *display_wayland = data;
  struct wl_output *output;

  if (display_wayland->list_protocols)
    gdk_debug_message ("    %s", interface);
  else
    GDK_DEBUG (MISC, "add global %u, interface %s, version %u", id, interface, version);

  if (match_global (display_wayland, interface, version, wl_compositor_interface.name, 0))
    {
      display_wayland->compositor =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &wl_compositor_interface, MIN (version, COMPOSITOR_VERSION));
    }
  else if (match_global (display_wayland, interface, version, wl_shm_interface.name, 0))
    {
      display_wayland->shm =
        wl_registry_bind (display_wayland->wl_registry, id, &wl_shm_interface, SHM_VERSION);
      wl_shm_add_listener (display_wayland->shm, &wl_shm_listener, display_wayland);
    }
  else if (match_global (display_wayland, interface, version, zwp_linux_dmabuf_v1_interface.name, LINUX_DMABUF_MIN_VERSION))
    {
      struct zwp_linux_dmabuf_feedback_v1 *feedback;

      display_wayland->linux_dmabuf =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &zwp_linux_dmabuf_v1_interface,
                          MIN (version, LINUX_DMABUF_VERSION));
      feedback = zwp_linux_dmabuf_v1_get_default_feedback (display_wayland->linux_dmabuf);
      display_wayland->dmabuf_formats_info = dmabuf_formats_info_new (GDK_DISPLAY (display_wayland),
                                                                      "default",
                                                                      feedback);
      _gdk_wayland_display_async_roundtrip (display_wayland);
    }
  else if (match_global (display_wayland, interface, version, xdg_wm_base_interface.name0))
    {
      display_wayland->xdg_wm_base_id = id;
      display_wayland->xdg_wm_base_version = version;
    }
  else if (match_global (display_wayland, interface, version, zxdg_shell_v6_interface.name, 0))
    {
      display_wayland->zxdg_shell_v6_id = id;
    }
  else if (match_global (display_wayland, interface, version, xdg_wm_dialog_v1_interface.name, 0))
    {
      display_wayland->xdg_wm_dialog =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &xdg_wm_dialog_v1_interface,
                          MIN (version, XDG_WM_DIALOG_VERSION));
    }
  else if (match_global (display_wayland, interface, version, xdg_session_manager_v1_interface.name, 0))
    {
      display_wayland->session_manager =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &xdg_session_manager_v1_interface,
                          version);
    }
  else if (match_global (display_wayland, interface, version, gtk_shell1_interface.name, 0))
    {
      display_wayland->gtk_shell =
        wl_registry_bind (display_wayland->wl_registry, id,
                          >k_shell1_interface,
                          MIN (version, GTK_SHELL1_VERSION));
      gtk_shell1_add_listener (display_wayland->gtk_shell, &gdk_display_gtk_shell_listener, display_wayland);
    }
  else if (match_global (display_wayland, interface, version, wl_output_interface.name, OUTPUT_MIN_VERSION))
    {
      output =
       wl_registry_bind (display_wayland->wl_registry, id, &wl_output_interface,
                         MIN (version, OUTPUT_VERSION));
      gdk_wayland_display_add_output (display_wayland, id, output);
      _gdk_wayland_display_async_roundtrip (display_wayland);
    }
  else if (match_global (display_wayland, interface, version, wl_seat_interface.name, 0))
    {
      SeatAddedClosure *closure;
      static const char *required_device_manager_globals[] = {
        "wl_compositor",
        "wl_data_device_manager",
        NULL
      };

      closure = g_new0 (SeatAddedClosure, 1);
      closure->base.handler = seat_added_closure_run;
      closure->base.required_globals = required_device_manager_globals;
      closure->id = id;
      closure->version = version;
      postpone_on_globals_closure (display_wayland, &closure->base);
    }
  else if (match_global (display_wayland, interface, version, wl_data_device_manager_interface.name, 0))
    {
      display_wayland->data_device_manager =
        wl_registry_bind (display_wayland->wl_registry, id, &wl_data_device_manager_interface,
                          MIN (version, DATA_DEVICE_MANAGER_VERSION));
    }
  else if (match_global (display_wayland, interface, version, wl_subcompositor_interface.name, 0))
    {
      display_wayland->subcompositor =
        wl_registry_bind (display_wayland->wl_registry, id, &wl_subcompositor_interface, SUBCOMPOSITOR_VERSION);
    }
  else if (match_global (display_wayland, interface, version, zwp_pointer_gestures_v1_interface.name, 0))
    {
      display_wayland->pointer_gestures =
        wl_registry_bind (display_wayland->wl_registry,
                          id, &zwp_pointer_gestures_v1_interface,
                          MIN (version, POINTER_GESTURES_VERSION));
    }
  else if (match_global (display_wayland, interface, version, zwp_primary_selection_device_manager_v1_interface.name, 0))
    {
      display_wayland->primary_selection_manager =
        wl_registry_bind(display_wayland->wl_registry, id,
                         &zwp_primary_selection_device_manager_v1_interface, PRIMARY_SELECTION_VERSION);
    }
  else if (match_global (display_wayland, interface, version, zwp_tablet_manager_v2_interface.name, 0))
    {
      display_wayland->tablet_manager =
        wl_registry_bind(display_wayland->wl_registry, id,
                         &zwp_tablet_manager_v2_interface, MIN (version, TABLET_VERSION));
    }
  else if (match_global (display_wayland, interface, version, zxdg_exporter_v1_interface.name, 0))
    {
      display_wayland->xdg_exporter =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &zxdg_exporter_v1_interface, EXPORTER_V1_VERSION);
    }
  else if (match_global (display_wayland, interface, version, zxdg_exporter_v2_interface.name, 0))
    {
      display_wayland->xdg_exporter_v2 =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &zxdg_exporter_v2_interface, EXPORTER_V2_VERSION);
    }
  else if (match_global (display_wayland, interface, version, zxdg_importer_v1_interface.name, 0))
    {
      display_wayland->xdg_importer =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &zxdg_importer_v1_interface, IMPORTER_V1_VERSION);
    }
  else if (match_global (display_wayland, interface, version, zxdg_importer_v2_interface.name, 0))
    {
      display_wayland->xdg_importer_v2 =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &zxdg_importer_v2_interface, IMPORTER_V2_VERSION);
    }
  else if (match_global (display_wayland, interface, version, zwp_keyboard_shortcuts_inhibit_manager_v1_interface.name, 0))
    {
      display_wayland->keyboard_shortcuts_inhibit =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, SHORTCUTS_INHIBIT_VERSION);
    }
  else if (match_global (display_wayland, interface, version, org_kde_kwin_server_decoration_manager_interface.name, 0))
    {
      display_wayland->server_decoration_manager =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &org_kde_kwin_server_decoration_manager_interface, SERVER_DECORATION_VERSION);
      org_kde_kwin_server_decoration_manager_add_listener (display_wayland->server_decoration_manager,
                                                           &server_decoration_listener,
                                                           display_wayland);
    }
  else if (match_global (display_wayland, interface, version, zxdg_output_manager_v1_interface.name, XDG_OUTPUT_MIN_VERSION))
    {
      display_wayland->xdg_output_manager =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &zxdg_output_manager_v1_interface,
                          MIN (version, XDG_OUTPUT_VERSION));
      gdk_wayland_display_init_xdg_output (display_wayland);
      _gdk_wayland_display_async_roundtrip (display_wayland);
    }
  else if (match_global (display_wayland, interface, version, zwp_idle_inhibit_manager_v1_interface.name, 0))
    {
      display_wayland->idle_inhibit_manager =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &zwp_idle_inhibit_manager_v1_interface, IDLE_INHIBIT_VERSION);
    }
  else if (match_global (display_wayland, interface, version, xdg_activation_v1_interface.name, 0))
    {
      display_wayland->xdg_activation =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &xdg_activation_v1_interface, ACTIVATION_VERSION);
    }
  else if (match_global (display_wayland, interface, version, wp_fractional_scale_manager_v1_interface.name, 0))
    {
      display_wayland->fractional_scale =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &wp_fractional_scale_manager_v1_interface, FRACTIONAL_SCALE_VERSION);
    }
  else if (match_global (display_wayland, interface, version, wp_viewporter_interface.name, 0))
    {
      display_wayland->viewporter =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &wp_viewporter_interface, VIEWPORTER_VERSION);
    }
  else if (match_global (display_wayland, interface, version, wp_presentation_interface.name, 0))
    {
      display_wayland->presentation =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &wp_presentation_interface,
                          MIN (version, PRESENTATION_VERSION));
    }
  else if (match_global (display_wayland, interface, version, wp_color_manager_v1_interface.name, 0))
    {
      gdk_wayland_color_set_color_manager (display_wayland->color, registry, id, version);
    }
  else if (match_global (display_wayland, interface, version, wp_color_representation_manager_v1_interface.name, 0))
    {
      gdk_wayland_color_set_color_representation (display_wayland->color, registry, id, version);
    }
  else if (match_global (display_wayland, interface, version, wp_single_pixel_buffer_manager_v1_interface.name, 0))
    {
      display_wayland->single_pixel_buffer =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &wp_single_pixel_buffer_manager_v1_interface,
                          MIN (version, SINGLE_PIXEL_BUFFER_VERSION));
    }
  else if (match_global (display_wayland, interface, version, xdg_system_bell_v1_interface.name, 0))
    {
      display_wayland->system_bell =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &xdg_system_bell_v1_interface, SYSTEM_BELL_VERSION);
    }
  else if (match_global (display_wayland, interface, version, wp_cursor_shape_manager_v1_interface.name, 0))
    {
      display_wayland->cursor_shape =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &wp_cursor_shape_manager_v1_interface, MIN (version, CURSOR_SHAPE_VERSION));
    }
  else if (match_global (display_wayland, interface, version, xdg_toplevel_icon_manager_v1_interface.name, 0))
    {
      display_wayland->toplevel_icon =
        wl_registry_bind (display_wayland->wl_registry, id,
                          &xdg_toplevel_icon_manager_v1_interface, XDG_TOPLEVEL_ICON_VERSION);
    }

  g_hash_table_insert (display_wayland->known_globals,
                       GUINT_TO_POINTER (id), g_strdup (interface));
}

static void
gdk_registry_handle_global_remove (void               *data,
                                   struct wl_registry *registry,
                                   uint32_t            id)
{
  GdkWaylandDisplay *display_wayland = data;

  GDK_DEBUG (MISC, "remove global %u", id);

  gdk_wayland_display_remove_seat (display_wayland, id);
  gdk_wayland_display_remove_output (display_wayland, id);

  g_hash_table_remove (display_wayland->known_globals, GUINT_TO_POINTER (id));

  /* FIXME: the object needs to be destroyed here, we're leaking */
}

static const struct wl_registry_listener registry_listener = {
    gdk_registry_handle_global,
    gdk_registry_handle_global_remove
};

/* }}} */
/* {{{ GObject implementation */

static int wayland_socket_fd = -1;

void
gdk_wayland_set_wayland_socket (int fd)
{
  wayland_socket_fd = fd;
}

GdkDisplay *
_gdk_wayland_display_open (const char *display_name)
{
  struct wl_display *wl_display = NULL;
  GdkDisplay *display;
  GdkWaylandDisplay *display_wayland;

  GDK_DEBUG (MISC, "opening display %s", display_name ? display_name : "");

  wl_log_set_handler_client (log_handler);

  if (wayland_socket_fd >= 0)
    wl_display = wl_display_connect_to_fd (g_steal_fd (&wayland_socket_fd));

  if (!wl_display)
    wl_display = wl_display_connect (display_name);

  if (!wl_display)
    return NULL;

  display = g_object_new (GDK_TYPE_WAYLAND_DISPLAY, NULL);
  display_wayland = GDK_WAYLAND_DISPLAY (display);
  display_wayland->wl_display = wl_display;
  gdk_wayland_display_install_gsources (display_wayland);

  display_wayland->color = gdk_wayland_color_new (display_wayland);

  init_skip_protocols (display_wayland);

  gdk_wayland_display_init_settings (display);

  display_wayland->known_globals =
    g_hash_table_new_full (NULL, NULL, NULL, g_free);

  display_wayland->wl_registry = wl_display_get_registry (display_wayland->wl_display);
  wl_registry_add_listener (display_wayland->wl_registry, ®istry_listener, display_wayland);
  if (wl_display_roundtrip (display_wayland->wl_display) < 0)
    {
      g_object_unref (display);
      return NULL;
    }

  process_on_globals_closures (display_wayland);

  /* Wait for initializing to complete. This means waiting for all
   * asynchronous roundtrips that were triggered during initial roundtrip.
   */

  while (display_wayland->async_roundtrips != NULL)
    {
      if (wl_display_dispatch (display_wayland->wl_display) < 0)
        {
          g_object_unref (display);
          return NULL;
        }
    }

  /* Check that we got all the required globals */
  if (display_wayland->compositor == NULL ||
      display_wayland->shm == NULL ||
      display_wayland->data_device_manager == NULL)
    {
      g_warning ("The Wayland compositor does not provide one or more of the required interfaces, "
                 "not using Wayland display");
      g_object_unref (display);

      return NULL;
    }

  if (display_wayland->xdg_wm_base_id)
    {
      display_wayland->shell_variant = GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL;
      display_wayland->xdg_wm_base =
        wl_registry_bind (display_wayland->wl_registry,
                          display_wayland->xdg_wm_base_id,
                          &xdg_wm_base_interface,
                          MIN (display_wayland->xdg_wm_base_version,
                               XDG_WM_BASE_VERSION));
      xdg_wm_base_add_listener (display_wayland->xdg_wm_base,
                                &xdg_wm_base_listener,
                                display_wayland);
    }
  else if (display_wayland->zxdg_shell_v6_id)
    {
      display_wayland->shell_variant = GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6;
      display_wayland->zxdg_shell_v6 =
        wl_registry_bind (display_wayland->wl_registry,
                          display_wayland->zxdg_shell_v6_id,
                          &zxdg_shell_v6_interface, 1);
      zxdg_shell_v6_add_listener (display_wayland->zxdg_shell_v6,
                                  &zxdg_shell_v6_listener,
                                  display_wayland);
    }
  else
    {
      g_warning ("The Wayland compositor does not provide any supported shell interface, "
                 "not using Wayland display");
      g_object_unref (display);

      return NULL;
    }

  gdk_wayland_color_prepare (display_wayland->color);

  gdk_display_emit_opened (display);

  return display;
}

static void
destroy_toplevel (gpointer data)
{
  _gdk_surface_destroy (GDK_SURFACE (data), FALSE);
}

static void
gdk_wayland_display_dispose (GObject *object)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (object);

  g_clear_list (&display_wayland->toplevels, destroy_toplevel);

  gdk_wayland_display_uninstall_gsources (display_wayland);

  g_clear_list (&display_wayland->async_roundtrips,
                (GDestroyNotify) wl_callback_destroy);

  g_clear_pointer (&display_wayland->known_globals, g_hash_table_destroy);

  g_clear_list (&display_wayland->on_has_globals_closures, g_free);

  g_clear_pointer (&display_wayland->compositor, wl_compositor_destroy);
  g_clear_pointer (&display_wayland->xdg_wm_base, xdg_wm_base_destroy);
  g_clear_pointer (&display_wayland->zxdg_shell_v6, zxdg_shell_v6_destroy);
  g_clear_pointer (&display_wayland->gtk_shell, gtk_shell1_destroy);
  g_clear_pointer (&display_wayland->data_device_manager, wl_data_device_manager_destroy);
  g_clear_pointer (&display_wayland->subcompositor, wl_subcompositor_destroy);
  g_clear_pointer (&display_wayland->pointer_gestures, zwp_pointer_gestures_v1_destroy);
  g_clear_pointer (&display_wayland->primary_selection_manager, zwp_primary_selection_device_manager_v1_destroy);
  g_clear_pointer (&display_wayland->tablet_manager, zwp_tablet_manager_v2_destroy);
  g_clear_pointer (&display_wayland->xdg_exporter, zxdg_exporter_v1_destroy);
  g_clear_pointer (&display_wayland->xdg_exporter_v2, zxdg_exporter_v2_destroy);
  g_clear_pointer (&display_wayland->xdg_importer, zxdg_importer_v1_destroy);
  g_clear_pointer (&display_wayland->xdg_importer_v2, zxdg_importer_v2_destroy);
  g_clear_pointer (&display_wayland->keyboard_shortcuts_inhibit, zwp_keyboard_shortcuts_inhibit_manager_v1_destroy);
  g_clear_pointer (&display_wayland->server_decoration_manager, org_kde_kwin_server_decoration_manager_destroy);
  g_clear_pointer (&display_wayland->xdg_output_manager, zxdg_output_manager_v1_destroy);
  g_clear_pointer (&display_wayland->idle_inhibit_manager, zwp_idle_inhibit_manager_v1_destroy);
  g_clear_pointer (&display_wayland->xdg_activation, xdg_activation_v1_destroy);
  g_clear_pointer (&display_wayland->fractional_scale, wp_fractional_scale_manager_v1_destroy);
  g_clear_pointer (&display_wayland->viewporter, wp_viewporter_destroy);
  g_clear_pointer (&display_wayland->presentation, wp_presentation_destroy);
  g_clear_pointer (&display_wayland->single_pixel_buffer, wp_single_pixel_buffer_manager_v1_destroy);
  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->system_bell, xdg_system_bell_v1_destroy);
  g_clear_pointer (&display_wayland->toplevel_icon, xdg_toplevel_icon_manager_v1_destroy);
  g_clear_pointer (&display_wayland->session, xdg_session_v1_destroy);
  g_clear_pointer (&display_wayland->session_manager, xdg_session_manager_v1_destroy);

  g_clear_pointer (&display_wayland->shm, wl_shm_destroy);
  g_clear_pointer (&display_wayland->wl_registry, wl_registry_destroy);

  g_list_store_remove_all (display_wayland->monitors);

  G_OBJECT_CLASS (gdk_wayland_display_parent_class)->dispose (object);

  g_clear_pointer (&display_wayland->wl_display, wl_display_disconnect);
}

static void
gdk_wayland_display_finalize (GObject *object)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (object);

  g_object_unref (display_wayland->monitors);

  g_free (display_wayland->startup_notification_id);
  xkb_context_unref (display_wayland->xkb_context);

  g_clear_object (&display_wayland->settings_portal);

  g_strfreev (display_wayland->skip_protocols);

  G_OBJECT_CLASS (gdk_wayland_display_parent_class)->finalize (object);
}

static const char *
gdk_wayland_display_get_name (GdkDisplay *display)
{
  const char *name;

  name = g_getenv ("WAYLAND_DISPLAY");
  if (name == NULL)
    name = "wayland-0";

  return name;
}

static void
gdk_wayland_display_beep (GdkDisplay *display)
{
  gdk_wayland_display_system_bell (display, NULL);
}

static void
gdk_wayland_display_sync (GdkDisplay *display)
{
  GdkWaylandDisplay *display_wayland;

  g_return_if_fail (GDK_IS_DISPLAY (display));

  display_wayland = GDK_WAYLAND_DISPLAY (display);

  wl_display_roundtrip (display_wayland->wl_display);
}

static void
gdk_wayland_display_flush (GdkDisplay *display)
{
  g_return_if_fail (GDK_IS_DISPLAY (display));

  if (!display->closed)
    wl_display_flush (GDK_WAYLAND_DISPLAY (display)->wl_display);
}

static void
gdk_wayland_display_make_default (GdkDisplay *display)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
  const char *startup_id;

  g_clear_pointer (&display_wayland->startup_notification_id, g_free);

  startup_id = gdk_get_startup_notification_id ();
  if (startup_id)
    display_wayland->startup_notification_id = g_strdup (startup_id);
}

static gulong
gdk_wayland_display_get_next_serial (GdkDisplay *display)
{
  static gulong serial = 0;
  return ++serial;
}

static void
gdk_wayland_display_notify_startup_complete (GdkDisplay  *display,
                                             const char *startup_id)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
  char *free_this = NULL;

  /* Will be signaled with focus activation */
  if (display_wayland->xdg_activation)
    return;

  if (startup_id == NULL)
    {
      startup_id = free_this = display_wayland->startup_notification_id;
      display_wayland->startup_notification_id = NULL;

      if (startup_id == NULL)
        return;
    }

  if (!display_wayland->xdg_activation && display_wayland->gtk_shell)
    gtk_shell1_set_startup_id (display_wayland->gtk_shell, startup_id);

  g_free (free_this);
}

static GdkKeymap *
_gdk_wayland_display_get_keymap (GdkDisplay *display)
{
  GdkSeat *seat;
  GdkDevice *core_keyboard = NULL;
  static GdkKeymap *tmp_keymap = NULL;

  seat = gdk_display_get_default_seat (display);
  if (seat)
    core_keyboard = gdk_seat_get_keyboard (seat);

  if (core_keyboard && tmp_keymap)
    {
      g_clear_object (&tmp_keymap);
    }

  if (core_keyboard)
    return _gdk_wayland_device_get_keymap (core_keyboard);

  if (!tmp_keymap)
    tmp_keymap = _gdk_wayland_keymap_new (display);

  return tmp_keymap;
}

static GListModel *
gdk_wayland_display_get_monitors (GdkDisplay *display)
{
  GdkWaylandDisplay *self = GDK_WAYLAND_DISPLAY (display);

  return G_LIST_MODEL (self->monitors);
}

static GdkMonitor *
gdk_wayland_display_get_monitor_at_surface (GdkDisplay *display,
                                            GdkSurface *window)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
  struct wl_output *output;
  uint32_t i, n;

  g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);

  output = gdk_wayland_surface_get_wl_output (window);
  if (output == NULL)
    return NULL;

  n = g_list_model_get_n_items (G_LIST_MODEL (display_wayland->monitors));
  for (i = 0; i < n; i++)
    {
      GdkMonitor *monitor = g_list_model_get_item (G_LIST_MODEL (display_wayland->monitors), i);

      g_object_unref (monitor);

      if (gdk_wayland_monitor_get_wl_output (monitor) == output)
        return monitor;
    }

  return NULL;
}

static void
_gdk_wayland_display_set_cursor_theme (GdkDisplay *display,
                                       const char *name,
                                       int         size)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY(display);

  display_wayland->cursor_theme_size = size ? size : 24;
}

static void
gdk_wayland_display_class_init (GdkWaylandDisplayClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (class);

  object_class->dispose = gdk_wayland_display_dispose;
  object_class->finalize = gdk_wayland_display_finalize;

  display_class->toplevel_type = GDK_TYPE_WAYLAND_TOPLEVEL;
  display_class->popup_type = GDK_TYPE_WAYLAND_POPUP;
  display_class->cairo_context_type = GDK_TYPE_WAYLAND_CAIRO_CONTEXT;

#ifdef GDK_RENDERING_VULKAN
  display_class->vk_context_type = GDK_TYPE_WAYLAND_VULKAN_CONTEXT;
  display_class->vk_extension_name = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
#endif

  display_class->get_name = gdk_wayland_display_get_name;
  display_class->beep = gdk_wayland_display_beep;
  display_class->sync = gdk_wayland_display_sync;
  display_class->flush = gdk_wayland_display_flush;
  display_class->make_default = gdk_wayland_display_make_default;
  display_class->queue_events = _gdk_wayland_display_queue_events;
  display_class->get_app_launch_context = gdk_wayland_display_get_app_launch_context;
  display_class->get_next_serial = gdk_wayland_display_get_next_serial;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  display_class->get_startup_notification_id = gdk_wayland_display_get_startup_notification_id;
G_GNUC_END_IGNORE_DEPRECATIONS
  display_class->notify_startup_complete = gdk_wayland_display_notify_startup_complete;
  display_class->get_keymap = _gdk_wayland_display_get_keymap;

  display_class->init_gl = gdk_wayland_display_init_gl;

  display_class->get_monitors = gdk_wayland_display_get_monitors;
  display_class->get_monitor_at_surface = gdk_wayland_display_get_monitor_at_surface;
  display_class->get_setting = gdk_wayland_display_get_setting;
  display_class->set_cursor_theme = _gdk_wayland_display_set_cursor_theme;
}

static void
gdk_wayland_display_init (GdkWaylandDisplay *self)
{
  self->cursor_theme_size = 24;
  self->xkb_context = xkb_context_new (0);
  self->monitors = g_list_store_new (GDK_TYPE_MONITOR);

  gdk_display_set_prefer_vulkan (GDK_DISPLAY (self), TRUE);
}

/* }}} */
/* {{{ Private API */

void
gdk_wayland_display_system_bell (GdkDisplay *display,
                                 GdkSurface *surface)
{
  GdkWaylandDisplay *display_wayland;
  struct gtk_surface1 *gtk_surface = NULL;
  struct wl_surface *wl_surface = NULL;
  gint64 now_ms;

  g_return_if_fail (GDK_IS_DISPLAY (display));

  display_wayland = GDK_WAYLAND_DISPLAY (display);

  if (!display_wayland->gtk_shell &&
      !display_wayland->system_bell)
    return;

  if (surface)
    {
      if (GDK_IS_WAYLAND_TOPLEVEL (surface))
        {
          GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);

          gtk_surface = gdk_wayland_toplevel_get_gtk_surface (toplevel);
        }

      wl_surface = gdk_wayland_surface_get_wl_surface (surface);
    }

  now_ms = g_get_monotonic_time () / 1000;
  if (now_ms - display_wayland->last_bell_time_ms < MIN_SYSTEM_BELL_DELAY_MS)
    return;

  display_wayland->last_bell_time_ms = now_ms;

  if (display_wayland->system_bell)
    xdg_system_bell_v1_ring (display_wayland->system_bell, wl_surface);
  else
    gtk_shell1_system_bell (display_wayland->gtk_shell, gtk_surface);
}

void
gdk_wayland_display_dispatch_queue (GdkDisplay            *display,
                                    struct wl_event_queue *event_queue)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);

  if (wl_display_dispatch_queue (display_wayland->wl_display, event_queue) == -1)
    {
      g_message ("Error %d (%s) dispatching to Wayland display.",
                 errno, g_strerror (errno));
      _exit (1);
    }
}

/* }}} */
/* {{{ Public API */

/*
 * gdk_wayland_display_prefers_ssd:
 * @display: (type GdkWaylandDisplay): a display
 *
 * Checks whether the Wayland compositor prefers to draw the window
 * decorations or if it leaves decorations to the application.
 *
 * Returns: true if the compositor prefers server-side decorations
 */

gboolean
gdk_wayland_display_prefers_ssd (GdkDisplay *display)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);

  if (display_wayland->server_decoration_manager)
    return display_wayland->server_decoration_mode == ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER;

  return FALSE;
}

/**
 * gdk_wayland_display_get_startup_notification_id:
 * @display: (type GdkWaylandDisplay): a display
 *
 * Gets the startup notification ID for a Wayland display, or `NULL`
 * if no ID has been defined.
 *
 * Returns: (nullable): the startup notification ID for @display
 *
 * Deprecated: 4.10.
 */

const char *
gdk_wayland_display_get_startup_notification_id (GdkDisplay  *display)
{
  return GDK_WAYLAND_DISPLAY (display)->startup_notification_id;
}

/**
 * gdk_wayland_display_set_startup_notification_id:
 * @display: (type GdkWaylandDisplay): a display
 * @startup_id: the startup notification ID (must be valid utf8)
 *
 * Sets the startup notification ID for a display.
 *
 * This is usually taken from the value of the `DESKTOP_STARTUP_ID`
 * environment variable, but in some cases (such as the application not
 * being launched using exec()) it can come from other sources.
 *
 * The startup ID is also what is used to signal that the startup is
 * complete (for example, when opening a window or when calling
 * [method@Gdk.Display.notify_startup_complete]).
 *
 * Deprecated: 4.10. Use [method@Gdk.Toplevel.set_startup_id]
 */

void
gdk_wayland_display_set_startup_notification_id (GdkDisplay *display,
                                                 const char *startup_id)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);

  g_free (display_wayland->startup_notification_id);
  display_wayland->startup_notification_id = g_strdup (startup_id);
}

/**
 * gdk_wayland_display_set_cursor_theme:
 * @display: (type GdkWaylandDisplay): a display
 * @name: the new cursor theme
 * @size: the size to use for cursors
 *
 * Sets the cursor theme for the given @display.
 *
 * Deprecated: 4.16: Use the cursor-related properties of
 *   [GtkSettings](../gtk4/class.Settings.html) to set the cursor theme
 */

void
gdk_wayland_display_set_cursor_theme (GdkDisplay *display,
                                      const char *name,
                                      int         size)
{
  _gdk_wayland_display_set_cursor_theme (display, name, size);
}

/**
 * gdk_wayland_display_get_wl_display: (skip)
 * @display: (type GdkWaylandDisplay): a display
 *
 * Returns the Wayland `wl_display` of a display.
 *
 * Returns: (transfer none): a Wayland `wl_display`
 */

struct wl_display *
gdk_wayland_display_get_wl_display (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), NULL);

  return GDK_WAYLAND_DISPLAY (display)->wl_display;
}

/**
 * gdk_wayland_display_get_wl_compositor: (skip)
 * @display: (type GdkWaylandDisplay): a display
 *
 * Returns the Wayland `wl_compositor` of a display.
 *
 * Returns: (transfer none): a Wayland `wl_compositor`
 */

struct wl_compositor *
gdk_wayland_display_get_wl_compositor (GdkDisplay *display)
{
  g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), NULL);

  return GDK_WAYLAND_DISPLAY (display)->compositor;
}

/**
 * gdk_wayland_display_query_registry:
 * @display: (type GdkWaylandDisplay): a display
 * @global: global interface to query in the registry
 *
 * Returns true if the interface was found in the display
 * `wl_registry.global` handler.
 *
 * Returns: true if the global is offered by the compositor
 */

gboolean
gdk_wayland_display_query_registry (GdkDisplay *display,
                                    const char *global)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
  GHashTableIter iter;
  char *value;

  g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
  g_return_val_if_fail (global != NULL, FALSE);

  g_hash_table_iter_init (&iter, display_wayland->known_globals);

  while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &value))
    {
      if (strcmp (value, global) == 0)
        return TRUE;
    }

  return FALSE;
}

gboolean
gdk_wayland_display_register_session (GdkDisplay                         *display,
                                      enum xdg_session_manager_v1_reason  reason,
                                      const char                         *name)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);

  GDK_DEBUG (MISC, "register session %s, reason %u", name, reason);

  if (!display_wayland->session_manager)
    return FALSE;

  g_clear_pointer (&display_wayland->session_id, g_free);
  display_wayland->session_id = g_strdup (name);

  display_wayland->session =
    xdg_session_manager_v1_get_session (display_wayland->session_manager,
                                        reason,
                                        name);
  xdg_session_v1_add_listener (display_wayland->session,
                               &session_listener,
                               display_wayland);

  wl_display_roundtrip (display_wayland->wl_display);
  return TRUE;
}

void
gdk_wayland_display_unregister_session (GdkDisplay *display)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);

  if (!display_wayland->session_manager)
    return;

  if (display_wayland->session)
    xdg_session_v1_remove (display_wayland->session);

  g_clear_pointer (&display_wayland->session_id, g_free);
  g_clear_pointer (&display_wayland->session, xdg_session_v1_destroy);
}

const char *
gdk_wayland_display_get_session_id (GdkDisplay *display)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);

  return display_wayland->session_id;
}

static gint
cmp_toplevel_session_id (GdkToplevel *toplevel,
                         const char  *expected)
{
  return g_strcmp0 (gdk_wayland_toplevel_get_session_id (toplevel), expected);
}

void
gdk_wayland_display_remove_session_toplevel (GdkDisplay *display,
                                             const char *name)
{
  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
  GList *found_toplevel = NULL;

  if (!display_wayland->session)
    return;

  found_toplevel = g_list_find_custom (display_wayland->toplevels, name,
                                       (GCompareFunc) cmp_toplevel_session_id);
  if (found_toplevel)
    {
      gdk_wayland_toplevel_remove_from_session (found_toplevel->data);
      return;
    }

  xdg_session_v1_remove_toplevel (display_wayland->session, name);
}

/* }}} */
/* vim:set foldmethod=marker: */

Messung V0.5 in Prozent
C=98 H=94 G=95

¤ Dauer der Verarbeitung: 0.40 Sekunden  (vorverarbeitet am  2026-07-02) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik