* [method@GdkWayland.WaylandSurface.get_wl_surface].
*/
-/**
- * GdkWaylandToplevel:
- *
- * The Wayland implementation of `GdkToplevel`.
- *
- * Beyond the [iface@Gdk.Toplevel] API, the Wayland implementation
- * has API to set up cross-process parent-child relationships between
- * surfaces with [method@GdkWayland.WaylandToplevel.export_handle] and
- * [method@GdkWayland.WaylandToplevel.set_transient_for_exported].
- */
-
-/**
- * GdkWaylandPopup:
- *
- * The Wayland implementation of `GdkPopup`.
- */
-
#define MAX_WL_BUFFER_SIZE (4083) /* 4096 minus header, string argument length and NUL byte */
G_DEFINE_TYPE (GdkWaylandSurface, gdk_wayland_surface, GDK_TYPE_SURFACE)
-struct _GdkWaylandToplevel
-{
- GdkWaylandSurface parent_instance;
-
- struct {
- struct gtk_surface1 *gtk_surface;
- struct xdg_toplevel *xdg_toplevel;
- struct zxdg_toplevel_v6 *zxdg_toplevel_v6;
- } display_server;
-
- GdkWaylandToplevel *transient_for;
-
- struct org_kde_kwin_server_decoration *server_decoration;
- struct zxdg_exported_v1 *xdg_exported;
- struct zxdg_exported_v2 *xdg_exported_v2;
-
- struct {
- int width;
- int height;
- GdkToplevelState state;
- gboolean is_resizing;
-
- int bounds_width;
- int bounds_height;
- gboolean has_bounds;
- } pending;
-
- struct {
- gboolean should_constrain;
- gboolean size_is_fixed;
- } next_layout;
-
- struct {
- GdkWaylandToplevelExported callback;
- gpointer user_data;
- GDestroyNotify destroy_func;
- } exported;
-
- struct {
- gboolean was_set;
-
- char *application_id;
- char *app_menu_path;
- char *menubar_path;
- char *window_object_path;
- char *application_object_path;
- char *unique_bus_name;
- } application;
-
- struct zwp_idle_inhibitor_v1 *idle_inhibitor;
- size_t idle_inhibitor_refcount;
-
- struct wl_output *initial_fullscreen_output;
-
- struct {
- GdkToplevelState unset_flags;
- GdkToplevelState set_flags;
- } initial_state;
-
- GdkToplevelLayout *layout;
- int bounds_width;
- int bounds_height;
- gboolean has_bounds;
-
- char *title;
-
- GdkGeometry geometry_hints;
- GdkSurfaceHints geometry_mask;
- GdkGeometry last_sent_geometry_hints;
-
- struct zxdg_imported_v1 *imported_transient_for;
- struct zxdg_imported_v2 *imported_transient_for_v2;
-
- GHashTable *shortcuts_inhibitors;
-};
-
-typedef struct
-{
- GdkWaylandSurfaceClass parent_class;
-} GdkWaylandToplevelClass;
-
-static void gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (GdkWaylandToplevel, gdk_wayland_toplevel, GDK_TYPE_WAYLAND_SURFACE,
- G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL,
- gdk_wayland_toplevel_iface_init))
-
-struct _GdkWaylandPopup
-{
- GdkWaylandSurface parent_instance;
-
- struct {
- struct xdg_popup *xdg_popup;
- struct zxdg_popup_v6 *zxdg_popup_v6;
- } display_server;
-
- PopupState state;
- unsigned int thaw_upon_show : 1;
- GdkPopupLayout *layout;
- int unconstrained_width;
- int unconstrained_height;
-
- struct {
- int x;
- int y;
- int width;
- int height;
- uint32_t repositioned_token;
- gboolean has_repositioned_token;
- } pending;
-
- struct {
- int x;
- int y;
- } next_layout;
-
- uint32_t reposition_token;
- uint32_t received_reposition_token;
-
- GdkSeat *grab_input_seat;
-};
-
-typedef struct
-{
- GdkWaylandSurfaceClass parent_class;
-} GdkWaylandPopupClass;
-
-static void gdk_wayland_popup_iface_init (GdkPopupInterface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (GdkWaylandPopup, gdk_wayland_popup, GDK_TYPE_WAYLAND_SURFACE,
- G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP,
- gdk_wayland_popup_iface_init))
-
static void gdk_wayland_surface_maybe_resize (GdkSurface *surface,
int width,
int height,
static void gdk_wayland_surface_configure (GdkSurface *surface);
-static void maybe_set_gtk_surface_dbus_properties (GdkWaylandToplevel *wayland_toplevel);
-static void maybe_set_gtk_surface_modal (GdkWaylandToplevel *wayland_toplevel);
-
static void gdk_wayland_surface_show (GdkSurface *surface);
static void gdk_wayland_surface_hide (GdkSurface *surface);
static gboolean gdk_wayland_toplevel_is_exported (GdkWaylandToplevel *wayland_toplevel);
-static void configure_toplevel_geometry (GdkWaylandToplevel *wayland_toplevel);
+static void configure_toplevel_geometry (GdkWaylandToplevel *toplevel);
+static void gdk_wayland_surface_create_xdg_toplevel (GdkWaylandToplevel *toplevel);
+static void gdk_wayland_surface_configure_toplevel (GdkWaylandToplevel *toplevel);
+static void gdk_wayland_toplevel_sync_parent (GdkWaylandToplevel *toplevel);
+static void gdk_wayland_toplevel_sync_parent_of_imported (GdkWaylandToplevel *toplevel);
+static void gdk_wayland_toplevel_sync_title (GdkWaylandToplevel *toplevel);
+static void gdk_wayland_toplevel_set_geometry_hints (GdkWaylandToplevel *toplevel,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask);
+static void gdk_wayland_toplevel_handle_configure (GdkWaylandToplevel *toplevel,
+ int32_t width,
+ int32_t height,
+ GdkToplevelState state);
+static void gdk_wayland_toplevel_hide_surface (GdkWaylandToplevel *toplevel);
+
+static void configure_popup_geometry (GdkWaylandPopup *popup);
+static void gdk_wayland_surface_configure_popup (GdkWaylandPopup *popup);
+static void frame_callback_popup (GdkWaylandPopup *popup);
+static void gdk_wayland_popup_hide_surface (GdkWaylandPopup *popup);
+
+/* {{{ Utilities */
static void
-gdk_wayland_surface_init (GdkWaylandSurface *impl)
+fill_presentation_time_from_frame_time (GdkFrameTimings *timings,
+ guint32 frame_time)
{
- impl->scale = 1;
- impl->saved_width = -1;
- impl->saved_height = -1;
+ /* The timestamp in a wayland frame is a msec time value that in some
+ * way reflects the time at which the server started drawing the frame.
+ * This is not useful from our perspective.
+ *
+ * However, for the DRM backend of Weston, on reasonably recent
+ * Linux, we know that the time is the
+ * clock_gettime (CLOCK_MONOTONIC) value at the vblank, and that
+ * backend starts drawing immediately after receiving the vblank
+ * notification. If we detect this, and make the assumption that the
+ * compositor will finish drawing before the next vblank, we can
+ * then determine the presentation time as the frame time we
+ * received plus one refresh interval.
+ *
+ * If a backend is using clock_gettime(CLOCK_MONOTONIC), but not
+ * picking values right at the vblank, then the presentation times
+ * we compute won't be accurate, but not really worse than then
+ * the alternative of not providing presentation times at all.
+ *
+ * The complexity here is dealing with the fact that we receive
+ * only the low 32 bits of the CLOCK_MONOTONIC value in milliseconds.
+ */
+ gint64 now_monotonic = g_get_monotonic_time ();
+ gint64 now_monotonic_msec = now_monotonic / 1000;
+ uint32_t now_monotonic_low = (uint32_t)now_monotonic_msec;
+
+ if (frame_time - now_monotonic_low < 1000 ||
+ frame_time - now_monotonic_low > (uint32_t)-1000)
+ {
+ /* Timestamp we received is within one second of the current time.
+ */
+ gint64 last_frame_time = now_monotonic + (gint64)1000 * (gint32)(frame_time - now_monotonic_low);
+ if ((gint32)now_monotonic_low < 0 && (gint32)frame_time > 0)
+ last_frame_time += (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
+ else if ((gint32)now_monotonic_low > 0 && (gint32)frame_time < 0)
+ last_frame_time -= (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
+
+ timings->presentation_time = last_frame_time + timings->refresh_interval;
+ }
}
static void
-gdk_wayland_surface_freeze_state (GdkSurface *surface)
+gdk_wayland_surface_get_window_geometry (GdkSurface *surface,
+ GdkRectangle *geometry)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- impl->state_freeze_count++;
+ *geometry = (GdkRectangle) {
+ .x = impl->shadow_left,
+ .y = impl->shadow_top,
+ .width = surface->width - (impl->shadow_left + impl->shadow_right),
+ .height = surface->height - (impl->shadow_top + impl->shadow_bottom)
+ };
}
-static void
-gdk_wayland_surface_thaw_state (GdkSurface *surface)
+static struct wl_region *
+wl_region_from_cairo_region (GdkWaylandDisplay *display,
+ cairo_region_t *region)
{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
-
- g_assert (impl->state_freeze_count > 0);
+ struct wl_region *wl_region;
+ int i, n_rects;
- impl->state_freeze_count--;
+ wl_region = wl_compositor_create_region (display->compositor);
+ if (wl_region == NULL)
+ return NULL;
- if (impl->state_freeze_count > 0)
- return;
+ n_rects = cairo_region_num_rectangles (region);
+ for (i = 0; i < n_rects; i++)
+ {
+ cairo_rectangle_int_t rect;
+ cairo_region_get_rectangle (region, i, &rect);
+ wl_region_add (wl_region, rect.x, rect.y, rect.width, rect.height);
+ }
- if (impl->pending.is_dirty)
- gdk_wayland_surface_configure (surface);
+ return wl_region;
}
-static void
-_gdk_wayland_surface_save_size (GdkSurface *surface)
+static const char *
+get_default_title (void)
{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
-
- if (surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN |
- GDK_TOPLEVEL_STATE_MAXIMIZED |
- GDK_TOPLEVEL_STATE_TILED))
- return;
+ const char *title;
- if (surface->width <= 1 || surface->height <= 1)
- return;
+ title = g_get_application_name ();
+ if (!title)
+ title = g_get_prgname ();
+ if (!title)
+ title = "";
- impl->saved_width = surface->width - impl->shadow_left - impl->shadow_right;
- impl->saved_height = surface->height - impl->shadow_top - impl->shadow_bottom;
+ return title;
}
-static void
-_gdk_wayland_surface_clear_saved_size (GdkSurface *surface)
+static gboolean
+is_realized_shell_surface (GdkWaylandSurface *impl)
+{
+ return (impl->display_server.xdg_surface ||
+ impl->display_server.zxdg_surface_v6);
+}
+
+static enum xdg_positioner_anchor
+rect_anchor_to_anchor (GdkGravity rect_anchor)
+{
+ switch (rect_anchor)
+ {
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_STATIC:
+ return XDG_POSITIONER_ANCHOR_TOP_LEFT;
+ case GDK_GRAVITY_NORTH:
+ return XDG_POSITIONER_ANCHOR_TOP;
+ case GDK_GRAVITY_NORTH_EAST:
+ return XDG_POSITIONER_ANCHOR_TOP_RIGHT;
+ case GDK_GRAVITY_WEST:
+ return XDG_POSITIONER_ANCHOR_LEFT;
+ case GDK_GRAVITY_CENTER:
+ return XDG_POSITIONER_ANCHOR_NONE;
+ case GDK_GRAVITY_EAST:
+ return XDG_POSITIONER_ANCHOR_RIGHT;
+ case GDK_GRAVITY_SOUTH_WEST:
+ return XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
+ case GDK_GRAVITY_SOUTH:
+ return XDG_POSITIONER_ANCHOR_BOTTOM;
+ case GDK_GRAVITY_SOUTH_EAST:
+ return XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static enum xdg_positioner_gravity
+surface_anchor_to_gravity (GdkGravity rect_anchor)
+{
+ switch (rect_anchor)
+ {
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_STATIC:
+ return XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT;
+ case GDK_GRAVITY_NORTH:
+ return XDG_POSITIONER_GRAVITY_BOTTOM;
+ case GDK_GRAVITY_NORTH_EAST:
+ return XDG_POSITIONER_GRAVITY_BOTTOM_LEFT;
+ case GDK_GRAVITY_WEST:
+ return XDG_POSITIONER_GRAVITY_RIGHT;
+ case GDK_GRAVITY_CENTER:
+ return XDG_POSITIONER_GRAVITY_NONE;
+ case GDK_GRAVITY_EAST:
+ return XDG_POSITIONER_GRAVITY_LEFT;
+ case GDK_GRAVITY_SOUTH_WEST:
+ return XDG_POSITIONER_GRAVITY_TOP_RIGHT;
+ case GDK_GRAVITY_SOUTH:
+ return XDG_POSITIONER_GRAVITY_TOP;
+ case GDK_GRAVITY_SOUTH_EAST:
+ return XDG_POSITIONER_GRAVITY_TOP_LEFT;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static enum zxdg_positioner_v6_anchor
+rect_anchor_to_anchor_legacy (GdkGravity rect_anchor)
+{
+ switch (rect_anchor)
+ {
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_STATIC:
+ return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
+ ZXDG_POSITIONER_V6_ANCHOR_LEFT);
+ case GDK_GRAVITY_NORTH:
+ return ZXDG_POSITIONER_V6_ANCHOR_TOP;
+ case GDK_GRAVITY_NORTH_EAST:
+ return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
+ ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
+ case GDK_GRAVITY_WEST:
+ return ZXDG_POSITIONER_V6_ANCHOR_LEFT;
+ case GDK_GRAVITY_CENTER:
+ return ZXDG_POSITIONER_V6_ANCHOR_NONE;
+ case GDK_GRAVITY_EAST:
+ return ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
+ case GDK_GRAVITY_SOUTH_WEST:
+ return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
+ ZXDG_POSITIONER_V6_ANCHOR_LEFT);
+ case GDK_GRAVITY_SOUTH:
+ return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
+ case GDK_GRAVITY_SOUTH_EAST:
+ return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
+ ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
+ default:
+ g_assert_not_reached ();
+ }
+
+ return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
+ ZXDG_POSITIONER_V6_ANCHOR_LEFT);
+}
+
+static enum zxdg_positioner_v6_gravity
+surface_anchor_to_gravity_legacy (GdkGravity rect_anchor)
+{
+ switch (rect_anchor)
+ {
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_STATIC:
+ return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
+ case GDK_GRAVITY_NORTH:
+ return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
+ case GDK_GRAVITY_NORTH_EAST:
+ return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_LEFT);
+ case GDK_GRAVITY_WEST:
+ return ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
+ case GDK_GRAVITY_CENTER:
+ return ZXDG_POSITIONER_V6_GRAVITY_NONE;
+ case GDK_GRAVITY_EAST:
+ return ZXDG_POSITIONER_V6_GRAVITY_LEFT;
+ case GDK_GRAVITY_SOUTH_WEST:
+ return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
+ ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
+ case GDK_GRAVITY_SOUTH:
+ return ZXDG_POSITIONER_V6_GRAVITY_TOP;
+ case GDK_GRAVITY_SOUTH_EAST:
+ return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
+ ZXDG_POSITIONER_V6_GRAVITY_LEFT);
+ default:
+ g_assert_not_reached ();
+ }
+
+ return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
+}
+
+/* }}} */
+/* {{{ Surface implementation */
+
+static void
+gdk_wayland_surface_init (GdkWaylandSurface *impl)
+{
+ impl->scale = 1;
+ impl->saved_width = -1;
+ impl->saved_height = -1;
+}
+
+static void
+gdk_wayland_surface_freeze_state (GdkSurface *surface)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ impl->state_freeze_count++;
+}
+
+static void
+gdk_wayland_surface_thaw_state (GdkSurface *surface)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ g_assert (impl->state_freeze_count > 0);
+
+ impl->state_freeze_count--;
+
+ if (impl->state_freeze_count > 0)
+ return;
+
+ if (impl->pending.is_dirty)
+ gdk_wayland_surface_configure (surface);
+}
+
+static void
+_gdk_wayland_surface_save_size (GdkSurface *surface)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ if (surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN |
+ GDK_TOPLEVEL_STATE_MAXIMIZED |
+ GDK_TOPLEVEL_STATE_TILED))
+ return;
+
+ if (surface->width <= 1 || surface->height <= 1)
+ return;
+
+ impl->saved_width = surface->width - impl->shadow_left - impl->shadow_right;
+ impl->saved_height = surface->height - impl->shadow_top - impl->shadow_bottom;
+}
+
+static void
+_gdk_wayland_surface_clear_saved_size (GdkSurface *surface)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
_gdk_surface_update_size (surface);
}
-static const char *
-get_default_title (void)
-{
- const char *title;
-
- title = g_get_application_name ();
- if (!title)
- title = g_get_prgname ();
- if (!title)
- title = "";
-
- return title;
-}
-
-static void
-fill_presentation_time_from_frame_time (GdkFrameTimings *timings,
- guint32 frame_time)
-{
- /* The timestamp in a wayland frame is a msec time value that in some
- * way reflects the time at which the server started drawing the frame.
- * This is not useful from our perspective.
- *
- * However, for the DRM backend of Weston, on reasonably recent
- * Linux, we know that the time is the
- * clock_gettime (CLOCK_MONOTONIC) value at the vblank, and that
- * backend starts drawing immediately after receiving the vblank
- * notification. If we detect this, and make the assumption that the
- * compositor will finish drawing before the next vblank, we can
- * then determine the presentation time as the frame time we
- * received plus one refresh interval.
- *
- * If a backend is using clock_gettime(CLOCK_MONOTONIC), but not
- * picking values right at the vblank, then the presentation times
- * we compute won't be accurate, but not really worse than then
- * the alternative of not providing presentation times at all.
- *
- * The complexity here is dealing with the fact that we receive
- * only the low 32 bits of the CLOCK_MONOTONIC value in milliseconds.
- */
- gint64 now_monotonic = g_get_monotonic_time ();
- gint64 now_monotonic_msec = now_monotonic / 1000;
- uint32_t now_monotonic_low = (uint32_t)now_monotonic_msec;
-
- if (frame_time - now_monotonic_low < 1000 ||
- frame_time - now_monotonic_low > (uint32_t)-1000)
- {
- /* Timestamp we received is within one second of the current time.
- */
- gint64 last_frame_time = now_monotonic + (gint64)1000 * (gint32)(frame_time - now_monotonic_low);
- if ((gint32)now_monotonic_low < 0 && (gint32)frame_time > 0)
- last_frame_time += (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
- else if ((gint32)now_monotonic_low > 0 && (gint32)frame_time < 0)
- last_frame_time -= (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
-
- timings->presentation_time = last_frame_time + timings->refresh_interval;
- }
-}
-
static GdkSurface *
get_popup_toplevel (GdkSurface *surface)
{
gdk_wayland_surface_thaw_state (toplevel);
}
-static void
-finish_pending_relayout (GdkWaylandPopup *wayland_popup)
-{
- g_assert (wayland_popup->state == POPUP_STATE_WAITING_FOR_FRAME);
- wayland_popup->state = POPUP_STATE_IDLE;
-
- thaw_popup_toplevel_state (wayland_popup);
-}
-
static void
frame_callback (void *data,
struct wl_callback *callback,
return;
if (GDK_IS_WAYLAND_POPUP (surface))
- {
- GdkWaylandPopup *wayland_popup = GDK_WAYLAND_POPUP (surface);
-
- switch (wayland_popup->state)
- {
- case POPUP_STATE_IDLE:
- case POPUP_STATE_WAITING_FOR_REPOSITIONED:
- case POPUP_STATE_WAITING_FOR_CONFIGURE:
- break;
- case POPUP_STATE_WAITING_FOR_FRAME:
- finish_pending_relayout (wayland_popup);
- break;
- default:
- g_assert_not_reached ();
- }
- }
+ frame_callback_popup (GDK_WAYLAND_POPUP (surface));
impl->awaiting_frame = FALSE;
if (impl->awaiting_frame_frozen)
gdk_surface_apply_state_change (surface);
}
-static void
-configure_popup_geometry (GdkWaylandPopup *wayland_popup)
-{
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_popup);
- int x, y;
- int width, height;
-
- x = wayland_popup->next_layout.x - wayland_surface->shadow_left;
- y = wayland_popup->next_layout.y - wayland_surface->shadow_top;
- width =
- wayland_surface->next_layout.configured_width +
- (wayland_surface->shadow_left + wayland_surface->shadow_right);
- height =
- wayland_surface->next_layout.configured_height +
- (wayland_surface->shadow_top + wayland_surface->shadow_bottom);
-
- gdk_wayland_surface_move_resize (GDK_SURFACE (wayland_popup), x, y, width, height);
-}
-
static void
configure_drag_surface_geometry (GdkSurface *surface)
{
{
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
GdkSurface *surface;
- GdkWaylandSurface *impl;
GdkFrameClock *frame_clock;
if (parent)
switch (surface_type)
{
case GDK_SURFACE_TOPLEVEL:
+ g_warn_if_fail (parent == NULL);
surface = g_object_new (GDK_TYPE_WAYLAND_TOPLEVEL,
"display", display,
"frame-clock", frame_clock,
"title", get_default_title (),
NULL);
- display_wayland->toplevels = g_list_prepend (display_wayland->toplevels,
- surface);
- g_warn_if_fail (!parent);
+ display_wayland->toplevels = g_list_prepend (display_wayland->toplevels, surface);
break;
case GDK_SURFACE_POPUP:
+ g_warn_if_fail (parent != NULL);
surface = g_object_new (GDK_TYPE_WAYLAND_POPUP,
"parent", parent,
"display", display,
NULL);
break;
case GDK_SURFACE_DRAG:
+ g_warn_if_fail (parent == NULL);
surface = g_object_new (GDK_TYPE_WAYLAND_DRAG_SURFACE,
"display", display,
"frame-clock", frame_clock,
break;
}
- impl = GDK_WAYLAND_SURFACE (surface);
-
if (width > 65535)
{
g_warning ("Native Surfaces wider than 65535 pixels are not supported");
GdkMonitor *monitor = g_list_model_get_item (gdk_display_get_monitors (display), 0);
if (monitor)
{
- impl->scale = gdk_monitor_get_scale_factor (monitor);
+ GDK_WAYLAND_SURFACE (surface)->scale = gdk_monitor_get_scale_factor (monitor);
g_object_unref (monitor);
}
}
static gboolean
gdk_wayland_surface_beep (GdkSurface *surface)
{
- gdk_wayland_display_system_bell (gdk_surface_get_display (surface),
- surface);
+ gdk_wayland_display_system_bell (gdk_surface_get_display (surface), surface);
return TRUE;
}
G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->finalize (object);
}
-static gboolean
-is_realized_shell_surface (GdkWaylandSurface *impl)
-{
- return (impl->display_server.xdg_surface ||
- impl->display_server.zxdg_surface_v6);
-}
-
-static gboolean
-is_realized_toplevel (GdkWaylandSurface *impl)
-{
- GdkWaylandToplevel *toplevel;
-
- if (!GDK_IS_WAYLAND_TOPLEVEL (impl))
- return FALSE;
-
- toplevel = GDK_WAYLAND_TOPLEVEL (impl);
-
- return (toplevel->display_server.xdg_toplevel ||
- toplevel->display_server.zxdg_toplevel_v6);
-}
-
-static gboolean
-is_realized_popup (GdkWaylandSurface *impl)
-{
- GdkWaylandPopup *popup;
-
- if (!GDK_IS_WAYLAND_POPUP (impl))
- return FALSE;
-
- popup = GDK_WAYLAND_POPUP (impl);
-
- return (popup->display_server.xdg_popup ||
- popup->display_server.zxdg_popup_v6);
-}
-
static void
gdk_wayland_surface_maybe_resize (GdkSurface *surface,
int width,
* force the new size onto the compositor. See bug #772505.
*/
- is_xdg_popup = is_realized_popup (impl);
+ is_xdg_popup = GDK_IS_WAYLAND_POPUP (surface);
is_visible = gdk_surface_get_mapped (surface);
if (is_xdg_popup && is_visible && !impl->initial_configure_received)
gdk_wayland_surface_show (surface);
}
-static void
-gdk_wayland_surface_sync_parent (GdkSurface *surface,
- GdkSurface *parent)
-{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (impl);
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- GdkWaylandSurface *impl_parent = NULL;
-
- g_assert (parent == NULL ||
- gdk_surface_get_display (surface) == gdk_surface_get_display (parent));
-
- if (!is_realized_toplevel (impl))
- return;
-
- if (toplevel->transient_for)
- impl_parent = GDK_WAYLAND_SURFACE (toplevel->transient_for);
- else if (parent)
- impl_parent = GDK_WAYLAND_SURFACE (parent);
-
- /* XXX: Is this correct? */
- if (impl_parent && !impl_parent->display_server.wl_surface)
- return;
-
- switch (display_wayland->shell_variant)
- {
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- {
- struct xdg_toplevel *parent_toplevel;
-
- if (impl_parent)
- parent_toplevel = GDK_WAYLAND_TOPLEVEL (impl_parent)->display_server.xdg_toplevel;
- else
- parent_toplevel = NULL;
-
- xdg_toplevel_set_parent (GDK_WAYLAND_TOPLEVEL (impl)->display_server.xdg_toplevel, parent_toplevel);
- break;
- }
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- {
- struct zxdg_toplevel_v6 *parent_toplevel;
-
- if (impl_parent)
- parent_toplevel = GDK_WAYLAND_TOPLEVEL (impl_parent)->display_server.zxdg_toplevel_v6;
- else
- parent_toplevel = NULL;
-
- zxdg_toplevel_v6_set_parent (GDK_WAYLAND_TOPLEVEL (impl)->display_server.zxdg_toplevel_v6, parent_toplevel);
- break;
- }
- default:
- g_assert_not_reached ();
- }
-}
-
-static void
-gdk_wayland_toplevel_sync_parent_of_imported (GdkWaylandToplevel *toplevel)
-{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
-
- if (!toplevel->imported_transient_for && !toplevel->imported_transient_for_v2)
- return;
-
- if (!impl->display_server.wl_surface)
- return;
-
- if (toplevel->imported_transient_for)
- zxdg_imported_v1_set_parent_of (toplevel->imported_transient_for,
- impl->display_server.wl_surface);
- else
- zxdg_imported_v2_set_parent_of (toplevel->imported_transient_for_v2,
- impl->display_server.wl_surface);
-}
-
-static void
-gdk_wayland_toplevel_sync_title (GdkWaylandToplevel *toplevel)
-{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
-
- if (!is_realized_toplevel (impl))
- return;
-
- if (!toplevel->title)
- return;
-
- switch (display_wayland->shell_variant)
- {
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_set_title (toplevel->display_server.xdg_toplevel, toplevel->title);
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_set_title (toplevel->display_server.zxdg_toplevel_v6, toplevel->title);
- break;
- default:
- g_assert_not_reached ();
- }
-}
-
-static void
-gdk_wayland_surface_get_window_geometry (GdkSurface *surface,
- GdkRectangle *geometry)
-{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
-
- *geometry = (GdkRectangle) {
- .x = impl->shadow_left,
- .y = impl->shadow_top,
- .width = surface->width - (impl->shadow_left + impl->shadow_right),
- .height = surface->height - (impl->shadow_top + impl->shadow_bottom)
- };
-}
-
-static void gdk_wayland_toplevel_set_geometry_hints (GdkWaylandToplevel *toplevel,
- const GdkGeometry *geometry,
- GdkSurfaceHints geom_mask);
-
static void
gdk_wayland_surface_sync_shadow (GdkSurface *surface)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
GdkRectangle geometry;
if (!is_realized_shell_surface (impl))
if (GDK_IS_WAYLAND_TOPLEVEL (impl))
{
GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (impl);
- gdk_wayland_toplevel_set_geometry_hints (toplevel,
- &toplevel->geometry_hints,
- toplevel->geometry_mask);
+ gdk_wayland_toplevel_set_geometry_hints (toplevel, NULL, 0);
}
if (gdk_rectangle_equal (&geometry, &impl->last_sent_window_geometry))
impl->last_sent_window_geometry = geometry;
}
-static struct wl_region *
-wl_region_from_cairo_region (GdkWaylandDisplay *display,
- cairo_region_t *region)
-{
- struct wl_region *wl_region;
- int i, n_rects;
-
- wl_region = wl_compositor_create_region (display->compositor);
- if (wl_region == NULL)
- return NULL;
-
- n_rects = cairo_region_num_rectangles (region);
- for (i = 0; i < n_rects; i++)
- {
- cairo_rectangle_int_t rect;
- cairo_region_get_rectangle (region, i, &rect);
- wl_region_add (wl_region, rect.x, rect.y, rect.width, rect.height);
- }
-
- return wl_region;
-}
-
static void
gdk_wayland_surface_sync_opaque_region (GdkSurface *surface)
{
}
static void
-configure_toplevel_geometry (GdkWaylandToplevel *wayland_toplevel)
+maybe_notify_mapped (GdkSurface *surface)
{
- GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_toplevel);
- GdkDisplay *display = gdk_surface_get_display (surface);
- int bounds_width, bounds_height;
- GdkToplevelSize size;
- GdkToplevelLayout *layout;
- GdkGeometry geometry;
- GdkSurfaceHints mask;
+ if (surface->destroyed)
+ return;
- if (wayland_toplevel->has_bounds)
+ if (!GDK_SURFACE_IS_MAPPED (surface))
+ gdk_surface_set_is_mapped (surface, TRUE);
+}
+
+static void
+gdk_wayland_surface_configure (GdkSurface *surface)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ if (!impl->initial_configure_received)
{
- bounds_width = wayland_toplevel->bounds_width;
- bounds_height = wayland_toplevel->bounds_height;
+ gdk_surface_thaw_updates (surface);
+ impl->initial_configure_received = TRUE;
+ impl->pending.is_initial_configure = TRUE;
+ maybe_notify_mapped (surface);
}
- else
- {
- GdkMonitor *monitor;
- GListModel *monitors;
- GdkRectangle monitor_geometry, display_geometry = { 0 };
- guint i;
- monitors = gdk_display_get_monitors (display);
+ impl->has_uncommitted_ack_configure = TRUE;
- for (i = 0; i < g_list_model_get_n_items (monitors); i++)
- {
- monitor = g_list_model_get_item (monitors, i);
- gdk_monitor_get_geometry (monitor, &monitor_geometry);
- gdk_rectangle_union (&display_geometry, &monitor_geometry, &display_geometry);
- g_object_unref (monitor);
- }
+ if (GDK_IS_WAYLAND_POPUP (surface))
+ gdk_wayland_surface_configure_popup (GDK_WAYLAND_POPUP (surface));
+ else if (GDK_IS_WAYLAND_TOPLEVEL (surface))
+ gdk_wayland_surface_configure_toplevel (GDK_WAYLAND_TOPLEVEL (surface));
+ else
+ g_warn_if_reached ();
- bounds_width = display_geometry.width;
- bounds_height = display_geometry.height;
- }
+ impl->last_configure_serial = impl->pending.serial;
- gdk_toplevel_size_init (&size, bounds_width, bounds_height);
- gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size);
- g_warn_if_fail (size.width > 0);
- g_warn_if_fail (size.height > 0);
+ memset (&impl->pending, 0, sizeof (impl->pending));
+}
- layout = wayland_toplevel->layout;
- if (gdk_toplevel_layout_get_resizable (layout))
- {
- geometry.min_width = size.min_width;
- geometry.min_height = size.min_height;
- mask = GDK_HINT_MIN_SIZE;
- }
- else
- {
- geometry.max_width = geometry.min_width = size.width;
- geometry.max_height = geometry.min_height = size.height;
- mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
- }
+static void
+gdk_wayland_surface_handle_configure (GdkWaylandSurface *impl,
+ uint32_t serial)
+{
+ impl->pending.is_dirty = TRUE;
+ impl->pending.serial = serial;
- gdk_wayland_toplevel_set_geometry_hints (wayland_toplevel, &geometry, mask);
+ if (impl->state_freeze_count > 0)
+ return;
- if (size.shadow.is_valid)
- {
- wayland_surface->shadow_left = size.shadow.left;
- wayland_surface->shadow_right = size.shadow.right;
- wayland_surface->shadow_top = size.shadow.top;
- wayland_surface->shadow_bottom = size.shadow.bottom;
- }
+ gdk_wayland_surface_configure (GDK_SURFACE (impl));
+}
- if (wayland_surface->next_layout.configured_width > 0 &&
- wayland_surface->next_layout.configured_height > 0)
- {
- int width, height;
+static void
+gdk_wayland_surface_handle_close (GdkSurface *surface)
+{
+ GdkDisplay *display;
+ GdkEvent *event;
- width = wayland_surface->next_layout.configured_width +
- wayland_surface->shadow_left + wayland_surface->shadow_right;
- height = wayland_surface->next_layout.configured_height +
- wayland_surface->shadow_top + wayland_surface->shadow_bottom;
+ display = gdk_surface_get_display (surface);
- if (wayland_toplevel->next_layout.should_constrain)
- {
- gdk_surface_constrain_size (&wayland_toplevel->geometry_hints,
- wayland_toplevel->geometry_mask,
- width, height,
- &width, &height);
- }
- gdk_wayland_surface_update_size (surface, width, height, wayland_surface->scale);
+ GDK_DISPLAY_DEBUG (display, EVENTS, "close %p", surface);
- if (!wayland_toplevel->next_layout.size_is_fixed)
- {
- wayland_toplevel->next_layout.should_constrain = FALSE;
- wayland_surface->next_layout.configured_width = 0;
- wayland_surface->next_layout.configured_height = 0;
- }
- }
- else
- {
- int width, height;
+ event = gdk_delete_event_new (surface);
- width = size.width;
- height = size.height;
- gdk_surface_constrain_size (&geometry, mask,
- width, height,
- &width, &height);
- gdk_wayland_surface_update_size (surface, width, height, wayland_surface->scale);
- }
+ _gdk_wayland_display_deliver_event (display, event);
}
static void
-synthesize_initial_surface_state (GdkWaylandToplevel *wayland_toplevel,
- GdkToplevelState unset_flags,
- GdkToplevelState set_flags)
+xdg_surface_configure (void *data,
+ struct xdg_surface *xdg_surface,
+ uint32_t serial)
{
- wayland_toplevel->initial_state.unset_flags |= unset_flags;
- wayland_toplevel->initial_state.set_flags &= ~unset_flags;
-
- wayland_toplevel->initial_state.set_flags |= set_flags;
- wayland_toplevel->initial_state.unset_flags &= ~set_flags;
+ gdk_wayland_surface_handle_configure (GDK_WAYLAND_SURFACE (data), serial);
}
+static const struct xdg_surface_listener xdg_surface_listener = {
+ xdg_surface_configure,
+};
+
static void
-gdk_wayland_surface_configure_toplevel (GdkWaylandToplevel *wayland_toplevel)
+zxdg_surface_v6_configure (void *data,
+ struct zxdg_surface_v6 *xdg_surface,
+ uint32_t serial)
{
- GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_toplevel);
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- GdkToplevelState new_state;
- int width, height;
- gboolean is_resizing;
- gboolean fixed_size;
- gboolean was_fixed_size;
- gboolean saved_size;
+ gdk_wayland_surface_handle_configure (GDK_WAYLAND_SURFACE (data), serial);
+}
- new_state = wayland_toplevel->pending.state;
- wayland_toplevel->pending.state = 0;
+static const struct zxdg_surface_v6_listener zxdg_surface_v6_listener = {
+ zxdg_surface_v6_configure,
+};
- is_resizing = wayland_toplevel->pending.is_resizing;
- wayland_toplevel->pending.is_resizing = FALSE;
+static void
+gdk_wayland_surface_create_xdg_surface_resources (GdkSurface *surface)
+{
+ GdkWaylandDisplay *display =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- if (wayland_toplevel->pending.has_bounds)
+ switch (display->shell_variant)
{
- wayland_toplevel->bounds_width = wayland_toplevel->pending.bounds_width;
- wayland_toplevel->bounds_height = wayland_toplevel->pending.bounds_height;
- wayland_toplevel->has_bounds = TRUE;
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ impl->display_server.xdg_surface =
+ xdg_wm_base_get_xdg_surface (display->xdg_wm_base,
+ impl->display_server.wl_surface);
+ wl_proxy_set_queue ((struct wl_proxy *) impl->display_server.xdg_surface,
+ impl->event_queue);
+ xdg_surface_add_listener (impl->display_server.xdg_surface,
+ &xdg_surface_listener,
+ surface);
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ impl->display_server.zxdg_surface_v6 =
+ zxdg_shell_v6_get_xdg_surface (display->zxdg_shell_v6,
+ impl->display_server.wl_surface);
+ zxdg_surface_v6_add_listener (impl->display_server.zxdg_surface_v6,
+ &zxdg_surface_v6_listener,
+ surface);
+ break;
+ default:
+ g_assert_not_reached ();
}
+}
- fixed_size =
- new_state & (GDK_TOPLEVEL_STATE_MAXIMIZED |
- GDK_TOPLEVEL_STATE_FULLSCREEN |
- GDK_TOPLEVEL_STATE_TILED) ||
- is_resizing;
-
- was_fixed_size =
- surface->state & (GDK_TOPLEVEL_STATE_MAXIMIZED |
- GDK_TOPLEVEL_STATE_FULLSCREEN |
- GDK_TOPLEVEL_STATE_TILED);
+static void
+gdk_wayland_surface_map_toplevel (GdkSurface *surface)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- width = wayland_toplevel->pending.width;
- height = wayland_toplevel->pending.height;
+ if (!GDK_IS_WAYLAND_TOPLEVEL (surface))
+ return;
- saved_size = (width == 0 && height == 0);
- /* According to xdg_shell, an xdg_surface.configure with size 0x0
- * should be interpreted as that it is up to the client to set a
- * size.
- *
- * When transitioning from maximize or fullscreen state, this means
- * the client should configure its size back to what it was before
- * being maximize or fullscreen.
- */
- if (saved_size && !fixed_size && was_fixed_size)
- {
- width = wayland_surface->saved_width;
- height = wayland_surface->saved_height;
- }
+ if (impl->mapped)
+ return;
- if (width > 0 && height > 0)
- {
- if (!saved_size)
- {
- wayland_toplevel->next_layout.should_constrain = TRUE;
+ gdk_wayland_surface_create_xdg_toplevel (GDK_WAYLAND_TOPLEVEL (surface));
- /* Save size for next time we get 0x0 */
- _gdk_wayland_surface_save_size (surface);
- }
- else if (is_resizing)
- {
- wayland_toplevel->next_layout.should_constrain = TRUE;
- }
- else
- {
- wayland_toplevel->next_layout.should_constrain = FALSE;
- }
+ impl->mapped = TRUE;
+}
- wayland_toplevel->next_layout.size_is_fixed = fixed_size;
- wayland_surface->next_layout.configured_width = width;
- wayland_surface->next_layout.configured_height = height;
- }
- else
- {
- wayland_toplevel->next_layout.should_constrain = FALSE;
- wayland_toplevel->next_layout.size_is_fixed = FALSE;
- wayland_surface->next_layout.configured_width = 0;
- wayland_surface->next_layout.configured_height = 0;
- }
+static void
+gdk_wayland_surface_show (GdkSurface *surface)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- wayland_surface->next_layout.surface_geometry_dirty = TRUE;
- gdk_surface_request_layout (surface);
+ if (!impl->display_server.wl_surface)
+ gdk_wayland_surface_create_wl_surface (surface);
- GDK_DISPLAY_DEBUG (gdk_surface_get_display (surface), EVENTS,
- "configure, surface %p %dx%d,%s%s%s%s",
- surface, width, height,
- (new_state & GDK_TOPLEVEL_STATE_FULLSCREEN) ? " fullscreen" : "",
- (new_state & GDK_TOPLEVEL_STATE_MAXIMIZED) ? " maximized" : "",
- (new_state & GDK_TOPLEVEL_STATE_FOCUSED) ? " focused" : "",
- (new_state & GDK_TOPLEVEL_STATE_TILED) ? " tiled" : "");
+ gdk_wayland_surface_map_toplevel (surface);
+}
- gdk_surface_queue_state_change (surface, ~0 & ~new_state, new_state);
+static void
+unmap_popups_for_surface (GdkSurface *surface)
+{
+ GdkWaylandDisplay *display_wayland;
+ GList *l;
- switch (display_wayland->shell_variant)
+ display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ for (l = display_wayland->current_popups; l; l = l->next)
{
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_surface_ack_configure (wayland_surface->display_server.xdg_surface,
- wayland_surface->pending.serial);
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_surface_v6_ack_configure (wayland_surface->display_server.zxdg_surface_v6,
- wayland_surface->pending.serial);
- break;
- default:
- g_assert_not_reached ();
+ GdkSurface *popup = l->data;
+
+ if (popup->parent == surface)
+ {
+ g_warning ("Tried to unmap the parent of a popup");
+ gdk_surface_hide (popup);
+
+ return;
+ }
}
}
static void
-gdk_wayland_surface_configure_popup (GdkWaylandPopup *wayland_popup)
+gdk_wayland_surface_hide_surface (GdkSurface *surface)
{
- GdkSurface *surface = GDK_SURFACE (wayland_popup);
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_popup);
- GdkRectangle parent_geometry;
- int x, y, width, height;
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- if (wayland_popup->display_server.xdg_popup)
- {
- xdg_surface_ack_configure (wayland_surface->display_server.xdg_surface,
- wayland_surface->pending.serial);
- }
- else if (wayland_popup->display_server.zxdg_popup_v6)
+ unmap_popups_for_surface (surface);
+
+ if (impl->display_server.wl_surface)
{
- zxdg_surface_v6_ack_configure (wayland_surface->display_server.zxdg_surface_v6,
- wayland_surface->pending.serial);
- }
+ if (impl->display_server.egl_window)
+ {
+ gdk_surface_set_egl_native_window (surface, NULL);
+ wl_egl_window_destroy (impl->display_server.egl_window);
+ impl->display_server.egl_window = NULL;
+ }
- if (wayland_popup->pending.has_repositioned_token)
- wayland_popup->received_reposition_token = wayland_popup->pending.repositioned_token;
+ if (impl->display_server.xdg_surface)
+ {
+ xdg_surface_destroy (impl->display_server.xdg_surface);
+ impl->display_server.xdg_surface = NULL;
+ if (!impl->initial_configure_received)
+ gdk_surface_thaw_updates (surface);
+ else
+ impl->initial_configure_received = FALSE;
+ }
+ if (impl->display_server.zxdg_surface_v6)
+ {
+ g_clear_pointer (&impl->display_server.zxdg_surface_v6, zxdg_surface_v6_destroy);
+ if (!impl->initial_configure_received)
+ gdk_surface_thaw_updates (surface);
+ else
+ impl->initial_configure_received = FALSE;
+ }
- switch (wayland_popup->state)
- {
- case POPUP_STATE_WAITING_FOR_REPOSITIONED:
- if (wayland_popup->received_reposition_token != wayland_popup->reposition_token)
- return;
- else
- gdk_surface_thaw_updates (surface);
- G_GNUC_FALLTHROUGH;
- case POPUP_STATE_WAITING_FOR_CONFIGURE:
- wayland_popup->state = POPUP_STATE_WAITING_FOR_FRAME;
- break;
- case POPUP_STATE_IDLE:
- case POPUP_STATE_WAITING_FOR_FRAME:
- break;
- default:
- g_assert_not_reached ();
+ impl->awaiting_frame = FALSE;
+ if (impl->awaiting_frame_frozen)
+ {
+ impl->awaiting_frame_frozen = FALSE;
+ gdk_surface_thaw_updates (surface);
+ }
+
+ if (GDK_IS_WAYLAND_TOPLEVEL (surface))
+ gdk_wayland_toplevel_hide_surface (GDK_WAYLAND_TOPLEVEL (surface));
+
+ if (GDK_IS_WAYLAND_POPUP (surface))
+ gdk_wayland_popup_hide_surface (GDK_WAYLAND_POPUP (surface));
+
+ g_clear_pointer (&impl->display_server.wl_surface, wl_surface_destroy);
+
+ g_slist_free (impl->display_server.outputs);
+ impl->display_server.outputs = NULL;
}
- x = wayland_popup->pending.x;
- y = wayland_popup->pending.y;
- width = wayland_popup->pending.width;
- height = wayland_popup->pending.height;
+ impl->has_uncommitted_ack_configure = FALSE;
+ impl->input_region_dirty = TRUE;
+ impl->opaque_region_dirty = TRUE;
- gdk_wayland_surface_get_window_geometry (surface->parent, &parent_geometry);
- x += parent_geometry.x;
- y += parent_geometry.y;
+ unset_transient_for_exported (surface);
- update_popup_layout_state (wayland_popup,
- x, y,
- width, height,
- wayland_popup->layout);
+ impl->last_sent_window_geometry = (GdkRectangle) { 0 };
- wayland_popup->next_layout.x = x;
- wayland_popup->next_layout.y = y;
- wayland_surface->next_layout.configured_width = width;
- wayland_surface->next_layout.configured_height = height;
- wayland_surface->next_layout.surface_geometry_dirty = TRUE;
- gdk_surface_request_layout (surface);
+ _gdk_wayland_surface_clear_saved_size (surface);
+ impl->mapped = FALSE;
}
static void
-maybe_notify_mapped (GdkSurface *surface)
+gdk_wayland_surface_hide (GdkSurface *surface)
{
- if (surface->destroyed)
- return;
+ GdkSeat *seat;
- if (!GDK_SURFACE_IS_MAPPED (surface))
- gdk_surface_set_is_mapped (surface, TRUE);
+ seat = gdk_display_get_default_seat (surface->display);
+ if (seat)
+ {
+ if (surface->autohide)
+ gdk_seat_ungrab (seat);
+
+ gdk_wayland_seat_clear_touchpoints (GDK_WAYLAND_SEAT (seat), surface);
+ }
+ gdk_wayland_surface_hide_surface (surface);
+ _gdk_surface_clear_update_area (surface);
}
static void
-gdk_wayland_surface_configure (GdkSurface *surface)
+gdk_wayland_surface_move_resize (GdkSurface *surface,
+ int x,
+ int y,
+ int width,
+ int height)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- if (!impl->initial_configure_received)
- {
- gdk_surface_thaw_updates (surface);
- impl->initial_configure_received = TRUE;
- impl->pending.is_initial_configure = TRUE;
- maybe_notify_mapped (surface);
- }
-
- impl->has_uncommitted_ack_configure = TRUE;
+ surface->x = x;
+ surface->y = y;
+ gdk_wayland_surface_maybe_resize (surface, width, height, impl->scale);
+}
- if (is_realized_popup (impl))
- {
- g_assert (GDK_IS_WAYLAND_POPUP (surface));
- GdkWaylandPopup *wayland_popup = GDK_WAYLAND_POPUP (surface);
- gdk_wayland_surface_configure_popup (wayland_popup);
- }
- else if (is_realized_toplevel (impl))
+static void
+gdk_wayland_surface_get_geometry (GdkSurface *surface,
+ int *x,
+ int *y,
+ int *width,
+ int *height)
+{
+ if (!GDK_SURFACE_DESTROYED (surface))
{
- g_assert (GDK_IS_WAYLAND_TOPLEVEL (surface));
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- gdk_wayland_surface_configure_toplevel (wayland_toplevel);
+ if (x)
+ *x = surface->x;
+ if (y)
+ *y = surface->y;
+ if (width)
+ *width = surface->width;
+ if (height)
+ *height = surface->height;
}
- else
- g_warn_if_reached ();
-
- impl->last_configure_serial = impl->pending.serial;
-
- memset (&impl->pending, 0, sizeof (impl->pending));
}
static void
-gdk_wayland_surface_handle_configure (GdkSurface *surface,
- uint32_t serial)
+gdk_wayland_surface_get_root_coords (GdkSurface *surface,
+ int x,
+ int y,
+ int *root_x,
+ int *root_y)
{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
-
- impl->pending.is_dirty = TRUE;
- impl->pending.serial = serial;
+ /*
+ * Wayland does not have a global coordinate space shared between surfaces. In
+ * fact, for regular toplevels, we have no idea where our surfaces are
+ * positioned, relatively.
+ *
+ * However, there are some cases like popups and subsurfaces where we do have
+ * some amount of control over the placement of our surface, and we can
+ * semi-accurately control the x/y position of these surfaces, if they are
+ * relative to another surface.
+ *
+ * To pretend we have something called a root coordinate space, assume all
+ * parent-less surfaces are positioned in (0, 0), and all relative positioned
+ * popups and subsurfaces are placed within this fake root coordinate space.
+ *
+ * For example a 200x200 large toplevel surface will have the position (0, 0).
+ * If a popup positioned in the middle of the toplevel will have the fake
+ * position (100,100). Furthermore, if a positioned is placed in the middle
+ * that popup, will have the fake position (150,150), even though it has the
+ * relative position (50,50). These three surfaces would make up one single
+ * fake root coordinate space.
+ */
- if (impl->state_freeze_count > 0)
- return;
+ if (root_x)
+ *root_x = surface->x + x;
- gdk_wayland_surface_configure (surface);
+ if (root_y)
+ *root_y = surface->y + y;
}
-static void
-gdk_wayland_surface_handle_configure_toplevel (GdkSurface *surface,
- int32_t width,
- int32_t height,
- GdkToplevelState state)
+static gboolean
+gdk_wayland_surface_get_device_state (GdkSurface *surface,
+ GdkDevice *device,
+ double *x,
+ double *y,
+ GdkModifierType *mask)
{
- GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
+ if (GDK_SURFACE_DESTROYED (surface))
+ return FALSE;
- toplevel->pending.state |= state;
- toplevel->pending.width = width;
- toplevel->pending.height = height;
+ gdk_wayland_device_query_state (device, surface, x, y, mask);
+
+ return *x >= 0 && *y >= 0 && *x < surface->width && *y < surface->height;
}
static void
-gdk_wayland_surface_handle_close (GdkSurface *surface)
+gdk_wayland_surface_set_input_region (GdkSurface *surface,
+ cairo_region_t *input_region)
{
- GdkDisplay *display;
- GdkEvent *event;
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- display = gdk_surface_get_display (surface);
+ if (GDK_SURFACE_DESTROYED (surface))
+ return;
- GDK_DISPLAY_DEBUG (display, EVENTS, "close %p", surface);
+ g_clear_pointer (&impl->input_region, cairo_region_destroy);
- event = gdk_delete_event_new (surface);
+ if (input_region)
+ impl->input_region = cairo_region_copy (input_region);
- _gdk_wayland_display_deliver_event (display, event);
+ impl->input_region_dirty = TRUE;
}
static void
-xdg_surface_configure (void *data,
- struct xdg_surface *xdg_surface,
- uint32_t serial)
+gdk_wayland_surface_destroy (GdkSurface *surface,
+ gboolean foreign_destroy)
{
- GdkSurface *surface = GDK_SURFACE (data);
+ GdkWaylandDisplay *display;
+ GdkFrameClock *frame_clock;
- gdk_wayland_surface_handle_configure (surface, serial);
-}
+ g_return_if_fail (GDK_IS_SURFACE (surface));
-static const struct xdg_surface_listener xdg_surface_listener = {
- xdg_surface_configure,
-};
+ /* Wayland surfaces can't be externally destroyed; we may possibly
+ * eventually want to use this path at display close-down
+ */
+ g_return_if_fail (!foreign_destroy);
-static void
-zxdg_surface_v6_configure (void *data,
- struct zxdg_surface_v6 *xdg_surface,
- uint32_t serial)
-{
- GdkSurface *surface = GDK_SURFACE (data);
+ gdk_wayland_surface_hide_surface (surface);
- gdk_wayland_surface_handle_configure (surface, serial);
-}
+ frame_clock = gdk_surface_get_frame_clock (surface);
+ g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface);
+ g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_after_paint, surface);
-static const struct zxdg_surface_v6_listener zxdg_surface_v6_listener = {
- zxdg_surface_v6_configure,
-};
+ display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ display->toplevels = g_list_remove (display->toplevels, surface);
+}
static void
-gdk_wayland_surface_create_xdg_surface_resources (GdkSurface *surface)
+gdk_wayland_surface_destroy_notify (GdkSurface *surface)
{
- GdkWaylandDisplay *display =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
-
- switch (display->shell_variant)
+ if (!GDK_SURFACE_DESTROYED (surface))
{
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- impl->display_server.xdg_surface =
- xdg_wm_base_get_xdg_surface (display->xdg_wm_base,
- impl->display_server.wl_surface);
- wl_proxy_set_queue ((struct wl_proxy *) impl->display_server.xdg_surface,
- impl->event_queue);
- xdg_surface_add_listener (impl->display_server.xdg_surface,
- &xdg_surface_listener,
- surface);
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- impl->display_server.zxdg_surface_v6 =
- zxdg_shell_v6_get_xdg_surface (display->zxdg_shell_v6,
- impl->display_server.wl_surface);
- zxdg_surface_v6_add_listener (impl->display_server.zxdg_surface_v6,
- &zxdg_surface_v6_listener,
- surface);
- break;
- default:
- g_assert_not_reached ();
+ g_warning ("GdkSurface %p unexpectedly destroyed", surface);
+ _gdk_surface_destroy (surface, TRUE);
}
+
+ g_object_unref (surface);
}
-static void
-xdg_toplevel_configure (void *data,
- struct xdg_toplevel *xdg_toplevel,
- int32_t width,
- int32_t height,
- struct wl_array *states)
+static int
+gdk_wayland_surface_get_scale_factor (GdkSurface *surface)
{
- GdkSurface *surface = GDK_SURFACE (data);
- GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- uint32_t *p;
- GdkToplevelState pending_state = 0;
-
- toplevel->pending.is_resizing = FALSE;
-
- wl_array_for_each (p, states)
- {
- uint32_t state = *p;
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- switch (state)
- {
- case XDG_TOPLEVEL_STATE_FULLSCREEN:
- pending_state |= GDK_TOPLEVEL_STATE_FULLSCREEN;
- break;
- case XDG_TOPLEVEL_STATE_MAXIMIZED:
- pending_state |= GDK_TOPLEVEL_STATE_MAXIMIZED;
- break;
- case XDG_TOPLEVEL_STATE_ACTIVATED:
- pending_state |= GDK_TOPLEVEL_STATE_FOCUSED;
- break;
- case XDG_TOPLEVEL_STATE_RESIZING:
- toplevel->pending.is_resizing = TRUE;
- break;
- case XDG_TOPLEVEL_STATE_TILED_TOP:
- pending_state |= (GDK_TOPLEVEL_STATE_TILED |
- GDK_TOPLEVEL_STATE_TOP_TILED);
- break;
- case XDG_TOPLEVEL_STATE_TILED_RIGHT:
- pending_state |= (GDK_TOPLEVEL_STATE_TILED |
- GDK_TOPLEVEL_STATE_RIGHT_TILED);
- break;
- case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
- pending_state |= (GDK_TOPLEVEL_STATE_TILED |
- GDK_TOPLEVEL_STATE_BOTTOM_TILED);
- break;
- case XDG_TOPLEVEL_STATE_TILED_LEFT:
- pending_state |= (GDK_TOPLEVEL_STATE_TILED |
- GDK_TOPLEVEL_STATE_LEFT_TILED);
- break;
- default:
- /* Unknown state */
- break;
- }
- }
+ if (GDK_SURFACE_DESTROYED (surface))
+ return 1;
- gdk_wayland_surface_handle_configure_toplevel (surface, width, height, pending_state);
+ return impl->scale;
}
static void
-xdg_toplevel_close (void *data,
- struct xdg_toplevel *xdg_toplevel)
+gdk_wayland_surface_set_opaque_region (GdkSurface *surface,
+ cairo_region_t *region)
{
- GdkSurface *surface = GDK_SURFACE (data);
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- gdk_wayland_surface_handle_close (surface);
+ if (GDK_SURFACE_DESTROYED (surface))
+ return;
+
+ g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
+ impl->opaque_region = cairo_region_reference (region);
+ impl->opaque_region_dirty = TRUE;
}
static void
-xdg_toplevel_configure_bounds (void *data,
- struct xdg_toplevel *xdg_toplevel,
- int32_t width,
- int32_t height)
+gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass)
{
- GdkSurface *surface = GDK_SURFACE (data);
- GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkSurfaceClass *impl_class = GDK_SURFACE_CLASS (klass);
- toplevel->pending.bounds_width = width;
- toplevel->pending.bounds_height = height;
- toplevel->pending.has_bounds = TRUE;
+ object_class->constructed = gdk_wayland_surface_constructed;
+ object_class->dispose = gdk_wayland_surface_dispose;
+ object_class->finalize = gdk_wayland_surface_finalize;
+
+ impl_class->hide = gdk_wayland_surface_hide;
+ impl_class->get_geometry = gdk_wayland_surface_get_geometry;
+ impl_class->get_root_coords = gdk_wayland_surface_get_root_coords;
+ impl_class->get_device_state = gdk_wayland_surface_get_device_state;
+ impl_class->set_input_region = gdk_wayland_surface_set_input_region;
+ impl_class->destroy = gdk_wayland_surface_destroy;
+ impl_class->beep = gdk_wayland_surface_beep;
+
+ impl_class->destroy_notify = gdk_wayland_surface_destroy_notify;
+ impl_class->drag_begin = _gdk_wayland_surface_drag_begin;
+ impl_class->get_scale_factor = gdk_wayland_surface_get_scale_factor;
+ impl_class->set_opaque_region = gdk_wayland_surface_set_opaque_region;
+ impl_class->request_layout = gdk_wayland_surface_request_layout;
+ impl_class->compute_size = gdk_wayland_surface_compute_size;
}
-static const struct xdg_toplevel_listener xdg_toplevel_listener = {
- xdg_toplevel_configure,
- xdg_toplevel_close,
- xdg_toplevel_configure_bounds,
-};
+/* }}} */
+/* {{{ Private Surface API */
-static void
-create_xdg_toplevel_resources (GdkWaylandToplevel *toplevel)
+struct wl_output *
+gdk_wayland_surface_get_wl_output (GdkSurface *surface)
{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
+ GdkWaylandSurface *impl;
- toplevel->display_server.xdg_toplevel =
- xdg_surface_get_toplevel (impl->display_server.xdg_surface);
- xdg_toplevel_add_listener (toplevel->display_server.xdg_toplevel,
- &xdg_toplevel_listener,
- toplevel);
+ g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL);
+
+ impl = GDK_WAYLAND_SURFACE (surface);
+ /* We pick the head of the list as this is the last entered output */
+ if (impl->display_server.outputs)
+ return (struct wl_output *) impl->display_server.outputs->data;
+
+ return NULL;
}
-static void
-zxdg_toplevel_v6_configure (void *data,
- struct zxdg_toplevel_v6 *xdg_toplevel,
- int32_t width,
- int32_t height,
- struct wl_array *states)
+void
+_gdk_wayland_surface_offset_next_wl_buffer (GdkSurface *surface,
+ int x,
+ int y)
{
- GdkSurface *surface = GDK_SURFACE (data);
- GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- uint32_t *p;
- GdkToplevelState pending_state = 0;
-
- toplevel->pending.is_resizing = FALSE;
+ GdkWaylandSurface *impl;
- wl_array_for_each (p, states)
- {
- uint32_t state = *p;
+ g_return_if_fail (GDK_IS_WAYLAND_SURFACE (surface));
- switch (state)
- {
- case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
- pending_state |= GDK_TOPLEVEL_STATE_FULLSCREEN;
- break;
- case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
- pending_state |= GDK_TOPLEVEL_STATE_MAXIMIZED;
- break;
- case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED:
- pending_state |= GDK_TOPLEVEL_STATE_FOCUSED;
- break;
- case ZXDG_TOPLEVEL_V6_STATE_RESIZING:
- toplevel->pending.is_resizing = TRUE;
- break;
- default:
- /* Unknown state */
- break;
- }
- }
+ impl = GDK_WAYLAND_SURFACE (surface);
- gdk_wayland_surface_handle_configure_toplevel (surface, width, height, pending_state);
+ impl->pending_buffer_offset_x = x;
+ impl->pending_buffer_offset_y = y;
}
-static void
-zxdg_toplevel_v6_close (void *data,
- struct zxdg_toplevel_v6 *xdg_toplevel)
+void
+gdk_wayland_surface_ensure_wl_egl_window (GdkSurface *surface)
{
- GdkSurface *surface = GDK_SURFACE (data);
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- gdk_wayland_surface_handle_close (surface);
+ if (impl->display_server.egl_window == NULL)
+ {
+ impl->display_server.egl_window =
+ wl_egl_window_create (impl->display_server.wl_surface,
+ surface->width * impl->scale,
+ surface->height * impl->scale);
+ wl_surface_set_buffer_scale (impl->display_server.wl_surface, impl->scale);
+
+ gdk_surface_set_egl_native_window (surface, impl->display_server.egl_window);
+ }
}
-static const struct zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
- zxdg_toplevel_v6_configure,
- zxdg_toplevel_v6_close,
-};
+/* }}} */
+/* {{{ Surface API */
-static void
-create_zxdg_toplevel_v6_resources (GdkWaylandToplevel *toplevel)
+/**
+ * gdk_wayland_surface_get_wl_surface: (skip)
+ * @surface: (type GdkWaylandSurface): a `GdkSurface`
+ *
+ * Returns the Wayland `wl_surface` of a `GdkSurface`.
+ *
+ * Returns: (transfer none): a Wayland `wl_surface`
+ */
+struct wl_surface *
+gdk_wayland_surface_get_wl_surface (GdkSurface *surface)
{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
+ g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL);
- toplevel->display_server.zxdg_toplevel_v6 =
- zxdg_surface_v6_get_toplevel (impl->display_server.zxdg_surface_v6);
- zxdg_toplevel_v6_add_listener (toplevel->display_server.zxdg_toplevel_v6,
- &zxdg_toplevel_v6_listener,
- toplevel);
+ return GDK_WAYLAND_SURFACE (surface)->display_server.wl_surface;
}
+/* }}}} */
+/* {{{ GdkWaylandPopup definition */
+
/**
- * gdk_wayland_toplevel_set_application_id:
- * @toplevel: (type GdkWaylandToplevel): a `GdkToplevel`
- * @application_id: the application id for the @toplevel
+ * GdkWaylandPopup:
*
- * Sets the application id on a `GdkToplevel`.
+ * The Wayland implementation of `GdkPopup`.
*/
-void
-gdk_wayland_toplevel_set_application_id (GdkToplevel *toplevel,
- const char *application_id)
+
+struct _GdkWaylandPopup
{
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- GdkWaylandSurface *impl;
- GdkWaylandDisplay *display_wayland;
+ GdkWaylandSurface parent_instance;
- g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
+ struct {
+ struct xdg_popup *xdg_popup;
+ struct zxdg_popup_v6 *zxdg_popup_v6;
+ } display_server;
- g_return_if_fail (application_id != NULL);
+ PopupState state;
+ unsigned int thaw_upon_show : 1;
+ GdkPopupLayout *layout;
+ int unconstrained_width;
+ int unconstrained_height;
- if (GDK_SURFACE_DESTROYED (toplevel))
- return;
+ struct {
+ int x;
+ int y;
+ int width;
+ int height;
+ uint32_t repositioned_token;
+ gboolean has_repositioned_token;
+ } pending;
- impl = GDK_WAYLAND_SURFACE (toplevel);
+ struct {
+ int x;
+ int y;
+ } next_layout;
- if (!is_realized_toplevel (impl))
- return;
+ uint32_t reposition_token;
+ uint32_t received_reposition_token;
- wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
+ GdkSeat *grab_input_seat;
+};
- switch (display_wayland->shell_variant)
+typedef struct
+{
+ GdkWaylandSurfaceClass parent_class;
+} GdkWaylandPopupClass;
+
+static void gdk_wayland_popup_iface_init (GdkPopupInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GdkWaylandPopup, gdk_wayland_popup, GDK_TYPE_WAYLAND_SURFACE,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP,
+ gdk_wayland_popup_iface_init))
+
+/* }}} */
+/* {{{ Popup implementation */
+
+static void
+gdk_wayland_popup_hide_surface (GdkWaylandPopup *popup)
+{
+ GdkSurface *surface = GDK_SURFACE (popup);
+ GdkDisplay *display = gdk_surface_get_display (surface);
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+
+ g_clear_pointer (&popup->display_server.xdg_popup, xdg_popup_destroy);
+ g_clear_pointer (&popup->display_server.zxdg_popup_v6, zxdg_popup_v6_destroy);
+ display_wayland->current_popups =
+ g_list_remove (display_wayland->current_popups, surface);
+ display_wayland->current_grabbing_popups =
+ g_list_remove (display_wayland->current_grabbing_popups, surface);
+
+ popup->thaw_upon_show = TRUE;
+ gdk_surface_freeze_updates (surface);
+
+ switch (popup->state)
{
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_set_app_id (wayland_toplevel->display_server.xdg_toplevel, application_id);
+ case POPUP_STATE_WAITING_FOR_REPOSITIONED:
+ gdk_surface_thaw_updates (surface);
+ G_GNUC_FALLTHROUGH;
+ case POPUP_STATE_WAITING_FOR_CONFIGURE:
+ case POPUP_STATE_WAITING_FOR_FRAME:
+ thaw_popup_toplevel_state (popup);
break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_set_app_id (wayland_toplevel->display_server.zxdg_toplevel_v6, application_id);
+ case POPUP_STATE_IDLE:
break;
default:
g_assert_not_reached ();
}
+
+ popup->state = POPUP_STATE_IDLE;
+
+ g_clear_pointer (&popup->layout, gdk_popup_layout_unref);
+}
+
+static gboolean
+is_realized_popup (GdkWaylandSurface *impl)
+{
+ GdkWaylandPopup *popup;
+
+ if (!GDK_IS_WAYLAND_POPUP (impl))
+ return FALSE;
+
+ popup = GDK_WAYLAND_POPUP (impl);
+
+ return (popup->display_server.xdg_popup ||
+ popup->display_server.zxdg_popup_v6);
}
static void
-gdk_wayland_surface_create_xdg_toplevel (GdkWaylandToplevel *wayland_toplevel)
+finish_pending_relayout (GdkWaylandPopup *wayland_popup)
{
- GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_toplevel);
- const char *app_id;
+ g_assert (wayland_popup->state == POPUP_STATE_WAITING_FOR_FRAME);
+ wayland_popup->state = POPUP_STATE_IDLE;
- gdk_surface_freeze_updates (surface);
- gdk_wayland_surface_create_xdg_surface_resources (surface);
+ thaw_popup_toplevel_state (wayland_popup);
+}
- switch (display_wayland->shell_variant)
+static void
+frame_callback_popup (GdkWaylandPopup *wayland_popup)
+{
+ switch (wayland_popup->state)
+ {
+ case POPUP_STATE_IDLE:
+ case POPUP_STATE_WAITING_FOR_REPOSITIONED:
+ case POPUP_STATE_WAITING_FOR_CONFIGURE:
+ break;
+ case POPUP_STATE_WAITING_FOR_FRAME:
+ finish_pending_relayout (wayland_popup);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+configure_popup_geometry (GdkWaylandPopup *wayland_popup)
+{
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_popup);
+ int x, y;
+ int width, height;
+
+ x = wayland_popup->next_layout.x - wayland_surface->shadow_left;
+ y = wayland_popup->next_layout.y - wayland_surface->shadow_top;
+ width =
+ wayland_surface->next_layout.configured_width +
+ (wayland_surface->shadow_left + wayland_surface->shadow_right);
+ height =
+ wayland_surface->next_layout.configured_height +
+ (wayland_surface->shadow_top + wayland_surface->shadow_bottom);
+
+ gdk_wayland_surface_move_resize (GDK_SURFACE (wayland_popup), x, y, width, height);
+}
+
+static void
+gdk_wayland_surface_configure_popup (GdkWaylandPopup *wayland_popup)
+{
+ GdkSurface *surface = GDK_SURFACE (wayland_popup);
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_popup);
+ GdkRectangle parent_geometry;
+ int x, y, width, height;
+
+ if (wayland_popup->display_server.xdg_popup)
{
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- create_xdg_toplevel_resources (wayland_toplevel);
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- create_zxdg_toplevel_v6_resources (wayland_toplevel);
- break;
- default:
- g_assert_not_reached ();
+ xdg_surface_ack_configure (wayland_surface->display_server.xdg_surface,
+ wayland_surface->pending.serial);
+ }
+ else if (wayland_popup->display_server.zxdg_popup_v6)
+ {
+ zxdg_surface_v6_ack_configure (wayland_surface->display_server.zxdg_surface_v6,
+ wayland_surface->pending.serial);
}
+ else
+ g_warn_if_reached ();
- gdk_wayland_surface_sync_parent (surface, NULL);
- gdk_wayland_toplevel_sync_parent_of_imported (wayland_toplevel);
- gdk_wayland_toplevel_sync_title (wayland_toplevel);
+ if (wayland_popup->pending.has_repositioned_token)
+ wayland_popup->received_reposition_token = wayland_popup->pending.repositioned_token;
- switch (display_wayland->shell_variant)
+ switch (wayland_popup->state)
{
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED)
- xdg_toplevel_set_maximized (wayland_toplevel->display_server.xdg_toplevel);
- if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED)
- xdg_toplevel_set_minimized (wayland_toplevel->display_server.xdg_toplevel);
- if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN)
- xdg_toplevel_set_fullscreen (wayland_toplevel->display_server.xdg_toplevel,
- wayland_toplevel->initial_fullscreen_output);
+ case POPUP_STATE_WAITING_FOR_REPOSITIONED:
+ if (wayland_popup->received_reposition_token != wayland_popup->reposition_token)
+ return;
+ else
+ gdk_surface_thaw_updates (surface);
+ G_GNUC_FALLTHROUGH;
+ case POPUP_STATE_WAITING_FOR_CONFIGURE:
+ wayland_popup->state = POPUP_STATE_WAITING_FOR_FRAME;
break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED)
- zxdg_toplevel_v6_set_maximized (wayland_toplevel->display_server.zxdg_toplevel_v6);
- if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED)
- zxdg_toplevel_v6_set_minimized (wayland_toplevel->display_server.zxdg_toplevel_v6);
- if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN)
- zxdg_toplevel_v6_set_fullscreen (wayland_toplevel->display_server.zxdg_toplevel_v6,
- wayland_toplevel->initial_fullscreen_output);
+ case POPUP_STATE_IDLE:
+ case POPUP_STATE_WAITING_FOR_FRAME:
break;
default:
g_assert_not_reached ();
}
- wayland_toplevel->initial_fullscreen_output = NULL;
-
- app_id = wayland_toplevel->application.application_id;
- if (app_id == NULL)
- app_id = g_get_prgname ();
-
- if (app_id == NULL)
- app_id = "GTK Application";
+ x = wayland_popup->pending.x;
+ y = wayland_popup->pending.y;
+ width = wayland_popup->pending.width;
+ height = wayland_popup->pending.height;
- gdk_wayland_toplevel_set_application_id (GDK_TOPLEVEL (wayland_toplevel), app_id);
+ gdk_wayland_surface_get_window_geometry (surface->parent, &parent_geometry);
+ x += parent_geometry.x;
+ y += parent_geometry.y;
- maybe_set_gtk_surface_dbus_properties (wayland_toplevel);
- maybe_set_gtk_surface_modal (wayland_toplevel);
+ update_popup_layout_state (wayland_popup,
+ x, y,
+ width, height,
+ wayland_popup->layout);
- gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "surface commit");
- wl_surface_commit (wayland_surface->display_server.wl_surface);
+ wayland_popup->next_layout.x = x;
+ wayland_popup->next_layout.y = y;
+ wayland_surface->next_layout.configured_width = width;
+ wayland_surface->next_layout.configured_height = height;
+ wayland_surface->next_layout.surface_geometry_dirty = TRUE;
+ gdk_surface_request_layout (surface);
}
static void
zxdg_popup_v6_done,
};
-static enum xdg_positioner_anchor
-rect_anchor_to_anchor (GdkGravity rect_anchor)
+static void
+calculate_popup_rect (GdkWaylandPopup *wayland_popup,
+ GdkPopupLayout *layout,
+ GdkRectangle *out_rect)
{
- switch (rect_anchor)
+ int width, height;
+ GdkRectangle anchor_rect;
+ int dx, dy;
+ int shadow_left, shadow_right, shadow_top, shadow_bottom;
+ int x = 0, y = 0;
+
+ gdk_popup_layout_get_shadow_width (layout,
+ &shadow_left,
+ &shadow_right,
+ &shadow_top,
+ &shadow_bottom);
+
+ width = (wayland_popup->unconstrained_width - (shadow_left + shadow_right));
+ height = (wayland_popup->unconstrained_height - (shadow_top + shadow_bottom));
+
+ anchor_rect = *gdk_popup_layout_get_anchor_rect (layout);
+ gdk_popup_layout_get_offset (layout, &dx, &dy);
+ anchor_rect.x += dx;
+ anchor_rect.y += dy;
+
+ switch (gdk_popup_layout_get_rect_anchor (layout))
{
- case GDK_GRAVITY_NORTH_WEST:
+ default:
case GDK_GRAVITY_STATIC:
- return XDG_POSITIONER_ANCHOR_TOP_LEFT;
+ case GDK_GRAVITY_NORTH_WEST:
+ x = anchor_rect.x;
+ y = anchor_rect.y;
+ break;
case GDK_GRAVITY_NORTH:
- return XDG_POSITIONER_ANCHOR_TOP;
+ x = anchor_rect.x + (anchor_rect.width / 2);
+ y = anchor_rect.y;
+ break;
case GDK_GRAVITY_NORTH_EAST:
- return XDG_POSITIONER_ANCHOR_TOP_RIGHT;
- case GDK_GRAVITY_WEST:
- return XDG_POSITIONER_ANCHOR_LEFT;
- case GDK_GRAVITY_CENTER:
- return XDG_POSITIONER_ANCHOR_NONE;
- case GDK_GRAVITY_EAST:
- return XDG_POSITIONER_ANCHOR_RIGHT;
- case GDK_GRAVITY_SOUTH_WEST:
- return XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
- case GDK_GRAVITY_SOUTH:
- return XDG_POSITIONER_ANCHOR_BOTTOM;
- case GDK_GRAVITY_SOUTH_EAST:
- return XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
- default:
- g_assert_not_reached ();
- }
-}
-
-static enum xdg_positioner_gravity
-surface_anchor_to_gravity (GdkGravity rect_anchor)
-{
- switch (rect_anchor)
- {
- case GDK_GRAVITY_NORTH_WEST:
- case GDK_GRAVITY_STATIC:
- return XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT;
- case GDK_GRAVITY_NORTH:
- return XDG_POSITIONER_GRAVITY_BOTTOM;
- case GDK_GRAVITY_NORTH_EAST:
- return XDG_POSITIONER_GRAVITY_BOTTOM_LEFT;
- case GDK_GRAVITY_WEST:
- return XDG_POSITIONER_GRAVITY_RIGHT;
- case GDK_GRAVITY_CENTER:
- return XDG_POSITIONER_GRAVITY_NONE;
- case GDK_GRAVITY_EAST:
- return XDG_POSITIONER_GRAVITY_LEFT;
- case GDK_GRAVITY_SOUTH_WEST:
- return XDG_POSITIONER_GRAVITY_TOP_RIGHT;
- case GDK_GRAVITY_SOUTH:
- return XDG_POSITIONER_GRAVITY_TOP;
- case GDK_GRAVITY_SOUTH_EAST:
- return XDG_POSITIONER_GRAVITY_TOP_LEFT;
- default:
- g_assert_not_reached ();
- }
-}
-
-static enum zxdg_positioner_v6_anchor
-rect_anchor_to_anchor_legacy (GdkGravity rect_anchor)
-{
- switch (rect_anchor)
- {
- case GDK_GRAVITY_NORTH_WEST:
- case GDK_GRAVITY_STATIC:
- return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
- ZXDG_POSITIONER_V6_ANCHOR_LEFT);
- case GDK_GRAVITY_NORTH:
- return ZXDG_POSITIONER_V6_ANCHOR_TOP;
- case GDK_GRAVITY_NORTH_EAST:
- return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
- ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
- case GDK_GRAVITY_WEST:
- return ZXDG_POSITIONER_V6_ANCHOR_LEFT;
- case GDK_GRAVITY_CENTER:
- return ZXDG_POSITIONER_V6_ANCHOR_NONE;
- case GDK_GRAVITY_EAST:
- return ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
- case GDK_GRAVITY_SOUTH_WEST:
- return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
- ZXDG_POSITIONER_V6_ANCHOR_LEFT);
- case GDK_GRAVITY_SOUTH:
- return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
- case GDK_GRAVITY_SOUTH_EAST:
- return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
- ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
- default:
- g_assert_not_reached ();
- }
-
- return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
- ZXDG_POSITIONER_V6_ANCHOR_LEFT);
-}
-
-static enum zxdg_positioner_v6_gravity
-surface_anchor_to_gravity_legacy (GdkGravity rect_anchor)
-{
- switch (rect_anchor)
- {
- case GDK_GRAVITY_NORTH_WEST:
- case GDK_GRAVITY_STATIC:
- return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
- case GDK_GRAVITY_NORTH:
- return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
- case GDK_GRAVITY_NORTH_EAST:
- return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_LEFT);
- case GDK_GRAVITY_WEST:
- return ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
- case GDK_GRAVITY_CENTER:
- return ZXDG_POSITIONER_V6_GRAVITY_NONE;
- case GDK_GRAVITY_EAST:
- return ZXDG_POSITIONER_V6_GRAVITY_LEFT;
- case GDK_GRAVITY_SOUTH_WEST:
- return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
- ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
- case GDK_GRAVITY_SOUTH:
- return ZXDG_POSITIONER_V6_GRAVITY_TOP;
- case GDK_GRAVITY_SOUTH_EAST:
- return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
- ZXDG_POSITIONER_V6_GRAVITY_LEFT);
- default:
- g_assert_not_reached ();
- }
-
- return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
-}
-
-void
-gdk_wayland_toplevel_announce_csd (GdkToplevel *toplevel)
-{
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
- GdkWaylandToplevel *toplevel_wayland;
-
- g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
- toplevel_wayland = GDK_WAYLAND_TOPLEVEL (toplevel);
-
- if (!display_wayland->server_decoration_manager)
- return;
- toplevel_wayland->server_decoration =
- org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
- gdk_wayland_surface_get_wl_surface (GDK_SURFACE (toplevel_wayland)));
- if (toplevel_wayland->server_decoration)
- org_kde_kwin_server_decoration_request_mode (toplevel_wayland->server_decoration,
- ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT);
-}
-
-void
-gdk_wayland_toplevel_announce_ssd (GdkToplevel *toplevel)
-{
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
- GdkWaylandToplevel *toplevel_wayland;
-
- g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
- toplevel_wayland = GDK_WAYLAND_TOPLEVEL (toplevel);
-
- if (!display_wayland->server_decoration_manager)
- return;
- toplevel_wayland->server_decoration =
- org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
- gdk_wayland_surface_get_wl_surface (GDK_SURFACE (toplevel_wayland)));
- if (toplevel_wayland->server_decoration)
- org_kde_kwin_server_decoration_request_mode (toplevel_wayland->server_decoration,
- ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER);
-}
-
-gboolean
-gdk_wayland_toplevel_inhibit_idle (GdkToplevel *toplevel)
-{
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
- GdkWaylandToplevel *wayland_toplevel;
-
- g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
- wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
-
- if (!display_wayland->idle_inhibit_manager)
- return FALSE;
-
- if (!wayland_toplevel->idle_inhibitor)
- {
- g_assert (wayland_toplevel->idle_inhibitor_refcount == 0);
-
- wayland_toplevel->idle_inhibitor =
- zwp_idle_inhibit_manager_v1_create_inhibitor (display_wayland->idle_inhibit_manager,
- gdk_wayland_surface_get_wl_surface (GDK_SURFACE (wayland_toplevel)));
- }
- ++wayland_toplevel->idle_inhibitor_refcount;
-
- return TRUE;
-}
-
-void
-gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel)
-{
- GdkWaylandToplevel *wayland_toplevel;
-
- g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
- wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
-
- g_assert (wayland_toplevel->idle_inhibitor &&
- wayland_toplevel->idle_inhibitor_refcount > 0);
-
- if (--wayland_toplevel->idle_inhibitor_refcount == 0)
- {
- g_clear_pointer (&wayland_toplevel->idle_inhibitor,
- zwp_idle_inhibitor_v1_destroy);
- }
-}
-
-static void
-calculate_popup_rect (GdkWaylandPopup *wayland_popup,
- GdkPopupLayout *layout,
- GdkRectangle *out_rect)
-{
- int width, height;
- GdkRectangle anchor_rect;
- int dx, dy;
- int shadow_left, shadow_right, shadow_top, shadow_bottom;
- int x = 0, y = 0;
-
- gdk_popup_layout_get_shadow_width (layout,
- &shadow_left,
- &shadow_right,
- &shadow_top,
- &shadow_bottom);
-
- width = (wayland_popup->unconstrained_width - (shadow_left + shadow_right));
- height = (wayland_popup->unconstrained_height - (shadow_top + shadow_bottom));
-
- anchor_rect = *gdk_popup_layout_get_anchor_rect (layout);
- gdk_popup_layout_get_offset (layout, &dx, &dy);
- anchor_rect.x += dx;
- anchor_rect.y += dy;
-
- switch (gdk_popup_layout_get_rect_anchor (layout))
- {
- default:
- case GDK_GRAVITY_STATIC:
- case GDK_GRAVITY_NORTH_WEST:
- x = anchor_rect.x;
- y = anchor_rect.y;
- break;
- case GDK_GRAVITY_NORTH:
- x = anchor_rect.x + (anchor_rect.width / 2);
- y = anchor_rect.y;
- break;
- case GDK_GRAVITY_NORTH_EAST:
- x = anchor_rect.x + anchor_rect.width;
- y = anchor_rect.y;
- break;
+ x = anchor_rect.x + anchor_rect.width;
+ y = anchor_rect.y;
+ break;
case GDK_GRAVITY_WEST:
x = anchor_rect.x;
y = anchor_rect.y + (anchor_rect.height / 2);
if (!is_realized_shell_surface (parent_impl))
return FALSE;
- if (is_realized_toplevel (impl))
- {
- g_warning ("Can't map popup, already mapped as toplevel");
- return FALSE;
- }
if (is_realized_popup (impl))
{
g_warning ("Can't map popup, already mapped");
return TRUE;
}
-static GdkWaylandSeat *
-find_grab_input_seat (GdkSurface *surface,
- GdkSurface *parent)
-{
- GdkWaylandPopup *popup = GDK_WAYLAND_POPUP (surface);
- GdkWaylandPopup *tmp_popup;
- /* Use the device that was used for the grab as the device for
- * the popup surface setup - so this relies on GTK taking the
- * grab before showing the popup surface.
- */
- if (popup->grab_input_seat)
- return GDK_WAYLAND_SEAT (popup->grab_input_seat);
-
- while (parent)
- {
- if (!GDK_IS_WAYLAND_POPUP (parent))
- break;
-
- tmp_popup = GDK_WAYLAND_POPUP (parent);
-
- if (tmp_popup->grab_input_seat)
- return GDK_WAYLAND_SEAT (tmp_popup->grab_input_seat);
-
- parent = parent->parent;
- }
-
- return NULL;
-}
-
-static void
-gdk_wayland_surface_map_toplevel (GdkSurface *surface)
-{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
-
- if (!GDK_IS_WAYLAND_TOPLEVEL (surface))
- return;
-
- if (impl->mapped)
- return;
-
- gdk_wayland_surface_create_xdg_toplevel (GDK_WAYLAND_TOPLEVEL (surface));
-
- impl->mapped = TRUE;
-}
+#define LAST_PROP 1
static void
-gdk_wayland_surface_show (GdkSurface *surface)
+gdk_wayland_popup_init (GdkWaylandPopup *popup)
{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
-
- if (!impl->display_server.wl_surface)
- gdk_wayland_surface_create_wl_surface (surface);
-
- gdk_wayland_surface_map_toplevel (surface);
}
static void
-unmap_popups_for_surface (GdkSurface *surface)
+gdk_wayland_popup_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- GdkWaylandDisplay *display_wayland;
- GList *l;
+ GdkSurface *surface = GDK_SURFACE (object);
- display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- for (l = display_wayland->current_popups; l; l = l->next)
+ switch (prop_id)
{
- GdkSurface *popup = l->data;
+ case LAST_PROP + GDK_POPUP_PROP_PARENT:
+ g_value_set_object (value, surface->parent);
+ break;
- if (popup->parent == surface)
- {
- g_warning ("Tried to unmap the parent of a popup");
- gdk_surface_hide (popup);
+ case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
+ g_value_set_boolean (value, surface->autohide);
+ break;
- return;
- }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
}
}
static void
-gdk_wayland_surface_hide_surface (GdkSurface *surface)
+gdk_wayland_popup_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- GdkDisplay *display = gdk_surface_get_display (surface);
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
-
- unmap_popups_for_surface (surface);
+ GdkSurface *surface = GDK_SURFACE (object);
- if (impl->display_server.wl_surface)
+ switch (prop_id)
{
- if (impl->display_server.egl_window)
- {
- gdk_surface_set_egl_native_window (surface, NULL);
- wl_egl_window_destroy (impl->display_server.egl_window);
- impl->display_server.egl_window = NULL;
- }
-
- if (GDK_IS_WAYLAND_TOPLEVEL (surface))
- {
- GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
-
- if (toplevel->display_server.xdg_toplevel)
- {
- xdg_toplevel_destroy (toplevel->display_server.xdg_toplevel);
- toplevel->display_server.xdg_toplevel = NULL;
- }
- if (toplevel->display_server.zxdg_toplevel_v6)
- {
- zxdg_toplevel_v6_destroy (toplevel->display_server.zxdg_toplevel_v6);
- toplevel->display_server.zxdg_toplevel_v6 = NULL;
- }
- }
-
- if (GDK_IS_WAYLAND_POPUP (surface))
- {
- GdkWaylandPopup *popup = GDK_WAYLAND_POPUP (surface);
-
- if (popup->display_server.xdg_popup)
- {
- xdg_popup_destroy (popup->display_server.xdg_popup);
- popup->display_server.xdg_popup = NULL;
- display_wayland->current_popups =
- g_list_remove (display_wayland->current_popups, surface);
- display_wayland->current_grabbing_popups =
- g_list_remove (display_wayland->current_grabbing_popups, surface);
- }
- if (popup->display_server.zxdg_popup_v6)
- {
- zxdg_popup_v6_destroy (popup->display_server.zxdg_popup_v6);
- popup->display_server.zxdg_popup_v6 = NULL;
- display_wayland->current_popups =
- g_list_remove (display_wayland->current_popups, surface);
- display_wayland->current_grabbing_popups =
- g_list_remove (display_wayland->current_grabbing_popups, surface);
- }
- }
-
- if (impl->display_server.xdg_surface)
- {
- xdg_surface_destroy (impl->display_server.xdg_surface);
- impl->display_server.xdg_surface = NULL;
- if (!impl->initial_configure_received)
- gdk_surface_thaw_updates (surface);
- else
- impl->initial_configure_received = FALSE;
- }
- if (impl->display_server.zxdg_surface_v6)
- {
- zxdg_surface_v6_destroy (impl->display_server.zxdg_surface_v6);
- impl->display_server.zxdg_surface_v6 = NULL;
- if (!impl->initial_configure_received)
- gdk_surface_thaw_updates (surface);
- else
- impl->initial_configure_received = FALSE;
- }
-
- impl->awaiting_frame = FALSE;
- if (impl->awaiting_frame_frozen)
- {
- impl->awaiting_frame_frozen = FALSE;
- gdk_surface_thaw_updates (surface);
- }
-
- if (GDK_IS_WAYLAND_POPUP (surface))
- {
- GdkWaylandPopup *wayland_popup = GDK_WAYLAND_POPUP (surface);
-
- wayland_popup->thaw_upon_show = TRUE;
- gdk_surface_freeze_updates (surface);
-
- switch (wayland_popup->state)
- {
- case POPUP_STATE_WAITING_FOR_REPOSITIONED:
- gdk_surface_thaw_updates (surface);
- G_GNUC_FALLTHROUGH;
- case POPUP_STATE_WAITING_FOR_CONFIGURE:
- case POPUP_STATE_WAITING_FOR_FRAME:
- thaw_popup_toplevel_state (wayland_popup);
- break;
- case POPUP_STATE_IDLE:
- break;
- default:
- g_assert_not_reached ();
- }
-
- wayland_popup->state = POPUP_STATE_IDLE;
- }
-
- if (GDK_IS_WAYLAND_TOPLEVEL (surface))
- {
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (surface);
-
- if (wayland_toplevel->display_server.gtk_surface)
- {
- if (display_wayland->gtk_shell_version >=
- GTK_SURFACE1_RELEASE_SINCE_VERSION)
- gtk_surface1_release (wayland_toplevel->display_server.gtk_surface);
- else
- gtk_surface1_destroy (wayland_toplevel->display_server.gtk_surface);
- wayland_toplevel->display_server.gtk_surface = NULL;
- wayland_toplevel->application.was_set = FALSE;
- }
-
- g_clear_pointer (&wayland_toplevel->layout, gdk_toplevel_layout_unref);
- }
-
- wl_surface_destroy (impl->display_server.wl_surface);
- impl->display_server.wl_surface = NULL;
-
- g_slist_free (impl->display_server.outputs);
- impl->display_server.outputs = NULL;
-
- if (GDK_IS_WAYLAND_POPUP (surface))
- {
- GdkWaylandPopup *wayland_popup = GDK_WAYLAND_POPUP (surface);
- g_clear_pointer (&wayland_popup->layout, gdk_popup_layout_unref);
- }
- }
-
- impl->has_uncommitted_ack_configure = FALSE;
- impl->input_region_dirty = TRUE;
- impl->opaque_region_dirty = TRUE;
-
- unset_transient_for_exported (surface);
+ case LAST_PROP + GDK_POPUP_PROP_PARENT:
+ surface->parent = g_value_dup_object (value);
+ if (surface->parent != NULL)
+ surface->parent->children = g_list_prepend (surface->parent->children, surface);
+ break;
- impl->last_sent_window_geometry = (GdkRectangle) { 0 };
+ case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
+ surface->autohide = g_value_get_boolean (value);
+ break;
- if (GDK_IS_WAYLAND_TOPLEVEL (impl))
- {
- GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (impl);
- toplevel->last_sent_geometry_hints.min_width = 0;
- toplevel->last_sent_geometry_hints.min_height = 0;
- toplevel->last_sent_geometry_hints.max_width = 0;
- toplevel->last_sent_geometry_hints.max_height = 0;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
}
-
- _gdk_wayland_surface_clear_saved_size (surface);
- impl->mapped = FALSE;
}
static void
-gdk_wayland_surface_hide (GdkSurface *surface)
+gdk_wayland_popup_class_init (GdkWaylandPopupClass *class)
{
- GdkSeat *seat;
-
- seat = gdk_display_get_default_seat (surface->display);
- if (seat)
- {
- if (surface->autohide)
- gdk_seat_ungrab (seat);
-
- gdk_wayland_seat_clear_touchpoints (GDK_WAYLAND_SEAT (seat), surface);
- }
- gdk_wayland_surface_hide_surface (surface);
- _gdk_surface_clear_update_area (surface);
-}
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
-static void
-gdk_wayland_surface_move_resize (GdkSurface *surface,
- int x,
- int y,
- int width,
- int height)
-{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ object_class->get_property = gdk_wayland_popup_get_property;
+ object_class->set_property = gdk_wayland_popup_set_property;
- surface->x = x;
- surface->y = y;
- gdk_wayland_surface_maybe_resize (surface, width, height, impl->scale);
+ gdk_popup_install_properties (object_class, 1);
}
static gboolean
return TRUE;
}
+static GdkWaylandSeat *
+find_grab_input_seat (GdkSurface *surface,
+ GdkSurface *parent)
+{
+ GdkWaylandPopup *popup = GDK_WAYLAND_POPUP (surface);
+ GdkWaylandPopup *tmp_popup;
+
+ /* Use the device that was used for the grab as the device for
+ * the popup surface setup - so this relies on GTK taking the
+ * grab before showing the popup surface.
+ */
+ if (popup->grab_input_seat)
+ return GDK_WAYLAND_SEAT (popup->grab_input_seat);
+
+ while (parent)
+ {
+ if (!GDK_IS_WAYLAND_POPUP (parent))
+ break;
+
+ tmp_popup = GDK_WAYLAND_POPUP (parent);
+
+ if (tmp_popup->grab_input_seat)
+ return GDK_WAYLAND_SEAT (tmp_popup->grab_input_seat);
+
+ parent = parent->parent;
+ }
+
+ return NULL;
+}
+
static void
gdk_wayland_surface_map_popup (GdkWaylandPopup *wayland_popup,
int width,
show_popup (wayland_popup, width, height, layout);
}
}
- else
- {
- if (wayland_popup->unconstrained_width == width &&
- wayland_popup->unconstrained_height == height &&
- gdk_popup_layout_equal (wayland_popup->layout, layout))
- return TRUE;
+ else
+ {
+ if (wayland_popup->unconstrained_width == width &&
+ wayland_popup->unconstrained_height == height &&
+ gdk_popup_layout_equal (wayland_popup->layout, layout))
+ return TRUE;
+
+ reposition_popup (wayland_popup, width, height, layout);
+ }
+
+ while (wayland_popup->display_server.xdg_popup && !is_relayout_finished (surface))
+ wl_display_dispatch_queue (display_wayland->wl_display, wayland_surface->event_queue);
+
+ if (wayland_popup->display_server.xdg_popup)
+ {
+ gdk_surface_invalidate_rect (surface, NULL);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static gboolean
+gdk_wayland_popup_present (GdkPopup *popup,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
+{
+ return gdk_wayland_surface_present_popup (GDK_WAYLAND_POPUP (popup), width, height, layout);
+}
+
+static GdkGravity
+gdk_wayland_popup_get_surface_anchor (GdkPopup *popup)
+{
+ return GDK_SURFACE (popup)->popup.surface_anchor;
+}
+
+static GdkGravity
+gdk_wayland_popup_get_rect_anchor (GdkPopup *popup)
+{
+ return GDK_SURFACE (popup)->popup.rect_anchor;
+}
+
+static int
+gdk_wayland_popup_get_position_x (GdkPopup *popup)
+{
+ return GDK_SURFACE (popup)->x;
+}
+
+static int
+gdk_wayland_popup_get_position_y (GdkPopup *popup)
+{
+ return GDK_SURFACE (popup)->y;
+}
+
+static void
+gdk_wayland_popup_iface_init (GdkPopupInterface *iface)
+{
+ iface->present = gdk_wayland_popup_present;
+ iface->get_surface_anchor = gdk_wayland_popup_get_surface_anchor;
+ iface->get_rect_anchor = gdk_wayland_popup_get_rect_anchor;
+ iface->get_position_x = gdk_wayland_popup_get_position_x;
+ iface->get_position_y = gdk_wayland_popup_get_position_y;
+}
+
+/* }}} */
+/* {{{ Private Popup API */
+
+void
+_gdk_wayland_surface_set_grab_seat (GdkSurface *surface,
+ GdkSeat *seat)
+{
+ GdkWaylandPopup *popup;
+
+ g_return_if_fail (surface != NULL);
+
+ popup = GDK_WAYLAND_POPUP (surface);
+ popup->grab_input_seat = seat;
+}
+
+/* }}} */
+/* {{{ GdkWaylandToplevel definition */
+
+/**
+ * GdkWaylandToplevel:
+ *
+ * The Wayland implementation of `GdkToplevel`.
+ *
+ * Beyond the [iface@Gdk.Toplevel] API, the Wayland implementation
+ * has API to set up cross-process parent-child relationships between
+ * surfaces with [method@GdkWayland.WaylandToplevel.export_handle] and
+ * [method@GdkWayland.WaylandToplevel.set_transient_for_exported].
+ */
+
+struct _GdkWaylandToplevel
+{
+ GdkWaylandSurface parent_instance;
+
+ struct {
+ struct gtk_surface1 *gtk_surface;
+ struct xdg_toplevel *xdg_toplevel;
+ struct zxdg_toplevel_v6 *zxdg_toplevel_v6;
+ } display_server;
+
+ GdkWaylandToplevel *transient_for;
+
+ struct org_kde_kwin_server_decoration *server_decoration;
+ struct zxdg_exported_v1 *xdg_exported;
+ struct zxdg_exported_v2 *xdg_exported_v2;
+
+ struct {
+ int width;
+ int height;
+ GdkToplevelState state;
+ gboolean is_resizing;
+
+ int bounds_width;
+ int bounds_height;
+ gboolean has_bounds;
+ } pending;
+
+ struct {
+ gboolean should_constrain;
+ gboolean size_is_fixed;
+ } next_layout;
+
+ struct {
+ GdkWaylandToplevelExported callback;
+ gpointer user_data;
+ GDestroyNotify destroy_func;
+ } exported;
+
+ struct {
+ gboolean was_set;
+
+ char *application_id;
+ char *app_menu_path;
+ char *menubar_path;
+ char *window_object_path;
+ char *application_object_path;
+ char *unique_bus_name;
+ } application;
+
+ struct zwp_idle_inhibitor_v1 *idle_inhibitor;
+ size_t idle_inhibitor_refcount;
+
+ struct wl_output *initial_fullscreen_output;
+
+ struct {
+ GdkToplevelState unset_flags;
+ GdkToplevelState set_flags;
+ } initial_state;
+
+ GdkToplevelLayout *layout;
+ int bounds_width;
+ int bounds_height;
+ gboolean has_bounds;
+
+ char *title;
+
+ GdkGeometry geometry_hints;
+ GdkSurfaceHints geometry_mask;
+ GdkGeometry last_sent_geometry_hints;
+
+ struct zxdg_imported_v1 *imported_transient_for;
+ struct zxdg_imported_v2 *imported_transient_for_v2;
+ GHashTable *shortcuts_inhibitors;
+};
+
+typedef struct
+{
+ GdkWaylandSurfaceClass parent_class;
+} GdkWaylandToplevelClass;
+
+static void gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GdkWaylandToplevel, gdk_wayland_toplevel, GDK_TYPE_WAYLAND_SURFACE,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL,
+ gdk_wayland_toplevel_iface_init))
+
+/* }}} */
+/* {{{ Toplevel implementation */
+
+static void maybe_set_gtk_surface_dbus_properties (GdkWaylandToplevel *wayland_toplevel);
+static void maybe_set_gtk_surface_modal (GdkWaylandToplevel *wayland_toplevel);
+
+static void
+gdk_wayland_toplevel_hide_surface (GdkWaylandToplevel *toplevel)
+{
+ GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel));
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+
+ g_clear_pointer (&toplevel->display_server.xdg_toplevel, xdg_toplevel_destroy);
+ g_clear_pointer (&toplevel->display_server.zxdg_toplevel_v6, zxdg_toplevel_v6_destroy);
+
+ if (toplevel->display_server.gtk_surface)
+ {
+ if (display_wayland->gtk_shell_version >= GTK_SURFACE1_RELEASE_SINCE_VERSION)
+ gtk_surface1_release (toplevel->display_server.gtk_surface);
+ else
+ gtk_surface1_destroy (toplevel->display_server.gtk_surface);
+ toplevel->display_server.gtk_surface = NULL;
+ toplevel->application.was_set = FALSE;
+ }
+
+ g_clear_pointer (&toplevel->layout, gdk_toplevel_layout_unref);
+
+ toplevel->last_sent_geometry_hints.min_width = 0;
+ toplevel->last_sent_geometry_hints.min_height = 0;
+ toplevel->last_sent_geometry_hints.max_width = 0;
+ toplevel->last_sent_geometry_hints.max_height = 0;
+}
+
+static gboolean
+is_realized_toplevel (GdkWaylandSurface *impl)
+{
+ GdkWaylandToplevel *toplevel;
+
+ if (!GDK_IS_WAYLAND_TOPLEVEL (impl))
+ return FALSE;
+
+ toplevel = GDK_WAYLAND_TOPLEVEL (impl);
+
+ return (toplevel->display_server.xdg_toplevel ||
+ toplevel->display_server.zxdg_toplevel_v6);
+}
+
+static void
+gdk_wayland_toplevel_sync_parent (GdkWaylandToplevel *toplevel)
+{
+ GdkSurface *surface = GDK_SURFACE (toplevel);
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ GdkWaylandToplevel *parent;
+
+ if (!is_realized_toplevel (GDK_WAYLAND_SURFACE (toplevel)))
+ return;
+
+ if (toplevel->transient_for)
+ parent = toplevel->transient_for;
+ else
+ parent = NULL;
+
+ /* XXX: Is this correct? */
+ if (parent && !is_realized_shell_surface (GDK_WAYLAND_SURFACE (parent)))
+ return;
+
+ switch (display_wayland->shell_variant)
+ {
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ {
+ struct xdg_toplevel *parent_toplevel;
+
+ if (parent)
+ parent_toplevel = parent->display_server.xdg_toplevel;
+ else
+ parent_toplevel = NULL;
+
+ xdg_toplevel_set_parent (toplevel->display_server.xdg_toplevel, parent_toplevel);
+ break;
+ }
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ {
+ struct zxdg_toplevel_v6 *parent_toplevel;
+
+ if (parent)
+ parent_toplevel = parent->display_server.zxdg_toplevel_v6;
+ else
+ parent_toplevel = NULL;
+
+ zxdg_toplevel_v6_set_parent (toplevel->display_server.zxdg_toplevel_v6, parent_toplevel);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+gdk_wayland_toplevel_sync_parent_of_imported (GdkWaylandToplevel *toplevel)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
+
+ if (!impl->display_server.wl_surface)
+ return;
+
+ if (!is_realized_toplevel (impl))
+ return;
+
+ if (toplevel->imported_transient_for)
+ zxdg_imported_v1_set_parent_of (toplevel->imported_transient_for,
+ impl->display_server.wl_surface);
+ else if (toplevel->imported_transient_for_v2)
+ zxdg_imported_v2_set_parent_of (toplevel->imported_transient_for_v2,
+ impl->display_server.wl_surface);
+}
+
+static void
+gdk_wayland_toplevel_sync_title (GdkWaylandToplevel *toplevel)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
+ GdkWaylandDisplay *display_wayland =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
+
+ if (!is_realized_toplevel (impl))
+ return;
+
+ if (!toplevel->title)
+ return;
+
+ switch (display_wayland->shell_variant)
+ {
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ xdg_toplevel_set_title (toplevel->display_server.xdg_toplevel, toplevel->title);
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ zxdg_toplevel_v6_set_title (toplevel->display_server.zxdg_toplevel_v6, toplevel->title);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+configure_toplevel_geometry (GdkWaylandToplevel *wayland_toplevel)
+{
+ GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_toplevel);
+ GdkDisplay *display = gdk_surface_get_display (surface);
+ int bounds_width, bounds_height;
+ GdkToplevelSize size;
+ GdkToplevelLayout *layout;
+ GdkGeometry geometry;
+ GdkSurfaceHints mask;
+
+ if (wayland_toplevel->has_bounds)
+ {
+ bounds_width = wayland_toplevel->bounds_width;
+ bounds_height = wayland_toplevel->bounds_height;
+ }
+ else
+ {
+ GdkMonitor *monitor;
+ GListModel *monitors;
+ GdkRectangle monitor_geometry, display_geometry = { 0 };
+ guint i;
+
+ monitors = gdk_display_get_monitors (display);
+
+ for (i = 0; i < g_list_model_get_n_items (monitors); i++)
+ {
+ monitor = g_list_model_get_item (monitors, i);
+ gdk_monitor_get_geometry (monitor, &monitor_geometry);
+ gdk_rectangle_union (&display_geometry, &monitor_geometry, &display_geometry);
+ g_object_unref (monitor);
+ }
+
+ bounds_width = display_geometry.width;
+ bounds_height = display_geometry.height;
+ }
+
+ gdk_toplevel_size_init (&size, bounds_width, bounds_height);
+ gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size);
+ g_warn_if_fail (size.width > 0);
+ g_warn_if_fail (size.height > 0);
+
+ layout = wayland_toplevel->layout;
+ if (gdk_toplevel_layout_get_resizable (layout))
+ {
+ geometry.min_width = size.min_width;
+ geometry.min_height = size.min_height;
+ mask = GDK_HINT_MIN_SIZE;
+ }
+ else
+ {
+ geometry.max_width = geometry.min_width = size.width;
+ geometry.max_height = geometry.min_height = size.height;
+ mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
+ }
+
+ gdk_wayland_toplevel_set_geometry_hints (wayland_toplevel, &geometry, mask);
+
+ if (size.shadow.is_valid)
+ {
+ wayland_surface->shadow_left = size.shadow.left;
+ wayland_surface->shadow_right = size.shadow.right;
+ wayland_surface->shadow_top = size.shadow.top;
+ wayland_surface->shadow_bottom = size.shadow.bottom;
+ }
+
+ if (wayland_surface->next_layout.configured_width > 0 &&
+ wayland_surface->next_layout.configured_height > 0)
+ {
+ int width, height;
+
+ width = wayland_surface->next_layout.configured_width +
+ wayland_surface->shadow_left + wayland_surface->shadow_right;
+ height = wayland_surface->next_layout.configured_height +
+ wayland_surface->shadow_top + wayland_surface->shadow_bottom;
+
+ if (wayland_toplevel->next_layout.should_constrain)
+ {
+ gdk_surface_constrain_size (&wayland_toplevel->geometry_hints,
+ wayland_toplevel->geometry_mask,
+ width, height,
+ &width, &height);
+ }
+ gdk_wayland_surface_update_size (surface, width, height, wayland_surface->scale);
+
+ if (!wayland_toplevel->next_layout.size_is_fixed)
+ {
+ wayland_toplevel->next_layout.should_constrain = FALSE;
+ wayland_surface->next_layout.configured_width = 0;
+ wayland_surface->next_layout.configured_height = 0;
+ }
+ }
+ else
+ {
+ int width, height;
+
+ width = size.width;
+ height = size.height;
+ gdk_surface_constrain_size (&geometry, mask,
+ width, height,
+ &width, &height);
+ gdk_wayland_surface_update_size (surface, width, height, wayland_surface->scale);
+ }
+}
+
+static void
+gdk_wayland_surface_configure_toplevel (GdkWaylandToplevel *wayland_toplevel)
+{
+ GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_toplevel);
+ GdkWaylandDisplay *display_wayland =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ GdkToplevelState new_state;
+ int width, height;
+ gboolean is_resizing;
+ gboolean fixed_size;
+ gboolean was_fixed_size;
+ gboolean saved_size;
+
+ new_state = wayland_toplevel->pending.state;
+ wayland_toplevel->pending.state = 0;
+
+ is_resizing = wayland_toplevel->pending.is_resizing;
+ wayland_toplevel->pending.is_resizing = FALSE;
+
+ if (wayland_toplevel->pending.has_bounds)
+ {
+ wayland_toplevel->bounds_width = wayland_toplevel->pending.bounds_width;
+ wayland_toplevel->bounds_height = wayland_toplevel->pending.bounds_height;
+ wayland_toplevel->has_bounds = TRUE;
+ }
+
+ fixed_size =
+ new_state & (GDK_TOPLEVEL_STATE_MAXIMIZED |
+ GDK_TOPLEVEL_STATE_FULLSCREEN |
+ GDK_TOPLEVEL_STATE_TILED) ||
+ is_resizing;
+
+ was_fixed_size =
+ surface->state & (GDK_TOPLEVEL_STATE_MAXIMIZED |
+ GDK_TOPLEVEL_STATE_FULLSCREEN |
+ GDK_TOPLEVEL_STATE_TILED);
+
+ width = wayland_toplevel->pending.width;
+ height = wayland_toplevel->pending.height;
+
+ saved_size = (width == 0 && height == 0);
+ /* According to xdg_shell, an xdg_surface.configure with size 0x0
+ * should be interpreted as that it is up to the client to set a
+ * size.
+ *
+ * When transitioning from maximize or fullscreen state, this means
+ * the client should configure its size back to what it was before
+ * being maximize or fullscreen.
+ */
+ if (saved_size && !fixed_size && was_fixed_size)
+ {
+ width = wayland_surface->saved_width;
+ height = wayland_surface->saved_height;
+ }
+
+ if (width > 0 && height > 0)
+ {
+ if (!saved_size)
+ {
+ wayland_toplevel->next_layout.should_constrain = TRUE;
+
+ /* Save size for next time we get 0x0 */
+ _gdk_wayland_surface_save_size (surface);
+ }
+ else if (is_resizing)
+ {
+ wayland_toplevel->next_layout.should_constrain = TRUE;
+ }
+ else
+ {
+ wayland_toplevel->next_layout.should_constrain = FALSE;
+ }
+
+ wayland_toplevel->next_layout.size_is_fixed = fixed_size;
+ wayland_surface->next_layout.configured_width = width;
+ wayland_surface->next_layout.configured_height = height;
+ }
+ else
+ {
+ wayland_toplevel->next_layout.should_constrain = FALSE;
+ wayland_toplevel->next_layout.size_is_fixed = FALSE;
+ wayland_surface->next_layout.configured_width = 0;
+ wayland_surface->next_layout.configured_height = 0;
+ }
- reposition_popup (wayland_popup, width, height, layout);
- }
+ wayland_surface->next_layout.surface_geometry_dirty = TRUE;
+ gdk_surface_request_layout (surface);
- while (wayland_popup->display_server.xdg_popup && !is_relayout_finished (surface))
- wl_display_dispatch_queue (display_wayland->wl_display, wayland_surface->event_queue);
+ GDK_DISPLAY_DEBUG (gdk_surface_get_display (surface), EVENTS,
+ "configure, surface %p %dx%d,%s%s%s%s",
+ surface, width, height,
+ (new_state & GDK_TOPLEVEL_STATE_FULLSCREEN) ? " fullscreen" : "",
+ (new_state & GDK_TOPLEVEL_STATE_MAXIMIZED) ? " maximized" : "",
+ (new_state & GDK_TOPLEVEL_STATE_FOCUSED) ? " focused" : "",
+ (new_state & GDK_TOPLEVEL_STATE_TILED) ? " tiled" : "");
- if (wayland_popup->display_server.xdg_popup)
- {
- gdk_surface_invalidate_rect (surface, NULL);
- return TRUE;
- }
- else
+ gdk_surface_queue_state_change (surface, ~0 & ~new_state, new_state);
+
+ switch (display_wayland->shell_variant)
{
- return FALSE;
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ xdg_surface_ack_configure (wayland_surface->display_server.xdg_surface,
+ wayland_surface->pending.serial);
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ zxdg_surface_v6_ack_configure (wayland_surface->display_server.zxdg_surface_v6,
+ wayland_surface->pending.serial);
+ break;
+ default:
+ g_assert_not_reached ();
}
}
static void
-gdk_wayland_surface_get_geometry (GdkSurface *surface,
- int *x,
- int *y,
- int *width,
- int *height)
+xdg_toplevel_configure (void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array *states)
{
- if (!GDK_SURFACE_DESTROYED (surface))
+ GdkSurface *surface = GDK_SURFACE (data);
+ GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
+ uint32_t *p;
+ GdkToplevelState pending_state = 0;
+
+ toplevel->pending.is_resizing = FALSE;
+
+ wl_array_for_each (p, states)
{
- if (x)
- *x = surface->x;
- if (y)
- *y = surface->y;
- if (width)
- *width = surface->width;
- if (height)
- *height = surface->height;
+ uint32_t state = *p;
+
+ switch (state)
+ {
+ case XDG_TOPLEVEL_STATE_FULLSCREEN:
+ pending_state |= GDK_TOPLEVEL_STATE_FULLSCREEN;
+ break;
+ case XDG_TOPLEVEL_STATE_MAXIMIZED:
+ pending_state |= GDK_TOPLEVEL_STATE_MAXIMIZED;
+ break;
+ case XDG_TOPLEVEL_STATE_ACTIVATED:
+ pending_state |= GDK_TOPLEVEL_STATE_FOCUSED;
+ break;
+ case XDG_TOPLEVEL_STATE_RESIZING:
+ toplevel->pending.is_resizing = TRUE;
+ break;
+ case XDG_TOPLEVEL_STATE_TILED_TOP:
+ pending_state |= (GDK_TOPLEVEL_STATE_TILED |
+ GDK_TOPLEVEL_STATE_TOP_TILED);
+ break;
+ case XDG_TOPLEVEL_STATE_TILED_RIGHT:
+ pending_state |= (GDK_TOPLEVEL_STATE_TILED |
+ GDK_TOPLEVEL_STATE_RIGHT_TILED);
+ break;
+ case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
+ pending_state |= (GDK_TOPLEVEL_STATE_TILED |
+ GDK_TOPLEVEL_STATE_BOTTOM_TILED);
+ break;
+ case XDG_TOPLEVEL_STATE_TILED_LEFT:
+ pending_state |= (GDK_TOPLEVEL_STATE_TILED |
+ GDK_TOPLEVEL_STATE_LEFT_TILED);
+ break;
+ default:
+ /* Unknown state */
+ break;
+ }
}
+
+ gdk_wayland_toplevel_handle_configure (toplevel, width, height, pending_state);
}
static void
-gdk_wayland_surface_get_root_coords (GdkSurface *surface,
- int x,
- int y,
- int *root_x,
- int *root_y)
+gdk_wayland_toplevel_handle_configure (GdkWaylandToplevel *toplevel,
+ int32_t width,
+ int32_t height,
+ GdkToplevelState state)
{
- /*
- * Wayland does not have a global coordinate space shared between surfaces. In
- * fact, for regular toplevels, we have no idea where our surfaces are
- * positioned, relatively.
- *
- * However, there are some cases like popups and subsurfaces where we do have
- * some amount of control over the placement of our surface, and we can
- * semi-accurately control the x/y position of these surfaces, if they are
- * relative to another surface.
- *
- * To pretend we have something called a root coordinate space, assume all
- * parent-less surfaces are positioned in (0, 0), and all relative positioned
- * popups and subsurfaces are placed within this fake root coordinate space.
- *
- * For example a 200x200 large toplevel surface will have the position (0, 0).
- * If a popup positioned in the middle of the toplevel will have the fake
- * position (100,100). Furthermore, if a positioned is placed in the middle
- * that popup, will have the fake position (150,150), even though it has the
- * relative position (50,50). These three surfaces would make up one single
- * fake root coordinate space.
- */
-
- if (root_x)
- *root_x = surface->x + x;
-
- if (root_y)
- *root_y = surface->y + y;
+ toplevel->pending.state |= state;
+ toplevel->pending.width = width;
+ toplevel->pending.height = height;
}
-static gboolean
-gdk_wayland_surface_get_device_state (GdkSurface *surface,
- GdkDevice *device,
- double *x,
- double *y,
- GdkModifierType *mask)
+static void
+xdg_toplevel_close (void *data,
+ struct xdg_toplevel *xdg_toplevel)
{
- if (GDK_SURFACE_DESTROYED (surface))
- return FALSE;
-
- gdk_wayland_device_query_state (device, surface, x, y, mask);
+ GdkSurface *surface = GDK_SURFACE (data);
- return *x >= 0 && *y >= 0 && *x < surface->width && *y < surface->height;
+ gdk_wayland_surface_handle_close (surface);
}
static void
-gdk_wayland_surface_set_input_region (GdkSurface *surface,
- cairo_region_t *input_region)
+xdg_toplevel_configure_bounds (void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ int32_t width,
+ int32_t height)
{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ GdkSurface *surface = GDK_SURFACE (data);
+ GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- if (GDK_SURFACE_DESTROYED (surface))
- return;
+ toplevel->pending.bounds_width = width;
+ toplevel->pending.bounds_height = height;
+ toplevel->pending.has_bounds = TRUE;
+}
- g_clear_pointer (&impl->input_region, cairo_region_destroy);
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+ xdg_toplevel_configure,
+ xdg_toplevel_close,
+ xdg_toplevel_configure_bounds,
+};
- if (input_region)
- impl->input_region = cairo_region_copy (input_region);
+static void
+create_xdg_toplevel_resources (GdkWaylandToplevel *toplevel)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
- impl->input_region_dirty = TRUE;
+ toplevel->display_server.xdg_toplevel =
+ xdg_surface_get_toplevel (impl->display_server.xdg_surface);
+ xdg_toplevel_add_listener (toplevel->display_server.xdg_toplevel,
+ &xdg_toplevel_listener,
+ toplevel);
}
static void
-gdk_wayland_surface_destroy (GdkSurface *surface,
- gboolean foreign_destroy)
+zxdg_toplevel_v6_configure (void *data,
+ struct zxdg_toplevel_v6 *xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array *states)
{
- GdkWaylandDisplay *display;
- GdkFrameClock *frame_clock;
+ GdkSurface *surface = GDK_SURFACE (data);
+ GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
+ uint32_t *p;
+ GdkToplevelState pending_state = 0;
- g_return_if_fail (GDK_IS_SURFACE (surface));
+ toplevel->pending.is_resizing = FALSE;
- /* Wayland surfaces can't be externally destroyed; we may possibly
- * eventually want to use this path at display close-down
- */
- g_return_if_fail (!foreign_destroy);
+ wl_array_for_each (p, states)
+ {
+ uint32_t state = *p;
- gdk_wayland_surface_hide_surface (surface);
+ switch (state)
+ {
+ case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
+ pending_state |= GDK_TOPLEVEL_STATE_FULLSCREEN;
+ break;
+ case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
+ pending_state |= GDK_TOPLEVEL_STATE_MAXIMIZED;
+ break;
+ case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED:
+ pending_state |= GDK_TOPLEVEL_STATE_FOCUSED;
+ break;
+ case ZXDG_TOPLEVEL_V6_STATE_RESIZING:
+ toplevel->pending.is_resizing = TRUE;
+ break;
+ default:
+ /* Unknown state */
+ break;
+ }
+ }
- frame_clock = gdk_surface_get_frame_clock (surface);
- g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface);
- g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_after_paint, surface);
+ gdk_wayland_toplevel_handle_configure (toplevel, width, height, pending_state);
+}
- display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- display->toplevels = g_list_remove (display->toplevels, surface);
+static void
+zxdg_toplevel_v6_close (void *data,
+ struct zxdg_toplevel_v6 *xdg_toplevel)
+{
+ GdkSurface *surface = GDK_SURFACE (data);
+
+ gdk_wayland_surface_handle_close (surface);
}
+static const struct zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
+ zxdg_toplevel_v6_configure,
+ zxdg_toplevel_v6_close,
+};
+
static void
-token_done (gpointer data,
- struct xdg_activation_token_v1 *provider,
- const char *token)
+create_zxdg_toplevel_v6_resources (GdkWaylandToplevel *toplevel)
{
- char **token_out = data;
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
- *token_out = g_strdup (token);
+ toplevel->display_server.zxdg_toplevel_v6 =
+ zxdg_surface_v6_get_toplevel (impl->display_server.zxdg_surface_v6);
+ zxdg_toplevel_v6_add_listener (toplevel->display_server.zxdg_toplevel_v6,
+ &zxdg_toplevel_v6_listener,
+ toplevel);
}
-static const struct xdg_activation_token_v1_listener token_listener = {
- token_done,
-};
-
static void
-gdk_wayland_toplevel_focus (GdkToplevel *toplevel,
- guint32 timestamp)
+gdk_wayland_surface_create_xdg_toplevel (GdkWaylandToplevel *wayland_toplevel)
{
- GdkSurface *surface = GDK_SURFACE (toplevel);
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (toplevel);
- GdkDisplay *display = gdk_surface_get_display (surface);
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
- gchar *startup_id = NULL;
+ GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_toplevel);
+ const char *app_id;
- startup_id = g_steal_pointer (&display_wayland->startup_notification_id);
+ gdk_surface_freeze_updates (surface);
+ gdk_wayland_surface_create_xdg_surface_resources (surface);
- if (display_wayland->xdg_activation)
+ switch (display_wayland->shell_variant)
{
- GdkWaylandSeat *seat =
- GDK_WAYLAND_SEAT (gdk_display_get_default_seat (display));
-
- /* If the focus request does not have a startup ID associated, get a
- * new token to activate the window.
- */
- if (!startup_id)
- {
- struct xdg_activation_token_v1 *token;
- struct wl_event_queue *event_queue;
- struct wl_surface *wl_surface = NULL;
- GdkSurface *focus_surface;
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ create_xdg_toplevel_resources (wayland_toplevel);
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ create_zxdg_toplevel_v6_resources (wayland_toplevel);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
- event_queue = wl_display_create_queue (display_wayland->wl_display);
+ gdk_wayland_toplevel_sync_parent (wayland_toplevel);
+ gdk_wayland_toplevel_sync_parent_of_imported (wayland_toplevel);
+ gdk_wayland_toplevel_sync_title (wayland_toplevel);
- token = xdg_activation_v1_get_activation_token (display_wayland->xdg_activation);
- wl_proxy_set_queue ((struct wl_proxy *) token, event_queue);
+ switch (display_wayland->shell_variant)
+ {
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED)
+ xdg_toplevel_set_maximized (wayland_toplevel->display_server.xdg_toplevel);
+ if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED)
+ xdg_toplevel_set_minimized (wayland_toplevel->display_server.xdg_toplevel);
+ if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN)
+ xdg_toplevel_set_fullscreen (wayland_toplevel->display_server.xdg_toplevel,
+ wayland_toplevel->initial_fullscreen_output);
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED)
+ zxdg_toplevel_v6_set_maximized (wayland_toplevel->display_server.zxdg_toplevel_v6);
+ if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED)
+ zxdg_toplevel_v6_set_minimized (wayland_toplevel->display_server.zxdg_toplevel_v6);
+ if (wayland_toplevel->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN)
+ zxdg_toplevel_v6_set_fullscreen (wayland_toplevel->display_server.zxdg_toplevel_v6,
+ wayland_toplevel->initial_fullscreen_output);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
- xdg_activation_token_v1_add_listener (token,
- &token_listener,
- &startup_id);
- xdg_activation_token_v1_set_serial (token,
- _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL),
- gdk_wayland_seat_get_wl_seat (GDK_SEAT (seat)));
+ wayland_toplevel->initial_fullscreen_output = NULL;
- focus_surface = gdk_wayland_device_get_focus (gdk_seat_get_keyboard (GDK_SEAT (seat)));
- if (focus_surface)
- wl_surface = gdk_wayland_surface_get_wl_surface (focus_surface);
- if (wl_surface)
- xdg_activation_token_v1_set_surface (token, wl_surface);
+ app_id = wayland_toplevel->application.application_id;
+ if (app_id == NULL)
+ app_id = g_get_prgname ();
- xdg_activation_token_v1_commit (token);
+ if (app_id == NULL)
+ app_id = "GTK Application";
- while (startup_id == NULL)
- wl_display_dispatch_queue (display_wayland->wl_display, event_queue);
+ gdk_wayland_toplevel_set_application_id (GDK_TOPLEVEL (wayland_toplevel), app_id);
- xdg_activation_token_v1_destroy (token);
- wl_event_queue_destroy (event_queue);
- }
+ maybe_set_gtk_surface_dbus_properties (wayland_toplevel);
+ maybe_set_gtk_surface_modal (wayland_toplevel);
- xdg_activation_v1_activate (display_wayland->xdg_activation,
- startup_id,
- wayland_surface->display_server.wl_surface);
- }
- else if (wayland_toplevel->display_server.gtk_surface)
- {
- if (timestamp != GDK_CURRENT_TIME)
- gtk_surface1_present (wayland_toplevel->display_server.gtk_surface, timestamp);
- else if (startup_id && display_wayland->gtk_shell_version >= 3)
- gtk_surface1_request_focus (wayland_toplevel->display_server.gtk_surface,
- startup_id);
- }
+ gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "surface commit");
+ wl_surface_commit (wayland_surface->display_server.wl_surface);
+}
- g_free (startup_id);
+static void
+gdk_wayland_toplevel_init (GdkWaylandToplevel *toplevel)
+{
+ toplevel->initial_fullscreen_output = NULL;
+ toplevel->shortcuts_inhibitors = g_hash_table_new (NULL, NULL);
}
static void
wayland_surface);
}
+static void
+gdk_wayland_toplevel_set_title (GdkWaylandToplevel *toplevel,
+ const char *title)
+{
+ const char *end;
+ gsize title_length;
+
+ g_return_if_fail (title != NULL);
+
+ if (GDK_SURFACE_DESTROYED (GDK_SURFACE (toplevel)))
+ return;
+
+ if (g_strcmp0 (toplevel->title, title) == 0)
+ return;
+
+ g_free (toplevel->title);
+
+ title_length = MIN (strlen (title), MAX_WL_BUFFER_SIZE);
+ if (g_utf8_validate (title, title_length, &end))
+ {
+ toplevel->title = g_malloc (end - title + 1);
+ memcpy (toplevel->title, title, end - title);
+ toplevel->title[end - title] = '\0';
+ }
+ else
+ {
+ toplevel->title = g_utf8_make_valid (title, title_length);
+ g_warning ("Invalid utf8 passed to gdk_surface_set_title: '%s'", title);
+ }
+
+ gdk_wayland_toplevel_sync_title (toplevel);
+}
+
+static void
+gdk_wayland_toplevel_set_startup_id (GdkWaylandToplevel *toplevel,
+ const char *startup_id)
+{
+ GdkWaylandDisplay *display =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
+ char *free_me = NULL;
+
+ if (!startup_id)
+ {
+ free_me = g_steal_pointer (&display_wayland->startup_notification_id);
+ startup_id = free_me;
+ }
+
+ if (startup_id)
+ {
+ xdg_activation_v1_activate (display_wayland->xdg_activation,
+ startup_id,
+ wayland_toplevel->display_server.wl_surface);
+ }
+
+ g_free (free_me);
+}
+
static void
maybe_set_gtk_surface_modal (GdkWaylandToplevel *wayland_toplevel)
{
GdkSurfaceHints geom_mask)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
- GdkWaylandDisplay *display_wayland;
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
int min_width, min_height;
int max_width, max_height;
if (GDK_SURFACE_DESTROYED (toplevel))
return;
- display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
+ if (!geometry)
+ {
+ geometry = &toplevel->geometry_hints;
+ geom_mask = toplevel->geometry_mask;
+ }
toplevel->geometry_hints = *geometry;
toplevel->geometry_mask = geom_mask;
max_height = MAX (0, (geometry->max_height -
(impl->shadow_top + impl->shadow_bottom)));
}
- else
- {
- max_width = 0;
- max_height = 0;
- }
-
- if (toplevel->last_sent_geometry_hints.min_width == min_width &&
- toplevel->last_sent_geometry_hints.min_height == min_height &&
- toplevel->last_sent_geometry_hints.max_width == max_width &&
- toplevel->last_sent_geometry_hints.max_height == max_height)
- return;
-
- switch (display_wayland->shell_variant)
- {
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_set_min_size (toplevel->display_server.xdg_toplevel,
- min_width, min_height);
- xdg_toplevel_set_max_size (toplevel->display_server.xdg_toplevel,
- max_width, max_height);
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_set_min_size (toplevel->display_server.zxdg_toplevel_v6,
- min_width, min_height);
- zxdg_toplevel_v6_set_max_size (toplevel->display_server.zxdg_toplevel_v6,
- max_width, max_height);
- break;
- default:
- g_assert_not_reached ();
- }
-
- toplevel->last_sent_geometry_hints.min_width = min_width;
- toplevel->last_sent_geometry_hints.min_height = min_height;
- toplevel->last_sent_geometry_hints.max_width = max_width;
- toplevel->last_sent_geometry_hints.max_height = max_height;
-}
-
-static void
-gdk_wayland_toplevel_set_title (GdkWaylandToplevel *toplevel,
- const char *title)
-{
- const char *end;
- gsize title_length;
-
- g_return_if_fail (title != NULL);
-
- if (GDK_SURFACE_DESTROYED (GDK_SURFACE (toplevel)))
- return;
-
- if (g_strcmp0 (toplevel->title, title) == 0)
- return;
-
- g_free (toplevel->title);
-
- title_length = MIN (strlen (title), MAX_WL_BUFFER_SIZE);
- if (g_utf8_validate (title, title_length, &end))
- {
- toplevel->title = g_malloc (end - title + 1);
- memcpy (toplevel->title, title, end - title);
- toplevel->title[end - title] = '\0';
- }
- else
- {
- toplevel->title = g_utf8_make_valid (title, title_length);
- g_warning ("Invalid utf8 passed to gdk_surface_set_title: '%s'", title);
- }
-
- gdk_wayland_toplevel_sync_title (toplevel);
-}
-
-static void
-gdk_wayland_surface_set_startup_id (GdkSurface *surface,
- const char *startup_id)
-{
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (surface);
- GdkDisplay *display = gdk_surface_get_display (surface);
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
- gchar *free_me = NULL;
-
- if (!startup_id)
+ else
{
- free_me = g_steal_pointer (&display_wayland->startup_notification_id);
- startup_id = free_me;
+ max_width = 0;
+ max_height = 0;
}
- if (startup_id)
+ if (toplevel->last_sent_geometry_hints.min_width == min_width &&
+ toplevel->last_sent_geometry_hints.min_height == min_height &&
+ toplevel->last_sent_geometry_hints.max_width == max_width &&
+ toplevel->last_sent_geometry_hints.max_height == max_height)
+ return;
+
+ switch (display_wayland->shell_variant)
{
- xdg_activation_v1_activate (display_wayland->xdg_activation,
- startup_id,
- wayland_surface->display_server.wl_surface);
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ xdg_toplevel_set_min_size (toplevel->display_server.xdg_toplevel,
+ min_width, min_height);
+ xdg_toplevel_set_max_size (toplevel->display_server.xdg_toplevel,
+ max_width, max_height);
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ zxdg_toplevel_v6_set_min_size (toplevel->display_server.zxdg_toplevel_v6,
+ min_width, min_height);
+ zxdg_toplevel_v6_set_max_size (toplevel->display_server.zxdg_toplevel_v6,
+ max_width, max_height);
+ break;
+ default:
+ g_assert_not_reached ();
}
- g_free (free_me);
+ toplevel->last_sent_geometry_hints.min_width = min_width;
+ toplevel->last_sent_geometry_hints.min_height = min_height;
+ toplevel->last_sent_geometry_hints.max_width = max_width;
+ toplevel->last_sent_geometry_hints.max_height = max_height;
}
static gboolean
else
toplevel->transient_for = NULL;
- gdk_wayland_surface_sync_parent (GDK_SURFACE (toplevel), NULL);
+ gdk_wayland_toplevel_sync_parent (toplevel);
}
-static gboolean
-gdk_wayland_toplevel_minimize (GdkToplevel *toplevel)
+static void
+gdk_wayland_toplevel_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- GdkSurface *surface = GDK_SURFACE (toplevel);
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- GdkWaylandDisplay *display_wayland;
+ GdkSurface *surface = GDK_SURFACE (object);
+ GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- if (GDK_SURFACE_DESTROYED (surface))
- return TRUE;
+ switch (prop_id)
+ {
+ case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
+ gdk_wayland_toplevel_set_title (toplevel, g_value_get_string (value));
+ g_object_notify_by_pspec (object, pspec);
+ break;
- if (!is_realized_toplevel (impl))
- return TRUE;
+ case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
+ gdk_wayland_toplevel_set_startup_id (toplevel, g_value_get_string (value));
+ g_object_notify_by_pspec (object, pspec);
+ break;
- /* FIXME: xdg_toplevel does not come with a minimized state that we can
- * query or get notified of. This means we cannot implement the full
- * GdkSurface API, and our state will not reflect minimization.
- */
- display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- switch (display_wayland->shell_variant)
- {
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_set_minimized (wayland_toplevel->display_server.xdg_toplevel);
+ case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
+ gdk_wayland_toplevel_set_transient_for (toplevel, g_value_get_object (value));
+ g_object_notify_by_pspec (object, pspec);
break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_set_minimized (wayland_toplevel->display_server.zxdg_toplevel_v6);
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
+ gdk_wayland_toplevel_set_modal_hint (toplevel, g_value_get_boolean (value));
+ g_object_notify_by_pspec (object, pspec);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
+ surface->fullscreen_mode = g_value_get_enum (value);
+ g_object_notify_by_pspec (object, pspec);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
+ break;
+
default:
- g_assert_not_reached ();
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
}
-
- return TRUE;
}
static void
-gdk_wayland_toplevel_maximize (GdkToplevel *toplevel)
+gdk_wayland_toplevel_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- GdkSurface *surface = GDK_SURFACE (toplevel);
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (surface);
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+ GdkSurface *surface = GDK_SURFACE (object);
+ GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- if (GDK_SURFACE_DESTROYED (surface))
- return;
+ switch (prop_id)
+ {
+ case LAST_PROP + GDK_TOPLEVEL_PROP_STATE:
+ g_value_set_flags (value, surface->state);
+ break;
- _gdk_wayland_surface_save_size (surface);
+ case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
+ g_value_set_string (value, toplevel->title);
+ break;
- if (is_realized_toplevel (wayland_surface))
- {
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
+ g_value_set_string (value, "");
+ break;
- switch (display_wayland->shell_variant)
- {
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_set_maximized (wayland_toplevel->display_server.xdg_toplevel);
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_set_maximized (wayland_toplevel->display_server.zxdg_toplevel_v6);
- break;
- default:
- g_assert_not_reached ();
- }
- }
- else
- {
- synthesize_initial_surface_state (wayland_toplevel, 0, GDK_TOPLEVEL_STATE_MAXIMIZED);
+ case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
+ g_value_set_object (value, toplevel->transient_for);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
+ g_value_set_boolean (value, surface->modal_hint);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
+ g_value_set_pointer (value, NULL);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
+ g_value_set_enum (value, surface->fullscreen_mode);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
+ g_value_set_boolean (value, surface->shortcuts_inhibited);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
}
}
static void
-gdk_wayland_toplevel_unmaximize (GdkToplevel *toplevel)
+gdk_wayland_toplevel_finalize (GObject *object)
+{
+ GdkWaylandToplevel *wayland_toplevel;
+
+ g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (object));
+
+ wayland_toplevel = GDK_WAYLAND_TOPLEVEL (object);
+
+ if (gdk_wayland_toplevel_is_exported (wayland_toplevel))
+ gdk_wayland_toplevel_unexport_handle (GDK_TOPLEVEL (wayland_toplevel));
+
+ g_free (wayland_toplevel->application.application_id);
+ g_free (wayland_toplevel->application.app_menu_path);
+ g_free (wayland_toplevel->application.menubar_path);
+ g_free (wayland_toplevel->application.window_object_path);
+ g_free (wayland_toplevel->application.application_object_path);
+ g_free (wayland_toplevel->application.unique_bus_name);
+
+ g_free (wayland_toplevel->title);
+ g_clear_pointer (&wayland_toplevel->shortcuts_inhibitors, g_hash_table_unref);
+
+ G_OBJECT_CLASS (gdk_wayland_toplevel_parent_class)->finalize (object);
+}
+
+static void
+gdk_wayland_toplevel_class_init (GdkWaylandToplevelClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->get_property = gdk_wayland_toplevel_get_property;
+ object_class->set_property = gdk_wayland_toplevel_set_property;
+ object_class->finalize = gdk_wayland_toplevel_finalize;
+
+ gdk_toplevel_install_properties (object_class, 1);
+}
+
+static void
+synthesize_initial_surface_state (GdkWaylandToplevel *wayland_toplevel,
+ GdkToplevelState unset_flags,
+ GdkToplevelState set_flags)
+{
+ wayland_toplevel->initial_state.unset_flags |= unset_flags;
+ wayland_toplevel->initial_state.set_flags &= ~unset_flags;
+
+ wayland_toplevel->initial_state.set_flags |= set_flags;
+ wayland_toplevel->initial_state.unset_flags &= ~set_flags;
+}
+
+static gboolean
+gdk_wayland_toplevel_minimize (GdkToplevel *toplevel)
{
GdkSurface *surface = GDK_SURFACE (toplevel);
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (surface);
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (surface);
+ GdkWaylandDisplay *display_wayland;
if (GDK_SURFACE_DESTROYED (surface))
- return;
+ return TRUE;
- if (is_realized_toplevel (wayland_surface))
- {
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ if (!is_realized_toplevel (impl))
+ return TRUE;
- switch (display_wayland->shell_variant)
- {
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_unset_maximized (wayland_toplevel->display_server.xdg_toplevel);
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_unset_maximized (wayland_toplevel->display_server.zxdg_toplevel_v6);
- break;
- default:
- g_assert_not_reached ();
- }
- }
- else
+ /* FIXME: xdg_toplevel does not come with a minimized state that we can
+ * query or get notified of. This means we cannot implement the full
+ * GdkSurface API, and our state will not reflect minimization.
+ */
+ display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ switch (display_wayland->shell_variant)
{
- synthesize_initial_surface_state (wayland_toplevel, GDK_TOPLEVEL_STATE_MAXIMIZED, 0);
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ xdg_toplevel_set_minimized (wayland_toplevel->display_server.xdg_toplevel);
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ zxdg_toplevel_v6_set_minimized (wayland_toplevel->display_server.zxdg_toplevel_v6);
+ break;
+ default:
+ g_assert_not_reached ();
}
+
+ return TRUE;
}
static void
-gdk_wayland_toplevel_fullscreen_on_monitor (GdkWaylandToplevel *wayland_toplevel,
- GdkMonitor *monitor)
+gdk_wayland_toplevel_maximize (GdkToplevel *toplevel)
{
- GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
+ GdkSurface *surface = GDK_SURFACE (toplevel);
GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (surface);
- struct wl_output *output = ((GdkWaylandMonitor *)monitor)->output;
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
if (GDK_SURFACE_DESTROYED (surface))
return;
switch (display_wayland->shell_variant)
{
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_set_fullscreen (wayland_toplevel->display_server.xdg_toplevel, output);
+ xdg_toplevel_set_maximized (wayland_toplevel->display_server.xdg_toplevel);
break;
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_set_fullscreen (wayland_toplevel->display_server.zxdg_toplevel_v6, output);
+ zxdg_toplevel_v6_set_maximized (wayland_toplevel->display_server.zxdg_toplevel_v6);
break;
default:
g_assert_not_reached ();
}
else
{
- synthesize_initial_surface_state (wayland_toplevel, 0, GDK_TOPLEVEL_STATE_FULLSCREEN);
- wayland_toplevel->initial_fullscreen_output = output;
+ synthesize_initial_surface_state (wayland_toplevel, 0, GDK_TOPLEVEL_STATE_MAXIMIZED);
}
}
static void
-gdk_wayland_toplevel_fullscreen (GdkWaylandToplevel *wayland_toplevel)
+gdk_wayland_toplevel_unmaximize (GdkToplevel *toplevel)
{
- GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_toplevel);
+ GdkSurface *surface = GDK_SURFACE (toplevel);
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (surface);
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
if (GDK_SURFACE_DESTROYED (surface))
return;
- wayland_toplevel->initial_fullscreen_output = NULL;
-
- _gdk_wayland_surface_save_size (surface);
-
if (is_realized_toplevel (wayland_surface))
{
GdkWaylandDisplay *display_wayland =
switch (display_wayland->shell_variant)
{
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_set_fullscreen (wayland_toplevel->display_server.xdg_toplevel, NULL);
+ xdg_toplevel_unset_maximized (wayland_toplevel->display_server.xdg_toplevel);
break;
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_set_fullscreen (wayland_toplevel->display_server.zxdg_toplevel_v6, NULL);
+ zxdg_toplevel_v6_unset_maximized (wayland_toplevel->display_server.zxdg_toplevel_v6);
break;
default:
g_assert_not_reached ();
}
else
{
- synthesize_initial_surface_state (wayland_toplevel, 0, GDK_TOPLEVEL_STATE_FULLSCREEN);
+ synthesize_initial_surface_state (wayland_toplevel, GDK_TOPLEVEL_STATE_MAXIMIZED, 0);
}
}
static void
-gdk_wayland_toplevel_unfullscreen (GdkWaylandToplevel *wayland_toplevel)
+gdk_wayland_toplevel_fullscreen_on_monitor (GdkWaylandToplevel *wayland_toplevel,
+ GdkMonitor *monitor)
{
GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_toplevel);
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (surface);
+ struct wl_output *output = ((GdkWaylandMonitor *)monitor)->output;
if (GDK_SURFACE_DESTROYED (surface))
return;
- wayland_toplevel->initial_fullscreen_output = NULL;
+ _gdk_wayland_surface_save_size (surface);
if (is_realized_toplevel (wayland_surface))
{
switch (display_wayland->shell_variant)
{
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_unset_fullscreen (wayland_toplevel->display_server.xdg_toplevel);
+ xdg_toplevel_set_fullscreen (wayland_toplevel->display_server.xdg_toplevel, output);
break;
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_unset_fullscreen (wayland_toplevel->display_server.zxdg_toplevel_v6);
+ zxdg_toplevel_v6_set_fullscreen (wayland_toplevel->display_server.zxdg_toplevel_v6, output);
break;
default:
g_assert_not_reached ();
}
else
{
- synthesize_initial_surface_state (wayland_toplevel, GDK_TOPLEVEL_STATE_FULLSCREEN, 0);
- }
-}
-
-static void
-gdk_wayland_toplevel_begin_resize (GdkToplevel *toplevel,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- int button,
- double x,
- double y,
- guint32 timestamp)
-{
- GdkSurface *surface = GDK_SURFACE (toplevel);
- GdkWaylandSurface *impl;
- GdkWaylandToplevel *wayland_toplevel;
- GdkWaylandDisplay *display_wayland;
- GdkEventSequence *sequence;
- uint32_t resize_edges, serial;
-
- if (GDK_SURFACE_DESTROYED (surface))
- return;
-
- switch (edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT;
- break;
-
- case GDK_SURFACE_EDGE_NORTH:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP;
- break;
-
- case GDK_SURFACE_EDGE_NORTH_EAST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT;
- break;
-
- case GDK_SURFACE_EDGE_WEST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT;
- break;
-
- case GDK_SURFACE_EDGE_EAST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT;
- break;
-
- default:
- g_warning ("gdk_toplevel_begin_resize: bad resize edge %d!", edge);
- return;
- }
-
- impl = GDK_WAYLAND_SURFACE (surface);
- wayland_toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
-
- if (!is_realized_toplevel (impl))
- return;
-
- serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (gdk_device_get_seat (device)),
- &sequence);
-
- switch (display_wayland->shell_variant)
- {
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_resize (wayland_toplevel->display_server.xdg_toplevel,
- gdk_wayland_device_get_wl_seat (device),
- serial, resize_edges);
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_resize (wayland_toplevel->display_server.zxdg_toplevel_v6,
- gdk_wayland_device_get_wl_seat (device),
- serial, resize_edges);
- break;
- default:
- g_assert_not_reached ();
- }
-
- if (sequence)
- gdk_wayland_device_unset_touch_grab (device, sequence);
-}
-
-static void
-gdk_wayland_toplevel_begin_move (GdkToplevel *toplevel,
- GdkDevice *device,
- int button,
- double x,
- double y,
- guint32 timestamp)
-{
- GdkSurface *surface = GDK_SURFACE (toplevel);
- GdkWaylandSurface *impl;
- GdkWaylandToplevel *wayland_toplevel;
- GdkWaylandDisplay *display_wayland;
- GdkEventSequence *sequence;
- uint32_t serial;
-
- if (GDK_SURFACE_DESTROYED (surface))
- return;
-
- impl = GDK_WAYLAND_SURFACE (surface);
- wayland_toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
-
- if (!is_realized_toplevel (impl))
- return;
-
- serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (gdk_device_get_seat (device)),
- &sequence);
- switch (display_wayland->shell_variant)
- {
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_move (wayland_toplevel->display_server.xdg_toplevel,
- gdk_wayland_device_get_wl_seat (device),
- serial);
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_move (wayland_toplevel->display_server.zxdg_toplevel_v6,
- gdk_wayland_device_get_wl_seat (device),
- serial);
- break;
- default:
- g_assert_not_reached ();
- }
-
- if (sequence)
- gdk_wayland_device_unset_touch_grab (device, sequence);
-}
-
-static void
-gdk_wayland_surface_destroy_notify (GdkSurface *surface)
-{
- if (!GDK_SURFACE_DESTROYED (surface))
- {
- g_warning ("GdkSurface %p unexpectedly destroyed", surface);
- _gdk_surface_destroy (surface, TRUE);
+ synthesize_initial_surface_state (wayland_toplevel, 0, GDK_TOPLEVEL_STATE_FULLSCREEN);
+ wayland_toplevel->initial_fullscreen_output = output;
}
-
- g_object_unref (surface);
-}
-
-static int
-gdk_wayland_surface_get_scale_factor (GdkSurface *surface)
-{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
-
- if (GDK_SURFACE_DESTROYED (surface))
- return 1;
-
- return impl->scale;
}
static void
-gdk_wayland_surface_set_opaque_region (GdkSurface *surface,
- cairo_region_t *region)
+gdk_wayland_toplevel_fullscreen (GdkWaylandToplevel *wayland_toplevel)
{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_toplevel);
if (GDK_SURFACE_DESTROYED (surface))
return;
- g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
- impl->opaque_region = cairo_region_reference (region);
- impl->opaque_region_dirty = TRUE;
-}
-
-static gboolean
-gdk_wayland_toplevel_show_window_menu (GdkToplevel *toplevel,
- GdkEvent *event)
-{
- GdkSurface *surface = GDK_SURFACE (toplevel);
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- GdkSeat *seat;
- struct wl_seat *wl_seat;
- double x, y;
- uint32_t serial;
-
- GdkEventType event_type = gdk_event_get_event_type (event);
- switch ((guint) event_type)
- {
- case GDK_BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- case GDK_TOUCH_BEGIN:
- case GDK_TOUCH_END:
- break;
- default:
- return FALSE;
- }
-
- if (!is_realized_toplevel (impl))
- return FALSE;
+ wayland_toplevel->initial_fullscreen_output = NULL;
- seat = gdk_event_get_seat (event);
- wl_seat = gdk_wayland_seat_get_wl_seat (seat);
- gdk_event_get_position (event, &x, &y);
+ _gdk_wayland_surface_save_size (surface);
- serial = _gdk_wayland_seat_get_implicit_grab_serial (seat, event);
+ if (is_realized_toplevel (wayland_surface))
+ {
+ GdkWaylandDisplay *display_wayland =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- switch (display_wayland->shell_variant)
+ switch (display_wayland->shell_variant)
+ {
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ xdg_toplevel_set_fullscreen (wayland_toplevel->display_server.xdg_toplevel, NULL);
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ zxdg_toplevel_v6_set_fullscreen (wayland_toplevel->display_server.zxdg_toplevel_v6, NULL);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ else
{
- case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
- xdg_toplevel_show_window_menu (wayland_toplevel->display_server.xdg_toplevel,
- wl_seat, serial, x, y);
- break;
- case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
- zxdg_toplevel_v6_show_window_menu (wayland_toplevel->display_server.zxdg_toplevel_v6,
- wl_seat, serial, x, y);
- break;
- default:
- g_assert_not_reached ();
+ synthesize_initial_surface_state (wayland_toplevel, 0, GDK_TOPLEVEL_STATE_FULLSCREEN);
}
-
- return TRUE;
}
-static gboolean
-translate_gesture (GdkTitlebarGesture gesture,
- enum gtk_surface1_gesture *out_gesture)
+static void
+gdk_wayland_toplevel_unfullscreen (GdkWaylandToplevel *wayland_toplevel)
{
- switch (gesture)
- {
- case GDK_TITLEBAR_GESTURE_DOUBLE_CLICK:
- *out_gesture = GTK_SURFACE1_GESTURE_DOUBLE_CLICK;
- break;
+ GdkSurface *surface = GDK_SURFACE (wayland_toplevel);
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_toplevel);
- case GDK_TITLEBAR_GESTURE_RIGHT_CLICK:
- *out_gesture = GTK_SURFACE1_GESTURE_RIGHT_CLICK;
- break;
+ if (GDK_SURFACE_DESTROYED (surface))
+ return;
- case GDK_TITLEBAR_GESTURE_MIDDLE_CLICK:
- *out_gesture = GTK_SURFACE1_GESTURE_MIDDLE_CLICK;
- break;
+ wayland_toplevel->initial_fullscreen_output = NULL;
- default:
- g_warning ("Not handling unknown titlebar gesture %u", gesture);
- return FALSE;
- }
+ if (is_realized_toplevel (wayland_surface))
+ {
+ GdkWaylandDisplay *display_wayland =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- return TRUE;
+ switch (display_wayland->shell_variant)
+ {
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ xdg_toplevel_unset_fullscreen (wayland_toplevel->display_server.xdg_toplevel);
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ zxdg_toplevel_v6_unset_fullscreen (wayland_toplevel->display_server.zxdg_toplevel_v6);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ else
+ {
+ synthesize_initial_surface_state (wayland_toplevel, GDK_TOPLEVEL_STATE_FULLSCREEN, 0);
+ }
}
-static gboolean
-gdk_wayland_toplevel_titlebar_gesture (GdkToplevel *toplevel,
- GdkTitlebarGesture gesture)
+static void
+gdk_wayland_toplevel_present (GdkToplevel *toplevel,
+ GdkToplevelLayout *layout)
{
GdkSurface *surface = GDK_SURFACE (toplevel);
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (toplevel);
GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- struct gtk_surface1 *gtk_surface = wayland_toplevel->display_server.gtk_surface;
- enum gtk_surface1_gesture gtk_gesture;
- GdkSeat *seat;
- struct wl_seat *wl_seat;
- uint32_t serial;
-
- if (!gtk_surface)
- return FALSE;
+ gboolean pending_configure = FALSE;
+ gboolean maximize;
+ gboolean fullscreen;
- if (gtk_surface1_get_version (gtk_surface) < GTK_SURFACE1_TITLEBAR_GESTURE_SINCE_VERSION)
- return FALSE;
+ if (gdk_toplevel_layout_get_maximized (layout, &maximize))
+ {
+ if (maximize)
+ gdk_wayland_toplevel_maximize (toplevel);
+ else
+ gdk_wayland_toplevel_unmaximize (toplevel);
+ pending_configure = TRUE;
+ }
- if (!translate_gesture (gesture, >k_gesture))
- return FALSE;
+ if (gdk_toplevel_layout_get_fullscreen (layout, &fullscreen))
+ {
+ if (fullscreen)
+ {
+ GdkMonitor *monitor;
- seat = gdk_display_get_default_seat (surface->display);
- wl_seat = gdk_wayland_seat_get_wl_seat (seat);
+ monitor = gdk_toplevel_layout_get_fullscreen_monitor (layout);
+ if (monitor)
+ gdk_wayland_toplevel_fullscreen_on_monitor (wayland_toplevel, monitor);
+ else
+ gdk_wayland_toplevel_fullscreen (wayland_toplevel);
+ }
+ else
+ {
+ gdk_wayland_toplevel_unfullscreen (wayland_toplevel);
+ }
+ pending_configure = TRUE;
+ }
- serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (seat), NULL);
+ g_clear_pointer (&wayland_toplevel->layout, gdk_toplevel_layout_unref);
+ wayland_toplevel->layout = gdk_toplevel_layout_copy (layout);
- gtk_surface1_titlebar_gesture (wayland_toplevel->display_server.gtk_surface,
- serial,
- wl_seat,
- gtk_gesture);
+ gdk_wayland_surface_show (surface);
- return TRUE;
+ if (!pending_configure)
+ {
+ wayland_surface->next_layout.surface_geometry_dirty = TRUE;
+ gdk_surface_request_layout (surface);
+ }
}
static gboolean
-gdk_wayland_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
+gdk_wayland_toplevel_lower (GdkToplevel *toplevel)
{
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- struct gtk_surface1 *gtk_surface = wayland_toplevel->display_server.gtk_surface;
+ return FALSE;
+}
- if (!gtk_surface)
- return FALSE;
+static void
+inhibitor_active (void *data,
+ struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor)
+{
+ GdkToplevel *toplevel = GDK_TOPLEVEL (data);
+ GdkSurface *surface = GDK_SURFACE (toplevel);
- return gtk_surface1_get_version (gtk_surface) >= GTK_SURFACE1_CONFIGURE_EDGES_SINCE_VERSION;
+ surface->shortcuts_inhibited = TRUE;
+ g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
}
static void
-gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass)
+inhibitor_inactive (void *data,
+ struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdkSurfaceClass *impl_class = GDK_SURFACE_CLASS (klass);
+ GdkToplevel *toplevel = GDK_TOPLEVEL (data);
+ GdkSurface *surface = GDK_SURFACE (toplevel);
- object_class->constructed = gdk_wayland_surface_constructed;
- object_class->dispose = gdk_wayland_surface_dispose;
- object_class->finalize = gdk_wayland_surface_finalize;
+ surface->shortcuts_inhibited = FALSE;
+ g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
+}
- impl_class->hide = gdk_wayland_surface_hide;
- impl_class->get_geometry = gdk_wayland_surface_get_geometry;
- impl_class->get_root_coords = gdk_wayland_surface_get_root_coords;
- impl_class->get_device_state = gdk_wayland_surface_get_device_state;
- impl_class->set_input_region = gdk_wayland_surface_set_input_region;
- impl_class->destroy = gdk_wayland_surface_destroy;
- impl_class->beep = gdk_wayland_surface_beep;
+static const struct zwp_keyboard_shortcuts_inhibitor_v1_listener
+zwp_keyboard_shortcuts_inhibitor_listener = {
+ inhibitor_active,
+ inhibitor_inactive,
+};
- impl_class->destroy_notify = gdk_wayland_surface_destroy_notify;
- impl_class->drag_begin = _gdk_wayland_surface_drag_begin;
- impl_class->get_scale_factor = gdk_wayland_surface_get_scale_factor;
- impl_class->set_opaque_region = gdk_wayland_surface_set_opaque_region;
- impl_class->request_layout = gdk_wayland_surface_request_layout;
- impl_class->compute_size = gdk_wayland_surface_compute_size;
+static struct zwp_keyboard_shortcuts_inhibitor_v1 *
+gdk_wayland_toplevel_get_inhibitor (GdkWaylandToplevel *toplevel,
+ GdkSeat *gdk_seat)
+{
+ return g_hash_table_lookup (toplevel->shortcuts_inhibitors, gdk_seat);
}
void
-_gdk_wayland_surface_set_grab_seat (GdkSurface *surface,
- GdkSeat *seat)
+gdk_wayland_surface_inhibit_shortcuts (GdkSurface *surface,
+ GdkSeat *gdk_seat)
{
- GdkWaylandPopup *popup;
-
- g_return_if_fail (surface != NULL);
-
- popup = GDK_WAYLAND_POPUP (surface);
- popup->grab_input_seat = seat;
-}
+ GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ struct wl_surface *wl_surface = impl->display_server.wl_surface;
+ struct wl_seat *seat = gdk_wayland_seat_get_wl_seat (gdk_seat);
+ struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
+ GdkWaylandToplevel *toplevel;
-/**
- * gdk_wayland_surface_get_wl_surface: (skip)
- * @surface: (type GdkWaylandSurface): a `GdkSurface`
- *
- * Returns the Wayland `wl_surface` of a `GdkSurface`.
- *
- * Returns: (transfer none): a Wayland `wl_surface`
- */
-struct wl_surface *
-gdk_wayland_surface_get_wl_surface (GdkSurface *surface)
-{
- g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL);
+ if (display->keyboard_shortcuts_inhibit == NULL)
+ return;
- return GDK_WAYLAND_SURFACE (surface)->display_server.wl_surface;
-}
+ if (!is_realized_toplevel (GDK_WAYLAND_SURFACE (surface)))
+ return;
-struct wl_output *
-gdk_wayland_surface_get_wl_output (GdkSurface *surface)
-{
- GdkWaylandSurface *impl;
+ toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL);
+ if (gdk_wayland_toplevel_get_inhibitor (toplevel, gdk_seat))
+ return; /* Already inhibited */
- impl = GDK_WAYLAND_SURFACE (surface);
- /* We pick the head of the list as this is the last entered output */
- if (impl->display_server.outputs)
- return (struct wl_output *) impl->display_server.outputs->data;
+ inhibitor =
+ zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts (
+ display->keyboard_shortcuts_inhibit, wl_surface, seat);
- return NULL;
+ g_hash_table_insert (toplevel->shortcuts_inhibitors, gdk_seat, inhibitor);
}
void
-gdk_wayland_surface_ensure_wl_egl_window (GdkSurface *surface)
+gdk_wayland_surface_restore_shortcuts (GdkSurface *surface,
+ GdkSeat *gdk_seat)
{
+ GdkWaylandToplevel *toplevel;
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
- if (impl->display_server.egl_window == NULL)
- {
- impl->display_server.egl_window =
- wl_egl_window_create (impl->display_server.wl_surface,
- surface->width * impl->scale,
- surface->height * impl->scale);
- wl_surface_set_buffer_scale (impl->display_server.wl_surface, impl->scale);
-
- gdk_surface_set_egl_native_window (surface, impl->display_server.egl_window);
- }
-}
+ if (!is_realized_toplevel (impl))
+ return;
-struct gtk_surface1 *
-gdk_wayland_toplevel_get_gtk_surface (GdkWaylandToplevel *wayland_toplevel)
-{
- return wayland_toplevel->display_server.gtk_surface;
+ toplevel = GDK_WAYLAND_TOPLEVEL (impl);
+
+ inhibitor = gdk_wayland_toplevel_get_inhibitor (toplevel, gdk_seat);
+ if (inhibitor == NULL)
+ return; /* Not inhibitted */
+
+ zwp_keyboard_shortcuts_inhibitor_v1_destroy (inhibitor);
+ g_hash_table_remove (toplevel->shortcuts_inhibitors, gdk_seat);
}
static void
-maybe_set_gtk_surface_dbus_properties (GdkWaylandToplevel *wayland_toplevel)
+gdk_wayland_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel,
+ GdkEvent *event)
{
- if (wayland_toplevel->application.was_set)
- return;
+ struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
+ GdkSurface *surface = GDK_SURFACE (toplevel);
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+ GdkSeat *gdk_seat;
- if (wayland_toplevel->application.application_id == NULL &&
- wayland_toplevel->application.app_menu_path == NULL &&
- wayland_toplevel->application.menubar_path == NULL &&
- wayland_toplevel->application.window_object_path == NULL &&
- wayland_toplevel->application.application_object_path == NULL &&
- wayland_toplevel->application.unique_bus_name == NULL)
+ if (surface->shortcuts_inhibited)
return;
- gdk_wayland_toplevel_init_gtk_surface (wayland_toplevel);
- if (wayland_toplevel->display_server.gtk_surface == NULL)
+ gdk_seat = gdk_surface_get_seat_from_event (surface, event);
+ gdk_wayland_surface_inhibit_shortcuts (surface, gdk_seat);
+ inhibitor = gdk_wayland_toplevel_get_inhibitor (wayland_toplevel, gdk_seat);
+ if (!inhibitor)
return;
- gtk_surface1_set_dbus_properties (wayland_toplevel->display_server.gtk_surface,
- wayland_toplevel->application.application_id,
- wayland_toplevel->application.app_menu_path,
- wayland_toplevel->application.menubar_path,
- wayland_toplevel->application.window_object_path,
- wayland_toplevel->application.application_object_path,
- wayland_toplevel->application.unique_bus_name);
- wayland_toplevel->application.was_set = TRUE;
+ surface->current_shortcuts_inhibited_seat = gdk_seat;
+ zwp_keyboard_shortcuts_inhibitor_v1_add_listener
+ (inhibitor, &zwp_keyboard_shortcuts_inhibitor_listener, toplevel);
}
-void
-gdk_wayland_toplevel_set_dbus_properties (GdkToplevel *toplevel,
- const char *application_id,
- const char *app_menu_path,
- const char *menubar_path,
- const char *window_object_path,
- const char *application_object_path,
- const char *unique_bus_name)
+static void
+gdk_wayland_toplevel_restore_system_shortcuts (GdkToplevel *toplevel)
{
- GdkWaylandToplevel *wayland_toplevel;
+ GdkSurface *surface = GDK_SURFACE (toplevel);
- g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
+ gdk_wayland_surface_restore_shortcuts (surface, surface->current_shortcuts_inhibited_seat);
+ surface->current_shortcuts_inhibited_seat = NULL;
+ surface->shortcuts_inhibited = FALSE;
+ g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
+}
- wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+static void
+xdg_exported_handle_v1 (void *data,
+ struct zxdg_exported_v1 *zxdg_exported_v1,
+ const char *handle)
+{
+ g_task_return_pointer (G_TASK (data), g_strdup (handle), g_free);
+ g_object_unref (data);
+}
- wayland_toplevel->application.application_id = g_strdup (application_id);
- wayland_toplevel->application.app_menu_path = g_strdup (app_menu_path);
- wayland_toplevel->application.menubar_path = g_strdup (menubar_path);
- wayland_toplevel->application.window_object_path = g_strdup (window_object_path);
- wayland_toplevel->application.application_object_path =
- g_strdup (application_object_path);
- wayland_toplevel->application.unique_bus_name = g_strdup (unique_bus_name);
+static const struct zxdg_exported_v1_listener xdg_exported_listener_v1 = {
+ xdg_exported_handle_v1
+};
- maybe_set_gtk_surface_dbus_properties (wayland_toplevel);
+static void
+xdg_exported_handle_v2 (void *data,
+ struct zxdg_exported_v2 *zxdg_exported_v2,
+ const char *handle)
+{
+ g_task_return_pointer (G_TASK (data), g_strdup (handle), g_free);
+ g_object_unref (data);
}
-void
-_gdk_wayland_surface_offset_next_wl_buffer (GdkSurface *surface,
- int x,
- int y)
-{
- GdkWaylandSurface *impl;
+static const struct zxdg_exported_v2_listener xdg_exported_listener_v2 = {
+ xdg_exported_handle_v2
+};
- g_return_if_fail (GDK_IS_WAYLAND_SURFACE (surface));
+static void
+gdk_wayland_toplevel_real_export_handle (GdkToplevel *toplevel,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+ GdkSurface *surface = GDK_SURFACE (toplevel);
+ GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel));
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+ GTask *task;
- impl = GDK_WAYLAND_SURFACE (surface);
+ task = g_task_new (toplevel, cancellable, callback, user_data);
- impl->pending_buffer_offset_x = x;
- impl->pending_buffer_offset_y = y;
+ if (display_wayland->xdg_exporter_v2)
+ {
+ wayland_toplevel->xdg_exported_v2 =
+ zxdg_exporter_v2_export_toplevel (display_wayland->xdg_exporter_v2,
+ gdk_wayland_surface_get_wl_surface (surface));
+ zxdg_exported_v2_add_listener (wayland_toplevel->xdg_exported_v2,
+ &xdg_exported_listener_v2, task);
+ }
+ else if (display_wayland->xdg_exporter)
+ {
+ wayland_toplevel->xdg_exported =
+ zxdg_exporter_v1_export (display_wayland->xdg_exporter,
+ gdk_wayland_surface_get_wl_surface (surface));
+ zxdg_exported_v1_add_listener (wayland_toplevel->xdg_exported,
+ &xdg_exported_listener_v1, task);
+ }
+ else
+ {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Exporting surface handles not supported");
+ g_object_unref (task);
+ return;
+ }
}
-/**
- * GdkWaylandToplevelExported:
- * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` that is exported
- * @handle: the handle
- * @user_data: user data that was passed to [method@GdkWayland.WaylandToplevel.export_handle]
- *
- * Callback that gets called when the handle for a surface has been
- * obtained from the Wayland compositor.
- *
- * This callback is used in [method@GdkWayland.WaylandToplevel.export_handle].
- *
- * The @handle can be passed to other processes, for the purpose of
- * marking surfaces as transient for out-of-process surfaces.
- */
-
-static gboolean
-gdk_wayland_toplevel_is_exported (GdkWaylandToplevel *wayland_toplevel)
+static char *
+gdk_wayland_toplevel_real_export_handle_finish (GdkToplevel *toplevel,
+ GAsyncResult *result,
+ GError **error)
{
- return wayland_toplevel->xdg_exported != NULL || wayland_toplevel->xdg_exported_v2 != NULL;
+ return g_task_propagate_pointer (G_TASK (result), error);
}
-typedef struct {
- GdkWaylandToplevelExported callback;
- gpointer user_data;
- GDestroyNotify destroy;
-} ExportHandleData;
-
static void
-export_handle_done (GObject *source,
- GAsyncResult *result,
- void *user_data)
+gdk_wayland_toplevel_real_unexport_handle (GdkToplevel *toplevel)
{
- GdkToplevel *toplevel = GDK_TOPLEVEL (source);
- ExportHandleData *data = (ExportHandleData *)user_data;
- char *handle;
-
- handle = gdk_toplevel_export_handle_finish (toplevel, result, NULL);
- data->callback (toplevel, handle, data->user_data);
- g_free (handle);
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- if (data->destroy)
- data->destroy (data->user_data);
+ g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
+ g_return_if_fail (wayland_toplevel->xdg_exported_v2 || wayland_toplevel->xdg_exported);
- g_free (data);
+ g_clear_pointer (&wayland_toplevel->xdg_exported_v2, zxdg_exported_v2_destroy);
+ g_clear_pointer (&wayland_toplevel->xdg_exported, zxdg_exported_v1_destroy);
}
-/**
- * gdk_wayland_toplevel_export_handle:
- * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` to obtain a handle for
- * @callback: callback to call with the handle
- * @user_data: (closure): user data for @callback
- * @destroy_func: destroy notify for @user_data
- *
- * Asynchronously obtains a handle for a surface that can be passed
- * to other processes.
- *
- * When the handle has been obtained, @callback will be called.
- *
- * It is an error to call this function on a surface that is already
- * exported.
- *
- * When the handle is no longer needed, [method@GdkWayland.WaylandToplevel.unexport_handle]
- * should be called to clean up resources.
- *
- * The main purpose for obtaining a handle is to mark a surface
- * from another surface as transient for this one, see
- * [method@GdkWayland.WaylandToplevel.set_transient_for_exported].
- *
- * Note that this API depends on an unstable Wayland protocol,
- * and thus may require changes in the future.
- *
- * Return value: %TRUE if the handle has been requested, %FALSE if
- * an error occurred.
- */
-gboolean
-gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel,
- GdkWaylandToplevelExported callback,
- gpointer user_data,
- GDestroyNotify destroy_func)
+static gboolean
+gdk_wayland_toplevel_show_window_menu (GdkToplevel *toplevel,
+ GdkEvent *event)
{
- ExportHandleData *data;
+ GdkSurface *surface = GDK_SURFACE (toplevel);
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (surface);
+ GdkWaylandDisplay *display_wayland =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ GdkSeat *seat;
+ struct wl_seat *wl_seat;
+ double x, y;
+ uint32_t serial;
- g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
+ GdkEventType event_type = gdk_event_get_event_type (event);
+ switch ((guint) event_type)
+ {
+ case GDK_BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_TOUCH_BEGIN:
+ case GDK_TOUCH_END:
+ break;
+ default:
+ return FALSE;
+ }
- data = g_new (ExportHandleData, 1);
- data->callback = callback;
- data->user_data = user_data;
- data->destroy = destroy_func;
+ if (!is_realized_toplevel (impl))
+ return FALSE;
- gdk_toplevel_export_handle (toplevel, NULL, export_handle_done, data);
+ seat = gdk_event_get_seat (event);
+ wl_seat = gdk_wayland_seat_get_wl_seat (seat);
+ gdk_event_get_position (event, &x, &y);
- return TRUE;
-}
+ serial = _gdk_wayland_seat_get_implicit_grab_serial (seat, event);
-/**
- * gdk_wayland_toplevel_unexport_handle:
- * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` to unexport
- *
- * Destroys the handle that was obtained with
- * gdk_wayland_toplevel_export_handle().
- *
- * It is an error to call this function on a surface that
- * does not have a handle.
- *
- * Note that this API depends on an unstable Wayland protocol,
- * and thus may require changes in the future.
- */
-void
-gdk_wayland_toplevel_unexport_handle (GdkToplevel *toplevel)
-{
- g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
+ switch (display_wayland->shell_variant)
+ {
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ xdg_toplevel_show_window_menu (wayland_toplevel->display_server.xdg_toplevel,
+ wl_seat, serial, x, y);
+ break;
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ zxdg_toplevel_v6_show_window_menu (wayland_toplevel->display_server.zxdg_toplevel_v6,
+ wl_seat, serial, x, y);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
- gdk_toplevel_unexport_handle (toplevel);
+ return TRUE;
}
-static void
-unset_transient_for_exported (GdkSurface *surface)
+static gboolean
+translate_gesture (GdkTitlebarGesture gesture,
+ enum gtk_surface1_gesture *out_gesture)
{
- if (GDK_IS_WAYLAND_TOPLEVEL (surface))
+ switch (gesture)
{
- GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
+ case GDK_TITLEBAR_GESTURE_DOUBLE_CLICK:
+ *out_gesture = GTK_SURFACE1_GESTURE_DOUBLE_CLICK;
+ break;
- g_clear_pointer (&toplevel->imported_transient_for, zxdg_imported_v1_destroy);
- g_clear_pointer (&toplevel->imported_transient_for_v2, zxdg_imported_v2_destroy);
- }
-}
+ case GDK_TITLEBAR_GESTURE_RIGHT_CLICK:
+ *out_gesture = GTK_SURFACE1_GESTURE_RIGHT_CLICK;
+ break;
-static void
-xdg_imported_destroyed (void *data,
- struct zxdg_imported_v1 *imported)
-{
- unset_transient_for_exported (GDK_SURFACE (data));
-}
+ case GDK_TITLEBAR_GESTURE_MIDDLE_CLICK:
+ *out_gesture = GTK_SURFACE1_GESTURE_MIDDLE_CLICK;
+ break;
-static const struct zxdg_imported_v1_listener xdg_imported_listener = {
- xdg_imported_destroyed,
-};
+ default:
+ g_warning ("Not handling unknown titlebar gesture %u", gesture);
+ return FALSE;
+ }
-static void
-xdg_imported_v2_destroyed (void *data,
- struct zxdg_imported_v2 *imported)
-{
- unset_transient_for_exported (GDK_SURFACE (data));
+ return TRUE;
}
-static const struct zxdg_imported_v2_listener xdg_imported_listener_v2 = {
- xdg_imported_v2_destroyed,
-};
-
-/**
- * gdk_wayland_toplevel_set_transient_for_exported:
- * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` to make as transient
- * @parent_handle_str: an exported handle for a surface
- *
- * Marks @toplevel as transient for the surface to which the given
- * @parent_handle_str refers.
- *
- * Typically, the handle will originate from a
- * [method@GdkWayland.WaylandToplevel.export_handle] call in another process.
- *
- * Note that this API depends on an unstable Wayland protocol,
- * and thus may require changes in the future.
- *
- * Return value: %TRUE if the surface has been marked as transient,
- * %FALSE if an error occurred.
- */
-gboolean
-gdk_wayland_toplevel_set_transient_for_exported (GdkToplevel *toplevel,
- const char *parent_handle_str)
+static gboolean
+gdk_wayland_toplevel_titlebar_gesture (GdkToplevel *toplevel,
+ GdkTitlebarGesture gesture)
{
+ GdkSurface *surface = GDK_SURFACE (toplevel);
GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel));
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+ struct gtk_surface1 *gtk_surface = wayland_toplevel->display_server.gtk_surface;
+ enum gtk_surface1_gesture gtk_gesture;
+ GdkSeat *seat;
+ struct wl_seat *wl_seat;
+ uint32_t serial;
- g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
- g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
+ if (!gtk_surface)
+ return FALSE;
- display_wayland = GDK_WAYLAND_DISPLAY (display);
+ if (gtk_surface1_get_version (gtk_surface) < GTK_SURFACE1_TITLEBAR_GESTURE_SINCE_VERSION)
+ return FALSE;
- if (!display_wayland->xdg_importer && !display_wayland->xdg_importer_v2)
- {
- g_warning ("Server is missing xdg_foreign support");
- return FALSE;
- }
+ if (!translate_gesture (gesture, >k_gesture))
+ return FALSE;
- gdk_wayland_toplevel_set_transient_for (wayland_toplevel, NULL);
+ seat = gdk_display_get_default_seat (surface->display);
+ wl_seat = gdk_wayland_seat_get_wl_seat (seat);
- if (display_wayland->xdg_importer)
- {
- wayland_toplevel->imported_transient_for =
- zxdg_importer_v1_import (display_wayland->xdg_importer, parent_handle_str);
- zxdg_imported_v1_add_listener (wayland_toplevel->imported_transient_for,
- &xdg_imported_listener,
- toplevel);
- }
- else
- {
- wayland_toplevel->imported_transient_for_v2 =
- zxdg_importer_v2_import_toplevel (display_wayland->xdg_importer_v2, parent_handle_str);
- zxdg_imported_v2_add_listener (wayland_toplevel->imported_transient_for_v2,
- &xdg_imported_listener_v2,
- toplevel);
- }
+ serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (seat), NULL);
- gdk_wayland_toplevel_sync_parent_of_imported (wayland_toplevel);
+ gtk_surface1_titlebar_gesture (wayland_toplevel->display_server.gtk_surface,
+ serial,
+ wl_seat,
+ gtk_gesture);
return TRUE;
}
-static struct zwp_keyboard_shortcuts_inhibitor_v1 *
-gdk_wayland_toplevel_get_inhibitor (GdkWaylandToplevel *toplevel,
- GdkSeat *gdk_seat)
+static gboolean
+gdk_wayland_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
{
- return g_hash_table_lookup (toplevel->shortcuts_inhibitors, gdk_seat);
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+ struct gtk_surface1 *gtk_surface = wayland_toplevel->display_server.gtk_surface;
+
+ if (!gtk_surface)
+ return FALSE;
+
+ return gtk_surface1_get_version (gtk_surface) >= GTK_SURFACE1_CONFIGURE_EDGES_SINCE_VERSION;
}
-void
-gdk_wayland_surface_inhibit_shortcuts (GdkSurface *surface,
- GdkSeat *gdk_seat)
+static void
+gdk_wayland_toplevel_begin_resize (GdkToplevel *toplevel,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ int button,
+ double x,
+ double y,
+ guint32 timestamp)
{
- GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- struct wl_surface *wl_surface = impl->display_server.wl_surface;
- struct wl_seat *seat = gdk_wayland_seat_get_wl_seat (gdk_seat);
- struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
- GdkWaylandToplevel *toplevel;
-
- if (display->keyboard_shortcuts_inhibit == NULL)
- return;
+ GdkSurface *surface = GDK_SURFACE (toplevel);
+ GdkWaylandSurface *impl;
+ GdkWaylandToplevel *wayland_toplevel;
+ GdkWaylandDisplay *display_wayland;
+ GdkEventSequence *sequence;
+ uint32_t resize_edges, serial;
- if (!is_realized_toplevel (GDK_WAYLAND_SURFACE (surface)))
+ if (GDK_SURFACE_DESTROYED (surface))
return;
- toplevel = GDK_WAYLAND_TOPLEVEL (surface);
+ switch (edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT;
+ break;
- if (gdk_wayland_toplevel_get_inhibitor (toplevel, gdk_seat))
- return; /* Already inhibited */
+ case GDK_SURFACE_EDGE_NORTH:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP;
+ break;
- inhibitor =
- zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts (
- display->keyboard_shortcuts_inhibit, wl_surface, seat);
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT;
+ break;
- g_hash_table_insert (toplevel->shortcuts_inhibitors, gdk_seat, inhibitor);
-}
+ case GDK_SURFACE_EDGE_WEST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT;
+ break;
-void
-gdk_wayland_surface_restore_shortcuts (GdkSurface *surface,
- GdkSeat *gdk_seat)
-{
- GdkWaylandToplevel *toplevel;
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
+ case GDK_SURFACE_EDGE_EAST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT;
+ break;
- if (!is_realized_toplevel (impl))
- return;
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT;
+ break;
- toplevel = GDK_WAYLAND_TOPLEVEL (impl);
+ case GDK_SURFACE_EDGE_SOUTH:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM;
+ break;
- inhibitor = gdk_wayland_toplevel_get_inhibitor (toplevel, gdk_seat);
- if (inhibitor == NULL)
- return; /* Not inhibitted */
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT;
+ break;
- zwp_keyboard_shortcuts_inhibitor_v1_destroy (inhibitor);
- g_hash_table_remove (toplevel->shortcuts_inhibitors, gdk_seat);
-}
+ default:
+ g_warning ("gdk_toplevel_begin_resize: bad resize edge %d!", edge);
+ return;
+ }
-#define LAST_PROP 1
+ impl = GDK_WAYLAND_SURFACE (surface);
+ wayland_toplevel = GDK_WAYLAND_TOPLEVEL (surface);
+ display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
-static void
-gdk_wayland_popup_init (GdkWaylandPopup *popup)
-{
-}
+ if (!is_realized_toplevel (impl))
+ return;
-static void
-gdk_wayland_popup_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GdkSurface *surface = GDK_SURFACE (object);
+ serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (gdk_device_get_seat (device)),
+ &sequence);
- switch (prop_id)
+ switch (display_wayland->shell_variant)
{
- case LAST_PROP + GDK_POPUP_PROP_PARENT:
- g_value_set_object (value, surface->parent);
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ xdg_toplevel_resize (wayland_toplevel->display_server.xdg_toplevel,
+ gdk_wayland_device_get_wl_seat (device),
+ serial, resize_edges);
break;
-
- case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
- g_value_set_boolean (value, surface->autohide);
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ zxdg_toplevel_v6_resize (wayland_toplevel->display_server.zxdg_toplevel_v6,
+ gdk_wayland_device_get_wl_seat (device),
+ serial, resize_edges);
break;
-
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ g_assert_not_reached ();
}
+
+ if (sequence)
+ gdk_wayland_device_unset_touch_grab (device, sequence);
}
static void
-gdk_wayland_popup_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+gdk_wayland_toplevel_begin_move (GdkToplevel *toplevel,
+ GdkDevice *device,
+ int button,
+ double x,
+ double y,
+ guint32 timestamp)
{
- GdkSurface *surface = GDK_SURFACE (object);
+ GdkSurface *surface = GDK_SURFACE (toplevel);
+ GdkWaylandSurface *impl;
+ GdkWaylandToplevel *wayland_toplevel;
+ GdkWaylandDisplay *display_wayland;
+ GdkEventSequence *sequence;
+ uint32_t serial;
- switch (prop_id)
+ if (GDK_SURFACE_DESTROYED (surface))
+ return;
+
+ impl = GDK_WAYLAND_SURFACE (surface);
+ wayland_toplevel = GDK_WAYLAND_TOPLEVEL (surface);
+ display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+
+ if (!is_realized_toplevel (impl))
+ return;
+
+ serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (gdk_device_get_seat (device)),
+ &sequence);
+ switch (display_wayland->shell_variant)
{
- case LAST_PROP + GDK_POPUP_PROP_PARENT:
- surface->parent = g_value_dup_object (value);
- if (surface->parent != NULL)
- surface->parent->children = g_list_prepend (surface->parent->children, surface);
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ xdg_toplevel_move (wayland_toplevel->display_server.xdg_toplevel,
+ gdk_wayland_device_get_wl_seat (device),
+ serial);
break;
-
- case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
- surface->autohide = g_value_get_boolean (value);
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ zxdg_toplevel_v6_move (wayland_toplevel->display_server.zxdg_toplevel_v6,
+ gdk_wayland_device_get_wl_seat (device),
+ serial);
break;
-
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ g_assert_not_reached ();
}
+
+ if (sequence)
+ gdk_wayland_device_unset_touch_grab (device, sequence);
}
static void
-gdk_wayland_popup_class_init (GdkWaylandPopupClass *class)
+token_done (gpointer data,
+ struct xdg_activation_token_v1 *provider,
+ const char *token)
{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
-
- object_class->get_property = gdk_wayland_popup_get_property;
- object_class->set_property = gdk_wayland_popup_set_property;
+ char **token_out = data;
- gdk_popup_install_properties (object_class, 1);
+ *token_out = g_strdup (token);
}
-static gboolean
-gdk_wayland_popup_present (GdkPopup *popup,
- int width,
- int height,
- GdkPopupLayout *layout)
-{
- return gdk_wayland_surface_present_popup (GDK_WAYLAND_POPUP (popup), width, height, layout);
-}
+static const struct xdg_activation_token_v1_listener token_listener = {
+ token_done,
+};
-static GdkGravity
-gdk_wayland_popup_get_surface_anchor (GdkPopup *popup)
+static void
+gdk_wayland_toplevel_focus (GdkToplevel *toplevel,
+ guint32 timestamp)
{
- return GDK_SURFACE (popup)->popup.surface_anchor;
-}
+ GdkSurface *surface = GDK_SURFACE (toplevel);
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+ GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (toplevel);
+ GdkDisplay *display = gdk_surface_get_display (surface);
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+ gchar *startup_id = NULL;
-static GdkGravity
-gdk_wayland_popup_get_rect_anchor (GdkPopup *popup)
-{
- return GDK_SURFACE (popup)->popup.rect_anchor;
-}
+ startup_id = g_steal_pointer (&display_wayland->startup_notification_id);
-static int
-gdk_wayland_popup_get_position_x (GdkPopup *popup)
-{
- return GDK_SURFACE (popup)->x;
-}
+ if (display_wayland->xdg_activation)
+ {
+ GdkWaylandSeat *seat =
+ GDK_WAYLAND_SEAT (gdk_display_get_default_seat (display));
-static int
-gdk_wayland_popup_get_position_y (GdkPopup *popup)
-{
- return GDK_SURFACE (popup)->y;
+ /* If the focus request does not have a startup ID associated, get a
+ * new token to activate the window.
+ */
+ if (!startup_id)
+ {
+ struct xdg_activation_token_v1 *token;
+ struct wl_event_queue *event_queue;
+ struct wl_surface *wl_surface = NULL;
+ GdkSurface *focus_surface;
+
+ event_queue = wl_display_create_queue (display_wayland->wl_display);
+
+ token = xdg_activation_v1_get_activation_token (display_wayland->xdg_activation);
+ wl_proxy_set_queue ((struct wl_proxy *) token, event_queue);
+
+ xdg_activation_token_v1_add_listener (token,
+ &token_listener,
+ &startup_id);
+ xdg_activation_token_v1_set_serial (token,
+ _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL),
+ gdk_wayland_seat_get_wl_seat (GDK_SEAT (seat)));
+
+
+ focus_surface = gdk_wayland_device_get_focus (gdk_seat_get_keyboard (GDK_SEAT (seat)));
+ if (focus_surface)
+ wl_surface = gdk_wayland_surface_get_wl_surface (focus_surface);
+ if (wl_surface)
+ xdg_activation_token_v1_set_surface (token, wl_surface);
+
+ xdg_activation_token_v1_commit (token);
+
+ while (startup_id == NULL)
+ wl_display_dispatch_queue (display_wayland->wl_display, event_queue);
+
+ xdg_activation_token_v1_destroy (token);
+ wl_event_queue_destroy (event_queue);
+ }
+
+ xdg_activation_v1_activate (display_wayland->xdg_activation,
+ startup_id,
+ wayland_surface->display_server.wl_surface);
+ }
+ else if (wayland_toplevel->display_server.gtk_surface)
+ {
+ if (timestamp != GDK_CURRENT_TIME)
+ gtk_surface1_present (wayland_toplevel->display_server.gtk_surface, timestamp);
+ else if (startup_id && display_wayland->gtk_shell_version >= 3)
+ gtk_surface1_request_focus (wayland_toplevel->display_server.gtk_surface,
+ startup_id);
+ }
+
+ g_free (startup_id);
}
static void
-gdk_wayland_popup_iface_init (GdkPopupInterface *iface)
+gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface)
{
- iface->present = gdk_wayland_popup_present;
- iface->get_surface_anchor = gdk_wayland_popup_get_surface_anchor;
- iface->get_rect_anchor = gdk_wayland_popup_get_rect_anchor;
- iface->get_position_x = gdk_wayland_popup_get_position_x;
- iface->get_position_y = gdk_wayland_popup_get_position_y;
+ iface->present = gdk_wayland_toplevel_present;
+ iface->minimize = gdk_wayland_toplevel_minimize;
+ iface->lower = gdk_wayland_toplevel_lower;
+ iface->focus = gdk_wayland_toplevel_focus;
+ iface->show_window_menu = gdk_wayland_toplevel_show_window_menu;
+ iface->titlebar_gesture = gdk_wayland_toplevel_titlebar_gesture;
+ iface->supports_edge_constraints = gdk_wayland_toplevel_supports_edge_constraints;
+ iface->inhibit_system_shortcuts = gdk_wayland_toplevel_inhibit_system_shortcuts;
+ iface->restore_system_shortcuts = gdk_wayland_toplevel_restore_system_shortcuts;
+ iface->begin_resize = gdk_wayland_toplevel_begin_resize;
+ iface->begin_move = gdk_wayland_toplevel_begin_move;
+ iface->export_handle = gdk_wayland_toplevel_real_export_handle;
+ iface->export_handle_finish = gdk_wayland_toplevel_real_export_handle_finish;
+ iface->unexport_handle = gdk_wayland_toplevel_real_unexport_handle;
}
-static void
-gdk_wayland_toplevel_init (GdkWaylandToplevel *toplevel)
+/* }}} */
+/* {{{ Private Toplevel API */
+
+struct gtk_surface1 *
+gdk_wayland_toplevel_get_gtk_surface (GdkWaylandToplevel *wayland_toplevel)
{
- toplevel->initial_fullscreen_output = NULL;
- toplevel->shortcuts_inhibitors = g_hash_table_new (NULL, NULL);
+ return wayland_toplevel->display_server.gtk_surface;
}
static void
-gdk_wayland_toplevel_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+maybe_set_gtk_surface_dbus_properties (GdkWaylandToplevel *wayland_toplevel)
{
- GdkSurface *surface = GDK_SURFACE (object);
- GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
-
- switch (prop_id)
- {
- case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
- gdk_wayland_toplevel_set_title (toplevel, g_value_get_string (value));
- g_object_notify_by_pspec (G_OBJECT (surface), pspec);
- break;
-
- case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
- gdk_wayland_surface_set_startup_id (surface, g_value_get_string (value));
- g_object_notify_by_pspec (G_OBJECT (surface), pspec);
- break;
+ if (wayland_toplevel->application.was_set)
+ return;
- case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
- gdk_wayland_toplevel_set_transient_for (toplevel,
- g_value_get_object (value));
- g_object_notify_by_pspec (G_OBJECT (surface), pspec);
- break;
+ if (wayland_toplevel->application.application_id == NULL &&
+ wayland_toplevel->application.app_menu_path == NULL &&
+ wayland_toplevel->application.menubar_path == NULL &&
+ wayland_toplevel->application.window_object_path == NULL &&
+ wayland_toplevel->application.application_object_path == NULL &&
+ wayland_toplevel->application.unique_bus_name == NULL)
+ return;
- case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
- gdk_wayland_toplevel_set_modal_hint (toplevel, g_value_get_boolean (value));
- g_object_notify_by_pspec (G_OBJECT (surface), pspec);
- break;
+ gdk_wayland_toplevel_init_gtk_surface (wayland_toplevel);
+ if (wayland_toplevel->display_server.gtk_surface == NULL)
+ return;
- case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
- break;
+ gtk_surface1_set_dbus_properties (wayland_toplevel->display_server.gtk_surface,
+ wayland_toplevel->application.application_id,
+ wayland_toplevel->application.app_menu_path,
+ wayland_toplevel->application.menubar_path,
+ wayland_toplevel->application.window_object_path,
+ wayland_toplevel->application.application_object_path,
+ wayland_toplevel->application.unique_bus_name);
+ wayland_toplevel->application.was_set = TRUE;
+}
- case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
- break;
+void
+gdk_wayland_toplevel_set_dbus_properties (GdkToplevel *toplevel,
+ const char *application_id,
+ const char *app_menu_path,
+ const char *menubar_path,
+ const char *window_object_path,
+ const char *application_object_path,
+ const char *unique_bus_name)
+{
+ GdkWaylandToplevel *wayland_toplevel;
- case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
- break;
+ g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
- case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
- surface->fullscreen_mode = g_value_get_enum (value);
- g_object_notify_by_pspec (G_OBJECT (surface), pspec);
- break;
+ wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
- break;
+ wayland_toplevel->application.application_id = g_strdup (application_id);
+ wayland_toplevel->application.app_menu_path = g_strdup (app_menu_path);
+ wayland_toplevel->application.menubar_path = g_strdup (menubar_path);
+ wayland_toplevel->application.window_object_path = g_strdup (window_object_path);
+ wayland_toplevel->application.application_object_path =
+ g_strdup (application_object_path);
+ wayland_toplevel->application.unique_bus_name = g_strdup (unique_bus_name);
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
+ maybe_set_gtk_surface_dbus_properties (wayland_toplevel);
}
-static void
-gdk_wayland_toplevel_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GdkSurface *surface = GDK_SURFACE (object);
- GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
-
- switch (prop_id)
- {
- case LAST_PROP + GDK_TOPLEVEL_PROP_STATE:
- g_value_set_flags (value, surface->state);
- break;
+/* }}} */
+/* {{{ Toplevel API */
- case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
- g_value_set_string (value, toplevel->title);
- break;
+/**
+ * gdk_wayland_toplevel_set_application_id:
+ * @toplevel: (type GdkWaylandToplevel): a `GdkToplevel`
+ * @application_id: the application id for the @toplevel
+ *
+ * Sets the application id on a `GdkToplevel`.
+ */
+void
+gdk_wayland_toplevel_set_application_id (GdkToplevel *toplevel,
+ const char *application_id)
+{
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+ GdkWaylandSurface *impl;
+ GdkWaylandDisplay *display_wayland;
- case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
- g_value_set_string (value, "");
- break;
+ g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
- case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
- g_value_set_object (value, toplevel->transient_for);
- break;
+ g_return_if_fail (application_id != NULL);
- case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
- g_value_set_boolean (value, surface->modal_hint);
- break;
+ if (GDK_SURFACE_DESTROYED (toplevel))
+ return;
- case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
- g_value_set_pointer (value, NULL);
- break;
+ impl = GDK_WAYLAND_SURFACE (toplevel);
- case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
- break;
+ if (!is_realized_toplevel (impl))
+ return;
- case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
- break;
+ wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+ display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
- case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
- g_value_set_enum (value, surface->fullscreen_mode);
+ switch (display_wayland->shell_variant)
+ {
+ case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
+ xdg_toplevel_set_app_id (wayland_toplevel->display_server.xdg_toplevel, application_id);
break;
-
- case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
- g_value_set_boolean (value, surface->shortcuts_inhibited);
+ case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
+ zxdg_toplevel_v6_set_app_id (wayland_toplevel->display_server.zxdg_toplevel_v6, application_id);
break;
-
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ g_assert_not_reached ();
}
}
-static void
-gdk_wayland_toplevel_finalize (GObject *object)
+void
+gdk_wayland_toplevel_announce_csd (GdkToplevel *toplevel)
{
- GdkWaylandToplevel *wayland_toplevel;
-
- g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (object));
-
- wayland_toplevel = GDK_WAYLAND_TOPLEVEL (object);
-
- if (gdk_wayland_toplevel_is_exported (wayland_toplevel))
- gdk_wayland_toplevel_unexport_handle (GDK_TOPLEVEL (wayland_toplevel));
-
- g_free (wayland_toplevel->application.application_id);
- g_free (wayland_toplevel->application.app_menu_path);
- g_free (wayland_toplevel->application.menubar_path);
- g_free (wayland_toplevel->application.window_object_path);
- g_free (wayland_toplevel->application.application_object_path);
- g_free (wayland_toplevel->application.unique_bus_name);
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
+ GdkWaylandToplevel *toplevel_wayland;
- g_free (wayland_toplevel->title);
- g_clear_pointer (&wayland_toplevel->shortcuts_inhibitors, g_hash_table_unref);
+ g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
+ toplevel_wayland = GDK_WAYLAND_TOPLEVEL (toplevel);
- G_OBJECT_CLASS (gdk_wayland_toplevel_parent_class)->finalize (object);
+ if (!display_wayland->server_decoration_manager)
+ return;
+ toplevel_wayland->server_decoration =
+ org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
+ gdk_wayland_surface_get_wl_surface (GDK_SURFACE (toplevel_wayland)));
+ if (toplevel_wayland->server_decoration)
+ org_kde_kwin_server_decoration_request_mode (toplevel_wayland->server_decoration,
+ ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT);
}
-static void
-gdk_wayland_toplevel_class_init (GdkWaylandToplevelClass *class)
+void
+gdk_wayland_toplevel_announce_ssd (GdkToplevel *toplevel)
{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
+ GdkWaylandToplevel *toplevel_wayland;
- object_class->get_property = gdk_wayland_toplevel_get_property;
- object_class->set_property = gdk_wayland_toplevel_set_property;
- object_class->finalize = gdk_wayland_toplevel_finalize;
+ g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
+ toplevel_wayland = GDK_WAYLAND_TOPLEVEL (toplevel);
- gdk_toplevel_install_properties (object_class, 1);
+ if (!display_wayland->server_decoration_manager)
+ return;
+ toplevel_wayland->server_decoration =
+ org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
+ gdk_wayland_surface_get_wl_surface (GDK_SURFACE (toplevel_wayland)));
+ if (toplevel_wayland->server_decoration)
+ org_kde_kwin_server_decoration_request_mode (toplevel_wayland->server_decoration,
+ ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER);
}
-static void
-gdk_wayland_toplevel_present (GdkToplevel *toplevel,
- GdkToplevelLayout *layout)
+gboolean
+gdk_wayland_toplevel_inhibit_idle (GdkToplevel *toplevel)
{
- GdkSurface *surface = GDK_SURFACE (toplevel);
- GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (toplevel);
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- gboolean pending_configure = FALSE;
- gboolean maximize;
- gboolean fullscreen;
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel)));
+ GdkWaylandToplevel *wayland_toplevel;
- if (gdk_toplevel_layout_get_maximized (layout, &maximize))
- {
- if (maximize)
- gdk_wayland_toplevel_maximize (toplevel);
- else
- gdk_wayland_toplevel_unmaximize (toplevel);
- pending_configure = TRUE;
- }
+ g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
+ wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- if (gdk_toplevel_layout_get_fullscreen (layout, &fullscreen))
+ if (!display_wayland->idle_inhibit_manager)
+ return FALSE;
+
+ if (!wayland_toplevel->idle_inhibitor)
{
- if (fullscreen)
- {
- GdkMonitor *monitor;
+ g_assert (wayland_toplevel->idle_inhibitor_refcount == 0);
- monitor = gdk_toplevel_layout_get_fullscreen_monitor (layout);
- if (monitor)
- gdk_wayland_toplevel_fullscreen_on_monitor (wayland_toplevel, monitor);
- else
- gdk_wayland_toplevel_fullscreen (wayland_toplevel);
- }
- else
- {
- gdk_wayland_toplevel_unfullscreen (wayland_toplevel);
- }
- pending_configure = TRUE;
+ wayland_toplevel->idle_inhibitor =
+ zwp_idle_inhibit_manager_v1_create_inhibitor (display_wayland->idle_inhibit_manager,
+ gdk_wayland_surface_get_wl_surface (GDK_SURFACE (wayland_toplevel)));
}
+ ++wayland_toplevel->idle_inhibitor_refcount;
- g_clear_pointer (&wayland_toplevel->layout, gdk_toplevel_layout_unref);
- wayland_toplevel->layout = gdk_toplevel_layout_copy (layout);
+ return TRUE;
+}
- gdk_wayland_surface_show (surface);
+void
+gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel)
+{
+ GdkWaylandToplevel *wayland_toplevel;
- if (!pending_configure)
+ g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
+ wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+
+ g_assert (wayland_toplevel->idle_inhibitor &&
+ wayland_toplevel->idle_inhibitor_refcount > 0);
+
+ if (--wayland_toplevel->idle_inhibitor_refcount == 0)
{
- wayland_surface->next_layout.surface_geometry_dirty = TRUE;
- gdk_surface_request_layout (surface);
+ g_clear_pointer (&wayland_toplevel->idle_inhibitor,
+ zwp_idle_inhibitor_v1_destroy);
}
}
+/**
+ * GdkWaylandToplevelExported:
+ * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` that is exported
+ * @handle: the handle
+ * @user_data: user data that was passed to [method@GdkWayland.WaylandToplevel.export_handle]
+ *
+ * Callback that gets called when the handle for a surface has been
+ * obtained from the Wayland compositor.
+ *
+ * This callback is used in [method@GdkWayland.WaylandToplevel.export_handle].
+ *
+ * The @handle can be passed to other processes, for the purpose of
+ * marking surfaces as transient for out-of-process surfaces.
+ */
+
static gboolean
-gdk_wayland_toplevel_lower (GdkToplevel *toplevel)
+gdk_wayland_toplevel_is_exported (GdkWaylandToplevel *wayland_toplevel)
{
- return FALSE;
+ return wayland_toplevel->xdg_exported != NULL || wayland_toplevel->xdg_exported_v2 != NULL;
}
+typedef struct {
+ GdkWaylandToplevelExported callback;
+ gpointer user_data;
+ GDestroyNotify destroy;
+} ExportHandleData;
+
static void
-inhibitor_active (void *data,
- struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor)
+export_handle_done (GObject *source,
+ GAsyncResult *result,
+ void *user_data)
{
- GdkToplevel *toplevel = GDK_TOPLEVEL (data);
- GdkSurface *surface = GDK_SURFACE (toplevel);
+ GdkToplevel *toplevel = GDK_TOPLEVEL (source);
+ ExportHandleData *data = (ExportHandleData *)user_data;
+ char *handle;
- surface->shortcuts_inhibited = TRUE;
- g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
+ handle = gdk_toplevel_export_handle_finish (toplevel, result, NULL);
+ data->callback (toplevel, handle, data->user_data);
+ g_free (handle);
+
+ if (data->destroy)
+ data->destroy (data->user_data);
+
+ g_free (data);
}
-static void
-inhibitor_inactive (void *data,
- struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor)
+/**
+ * gdk_wayland_toplevel_export_handle:
+ * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` to obtain a handle for
+ * @callback: callback to call with the handle
+ * @user_data: (closure): user data for @callback
+ * @destroy_func: destroy notify for @user_data
+ *
+ * Asynchronously obtains a handle for a surface that can be passed
+ * to other processes.
+ *
+ * When the handle has been obtained, @callback will be called.
+ *
+ * It is an error to call this function on a surface that is already
+ * exported.
+ *
+ * When the handle is no longer needed, [method@GdkWayland.WaylandToplevel.unexport_handle]
+ * should be called to clean up resources.
+ *
+ * The main purpose for obtaining a handle is to mark a surface
+ * from another surface as transient for this one, see
+ * [method@GdkWayland.WaylandToplevel.set_transient_for_exported].
+ *
+ * Note that this API depends on an unstable Wayland protocol,
+ * and thus may require changes in the future.
+ *
+ * Return value: %TRUE if the handle has been requested, %FALSE if
+ * an error occurred.
+ */
+gboolean
+gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel,
+ GdkWaylandToplevelExported callback,
+ gpointer user_data,
+ GDestroyNotify destroy_func)
{
- GdkToplevel *toplevel = GDK_TOPLEVEL (data);
- GdkSurface *surface = GDK_SURFACE (toplevel);
+ ExportHandleData *data;
- surface->shortcuts_inhibited = FALSE;
- g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
-}
+ g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
-static const struct zwp_keyboard_shortcuts_inhibitor_v1_listener
-zwp_keyboard_shortcuts_inhibitor_listener = {
- inhibitor_active,
- inhibitor_inactive,
-};
+ data = g_new (ExportHandleData, 1);
+ data->callback = callback;
+ data->user_data = user_data;
+ data->destroy = destroy_func;
-static void
-gdk_wayland_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel,
- GdkEvent *event)
-{
- struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
- GdkSurface *surface = GDK_SURFACE (toplevel);
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- GdkSeat *gdk_seat;
+ gdk_toplevel_export_handle (toplevel, NULL, export_handle_done, data);
- if (surface->shortcuts_inhibited)
- return;
+ return TRUE;
+}
- gdk_seat = gdk_surface_get_seat_from_event (surface, event);
- gdk_wayland_surface_inhibit_shortcuts (surface, gdk_seat);
- inhibitor = gdk_wayland_toplevel_get_inhibitor (wayland_toplevel, gdk_seat);
- if (!inhibitor)
- return;
+/**
+ * gdk_wayland_toplevel_unexport_handle:
+ * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` to unexport
+ *
+ * Destroys the handle that was obtained with
+ * gdk_wayland_toplevel_export_handle().
+ *
+ * It is an error to call this function on a surface that
+ * does not have a handle.
+ *
+ * Note that this API depends on an unstable Wayland protocol,
+ * and thus may require changes in the future.
+ */
+void
+gdk_wayland_toplevel_unexport_handle (GdkToplevel *toplevel)
+{
+ g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
- surface->current_shortcuts_inhibited_seat = gdk_seat;
- zwp_keyboard_shortcuts_inhibitor_v1_add_listener
- (inhibitor, &zwp_keyboard_shortcuts_inhibitor_listener, toplevel);
+ gdk_toplevel_unexport_handle (toplevel);
}
static void
-gdk_wayland_toplevel_restore_system_shortcuts (GdkToplevel *toplevel)
+unset_transient_for_exported (GdkSurface *surface)
{
- GdkSurface *surface = GDK_SURFACE (toplevel);
+ if (GDK_IS_WAYLAND_TOPLEVEL (surface))
+ {
+ GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface);
- gdk_wayland_surface_restore_shortcuts (surface, surface->current_shortcuts_inhibited_seat);
- surface->current_shortcuts_inhibited_seat = NULL;
- surface->shortcuts_inhibited = FALSE;
- g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
+ g_clear_pointer (&toplevel->imported_transient_for, zxdg_imported_v1_destroy);
+ g_clear_pointer (&toplevel->imported_transient_for_v2, zxdg_imported_v2_destroy);
+ }
}
static void
-xdg_exported_handle_v1 (void *data,
- struct zxdg_exported_v1 *zxdg_exported_v1,
- const char *handle)
+xdg_imported_destroyed (void *data,
+ struct zxdg_imported_v1 *imported)
{
- g_task_return_pointer (G_TASK (data), g_strdup (handle), g_free);
- g_object_unref (data);
+ unset_transient_for_exported (GDK_SURFACE (data));
}
-static const struct zxdg_exported_v1_listener xdg_exported_listener_v1 = {
- xdg_exported_handle_v1
+static const struct zxdg_imported_v1_listener xdg_imported_listener = {
+ xdg_imported_destroyed,
};
static void
-xdg_exported_handle_v2 (void *data,
- struct zxdg_exported_v2 *zxdg_exported_v2,
- const char *handle)
+xdg_imported_v2_destroyed (void *data,
+ struct zxdg_imported_v2 *imported)
{
- g_task_return_pointer (G_TASK (data), g_strdup (handle), g_free);
- g_object_unref (data);
+ unset_transient_for_exported (GDK_SURFACE (data));
}
-static const struct zxdg_exported_v2_listener xdg_exported_listener_v2 = {
- xdg_exported_handle_v2
+static const struct zxdg_imported_v2_listener xdg_imported_listener_v2 = {
+ xdg_imported_v2_destroyed,
};
-static void
-gdk_wayland_toplevel_real_export_handle (GdkToplevel *toplevel,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+/**
+ * gdk_wayland_toplevel_set_transient_for_exported:
+ * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` to make as transient
+ * @parent_handle_str: an exported handle for a surface
+ *
+ * Marks @toplevel as transient for the surface to which the given
+ * @parent_handle_str refers.
+ *
+ * Typically, the handle will originate from a
+ * [method@GdkWayland.WaylandToplevel.export_handle] call in another process.
+ *
+ * Note that this API depends on an unstable Wayland protocol,
+ * and thus may require changes in the future.
+ *
+ * Return value: %TRUE if the surface has been marked as transient,
+ * %FALSE if an error occurred.
+ */
+gboolean
+gdk_wayland_toplevel_set_transient_for_exported (GdkToplevel *toplevel,
+ const char *parent_handle_str)
{
GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
- GdkSurface *surface = GDK_SURFACE (toplevel);
GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel));
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
- GTask *task;
- task = g_task_new (toplevel, cancellable, callback, user_data);
+ g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE);
+ g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
- if (display_wayland->xdg_exporter_v2)
+ display_wayland = GDK_WAYLAND_DISPLAY (display);
+
+ if (!display_wayland->xdg_importer && !display_wayland->xdg_importer_v2)
{
- wayland_toplevel->xdg_exported_v2 =
- zxdg_exporter_v2_export_toplevel (display_wayland->xdg_exporter_v2,
- gdk_wayland_surface_get_wl_surface (surface));
- zxdg_exported_v2_add_listener (wayland_toplevel->xdg_exported_v2,
- &xdg_exported_listener_v2, task);
+ g_warning ("Server is missing xdg_foreign support");
+ return FALSE;
}
- else if (display_wayland->xdg_exporter)
+
+ gdk_wayland_toplevel_set_transient_for (wayland_toplevel, NULL);
+
+ if (display_wayland->xdg_importer)
{
- wayland_toplevel->xdg_exported =
- zxdg_exporter_v1_export (display_wayland->xdg_exporter,
- gdk_wayland_surface_get_wl_surface (surface));
- zxdg_exported_v1_add_listener (wayland_toplevel->xdg_exported,
- &xdg_exported_listener_v1, task);
+ wayland_toplevel->imported_transient_for =
+ zxdg_importer_v1_import (display_wayland->xdg_importer, parent_handle_str);
+ zxdg_imported_v1_add_listener (wayland_toplevel->imported_transient_for,
+ &xdg_imported_listener,
+ toplevel);
}
else
{
- g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Exporting surface handles not supported");
- g_object_unref (task);
- return;
+ wayland_toplevel->imported_transient_for_v2 =
+ zxdg_importer_v2_import_toplevel (display_wayland->xdg_importer_v2, parent_handle_str);
+ zxdg_imported_v2_add_listener (wayland_toplevel->imported_transient_for_v2,
+ &xdg_imported_listener_v2,
+ toplevel);
}
-}
-
-static char *
-gdk_wayland_toplevel_real_export_handle_finish (GdkToplevel *toplevel,
- GAsyncResult *result,
- GError **error)
-{
- return g_task_propagate_pointer (G_TASK (result), error);
-}
-
-static void
-gdk_wayland_toplevel_real_unexport_handle (GdkToplevel *toplevel)
-{
- GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
-
- g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
- g_return_if_fail (wayland_toplevel->xdg_exported_v2 || wayland_toplevel->xdg_exported);
- g_clear_pointer (&wayland_toplevel->xdg_exported_v2, zxdg_exported_v2_destroy);
- g_clear_pointer (&wayland_toplevel->xdg_exported, zxdg_exported_v1_destroy);
-}
+ gdk_wayland_toplevel_sync_parent_of_imported (wayland_toplevel);
-static void
-gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface)
-{
- iface->present = gdk_wayland_toplevel_present;
- iface->minimize = gdk_wayland_toplevel_minimize;
- iface->lower = gdk_wayland_toplevel_lower;
- iface->focus = gdk_wayland_toplevel_focus;
- iface->show_window_menu = gdk_wayland_toplevel_show_window_menu;
- iface->titlebar_gesture = gdk_wayland_toplevel_titlebar_gesture;
- iface->supports_edge_constraints = gdk_wayland_toplevel_supports_edge_constraints;
- iface->inhibit_system_shortcuts = gdk_wayland_toplevel_inhibit_system_shortcuts;
- iface->restore_system_shortcuts = gdk_wayland_toplevel_restore_system_shortcuts;
- iface->begin_resize = gdk_wayland_toplevel_begin_resize;
- iface->begin_move = gdk_wayland_toplevel_begin_move;
- iface->export_handle = gdk_wayland_toplevel_real_export_handle;
- iface->export_handle_finish = gdk_wayland_toplevel_real_export_handle_finish;
- iface->unexport_handle = gdk_wayland_toplevel_real_unexport_handle;
+ return TRUE;
}
-
+/* }}} */
+/* vim:set foldmethod=marker expandtab: */