diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 124bcdd1b7031005f51127895e566239e87bdea2..7561a1589457aa063c445331d217cc7d47a0ae4f 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -72,7 +72,6 @@ #define SURFACE_IS_TOPLEVEL(surface) TRUE -#define MAX_WL_BUFFER_SIZE (4083) /* 4096 minus header, string argument length and NUL byte */ typedef enum _PopupState { @@ -82,10 +81,8 @@ typedef enum _PopupState POPUP_STATE_WAITING_FOR_FRAME, } PopupState; -struct _GdkWaylandSurface +struct _GdkWaylandSurfacePrivate { - GdkSurface parent_instance; - struct { /* The wl_outputs that this surface currently touches */ GSList *outputs; @@ -93,19 +90,14 @@ struct _GdkWaylandSurface struct wl_surface *wl_surface; struct xdg_surface *xdg_surface; - struct xdg_toplevel *xdg_toplevel; struct xdg_popup *xdg_popup; /* Legacy xdg-shell unstable v6 fallback support */ struct zxdg_surface_v6 *zxdg_surface_v6; - struct zxdg_toplevel_v6 *zxdg_toplevel_v6; struct zxdg_popup_v6 *zxdg_popup_v6; - struct gtk_surface1 *gtk_surface; struct wl_egl_window *egl_window; struct wl_egl_window *dummy_egl_window; - struct zxdg_exported_v1 *xdg_exported; - struct org_kde_kwin_server_decoration *server_decoration; } display_server; struct wl_event_queue *event_queue; @@ -128,22 +120,6 @@ struct _GdkWaylandSurface int pending_buffer_offset_x; int pending_buffer_offset_y; - char *title; - - 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; - - GdkGeometry geometry_hints; - GdkSurfaceHints geometry_mask; - GdkSeat *grab_input_seat; gint64 pending_frame_counter; @@ -155,8 +131,6 @@ struct _GdkWaylandSurface int shadow_bottom; gboolean shadow_dirty; - struct wl_output *initial_fullscreen_output; - cairo_region_t *opaque_region; gboolean opaque_region_dirty; @@ -164,20 +138,9 @@ struct _GdkWaylandSurface gboolean input_region_dirty; GdkRectangle last_sent_window_geometry; - int last_sent_min_width; - int last_sent_min_height; - int last_sent_max_width; - int last_sent_max_height; - - int saved_width; - int saved_height; gulong parent_surface_committed_handler; - struct { - GdkToplevelLayout *layout; - } toplevel; - struct { GdkPopupLayout *layout; int unconstrained_width; @@ -185,13 +148,6 @@ struct _GdkWaylandSurface } popup; struct { - struct { - int width; - int height; - GdkToplevelState state; - gboolean is_resizing; - } toplevel; - struct { int x; int y; @@ -207,16 +163,7 @@ struct _GdkWaylandSurface gboolean is_dirty; } pending; - struct { - GdkToplevelState unset_flags; - GdkToplevelState set_flags; - } initial_state; - struct { - struct { - gboolean should_constrain; - gboolean size_is_fixed; - } toplevel; struct { int x; int y; @@ -230,44 +177,11 @@ struct _GdkWaylandSurface int state_freeze_count; - struct { - GdkWaylandToplevelExported callback; - gpointer user_data; - GDestroyNotify destroy_func; - } exported; - - struct zxdg_imported_v1 *imported_transient_for; GHashTable *shortcuts_inhibitors; - - struct zwp_idle_inhibitor_v1 *idle_inhibitor; - size_t idle_inhibitor_refcount; -}; - -typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass; -struct _GdkWaylandSurfaceClass -{ - GdkSurfaceClass parent_class; -}; - -G_DEFINE_TYPE (GdkWaylandSurface, gdk_wayland_surface, GDK_TYPE_SURFACE) - -struct _GdkWaylandToplevel -{ - GdkWaylandSurface parent_instance; - - GdkWaylandToplevel *transient_for; }; +typedef struct _GdkWaylandSurfacePrivate GdkWaylandSurfacePrivate; -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)) +G_DEFINE_TYPE_WITH_PRIVATE (GdkWaylandSurface, gdk_wayland_surface, GDK_TYPE_SURFACE) struct _GdkWaylandPopup { @@ -313,15 +227,10 @@ static void gdk_wayland_surface_maybe_resize (GdkSurface *surface, static void gdk_wayland_surface_configure (GdkSurface *surface); -static void maybe_set_gtk_surface_dbus_properties (GdkWaylandSurface *impl); -static void maybe_set_gtk_surface_modal (GdkSurface *surface); - static void gdk_wayland_surface_sync_shadow (GdkSurface *surface); static void gdk_wayland_surface_sync_input_region (GdkSurface *surface); static void gdk_wayland_surface_sync_opaque_region (GdkSurface *surface); -static void unset_transient_for_exported (GdkSurface *surface); - static void gdk_wayland_surface_move_resize (GdkSurface *surface, int x, int y, @@ -335,99 +244,68 @@ static void update_popup_layout_state (GdkSurface *surface, int height, GdkPopupLayout *layout); -static gboolean gdk_wayland_surface_is_exported (GdkWaylandSurface *impl); - -static void configure_toplevel_geometry (GdkSurface *surface); static void gdk_wayland_surface_init (GdkWaylandSurface *impl) { - impl->scale = 1; - impl->initial_fullscreen_output = NULL; - impl->saved_width = -1; - impl->saved_height = -1; - impl->shortcuts_inhibitors = g_hash_table_new (NULL, NULL); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); + priv->scale = 1; + priv->shortcuts_inhibitors = g_hash_table_new (NULL, NULL); } static void gdk_wayland_surface_freeze_state (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - impl->state_freeze_count++; + priv->state_freeze_count++; } static void gdk_wayland_surface_thaw_state (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - g_assert (impl->state_freeze_count > 0); + g_assert (priv->state_freeze_count > 0); - impl->state_freeze_count--; + priv->state_freeze_count--; - if (impl->state_freeze_count > 0) + if (priv->state_freeze_count > 0) return; - if (impl->pending.is_dirty) + if (priv->pending.is_dirty) gdk_wayland_surface_configure (surface); - g_assert (!impl->display_server.xdg_popup); -} - -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); - - if (surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN | GDK_TOPLEVEL_STATE_MAXIMIZED)) - return; - - impl->saved_width = -1; - impl->saved_height = -1; + g_assert (!priv->display_server.xdg_popup); } -static void +void gdk_wayland_surface_update_size (GdkSurface *surface, int32_t width, int32_t height, int scale) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); gboolean width_changed, height_changed, scale_changed; width_changed = surface->width != width; height_changed = surface->height != height; - scale_changed = impl->scale != scale; + scale_changed = priv->scale != scale; if (!width_changed && !height_changed && !scale_changed) return; surface->width = width; surface->height = height; - impl->scale = scale; + priv->scale = scale; - if (impl->display_server.egl_window) - wl_egl_window_resize (impl->display_server.egl_window, width * scale, height * scale, 0, 0); - if (impl->display_server.wl_surface) - wl_surface_set_buffer_scale (impl->display_server.wl_surface, scale); + if (priv->display_server.egl_window) + wl_egl_window_resize (priv->display_server.egl_window, width * scale, height * scale, 0, 0); + if (priv->display_server.wl_surface) + wl_surface_set_buffer_scale (priv->display_server.wl_surface, scale); gdk_surface_invalidate_rect (surface, NULL); @@ -441,20 +319,6 @@ gdk_wayland_surface_update_size (GdkSurface *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) @@ -530,9 +394,10 @@ static void finish_pending_relayout (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - g_assert (impl->popup_state == POPUP_STATE_WAITING_FOR_FRAME); - impl->popup_state = POPUP_STATE_IDLE; + g_assert (priv->popup_state == POPUP_STATE_WAITING_FOR_FRAME); + priv->popup_state = POPUP_STATE_IDLE; thaw_popup_toplevel_state (surface); } @@ -544,6 +409,7 @@ frame_callback (void *data, { GdkSurface *surface = data; GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); GdkFrameClock *clock = gdk_surface_get_frame_clock (surface); @@ -557,10 +423,10 @@ frame_callback (void *data, if (GDK_SURFACE_DESTROYED (surface)) return; - if (!impl->awaiting_frame) + if (!priv->awaiting_frame) return; - switch (impl->popup_state) + switch (priv->popup_state) { case POPUP_STATE_IDLE: case POPUP_STATE_WAITING_FOR_REPOSITIONED: @@ -573,27 +439,27 @@ frame_callback (void *data, g_assert_not_reached (); } - impl->awaiting_frame = FALSE; - if (impl->awaiting_frame_frozen) + priv->awaiting_frame = FALSE; + if (priv->awaiting_frame_frozen) { - impl->awaiting_frame_frozen = FALSE; + priv->awaiting_frame_frozen = FALSE; gdk_surface_thaw_updates (surface); } - timings = gdk_frame_clock_get_timings (clock, impl->pending_frame_counter); - impl->pending_frame_counter = 0; + timings = gdk_frame_clock_get_timings (clock, priv->pending_frame_counter); + priv->pending_frame_counter = 0; if (timings == NULL) return; timings->refresh_interval = 16667; /* default to 1/60th of a second */ - if (impl->display_server.outputs) + if (priv->display_server.outputs) { /* We pick a random output out of the outputs that the surface touches * The rate here is in milli-hertz */ int refresh_rate = gdk_wayland_display_get_output_refresh_rate (display_wayland, - impl->display_server.outputs->data); + priv->display_server.outputs->data); if (refresh_rate != 0) timings->refresh_interval = G_GINT64_CONSTANT(1000000000) / refresh_rate; } @@ -654,17 +520,18 @@ static void configure_popup_geometry (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); int x, y; int width, height; - x = impl->next_layout.popup.x - impl->shadow_left; - y = impl->next_layout.popup.y - impl->shadow_top; + x = priv->next_layout.popup.x - priv->shadow_left; + y = priv->next_layout.popup.y - priv->shadow_top; width = - impl->next_layout.configured_width + - (impl->shadow_left + impl->shadow_right); + priv->next_layout.configured_width + + (priv->shadow_left + priv->shadow_right); height = - impl->next_layout.configured_height + - (impl->shadow_top + impl->shadow_bottom); + priv->next_layout.configured_height + + (priv->shadow_top + priv->shadow_bottom); gdk_wayland_surface_move_resize (surface, x, y, width, height); } @@ -673,28 +540,35 @@ static void configure_drag_surface_geometry (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); gdk_wayland_surface_update_size (surface, - impl->next_layout.configured_width, - impl->next_layout.configured_height, - impl->scale); + priv->next_layout.configured_width, + priv->next_layout.configured_height, + priv->scale); +} + +static void +gdk_wayland_surface_configure_geometry (GdkSurface *surface) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + if (GDK_IS_POPUP (impl)) + configure_popup_geometry (surface); + else if (GDK_IS_DRAG_SURFACE (impl)) + configure_drag_surface_geometry (surface); } static gboolean gdk_wayland_surface_compute_size (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - if (impl->next_layout.surface_geometry_dirty) + if (priv->next_layout.surface_geometry_dirty) { - if (GDK_IS_TOPLEVEL (impl)) - configure_toplevel_geometry (surface); - else if (GDK_IS_POPUP (impl)) - configure_popup_geometry (surface); - else if (GDK_IS_DRAG_SURFACE (impl)) - configure_drag_surface_geometry (surface); - - impl->next_layout.surface_geometry_dirty = FALSE; + gdk_wayland_surface_configure_geometry (surface); + priv->next_layout.surface_geometry_dirty = FALSE; } return FALSE; @@ -704,51 +578,56 @@ static void gdk_wayland_surface_request_layout (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - impl->next_layout.surface_geometry_dirty = TRUE; + priv->next_layout.surface_geometry_dirty = TRUE; } void gdk_wayland_surface_request_frame (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); struct wl_callback *callback; GdkFrameClock *clock; - if (impl->awaiting_frame) + if (priv->awaiting_frame) return; clock = gdk_surface_get_frame_clock (surface); - callback = wl_surface_frame (impl->display_server.wl_surface); + callback = wl_surface_frame (priv->display_server.wl_surface); wl_proxy_set_queue ((struct wl_proxy *) callback, NULL); wl_callback_add_listener (callback, &frame_listener, surface); - impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock); - impl->awaiting_frame = TRUE; + priv->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock); + priv->awaiting_frame = TRUE; } gboolean gdk_wayland_surface_has_surface (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - return !!impl->display_server.wl_surface; + return !!priv->display_server.wl_surface; } void gdk_wayland_surface_commit (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - wl_surface_commit (impl->display_server.wl_surface); + wl_surface_commit (priv->display_server.wl_surface); } void gdk_wayland_surface_notify_committed (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - impl->has_uncommitted_ack_configure = FALSE; + priv->has_uncommitted_ack_configure = FALSE; } static void @@ -756,17 +635,18 @@ on_frame_clock_after_paint (GdkFrameClock *clock, GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - if (surface->update_freeze_count == 0 && impl->has_uncommitted_ack_configure) + if (surface->update_freeze_count == 0 && priv->has_uncommitted_ack_configure) { gdk_wayland_surface_commit (surface); gdk_wayland_surface_notify_committed (surface); } - if (impl->awaiting_frame && - impl->pending_frame_counter == gdk_frame_clock_get_frame_counter (clock)) + if (priv->awaiting_frame && + priv->pending_frame_counter == gdk_frame_clock_get_frame_counter (clock)) { - impl->awaiting_frame_frozen = TRUE; + priv->awaiting_frame_frozen = TRUE; gdk_surface_freeze_updates (surface); } } @@ -775,6 +655,7 @@ void gdk_wayland_surface_update_scale (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); guint32 scale; GSList *l; @@ -786,7 +667,7 @@ gdk_wayland_surface_update_scale (GdkSurface *surface) } scale = 1; - for (l = impl->display_server.outputs; l != NULL; l = l->next) + for (l = priv->display_server.outputs; l != NULL; l = l->next) { guint32 output_scale = gdk_wayland_display_get_output_scale (display_wayland, l->data); scale = MAX (scale, output_scale); @@ -799,8 +680,6 @@ gdk_wayland_surface_update_scale (GdkSurface *surface) } static void gdk_wayland_surface_create_surface (GdkSurface *surface); -static void gdk_wayland_surface_set_title (GdkSurface *surface, - const char *title); GdkSurface * _gdk_wayland_display_create_surface (GdkDisplay *display, @@ -851,6 +730,7 @@ _gdk_wayland_display_create_surface (GdkDisplay *display, } impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); if (width > 65535) { @@ -876,14 +756,11 @@ _gdk_wayland_display_create_surface (GdkDisplay *display, GdkMonitor *monitor = g_list_model_get_item (gdk_display_get_monitors (display), 0); if (monitor) { - impl->scale = gdk_monitor_get_scale_factor (monitor); + priv->scale = gdk_monitor_get_scale_factor (monitor); g_object_unref (monitor); } } - gdk_wayland_surface_set_title (surface, get_default_title ()); - - gdk_wayland_surface_create_surface (surface); g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), surface); @@ -900,6 +777,7 @@ gdk_wayland_surface_attach_image (GdkSurface *surface, const cairo_region_t *damage) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkWaylandDisplay *display; cairo_rectangle_int_t rect; int i, n; @@ -910,34 +788,40 @@ gdk_wayland_surface_attach_image (GdkSurface *surface, g_assert (_gdk_wayland_is_shm_surface (cairo_surface)); /* Attach this new buffer to the surface */ - wl_surface_attach (impl->display_server.wl_surface, + wl_surface_attach (priv->display_server.wl_surface, _gdk_wayland_shm_surface_get_wl_buffer (cairo_surface), - impl->pending_buffer_offset_x, - impl->pending_buffer_offset_y); - impl->pending_buffer_offset_x = 0; - impl->pending_buffer_offset_y = 0; + priv->pending_buffer_offset_x, + priv->pending_buffer_offset_y); + priv->pending_buffer_offset_x = 0; + priv->pending_buffer_offset_y = 0; /* Only set the buffer scale if supported by the compositor */ display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); if (display->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE) - wl_surface_set_buffer_scale (impl->display_server.wl_surface, impl->scale); + wl_surface_set_buffer_scale (priv->display_server.wl_surface, priv->scale); n = cairo_region_num_rectangles (damage); for (i = 0; i < n; i++) { cairo_region_get_rectangle (damage, i, &rect); - wl_surface_damage (impl->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height); + wl_surface_damage (priv->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height); } } -void -gdk_wayland_surface_sync (GdkSurface *surface) +static void +gdk_wayland_surface_sync_real (GdkSurface *surface) { gdk_wayland_surface_sync_shadow (surface); gdk_wayland_surface_sync_opaque_region (surface); gdk_wayland_surface_sync_input_region (surface); } +void +gdk_wayland_surface_sync (GdkSurface *surface) +{ + GDK_WAYLAND_SURFACE_GET_CLASS(surface)->sync(surface); +} + static gboolean gdk_wayland_surface_beep (GdkSurface *surface) { @@ -952,14 +836,15 @@ gdk_wayland_surface_constructed (GObject *object) { GdkSurface *surface = GDK_SURFACE (object); GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->constructed (object); - impl->event_queue = wl_display_create_queue (display_wayland->wl_display); + priv->event_queue = wl_display_create_queue (display_wayland->wl_display); display_wayland->event_queues = g_list_prepend (display_wayland->event_queues, - impl->event_queue); + priv->event_queue); } static void @@ -967,19 +852,22 @@ gdk_wayland_surface_dispose (GObject *object) { GdkSurface *surface = GDK_SURFACE (object); GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; g_return_if_fail (GDK_IS_WAYLAND_SURFACE (surface)); impl = GDK_WAYLAND_SURFACE (surface); + priv = gdk_wayland_surface_get_instance_private (impl); - if (impl->event_queue) + + if (priv->event_queue) { GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); display_wayland->event_queues = g_list_remove (display_wayland->event_queues, surface); - g_clear_pointer (&impl->event_queue, wl_event_queue_destroy); + g_clear_pointer (&priv->event_queue, wl_event_queue_destroy); } G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->dispose (object); @@ -989,26 +877,16 @@ static void gdk_wayland_surface_finalize (GObject *object) { GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; g_return_if_fail (GDK_IS_WAYLAND_SURFACE (object)); impl = GDK_WAYLAND_SURFACE (object); + priv = gdk_wayland_surface_get_instance_private (impl); - if (gdk_wayland_surface_is_exported (impl)) - gdk_wayland_toplevel_unexport_handle (GDK_TOPLEVEL (impl)); - - g_free (impl->title); - - g_free (impl->application.application_id); - g_free (impl->application.app_menu_path); - g_free (impl->application.menubar_path); - g_free (impl->application.window_object_path); - g_free (impl->application.application_object_path); - g_free (impl->application.unique_bus_name); - - g_clear_pointer (&impl->opaque_region, cairo_region_destroy); - g_clear_pointer (&impl->input_region, cairo_region_destroy); - g_clear_pointer (&impl->shortcuts_inhibitors, g_hash_table_unref); + g_clear_pointer (&priv->opaque_region, cairo_region_destroy); + g_clear_pointer (&priv->input_region, cairo_region_destroy); + g_clear_pointer (&priv->shortcuts_inhibitors, g_hash_table_unref); G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->finalize (object); } @@ -1016,26 +894,20 @@ gdk_wayland_surface_finalize (GObject *object) static gboolean is_realized_shell_surface (GdkWaylandSurface *impl) { - return (impl->display_server.xdg_surface || - impl->display_server.zxdg_surface_v6); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); + return (priv->display_server.xdg_surface || + priv->display_server.zxdg_surface_v6); } -static gboolean -is_realized_toplevel (GdkWaylandSurface *impl) -{ - return (impl->display_server.xdg_toplevel || - impl->display_server.zxdg_toplevel_v6); -} static gboolean is_realized_popup (GdkWaylandSurface *impl) { - return (impl->display_server.xdg_popup || - impl->display_server.zxdg_popup_v6); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); + return (priv->display_server.xdg_popup || + priv->display_server.zxdg_popup_v6); } -static void gdk_wayland_surface_show (GdkSurface *surface, - gboolean already_mapped); static void gdk_wayland_surface_hide (GdkSurface *surface); static void @@ -1045,12 +917,13 @@ gdk_wayland_surface_maybe_resize (GdkSurface *surface, int scale) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); gboolean is_xdg_popup; gboolean is_visible; if (surface->width == width && surface->height == height && - impl->scale == scale) + priv->scale == scale) return; /* For xdg_popup using an xdg_positioner, there is a race condition if @@ -1062,140 +935,42 @@ gdk_wayland_surface_maybe_resize (GdkSurface *surface, is_xdg_popup = is_realized_popup (impl); is_visible = gdk_surface_get_mapped (surface); - if (is_xdg_popup && is_visible && !impl->initial_configure_received) + if (is_xdg_popup && is_visible && !priv->initial_configure_received) gdk_wayland_surface_hide (surface); gdk_wayland_surface_update_size (surface, width, height, scale); - if (is_xdg_popup && is_visible && !impl->initial_configure_received) + if (is_xdg_popup && is_visible && !priv->initial_configure_received) gdk_wayland_surface_show (surface, FALSE); } 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 = impl_parent->display_server.xdg_toplevel; - else - parent_toplevel = NULL; - - xdg_toplevel_set_parent (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 = impl_parent->display_server.zxdg_toplevel_v6; - else - parent_toplevel = NULL; - - zxdg_toplevel_v6_set_parent (impl->display_server.zxdg_toplevel_v6, - parent_toplevel); - break; - } - default: - g_assert_not_reached (); - } -} - -static void -gdk_wayland_surface_sync_parent_of_imported (GdkWaylandSurface *impl) -{ - if (!impl->display_server.wl_surface) - return; - - if (!impl->imported_transient_for) - return; - - if (!is_realized_toplevel (impl)) - return; - - zxdg_imported_v1_set_parent_of (impl->imported_transient_for, - impl->display_server.wl_surface); -} - -static void -gdk_wayland_surface_sync_title (GdkSurface *surface) +gdk_wayland_surface_get_window_geometry_real (GdkSurface *surface, + GdkRectangle *geometry) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - GdkWaylandDisplay *display_wayland = - GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); - - if (!is_realized_toplevel (impl)) - return; - - if (!impl->title) - return; + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - switch (display_wayland->shell_variant) - { - case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - xdg_toplevel_set_title (impl->display_server.xdg_toplevel, - impl->title); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_toplevel_v6_set_title (impl->display_server.zxdg_toplevel_v6, - impl->title); - break; - default: - g_assert_not_reached (); - } + *geometry = (GdkRectangle) { + .x = priv->shadow_left, + .y = priv->shadow_top, + .width = surface->width - (priv->shadow_left + priv->shadow_right), + .height = surface->height - (priv->shadow_top + priv->shadow_bottom) + }; } -static void -gdk_wayland_surface_get_window_geometry (GdkSurface *surface, +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) - }; + GDK_WAYLAND_SURFACE_GET_CLASS(surface)->get_window_geometry(surface, geometry); } -static void gdk_wayland_surface_set_geometry_hints (GdkWaylandSurface *impl, - const GdkGeometry *geometry, - GdkSurfaceHints geom_mask); - static void gdk_wayland_surface_sync_shadow (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); GdkRectangle geometry; @@ -1204,24 +979,21 @@ gdk_wayland_surface_sync_shadow (GdkSurface *surface) return; gdk_wayland_surface_get_window_geometry (surface, &geometry); - gdk_wayland_surface_set_geometry_hints (impl, - &impl->geometry_hints, - impl->geometry_mask); - if (gdk_rectangle_equal (&geometry, &impl->last_sent_window_geometry)) + if (gdk_rectangle_equal (&geometry, &priv->last_sent_window_geometry)) return; switch (display_wayland->shell_variant) { case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - xdg_surface_set_window_geometry (impl->display_server.xdg_surface, + xdg_surface_set_window_geometry (priv->display_server.xdg_surface, geometry.x, geometry.y, geometry.width, geometry.height); break; case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_surface_v6_set_window_geometry (impl->display_server.zxdg_surface_v6, + zxdg_surface_v6_set_window_geometry (priv->display_server.zxdg_surface_v6, geometry.x, geometry.y, geometry.width, @@ -1231,7 +1003,7 @@ gdk_wayland_surface_sync_shadow (GdkSurface *surface) g_assert_not_reached (); } - impl->last_sent_window_geometry = geometry; + priv->last_sent_window_geometry = geometry; } static struct wl_region * @@ -1260,48 +1032,50 @@ static void gdk_wayland_surface_sync_opaque_region (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); struct wl_region *wl_region = NULL; - if (!impl->display_server.wl_surface) + if (!priv->display_server.wl_surface) return; - if (!impl->opaque_region_dirty) + if (!priv->opaque_region_dirty) return; - if (impl->opaque_region != NULL) + if (priv->opaque_region != NULL) wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)), - impl->opaque_region); + priv->opaque_region); - wl_surface_set_opaque_region (impl->display_server.wl_surface, wl_region); + wl_surface_set_opaque_region (priv->display_server.wl_surface, wl_region); if (wl_region != NULL) wl_region_destroy (wl_region); - impl->opaque_region_dirty = FALSE; + priv->opaque_region_dirty = FALSE; } static void gdk_wayland_surface_sync_input_region (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); struct wl_region *wl_region = NULL; - if (!impl->display_server.wl_surface) + if (!priv->display_server.wl_surface) return; - if (!impl->input_region_dirty) + if (!priv->input_region_dirty) return; - if (impl->input_region != NULL) + if (priv->input_region != NULL) wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)), - impl->input_region); + priv->input_region); - wl_surface_set_input_region (impl->display_server.wl_surface, wl_region); + wl_surface_set_input_region (priv->display_server.wl_surface, wl_region); if (wl_region != NULL) wl_region_destroy (wl_region); - impl->input_region_dirty = FALSE; + priv->input_region_dirty = FALSE; } static void @@ -1311,13 +1085,14 @@ surface_enter (void *data, { GdkSurface *surface = GDK_SURFACE (data); GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkDisplay *display = gdk_surface_get_display (surface); GdkMonitor *monitor; GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, g_message ("surface enter, surface %p output %p", surface, output)); - impl->display_server.outputs = g_slist_prepend (impl->display_server.outputs, output); + priv->display_server.outputs = g_slist_prepend (priv->display_server.outputs, output); gdk_wayland_surface_update_scale (surface); @@ -1332,15 +1107,16 @@ surface_leave (void *data, { GdkSurface *surface = GDK_SURFACE (data); GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkDisplay *display = gdk_surface_get_display (surface); GdkMonitor *monitor; GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, g_message ("surface leave, surface %p output %p", surface, output)); - impl->display_server.outputs = g_slist_remove (impl->display_server.outputs, output); + priv->display_server.outputs = g_slist_remove (priv->display_server.outputs, output); - if (impl->display_server.outputs) + if (priv->display_server.outputs) gdk_wayland_surface_update_scale (surface); monitor = gdk_wayland_display_get_monitor_for_output (display, output); @@ -1356,247 +1132,38 @@ static void gdk_wayland_surface_create_surface (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); struct wl_surface *wl_surface; wl_surface = wl_compositor_create_surface (display_wayland->compositor); - wl_proxy_set_queue ((struct wl_proxy *) wl_surface, impl->event_queue); + wl_proxy_set_queue ((struct wl_proxy *) wl_surface, priv->event_queue); wl_surface_add_listener (wl_surface, &surface_listener, surface); - impl->display_server.wl_surface = wl_surface; -} - -static void -configure_toplevel_geometry (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - GdkDisplay *display = gdk_surface_get_display (surface); - GdkMonitor *monitor; - GdkRectangle monitor_geometry; - int bounds_width, bounds_height; - GdkToplevelSize size; - GdkToplevelLayout *layout; - GdkGeometry geometry; - GdkSurfaceHints mask; - - monitor = g_list_model_get_item (gdk_display_get_monitors (display), 0); - gdk_monitor_get_geometry (monitor, &monitor_geometry); - g_object_unref (monitor); - bounds_width = monitor_geometry.width; - bounds_height = monitor_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 = impl->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_surface_set_geometry_hints (impl, &geometry, mask); - - if (size.shadow.is_valid) - { - impl->shadow_left = size.shadow.left; - impl->shadow_right = size.shadow.right; - impl->shadow_top = size.shadow.top; - impl->shadow_bottom = size.shadow.bottom; - } - - if (impl->next_layout.configured_width > 0 && - impl->next_layout.configured_height > 0) - { - int width, height; - - width = impl->next_layout.configured_width + - impl->shadow_left + impl->shadow_right; - height = impl->next_layout.configured_height + - impl->shadow_top + impl->shadow_bottom; - - if (impl->next_layout.toplevel.should_constrain) - { - gdk_surface_constrain_size (&impl->geometry_hints, - impl->geometry_mask, - width, height, - &width, &height); - } - gdk_wayland_surface_update_size (surface, width, height, impl->scale); - - if (!impl->next_layout.toplevel.size_is_fixed) - { - impl->next_layout.toplevel.should_constrain = FALSE; - impl->next_layout.configured_width = 0; - impl->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, impl->scale); - } -} - -static void -synthesize_initial_surface_state (GdkSurface *surface, - GdkToplevelState unset_flags, - GdkToplevelState set_flags) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - impl->initial_state.unset_flags |= unset_flags; - impl->initial_state.set_flags &= ~unset_flags; - - impl->initial_state.set_flags |= set_flags; - impl->initial_state.unset_flags &= ~set_flags; -} - -static void -gdk_wayland_surface_configure_toplevel (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - GdkWaylandDisplay *display_wayland = - GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); - GdkToplevelState new_state; - int width, height; - gboolean is_resizing; - gboolean fixed_size; - gboolean saved_size; - - new_state = impl->pending.toplevel.state; - impl->pending.toplevel.state = 0; - - is_resizing = impl->pending.toplevel.is_resizing; - impl->pending.toplevel.is_resizing = FALSE; - - fixed_size = - new_state & (GDK_TOPLEVEL_STATE_MAXIMIZED | - GDK_TOPLEVEL_STATE_FULLSCREEN | - GDK_TOPLEVEL_STATE_TILED) || - is_resizing; - - width = impl->pending.toplevel.width; - height = impl->pending.toplevel.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) - { - width = impl->saved_width; - height = impl->saved_height; - } - - if (width > 0 && height > 0) - { - if (!saved_size) - { - impl->next_layout.toplevel.should_constrain = TRUE; - - /* Save size for next time we get 0x0 */ - _gdk_wayland_surface_save_size (surface); - } - else if (is_resizing) - { - impl->next_layout.toplevel.should_constrain = TRUE; - } - else - { - impl->next_layout.toplevel.should_constrain = FALSE; - } - - impl->next_layout.toplevel.size_is_fixed = fixed_size; - impl->next_layout.configured_width = width; - impl->next_layout.configured_height = height; - } - else - { - impl->next_layout.toplevel.should_constrain = FALSE; - impl->next_layout.toplevel.size_is_fixed = FALSE; - impl->next_layout.configured_width = 0; - impl->next_layout.configured_height = 0; - } - - impl->next_layout.surface_geometry_dirty = TRUE; - gdk_surface_request_layout (surface); - - GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, - g_message ("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_surface_queue_state_change (surface, ~0 & ~new_state, new_state); - - switch (display_wayland->shell_variant) - { - case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - xdg_surface_ack_configure (impl->display_server.xdg_surface, - impl->pending.serial); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_surface_v6_ack_configure (impl->display_server.zxdg_surface_v6, - impl->pending.serial); - break; - default: - g_assert_not_reached (); - } + priv->display_server.wl_surface = wl_surface; } static void gdk_wayland_surface_configure_popup (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkRectangle parent_geometry; int x, y, width, height; - if (impl->display_server.xdg_popup) - { - xdg_surface_ack_configure (impl->display_server.xdg_surface, - impl->pending.serial); - } - else if (impl->display_server.zxdg_popup_v6) - { - zxdg_surface_v6_ack_configure (impl->display_server.zxdg_surface_v6, - impl->pending.serial); - } - - if (impl->pending.popup.has_repositioned_token) - impl->received_reposition_token = impl->pending.popup.repositioned_token; + if (priv->pending.popup.has_repositioned_token) + priv->received_reposition_token = priv->pending.popup.repositioned_token; - switch (impl->popup_state) + switch (priv->popup_state) { case POPUP_STATE_WAITING_FOR_REPOSITIONED: - if (impl->received_reposition_token != impl->reposition_token) + if (priv->received_reposition_token != priv->reposition_token) return; else gdk_surface_thaw_updates (surface); G_GNUC_FALLTHROUGH; case POPUP_STATE_WAITING_FOR_CONFIGURE: - impl->popup_state = POPUP_STATE_WAITING_FOR_FRAME; + priv->popup_state = POPUP_STATE_WAITING_FOR_FRAME; break; case POPUP_STATE_IDLE: case POPUP_STATE_WAITING_FOR_FRAME: @@ -1605,10 +1172,10 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface) g_assert_not_reached (); } - x = impl->pending.popup.x; - y = impl->pending.popup.y; - width = impl->pending.popup.width; - height = impl->pending.popup.height; + x = priv->pending.popup.x; + y = priv->pending.popup.y; + width = priv->pending.popup.width; + height = priv->pending.popup.height; gdk_wayland_surface_get_window_geometry (surface->parent, &parent_geometry); x += parent_geometry.x; @@ -1617,13 +1184,13 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface) update_popup_layout_state (surface, x, y, width, height, - impl->popup.layout); + priv->popup.layout); - impl->next_layout.popup.x = x; - impl->next_layout.popup.y = y; - impl->next_layout.configured_width = width; - impl->next_layout.configured_height = height; - impl->next_layout.surface_geometry_dirty = TRUE; + priv->next_layout.popup.x = x; + priv->next_layout.popup.y = y; + priv->next_layout.configured_width = width; + priv->next_layout.configured_height = height; + priv->next_layout.surface_geometry_dirty = TRUE; gdk_surface_request_layout (surface); } @@ -1638,73 +1205,74 @@ maybe_notify_mapped (GdkSurface *surface) } static void -gdk_wayland_surface_configure (GdkSurface *surface) +gdk_wayland_surface_configure_surface_real (GdkSurface *surface) { 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; - if (is_realized_popup (impl)) gdk_wayland_surface_configure_popup (surface); - else if (is_realized_toplevel (impl)) - gdk_wayland_surface_configure_toplevel (surface); 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_configure_surface (GdkSurface *surface) { - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - impl->pending.is_dirty = TRUE; - impl->pending.serial = serial; - - if (impl->state_freeze_count > 0) - return; - - gdk_wayland_surface_configure (surface); + GDK_WAYLAND_SURFACE_GET_CLASS(surface)->configure_surface(surface); } static void -gdk_wayland_surface_handle_configure_toplevel (GdkSurface *surface, - int32_t width, - int32_t height, - GdkToplevelState state) +gdk_wayland_surface_configure (GdkSurface *surface) { - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandDisplay *display_wayland = + GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); + + if (!priv->initial_configure_received) + { + gdk_surface_thaw_updates (surface); + priv->initial_configure_received = TRUE; + priv->pending.is_initial_configure = TRUE; + maybe_notify_mapped (surface); + } + + priv->has_uncommitted_ack_configure = TRUE; + + gdk_wayland_surface_configure_surface (surface); + + switch (display_wayland->shell_variant) + { + case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: + xdg_surface_ack_configure (priv->display_server.xdg_surface, + priv->pending.serial); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_surface_v6_ack_configure (priv->display_server.zxdg_surface_v6, + priv->pending.serial); + break; + default: + g_assert_not_reached (); + } - impl->pending.toplevel.state |= state; - impl->pending.toplevel.width = width; - impl->pending.toplevel.height = height; + priv->last_configure_serial = priv->pending.serial; + + memset (&priv->pending, 0, sizeof (priv->pending)); } static void -gdk_wayland_surface_handle_close (GdkSurface *surface) +gdk_wayland_surface_handle_configure (GdkSurface *surface, + uint32_t serial) { - GdkDisplay *display; - GdkEvent *event; - - display = gdk_surface_get_display (surface); + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - GDK_DISPLAY_NOTE (display, EVENTS, g_message ("close %p", surface)); + priv->pending.is_dirty = TRUE; + priv->pending.serial = serial; - event = gdk_delete_event_new (surface); + if (priv->state_freeze_count > 0) + return; - _gdk_wayland_display_deliver_event (display, event); + gdk_wayland_surface_configure (surface); } static void @@ -1735,30 +1303,31 @@ static const struct zxdg_surface_v6_listener zxdg_surface_v6_listener = { zxdg_surface_v6_configure, }; -static void +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); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); switch (display->shell_variant) { case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - impl->display_server.xdg_surface = + priv->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, + priv->display_server.wl_surface); + wl_proxy_set_queue ((struct wl_proxy *) priv->display_server.xdg_surface, + priv->event_queue); + xdg_surface_add_listener (priv->display_server.xdg_surface, &xdg_surface_listener, surface); break; case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - impl->display_server.zxdg_surface_v6 = + priv->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, + priv->display_server.wl_surface); + zxdg_surface_v6_add_listener (priv->display_server.zxdg_surface_v6, &zxdg_surface_v6_listener, surface); break; @@ -1767,253 +1336,6 @@ gdk_wayland_surface_create_xdg_surface_resources (GdkSurface *surface) } } -static void -xdg_toplevel_configure (void *data, - struct xdg_toplevel *xdg_toplevel, - int32_t width, - int32_t height, - struct wl_array *states) -{ - GdkSurface *surface = GDK_SURFACE (data); - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - uint32_t *p; - GdkToplevelState pending_state = 0; - - impl->pending.toplevel.is_resizing = FALSE; - - wl_array_for_each (p, states) - { - 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: - impl->pending.toplevel.is_resizing = TRUE; - break; - default: - /* Unknown state */ - break; - } - } - - gdk_wayland_surface_handle_configure_toplevel (surface, width, height, - pending_state); -} - -static void -xdg_toplevel_close (void *data, - struct xdg_toplevel *xdg_toplevel) -{ - GdkSurface *surface = GDK_SURFACE (data); - - gdk_wayland_surface_handle_close (surface); -} - -static const struct xdg_toplevel_listener xdg_toplevel_listener = { - xdg_toplevel_configure, - xdg_toplevel_close, -}; - -static void -create_xdg_toplevel_resources (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - impl->display_server.xdg_toplevel = - xdg_surface_get_toplevel (impl->display_server.xdg_surface); - xdg_toplevel_add_listener (impl->display_server.xdg_toplevel, - &xdg_toplevel_listener, - surface); -} - -static void -zxdg_toplevel_v6_configure (void *data, - struct zxdg_toplevel_v6 *xdg_toplevel, - int32_t width, - int32_t height, - struct wl_array *states) -{ - GdkSurface *surface = GDK_SURFACE (data); - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - uint32_t *p; - GdkToplevelState pending_state = 0; - - impl->pending.toplevel.is_resizing = FALSE; - - wl_array_for_each (p, states) - { - uint32_t state = *p; - - 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: - impl->pending.toplevel.is_resizing = TRUE; - break; - default: - /* Unknown state */ - break; - } - } - - gdk_wayland_surface_handle_configure_toplevel (surface, width, height, - pending_state); -} - -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 -create_zxdg_toplevel_v6_resources (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - impl->display_server.zxdg_toplevel_v6 = - zxdg_surface_v6_get_toplevel (impl->display_server.zxdg_surface_v6); - zxdg_toplevel_v6_add_listener (impl->display_server.zxdg_toplevel_v6, - &zxdg_toplevel_v6_listener, - surface); -} - -/** - * 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) -{ - GdkWaylandSurface *impl; - GdkWaylandDisplay *display_wayland; - - g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); - - g_return_if_fail (application_id != NULL); - - if (GDK_SURFACE_DESTROYED (toplevel)) - return; - - impl = GDK_WAYLAND_SURFACE (toplevel); - - if (!is_realized_toplevel (impl)) - return; - - display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel))); - - switch (display_wayland->shell_variant) - { - case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - xdg_toplevel_set_app_id (impl->display_server.xdg_toplevel, - application_id); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_toplevel_v6_set_app_id (impl->display_server.zxdg_toplevel_v6, - application_id); - break; - default: - g_assert_not_reached (); - } -} - -static void -gdk_wayland_surface_create_xdg_toplevel (GdkSurface *surface) -{ - GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - const char *app_id; - - gdk_surface_freeze_updates (surface); - gdk_wayland_surface_create_xdg_surface_resources (surface); - - switch (display_wayland->shell_variant) - { - case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - create_xdg_toplevel_resources (surface); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - create_zxdg_toplevel_v6_resources (surface); - break; - default: - g_assert_not_reached (); - } - - gdk_wayland_surface_sync_parent (surface, NULL); - gdk_wayland_surface_sync_parent_of_imported (impl); - gdk_wayland_surface_sync_title (surface); - - switch (display_wayland->shell_variant) - { - case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED) - xdg_toplevel_set_maximized (impl->display_server.xdg_toplevel); - if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED) - xdg_toplevel_set_minimized (impl->display_server.xdg_toplevel); - if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN) - xdg_toplevel_set_fullscreen (impl->display_server.xdg_toplevel, - impl->initial_fullscreen_output); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED) - zxdg_toplevel_v6_set_maximized (impl->display_server.zxdg_toplevel_v6); - if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED) - zxdg_toplevel_v6_set_minimized (impl->display_server.zxdg_toplevel_v6); - if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN) - zxdg_toplevel_v6_set_fullscreen (impl->display_server.zxdg_toplevel_v6, - impl->initial_fullscreen_output); - break; - default: - g_assert_not_reached (); - } - - impl->initial_fullscreen_output = NULL; - - app_id = impl->application.application_id; - if (app_id == NULL) - app_id = g_get_prgname (); - - if (app_id == NULL) - app_id = "GTK Application"; - - gdk_wayland_toplevel_set_application_id (GDK_TOPLEVEL (impl), app_id); - - maybe_set_gtk_surface_dbus_properties (impl); - maybe_set_gtk_surface_modal (surface); - - gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "surface commit"); - wl_surface_commit (impl->display_server.wl_surface); -} - static void gdk_wayland_surface_handle_configure_popup (GdkSurface *surface, int32_t x, @@ -2022,11 +1344,12 @@ gdk_wayland_surface_handle_configure_popup (GdkSurface *surface, int32_t height) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - impl->pending.popup.x = x; - impl->pending.popup.y = y; - impl->pending.popup.width = width; - impl->pending.popup.height = height; + priv->pending.popup.x = x; + priv->pending.popup.y = y; + priv->pending.popup.width = width; + priv->pending.popup.height = height; } static void @@ -2060,18 +1383,19 @@ xdg_popup_repositioned (void *data, { GdkSurface *surface = GDK_SURFACE (data); GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, g_message ("repositioned %p", surface)); - if (impl->popup_state != POPUP_STATE_WAITING_FOR_REPOSITIONED) + if (priv->popup_state != POPUP_STATE_WAITING_FOR_REPOSITIONED) { g_warning ("Unexpected xdg_popup.repositioned event, probably buggy compositor"); return; } - impl->pending.popup.repositioned_token = token; - impl->pending.popup.has_repositioned_token = TRUE; + priv->pending.popup.repositioned_token = token; + priv->pending.popup.has_repositioned_token = TRUE; } static const struct xdg_popup_listener xdg_popup_listener = { @@ -2240,87 +1564,13 @@ surface_anchor_to_gravity_legacy (GdkGravity rect_anchor) 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))); - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel); - - g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); - - if (!display_wayland->server_decoration_manager) - return; - impl->display_server.server_decoration = - org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager, - impl->display_server.wl_surface); - if (impl->display_server.server_decoration) - org_kde_kwin_server_decoration_request_mode (impl->display_server.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))); - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel); - - g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); - - if (!display_wayland->server_decoration_manager) - return; - impl->display_server.server_decoration = - org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager, - impl->display_server.wl_surface); - if (impl->display_server.server_decoration) - org_kde_kwin_server_decoration_request_mode (impl->display_server.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))); - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel); - - g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE); - - if (!display_wayland->idle_inhibit_manager) - return FALSE; - - if (!impl->idle_inhibitor) - { - g_assert (impl->idle_inhibitor_refcount == 0); - impl->idle_inhibitor = - zwp_idle_inhibit_manager_v1_create_inhibitor (display_wayland->idle_inhibit_manager, - impl->display_server.wl_surface); - } - ++impl->idle_inhibitor_refcount; - - return TRUE; -} - -void -gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel); - - g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); - - g_assert (impl->idle_inhibitor && impl->idle_inhibitor_refcount > 0); - - if (--impl->idle_inhibitor_refcount == 0) - { - zwp_idle_inhibitor_v1_destroy (impl->idle_inhibitor); - impl->idle_inhibitor = NULL; - } -} - static void calculate_popup_rect (GdkSurface *surface, GdkPopupLayout *layout, GdkRectangle *out_rect) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); int width, height; GdkRectangle anchor_rect; int dx, dy; @@ -2333,8 +1583,8 @@ calculate_popup_rect (GdkSurface *surface, &shadow_top, &shadow_bottom); - width = (impl->popup.unconstrained_width - (shadow_left + shadow_right)); - height = (impl->popup.unconstrained_height - (shadow_top + shadow_bottom)); + width = (priv->popup.unconstrained_width - (shadow_left + shadow_right)); + height = (priv->popup.unconstrained_height - (shadow_top + shadow_bottom)); anchor_rect = *gdk_popup_layout_get_anchor_rect (layout); gdk_popup_layout_get_offset (layout, &dx, &dy); @@ -2520,6 +1770,7 @@ create_dynamic_positioner (GdkSurface *surface, { GdkSurface *parent = surface->parent; GdkWaylandSurface *parent_impl = GDK_WAYLAND_SURFACE (parent); + GdkWaylandSurfacePrivate *parent_priv = gdk_wayland_surface_get_instance_private (parent_impl); GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); GdkRectangle geometry; @@ -2617,7 +1868,7 @@ create_dynamic_positioner (GdkSurface *surface, parent_geometry.width, parent_geometry.height); xdg_positioner_set_parent_configure (positioner, - parent_impl->last_configure_serial); + parent_priv->last_configure_serial); } return positioner; @@ -2695,20 +1946,17 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface, { GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkWaylandSurface *parent_impl = GDK_WAYLAND_SURFACE (parent); + GdkWaylandSurfacePrivate *parent_priv = gdk_wayland_surface_get_instance_private (parent_impl); gpointer positioner; - if (!impl->display_server.wl_surface) + if (!priv->display_server.wl_surface) return FALSE; 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"); @@ -2730,21 +1978,21 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface, switch (display->shell_variant) { case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - impl->display_server.xdg_popup = - xdg_surface_get_popup (impl->display_server.xdg_surface, - parent_impl->display_server.xdg_surface, + priv->display_server.xdg_popup = + xdg_surface_get_popup (priv->display_server.xdg_surface, + parent_priv->display_server.xdg_surface, positioner); - xdg_popup_add_listener (impl->display_server.xdg_popup, + xdg_popup_add_listener (priv->display_server.xdg_popup, &xdg_popup_listener, surface); xdg_positioner_destroy (positioner); break; case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - impl->display_server.zxdg_popup_v6 = - zxdg_surface_v6_get_popup (impl->display_server.zxdg_surface_v6, - parent_impl->display_server.zxdg_surface_v6, + priv->display_server.zxdg_popup_v6 = + zxdg_surface_v6_get_popup (priv->display_server.zxdg_surface_v6, + parent_priv->display_server.zxdg_surface_v6, positioner); - zxdg_popup_v6_add_listener (impl->display_server.zxdg_popup_v6, + zxdg_popup_v6_add_listener (priv->display_server.zxdg_popup_v6, &zxdg_popup_v6_listener, surface); zxdg_positioner_v6_destroy (positioner); @@ -2754,10 +2002,10 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface, } gdk_popup_layout_get_shadow_width (layout, - &impl->shadow_left, - &impl->shadow_right, - &impl->shadow_top, - &impl->shadow_bottom); + &priv->shadow_left, + &priv->shadow_right, + &priv->shadow_top, + &priv->shadow_bottom); if (grab_input_seat) { @@ -2770,10 +2018,10 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface, switch (display->shell_variant) { case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - xdg_popup_grab (impl->display_server.xdg_popup, seat, serial); + xdg_popup_grab (priv->display_server.xdg_popup, seat, serial); break; case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_popup_v6_grab (impl->display_server.zxdg_popup_v6, seat, serial); + zxdg_popup_v6_grab (priv->display_server.zxdg_popup_v6, seat, serial); break; default: g_assert_not_reached (); @@ -2781,12 +2029,12 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface, } gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "surface commit"); - wl_surface_commit (impl->display_server.wl_surface); + wl_surface_commit (priv->display_server.wl_surface); if (GDK_IS_POPUP (surface)) { - g_assert (impl->popup_state == POPUP_STATE_IDLE); - impl->popup_state = POPUP_STATE_WAITING_FOR_CONFIGURE; + g_assert (priv->popup_state == POPUP_STATE_IDLE); + priv->popup_state = POPUP_STATE_WAITING_FOR_CONFIGURE; freeze_popup_toplevel_state (surface); } @@ -2805,21 +2053,24 @@ find_grab_input_seat (GdkSurface *surface, GdkSurface *parent) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkWaylandSurface *tmp_impl; + GdkWaylandSurfacePrivate *tmp_priv; /* 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 (impl->grab_input_seat) - return GDK_WAYLAND_SEAT (impl->grab_input_seat); + if (priv->grab_input_seat) + return GDK_WAYLAND_SEAT (priv->grab_input_seat); while (parent) { tmp_impl = GDK_WAYLAND_SURFACE (parent); + tmp_priv = gdk_wayland_surface_get_instance_private (tmp_impl); - if (tmp_impl->grab_input_seat) - return GDK_WAYLAND_SEAT (tmp_impl->grab_input_seat); + if (tmp_priv->grab_input_seat) + return GDK_WAYLAND_SEAT (tmp_priv->grab_input_seat); parent = parent->parent; } @@ -2827,47 +2078,15 @@ find_grab_input_seat (GdkSurface *surface, return NULL; } -static gboolean -should_be_mapped (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - /* Don't map crazy temp that GTK uses for internal X11 shenanigans. */ - if (GDK_IS_DRAG_SURFACE (surface) && surface->x < 0 && surface->y < 0) - return FALSE; - - if (impl->is_drag_surface) - return FALSE; - - return TRUE; -} - -static void -gdk_wayland_surface_map_toplevel (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - if (!should_be_mapped (surface)) - return; - - if (impl->mapped) - return; - - gdk_wayland_surface_create_xdg_toplevel (surface); - - impl->mapped = TRUE; -} - -static void +void gdk_wayland_surface_show (GdkSurface *surface, gboolean already_mapped) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - if (!impl->display_server.wl_surface) + if (!priv->display_server.wl_surface) gdk_wayland_surface_create_surface (surface); - - gdk_wayland_surface_map_toplevel (surface); } static void @@ -2896,93 +2115,84 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface) { GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); unmap_popups_for_surface (surface); - if (impl->display_server.wl_surface) + if (priv->display_server.wl_surface) { - if (impl->dummy_egl_surface) + if (priv->dummy_egl_surface) { - eglDestroySurface (display_wayland->egl_display, impl->dummy_egl_surface); - impl->dummy_egl_surface = NULL; + eglDestroySurface (display_wayland->egl_display, priv->dummy_egl_surface); + priv->dummy_egl_surface = NULL; } - if (impl->display_server.dummy_egl_window) + if (priv->display_server.dummy_egl_window) { - wl_egl_window_destroy (impl->display_server.dummy_egl_window); - impl->display_server.dummy_egl_window = NULL; + wl_egl_window_destroy (priv->display_server.dummy_egl_window); + priv->display_server.dummy_egl_window = NULL; } - if (impl->egl_surface) + if (priv->egl_surface) { - eglDestroySurface (display_wayland->egl_display, impl->egl_surface); - impl->egl_surface = NULL; + eglDestroySurface (display_wayland->egl_display, priv->egl_surface); + priv->egl_surface = NULL; } - if (impl->display_server.egl_window) + if (priv->display_server.egl_window) { - wl_egl_window_destroy (impl->display_server.egl_window); - impl->display_server.egl_window = NULL; + wl_egl_window_destroy (priv->display_server.egl_window); + priv->display_server.egl_window = NULL; } - if (impl->display_server.xdg_toplevel) + if (priv->display_server.xdg_popup) { - xdg_toplevel_destroy (impl->display_server.xdg_toplevel); - impl->display_server.xdg_toplevel = NULL; - } - else if (impl->display_server.xdg_popup) - { - xdg_popup_destroy (impl->display_server.xdg_popup); - impl->display_server.xdg_popup = NULL; + xdg_popup_destroy (priv->display_server.xdg_popup); + priv->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 (impl->display_server.xdg_surface) + if (priv->display_server.xdg_surface) { - xdg_surface_destroy (impl->display_server.xdg_surface); - impl->display_server.xdg_surface = NULL; - if (!impl->initial_configure_received) + xdg_surface_destroy (priv->display_server.xdg_surface); + priv->display_server.xdg_surface = NULL; + if (!priv->initial_configure_received) gdk_surface_thaw_updates (surface); else - impl->initial_configure_received = FALSE; + priv->initial_configure_received = FALSE; } - if (impl->display_server.zxdg_toplevel_v6) - { - zxdg_toplevel_v6_destroy (impl->display_server.zxdg_toplevel_v6); - impl->display_server.zxdg_toplevel_v6 = NULL; - } - else if (impl->display_server.zxdg_popup_v6) + if (priv->display_server.zxdg_popup_v6) { - zxdg_popup_v6_destroy (impl->display_server.zxdg_popup_v6); - impl->display_server.zxdg_popup_v6 = NULL; + zxdg_popup_v6_destroy (priv->display_server.zxdg_popup_v6); + priv->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.zxdg_surface_v6) + if (priv->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) + zxdg_surface_v6_destroy (priv->display_server.zxdg_surface_v6); + priv->display_server.zxdg_surface_v6 = NULL; + if (!priv->initial_configure_received) gdk_surface_thaw_updates (surface); else - impl->initial_configure_received = FALSE; + priv->initial_configure_received = FALSE; } - impl->awaiting_frame = FALSE; - if (impl->awaiting_frame_frozen) + priv->awaiting_frame = FALSE; + if (priv->awaiting_frame_frozen) { - impl->awaiting_frame_frozen = FALSE; + priv->awaiting_frame_frozen = FALSE; gdk_surface_thaw_updates (surface); } if (GDK_IS_POPUP (surface)) { - switch (impl->popup_state) + switch (priv->popup_state) { case POPUP_STATE_WAITING_FOR_REPOSITIONED: gdk_surface_thaw_updates (surface); @@ -2997,43 +2207,23 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface) g_assert_not_reached (); } - impl->popup_state = POPUP_STATE_IDLE; - } - - if (impl->display_server.gtk_surface) - { - if (display_wayland->gtk_shell_version >= - GTK_SURFACE1_RELEASE_SINCE_VERSION) - gtk_surface1_release (impl->display_server.gtk_surface); - else - gtk_surface1_destroy (impl->display_server.gtk_surface); - impl->display_server.gtk_surface = NULL; - impl->application.was_set = FALSE; + priv->popup_state = POPUP_STATE_IDLE; } - wl_surface_destroy (impl->display_server.wl_surface); - impl->display_server.wl_surface = NULL; + wl_surface_destroy (priv->display_server.wl_surface); + priv->display_server.wl_surface = NULL; - g_slist_free (impl->display_server.outputs); - impl->display_server.outputs = NULL; + g_slist_free (priv->display_server.outputs); + priv->display_server.outputs = NULL; - g_clear_pointer (&impl->toplevel.layout, gdk_toplevel_layout_unref); - g_clear_pointer (&impl->popup.layout, gdk_popup_layout_unref); + g_clear_pointer (&priv->popup.layout, gdk_popup_layout_unref); } - impl->has_uncommitted_ack_configure = FALSE; - impl->input_region_dirty = TRUE; + priv->has_uncommitted_ack_configure = FALSE; + priv->input_region_dirty = TRUE; - unset_transient_for_exported (surface); - - impl->last_sent_window_geometry = (GdkRectangle) { 0 }; - impl->last_sent_min_width = 0; - impl->last_sent_min_height = 0; - impl->last_sent_max_width = 0; - impl->last_sent_max_height = 0; - - _gdk_wayland_surface_clear_saved_size (surface); - impl->mapped = FALSE; + priv->last_sent_window_geometry = (GdkRectangle) { 0 }; + priv->mapped = FALSE; } static void @@ -3061,22 +2251,28 @@ gdk_wayland_surface_move_resize (GdkSurface *surface, int height) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); surface->x = x; surface->y = y; - gdk_wayland_surface_maybe_resize (surface, width, height, impl->scale); + gdk_wayland_surface_maybe_resize (surface, width, height, priv->scale); } static gboolean is_fallback_relayout_possible (GdkSurface *surface) { GList *l; + GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; for (l = surface->children; l; l = l->next) { GdkSurface *child = l->data; - if (GDK_WAYLAND_SURFACE (child)->mapped) + impl = GDK_WAYLAND_SURFACE (child); + priv = gdk_wayland_surface_get_instance_private (impl); + + if (priv->mapped) return FALSE; } @@ -3093,14 +2289,15 @@ queue_relayout_fallback (GdkSurface *surface, GdkPopupLayout *layout) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); if (!is_fallback_relayout_possible (surface)) return; gdk_wayland_surface_hide_surface (surface); gdk_wayland_surface_present_popup (surface, - impl->popup.unconstrained_width, - impl->popup.unconstrained_height, + priv->popup.unconstrained_width, + priv->popup.unconstrained_height, layout); } @@ -3111,19 +2308,20 @@ do_queue_relayout (GdkSurface *surface, GdkPopupLayout *layout) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); struct xdg_positioner *positioner; g_assert (is_realized_popup (impl)); - g_assert (impl->popup_state == POPUP_STATE_IDLE || - impl->popup_state == POPUP_STATE_WAITING_FOR_FRAME); + g_assert (priv->popup_state == POPUP_STATE_IDLE || + priv->popup_state == POPUP_STATE_WAITING_FOR_FRAME); - g_clear_pointer (&impl->popup.layout, gdk_popup_layout_unref); - impl->popup.layout = gdk_popup_layout_copy (layout); - impl->popup.unconstrained_width = width; - impl->popup.unconstrained_height = height; + g_clear_pointer (&priv->popup.layout, gdk_popup_layout_unref); + priv->popup.layout = gdk_popup_layout_copy (layout); + priv->popup.unconstrained_width = width; + priv->popup.unconstrained_height = height; - if (!impl->display_server.xdg_popup || - xdg_popup_get_version (impl->display_server.xdg_popup) < + if (!priv->display_server.xdg_popup || + xdg_popup_get_version (priv->display_server.xdg_popup) < XDG_POPUP_REPOSITION_SINCE_VERSION) { g_warning_once ("Compositor doesn't support moving popups, " @@ -3136,14 +2334,14 @@ do_queue_relayout (GdkSurface *surface, positioner = create_dynamic_positioner (surface, width, height, layout, TRUE); - xdg_popup_reposition (impl->display_server.xdg_popup, + xdg_popup_reposition (priv->display_server.xdg_popup, positioner, - ++impl->reposition_token); + ++priv->reposition_token); xdg_positioner_destroy (positioner); gdk_surface_freeze_updates (surface); - switch (impl->popup_state) + switch (priv->popup_state) { case POPUP_STATE_IDLE: freeze_popup_toplevel_state (surface); @@ -3156,18 +2354,19 @@ do_queue_relayout (GdkSurface *surface, g_assert_not_reached (); } - impl->popup_state = POPUP_STATE_WAITING_FOR_REPOSITIONED; + priv->popup_state = POPUP_STATE_WAITING_FOR_REPOSITIONED; } static gboolean is_relayout_finished (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - if (!impl->initial_configure_received) + if (!priv->initial_configure_received) return FALSE; - if (impl->reposition_token != impl->received_reposition_token) + if (priv->reposition_token != priv->received_reposition_token) return FALSE; return TRUE; @@ -3180,6 +2379,7 @@ gdk_wayland_surface_map_popup (GdkSurface *surface, GdkPopupLayout *layout) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkSurface *parent; GdkWaylandSeat *grab_input_seat; @@ -3203,10 +2403,10 @@ gdk_wayland_surface_map_popup (GdkSurface *surface, layout)) return; - impl->popup.layout = gdk_popup_layout_copy (layout); - impl->popup.unconstrained_width = width; - impl->popup.unconstrained_height = height; - impl->mapped = TRUE; + priv->popup.layout = gdk_popup_layout_copy (layout); + priv->popup.unconstrained_width = width; + priv->popup.unconstrained_height = height; + priv->mapped = TRUE; } static void @@ -3216,8 +2416,9 @@ show_popup (GdkSurface *surface, GdkPopupLayout *layout) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - if (!impl->display_server.wl_surface) + if (!priv->display_server.wl_surface) gdk_wayland_surface_create_surface (surface); gdk_wayland_surface_map_popup (surface, width, height, layout); @@ -3247,8 +2448,9 @@ reposition_popup (GdkSurface *surface, GdkPopupLayout *layout) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - switch (impl->popup_state) + switch (priv->popup_state) { case POPUP_STATE_IDLE: case POPUP_STATE_WAITING_FOR_FRAME: @@ -3274,8 +2476,9 @@ gdk_wayland_surface_present_popup (GdkSurface *surface, GdkWaylandSurface *impl; impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); - if (!impl->mapped) + if (!priv->mapped) { if (surface->autohide) { @@ -3316,18 +2519,18 @@ gdk_wayland_surface_present_popup (GdkSurface *surface, } else { - if (impl->popup.unconstrained_width == width && - impl->popup.unconstrained_height == height && - gdk_popup_layout_equal (impl->popup.layout, layout)) + if (priv->popup.unconstrained_width == width && + priv->popup.unconstrained_height == height && + gdk_popup_layout_equal (priv->popup.layout, layout)) return TRUE; reposition_popup (surface, width, height, layout); } - while (impl->display_server.xdg_popup && !is_relayout_finished (surface)) - wl_display_dispatch_queue (display_wayland->wl_display, impl->event_queue); + while (priv->display_server.xdg_popup && !is_relayout_finished (surface)) + wl_display_dispatch_queue (display_wayland->wl_display, priv->event_queue); - if (impl->display_server.xdg_popup) + if (priv->display_server.xdg_popup) { gdk_surface_invalidate_rect (surface, NULL); return TRUE; @@ -3414,16 +2617,17 @@ gdk_wayland_surface_set_input_region (GdkSurface *surface, cairo_region_t *input_region) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); if (GDK_SURFACE_DESTROYED (surface)) return; - g_clear_pointer (&impl->input_region, cairo_region_destroy); + g_clear_pointer (&priv->input_region, cairo_region_destroy); if (input_region) - impl->input_region = cairo_region_copy (input_region); + priv->input_region = cairo_region_copy (input_region); - impl->input_region_dirty = TRUE; + priv->input_region_dirty = TRUE; } static void @@ -3440,7 +2644,7 @@ gdk_wayland_surface_destroy (GdkSurface *surface, */ g_return_if_fail (!foreign_destroy); - gdk_wayland_surface_hide_surface (surface); + gdk_surface_hide (surface); frame_clock = gdk_surface_get_frame_clock (surface); g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface); @@ -3451,693 +2655,27 @@ gdk_wayland_surface_destroy (GdkSurface *surface, } static void -gdk_wayland_surface_focus (GdkSurface *surface, - guint32 timestamp) +gdk_wayland_surface_destroy_notify (GdkSurface *surface) { - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - if (!impl->display_server.gtk_surface) - return; - - if (timestamp == GDK_CURRENT_TIME) + if (!GDK_SURFACE_DESTROYED (surface)) { - GdkWaylandDisplay *display_wayland = - GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + g_warning ("GdkSurface %p unexpectedly destroyed", surface); + _gdk_surface_destroy (surface, TRUE); + } - if (display_wayland->startup_notification_id) - { - if (display_wayland->xdg_activation) - { - xdg_activation_v1_activate (display_wayland->xdg_activation, - display_wayland->startup_notification_id, - impl->display_server.wl_surface); - } - else if (display_wayland->gtk_shell_version >= 3) - { - gtk_surface1_request_focus (impl->display_server.gtk_surface, - display_wayland->startup_notification_id); - } - - g_clear_pointer (&display_wayland->startup_notification_id, g_free); - } - } - else - gtk_surface1_present (impl->display_server.gtk_surface, timestamp); -} - -static void -gtk_surface_configure (void *data, - struct gtk_surface1 *gtk_surface, - struct wl_array *states) -{ - GdkSurface *surface = GDK_SURFACE (data); - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - GdkToplevelState new_state = 0; - uint32_t *p; - - wl_array_for_each (p, states) - { - uint32_t state = *p; - - switch (state) - { - case GTK_SURFACE1_STATE_TILED: - new_state |= GDK_TOPLEVEL_STATE_TILED; - break; - - /* Since v2 */ - case GTK_SURFACE1_STATE_TILED_TOP: - new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_TOP_TILED); - break; - case GTK_SURFACE1_STATE_TILED_RIGHT: - new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_RIGHT_TILED); - break; - case GTK_SURFACE1_STATE_TILED_BOTTOM: - new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_BOTTOM_TILED); - break; - case GTK_SURFACE1_STATE_TILED_LEFT: - new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_LEFT_TILED); - break; - default: - /* Unknown state */ - break; - } - } - - impl->pending.toplevel.state |= new_state; -} - -static void -gtk_surface_configure_edges (void *data, - struct gtk_surface1 *gtk_surface, - struct wl_array *edge_constraints) -{ - GdkSurface *surface = GDK_SURFACE (data); - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - GdkToplevelState new_state = 0; - uint32_t *p; - - wl_array_for_each (p, edge_constraints) - { - uint32_t constraint = *p; - - switch (constraint) - { - case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_TOP: - new_state |= GDK_TOPLEVEL_STATE_TOP_RESIZABLE; - break; - case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_RIGHT: - new_state |= GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE; - break; - case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_BOTTOM: - new_state |= GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE; - break; - case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_LEFT: - new_state |= GDK_TOPLEVEL_STATE_LEFT_RESIZABLE; - break; - default: - /* Unknown state */ - break; - } - } - - impl->pending.toplevel.state |= new_state; -} - -static const struct gtk_surface1_listener gtk_surface_listener = { - gtk_surface_configure, - gtk_surface_configure_edges -}; - -static void -gdk_wayland_surface_init_gtk_surface (GdkWaylandSurface *impl) -{ - GdkWaylandDisplay *display = - GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (impl))); - - if (impl->display_server.gtk_surface != NULL) - return; - if (!is_realized_toplevel (impl)) - return; - if (display->gtk_shell == NULL) - return; - - impl->display_server.gtk_surface = - gtk_shell1_get_gtk_surface (display->gtk_shell, - impl->display_server.wl_surface); - wl_proxy_set_queue ((struct wl_proxy *) impl->display_server.gtk_surface, - impl->event_queue); - gdk_wayland_surface_set_geometry_hints (impl, - &impl->geometry_hints, - impl->geometry_mask); - gtk_surface1_add_listener (impl->display_server.gtk_surface, - >k_surface_listener, - impl); -} - -static void -maybe_set_gtk_surface_modal (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - gdk_wayland_surface_init_gtk_surface (impl); - if (impl->display_server.gtk_surface == NULL) - return; - - if (surface->modal_hint) - gtk_surface1_set_modal (impl->display_server.gtk_surface); - else - gtk_surface1_unset_modal (impl->display_server.gtk_surface); - -} - -static void -gdk_wayland_surface_set_modal_hint (GdkSurface *surface, - gboolean modal) -{ - surface->modal_hint = modal; - maybe_set_gtk_surface_modal (surface); -} - -static void -gdk_wayland_surface_set_geometry_hints (GdkWaylandSurface *impl, - const GdkGeometry *geometry, - GdkSurfaceHints geom_mask) -{ - GdkWaylandDisplay *display_wayland; - int min_width, min_height; - int max_width, max_height; - - if (GDK_SURFACE_DESTROYED (impl) || - !SURFACE_IS_TOPLEVEL (impl)) - return; - - display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (impl))); - - impl->geometry_hints = *geometry; - impl->geometry_mask = geom_mask; - - if (!is_realized_toplevel (impl)) - return; - - if (geom_mask & GDK_HINT_MIN_SIZE) - { - min_width = MAX (0, (geometry->min_width - - (impl->shadow_left + impl->shadow_right))); - min_height = MAX (0, (geometry->min_height - - (impl->shadow_top + impl->shadow_bottom))); - } - else - { - min_width = 0; - min_height = 0; - } - - if (geom_mask & GDK_HINT_MAX_SIZE) - { - max_width = MAX (0, (geometry->max_width - - (impl->shadow_left + impl->shadow_right))); - max_height = MAX (0, (geometry->max_height - - (impl->shadow_top + impl->shadow_bottom))); - } - else - { - max_width = 0; - max_height = 0; - } - - if (impl->last_sent_min_width == min_width && - impl->last_sent_min_height == min_height && - impl->last_sent_max_width == max_width && - impl->last_sent_max_height == max_height) - return; - - switch (display_wayland->shell_variant) - { - case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - xdg_toplevel_set_min_size (impl->display_server.xdg_toplevel, - min_width, min_height); - xdg_toplevel_set_max_size (impl->display_server.xdg_toplevel, - max_width, max_height); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_toplevel_v6_set_min_size (impl->display_server.zxdg_toplevel_v6, - min_width, min_height); - zxdg_toplevel_v6_set_max_size (impl->display_server.zxdg_toplevel_v6, - max_width, max_height); - break; - default: - g_assert_not_reached (); - } - - impl->last_sent_min_width = min_width; - impl->last_sent_min_height = min_height; - impl->last_sent_max_width = max_width; - impl->last_sent_max_height = max_height; -} - -static void -gdk_wayland_surface_set_title (GdkSurface *surface, - const char *title) -{ - GdkWaylandSurface *impl; - const char *end; - gsize title_length; - - g_return_if_fail (title != NULL); - - if (GDK_SURFACE_DESTROYED (surface)) - return; - - impl = GDK_WAYLAND_SURFACE (surface); - - if (g_strcmp0 (impl->title, title) == 0) - return; - - g_free (impl->title); - - title_length = MIN (strlen (title), MAX_WL_BUFFER_SIZE); - if (g_utf8_validate (title, title_length, &end)) - { - impl->title = g_malloc (end - title + 1); - memcpy (impl->title, title, end - title); - impl->title[end - title] = '\0'; - } - else - { - impl->title = g_utf8_make_valid (title, title_length); - g_warning ("Invalid utf8 passed to gdk_surface_set_title: '%s'", title); - } - - gdk_wayland_surface_sync_title (surface); -} - -static void -gdk_wayland_surface_set_startup_id (GdkSurface *surface, - const char *startup_id) -{ -} - -static gboolean -check_transient_for_loop (GdkWaylandToplevel *toplevel, - GdkWaylandToplevel *parent) -{ - while (parent) - { - if (parent->transient_for == toplevel) - return TRUE; - parent = parent->transient_for; - } - return FALSE; -} - -static void -gdk_wayland_toplevel_set_transient_for (GdkWaylandToplevel *toplevel, - GdkSurface *parent) -{ - g_return_if_fail (!parent || GDK_IS_WAYLAND_TOPLEVEL (parent)); - g_return_if_fail (!parent || - gdk_surface_get_display (GDK_SURFACE (toplevel)) == gdk_surface_get_display (parent)); - - if (parent) - { - GdkWaylandToplevel *parent_toplevel = GDK_WAYLAND_TOPLEVEL (parent); - - if (check_transient_for_loop (toplevel, parent_toplevel)) - { - g_warning ("Setting %p transient for %p would create a loop", - toplevel, parent); - return; - } - } - - unset_transient_for_exported (GDK_SURFACE (toplevel)); - - if (parent) - toplevel->transient_for = GDK_WAYLAND_TOPLEVEL (parent); - else - toplevel->transient_for = NULL; - - gdk_wayland_surface_sync_parent (GDK_SURFACE (toplevel), NULL); -} - -static void -gdk_wayland_surface_minimize (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - GdkWaylandDisplay *display_wayland; - - if (GDK_SURFACE_DESTROYED (surface) || - !SURFACE_IS_TOPLEVEL (surface)) - return; - - if (!is_realized_toplevel (GDK_WAYLAND_SURFACE (surface))) - return; - - /* 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 (impl->display_server.xdg_toplevel); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_toplevel_v6_set_minimized (impl->display_server.zxdg_toplevel_v6); - break; - default: - g_assert_not_reached (); - } -} - -static void -gdk_wayland_surface_maximize (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - if (GDK_SURFACE_DESTROYED (surface)) - return; - - _gdk_wayland_surface_save_size (surface); - - if (is_realized_toplevel (impl)) - { - GdkWaylandDisplay *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_maximized (impl->display_server.xdg_toplevel); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_toplevel_v6_set_maximized (impl->display_server.zxdg_toplevel_v6); - break; - default: - g_assert_not_reached (); - } - } - else - { - synthesize_initial_surface_state (surface, 0, GDK_TOPLEVEL_STATE_MAXIMIZED); - } -} - -static void -gdk_wayland_surface_unmaximize (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - if (GDK_SURFACE_DESTROYED (surface)) - return; - - if (is_realized_toplevel (impl)) - { - GdkWaylandDisplay *display_wayland = - GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); - - switch (display_wayland->shell_variant) - { - case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - xdg_toplevel_unset_maximized (impl->display_server.xdg_toplevel); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_toplevel_v6_unset_maximized (impl->display_server.zxdg_toplevel_v6); - break; - default: - g_assert_not_reached (); - } - } - else - { - synthesize_initial_surface_state (surface, GDK_TOPLEVEL_STATE_MAXIMIZED, 0); - } -} - -static void -gdk_wayland_surface_fullscreen_on_monitor (GdkSurface *surface, - GdkMonitor *monitor) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - struct wl_output *output = ((GdkWaylandMonitor *)monitor)->output; - - if (GDK_SURFACE_DESTROYED (surface)) - return; - - _gdk_wayland_surface_save_size (surface); - - if (is_realized_toplevel (impl)) - { - GdkWaylandDisplay *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_fullscreen (impl->display_server.xdg_toplevel, - output); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_toplevel_v6_set_fullscreen (impl->display_server.zxdg_toplevel_v6, - output); - break; - default: - g_assert_not_reached (); - } - } - else - { - synthesize_initial_surface_state (surface, 0, GDK_TOPLEVEL_STATE_FULLSCREEN); - impl->initial_fullscreen_output = output; - } -} - -static void -gdk_wayland_surface_fullscreen (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - if (GDK_SURFACE_DESTROYED (surface)) - return; - - impl->initial_fullscreen_output = NULL; - - _gdk_wayland_surface_save_size (surface); - - if (is_realized_toplevel (impl)) - { - GdkWaylandDisplay *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_fullscreen (impl->display_server.xdg_toplevel, - NULL); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_toplevel_v6_set_fullscreen (impl->display_server.zxdg_toplevel_v6, - NULL); - break; - default: - g_assert_not_reached (); - } - } - else - { - synthesize_initial_surface_state (surface, 0, GDK_TOPLEVEL_STATE_FULLSCREEN); - } -} - -static void -gdk_wayland_surface_unfullscreen (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - - if (GDK_SURFACE_DESTROYED (surface)) - return; - - impl->initial_fullscreen_output = NULL; - - if (is_realized_toplevel (impl)) - { - GdkWaylandDisplay *display_wayland = - GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); - - switch (display_wayland->shell_variant) - { - case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - xdg_toplevel_unset_fullscreen (impl->display_server.xdg_toplevel); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_toplevel_v6_unset_fullscreen (impl->display_server.zxdg_toplevel_v6); - break; - default: - g_assert_not_reached (); - } - } - else - { - synthesize_initial_surface_state (surface, 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; - GdkWaylandDisplay *display_wayland; - GdkEventSequence *sequence; - uint32_t resize_edges, serial; - - if (GDK_SURFACE_DESTROYED (surface) || - !SURFACE_IS_TOPLEVEL (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); - 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 (impl->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 (impl->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; - GdkWaylandDisplay *display_wayland; - GdkEventSequence *sequence; - uint32_t serial; - - if (GDK_SURFACE_DESTROYED (surface) || - !SURFACE_IS_TOPLEVEL (surface)) - return; - - impl = GDK_WAYLAND_SURFACE (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 (impl->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 (impl->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); - } - - g_object_unref (surface); -} + g_object_unref (surface); +} static int gdk_wayland_surface_get_scale_factor (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); if (GDK_SURFACE_DESTROYED (surface)) return 1; - return impl->scale; + return priv->scale; } static void @@ -4145,75 +2683,14 @@ gdk_wayland_surface_set_opaque_region (GdkSurface *surface, cairo_region_t *region) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); 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_surface_show_window_menu (GdkSurface *surface, - GdkEvent *event) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (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; - - seat = gdk_event_get_seat (event); - wl_seat = gdk_wayland_seat_get_wl_seat (seat); - gdk_event_get_position (event, &x, &y); - - serial = _gdk_wayland_seat_get_implicit_grab_serial (seat, event); - - switch (display_wayland->shell_variant) - { - case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: - xdg_toplevel_show_window_menu (impl->display_server.xdg_toplevel, - wl_seat, serial, x, y); - break; - case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: - zxdg_toplevel_v6_show_window_menu (impl->display_server.zxdg_toplevel_v6, - wl_seat, serial, x, y); - break; - default: - g_assert_not_reached (); - } - - return TRUE; -} - -static gboolean -gdk_wayland_surface_supports_edge_constraints (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - struct gtk_surface1 *gtk_surface = impl->display_server.gtk_surface; - - if (!gtk_surface) - return FALSE; - - return gtk_surface1_get_version (gtk_surface) >= GTK_SURFACE1_CONFIGURE_EDGES_SINCE_VERSION; + g_clear_pointer (&priv->opaque_region, cairo_region_destroy); + priv->opaque_region = cairo_region_reference (region); + priv->opaque_region_dirty = TRUE; } static void @@ -4241,6 +2718,10 @@ gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass) impl_class->create_gl_context = gdk_wayland_surface_create_gl_context; impl_class->request_layout = gdk_wayland_surface_request_layout; impl_class->compute_size = gdk_wayland_surface_compute_size; + + klass->sync = gdk_wayland_surface_sync_real; + klass->get_window_geometry = gdk_wayland_surface_get_window_geometry_real; + klass->configure_surface = gdk_wayland_surface_configure_surface_real; } void @@ -4248,399 +2729,183 @@ _gdk_wayland_surface_set_grab_seat (GdkSurface *surface, GdkSeat *seat) { GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; g_return_if_fail (surface != NULL); impl = GDK_WAYLAND_SURFACE (surface); - impl->grab_input_seat = seat; + priv = gdk_wayland_surface_get_instance_private (impl); + priv->grab_input_seat = seat; } /** * 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); - - return GDK_WAYLAND_SURFACE (surface)->display_server.wl_surface; -} - -struct wl_output * -gdk_wayland_surface_get_wl_output (GdkSurface *surface) -{ - GdkWaylandSurface *impl; - - 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 struct wl_egl_window * -gdk_wayland_surface_get_wl_egl_window (GdkSurface *surface) -{ - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (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); - } - - return impl->display_server.egl_window; -} - -EGLSurface -gdk_wayland_surface_get_egl_surface (GdkSurface *surface, - EGLConfig config) -{ - GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); - GdkWaylandSurface *impl; - struct wl_egl_window *egl_window; - - g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL); - - impl = GDK_WAYLAND_SURFACE (surface); - - if (impl->egl_surface == NULL) - { - egl_window = gdk_wayland_surface_get_wl_egl_window (surface); - - impl->egl_surface = - eglCreateWindowSurface (display->egl_display, config, egl_window, NULL); - } - - return impl->egl_surface; -} - -EGLSurface -gdk_wayland_surface_get_dummy_egl_surface (GdkSurface *surface, - EGLConfig config) -{ - GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); - GdkWaylandSurface *impl; - - g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL); - - impl = GDK_WAYLAND_SURFACE (surface); - - if (impl->dummy_egl_surface == NULL) - { - impl->display_server.dummy_egl_window = - wl_egl_window_create (impl->display_server.wl_surface, 1, 1); - - impl->dummy_egl_surface = - eglCreateWindowSurface (display->egl_display, config, impl->display_server.dummy_egl_window, NULL); - } - - return impl->dummy_egl_surface; -} - -struct gtk_surface1 * -gdk_wayland_surface_get_gtk_surface (GdkSurface *surface) -{ - g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL); - - return GDK_WAYLAND_SURFACE (surface)->display_server.gtk_surface; -} - -static void -maybe_set_gtk_surface_dbus_properties (GdkWaylandSurface *impl) -{ - if (impl->application.was_set) - return; - - if (impl->application.application_id == NULL && - impl->application.app_menu_path == NULL && - impl->application.menubar_path == NULL && - impl->application.window_object_path == NULL && - impl->application.application_object_path == NULL && - impl->application.unique_bus_name == NULL) - return; - - gdk_wayland_surface_init_gtk_surface (impl); - if (impl->display_server.gtk_surface == NULL) - return; - - gtk_surface1_set_dbus_properties (impl->display_server.gtk_surface, - impl->application.application_id, - impl->application.app_menu_path, - impl->application.menubar_path, - impl->application.window_object_path, - impl->application.application_object_path, - impl->application.unique_bus_name); - impl->application.was_set = TRUE; -} - -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) -{ - GdkWaylandSurface *impl; - - g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); - - impl = GDK_WAYLAND_SURFACE (toplevel); - - impl->application.application_id = g_strdup (application_id); - impl->application.app_menu_path = g_strdup (app_menu_path); - impl->application.menubar_path = g_strdup (menubar_path); - impl->application.window_object_path = g_strdup (window_object_path); - impl->application.application_object_path = - g_strdup (application_object_path); - impl->application.unique_bus_name = g_strdup (unique_bus_name); - - maybe_set_gtk_surface_dbus_properties (impl); -} - -void -_gdk_wayland_surface_offset_next_wl_buffer (GdkSurface *surface, - int x, - int y) -{ - GdkWaylandSurface *impl; - - g_return_if_fail (GDK_IS_WAYLAND_SURFACE (surface)); - - impl = GDK_WAYLAND_SURFACE (surface); - - impl->pending_buffer_offset_x = x; - impl->pending_buffer_offset_y = y; -} - -static void -xdg_exported_handle (void *data, - struct zxdg_exported_v1 *zxdg_exported_v1, - const char *handle) -{ - GdkToplevel *toplevel = data; - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel); - - impl->exported.callback (toplevel, handle, impl->exported.user_data); - if (impl->exported.destroy_func) - { - g_clear_pointer (&impl->exported.user_data, - impl->exported.destroy_func); - } -} - -static const struct zxdg_exported_v1_listener xdg_exported_listener = { - xdg_exported_handle -}; - -/** - * 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_surface_is_exported (GdkWaylandSurface *impl) -{ - return !!impl->display_server.xdg_exported; -} - -/** - * 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. + * Returns the Wayland `wl_surface` of a `GdkSurface`. * - * Return value: %TRUE if the handle has been requested, %FALSE if - * an error occurred. + * Returns: (transfer none): a Wayland `wl_surface` */ -gboolean -gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel, - GdkWaylandToplevelExported callback, - gpointer user_data, - GDestroyNotify destroy_func) +struct wl_surface * +gdk_wayland_surface_get_wl_surface (GdkSurface *surface) { GdkWaylandSurface *impl; - GdkWaylandDisplay *display_wayland; - GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel)); - struct zxdg_exported_v1 *xdg_exported; + GdkWaylandSurfacePrivate *priv; - g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE); - g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE); + g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL); - impl = GDK_WAYLAND_SURFACE (toplevel); - display_wayland = GDK_WAYLAND_DISPLAY (display); + impl = GDK_WAYLAND_SURFACE (surface); + priv = gdk_wayland_surface_get_instance_private (impl); + return priv->display_server.wl_surface; +} - g_return_val_if_fail (!impl->display_server.xdg_exported, FALSE); +struct wl_output * +gdk_wayland_surface_get_wl_output (GdkSurface *surface) +{ + GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; - if (!display_wayland->xdg_exporter) - { - g_warning ("Server is missing xdg_foreign support"); - return FALSE; - } + g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL); - xdg_exported = zxdg_exporter_v1_export (display_wayland->xdg_exporter, - impl->display_server.wl_surface); - zxdg_exported_v1_add_listener (xdg_exported, &xdg_exported_listener, impl); + impl = GDK_WAYLAND_SURFACE (surface); + priv = gdk_wayland_surface_get_instance_private (impl); + /* We pick the head of the list as this is the last entered output */ + if (priv->display_server.outputs) + return (struct wl_output *) priv->display_server.outputs->data; - impl->display_server.xdg_exported = xdg_exported; - impl->exported.callback = callback; - impl->exported.user_data = user_data; - impl->exported.destroy_func = destroy_func; + return NULL; +} - return TRUE; +struct xdg_surface * +gdk_wayland_surface_get_xdg_surface (GdkSurface *surface) +{ + GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; + + g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL); + + impl = GDK_WAYLAND_SURFACE (surface); + priv = gdk_wayland_surface_get_instance_private (impl); + return priv->display_server.xdg_surface; } -/** - * 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) +struct zxdg_surface_v6 * +gdk_wayland_surface_get_zxdg_surface_v6 (GdkSurface *surface) { GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; - g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); + g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL); - impl = GDK_WAYLAND_SURFACE (toplevel); + impl = GDK_WAYLAND_SURFACE (surface); + priv = gdk_wayland_surface_get_instance_private (impl); + return priv->display_server.zxdg_surface_v6; +} - g_return_if_fail (impl->display_server.xdg_exported); +struct wl_event_queue * +gdk_wayland_surface_get_event_queue (GdkSurface *surface) +{ + GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; - g_clear_pointer (&impl->display_server.xdg_exported, - zxdg_exported_v1_destroy); - if (impl->exported.destroy_func) - { - g_clear_pointer (&impl->exported.user_data, - impl->exported.destroy_func); - } + g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL); + + impl = GDK_WAYLAND_SURFACE (surface); + priv = gdk_wayland_surface_get_instance_private (impl); + return priv->event_queue; } -static void -unset_transient_for_exported (GdkSurface *surface) +static struct wl_egl_window * +gdk_wayland_surface_get_wl_egl_window (GdkSurface *surface) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); + + if (priv->display_server.egl_window == NULL) + { + priv->display_server.egl_window = + wl_egl_window_create (priv->display_server.wl_surface, + surface->width * priv->scale, + surface->height * priv->scale); + wl_surface_set_buffer_scale (priv->display_server.wl_surface, priv->scale); + } - g_clear_pointer (&impl->imported_transient_for, zxdg_imported_v1_destroy); + return priv->display_server.egl_window; } -static void -xdg_imported_destroyed (void *data, - struct zxdg_imported_v1 *zxdg_imported_v1) +EGLSurface +gdk_wayland_surface_get_egl_surface (GdkSurface *surface, + EGLConfig config) { - GdkSurface *surface = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; + struct wl_egl_window *egl_window; - unset_transient_for_exported (surface); -} + g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL); -static const struct zxdg_imported_v1_listener xdg_imported_listener = { - xdg_imported_destroyed, -}; + impl = GDK_WAYLAND_SURFACE (surface); + priv = gdk_wayland_surface_get_instance_private (impl); -/** - * 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) + if (priv->egl_surface == NULL) + { + egl_window = gdk_wayland_surface_get_wl_egl_window (surface); + + priv->egl_surface = + eglCreateWindowSurface (display->egl_display, config, egl_window, NULL); + } + + return priv->egl_surface; +} + +EGLSurface +gdk_wayland_surface_get_dummy_egl_surface (GdkSurface *surface, + EGLConfig config) { + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); GdkWaylandSurface *impl; - GdkWaylandDisplay *display_wayland; - GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel)); + GdkWaylandSurfacePrivate *priv; - g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE); - g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE); + g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (surface), NULL); - impl = GDK_WAYLAND_SURFACE (toplevel); - display_wayland = GDK_WAYLAND_DISPLAY (display); + impl = GDK_WAYLAND_SURFACE (surface); + priv = gdk_wayland_surface_get_instance_private (impl); - if (!display_wayland->xdg_importer) + if (priv->dummy_egl_surface == NULL) { - g_warning ("Server is missing xdg_foreign support"); - return FALSE; + priv->display_server.dummy_egl_window = + wl_egl_window_create (priv->display_server.wl_surface, 1, 1); + + priv->dummy_egl_surface = + eglCreateWindowSurface (display->egl_display, config, priv->display_server.dummy_egl_window, NULL); } - gdk_wayland_toplevel_set_transient_for (GDK_WAYLAND_TOPLEVEL (impl), NULL); + return priv->dummy_egl_surface; +} - impl->imported_transient_for = - zxdg_importer_v1_import (display_wayland->xdg_importer, parent_handle_str); - zxdg_imported_v1_add_listener (impl->imported_transient_for, - &xdg_imported_listener, - toplevel); +void +_gdk_wayland_surface_offset_next_wl_buffer (GdkSurface *surface, + int x, + int y) +{ + GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; - gdk_wayland_surface_sync_parent_of_imported (impl); + g_return_if_fail (GDK_IS_WAYLAND_SURFACE (surface)); - return TRUE; + impl = GDK_WAYLAND_SURFACE (surface); + priv = gdk_wayland_surface_get_instance_private (impl); + + priv->pending_buffer_offset_x = x; + priv->pending_buffer_offset_y = y; } -static struct zwp_keyboard_shortcuts_inhibitor_v1 * +struct zwp_keyboard_shortcuts_inhibitor_v1 * gdk_wayland_surface_get_inhibitor (GdkWaylandSurface *impl, GdkSeat *gdk_seat) { - return g_hash_table_lookup (impl->shortcuts_inhibitors, gdk_seat); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); + return g_hash_table_lookup (priv->shortcuts_inhibitors, gdk_seat); } /* @@ -4654,9 +2919,10 @@ void gdk_wayland_surface_inhibit_shortcuts (GdkSurface *surface, GdkSeat *gdk_seat) { - GdkWaylandSurface *impl= GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); - struct wl_surface *wl_surface = impl->display_server.wl_surface; + struct wl_surface *wl_surface = priv->display_server.wl_surface; struct wl_seat *seat = gdk_wayland_seat_get_wl_seat (gdk_seat); struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor; @@ -4670,7 +2936,7 @@ gdk_wayland_surface_inhibit_shortcuts (GdkSurface *surface, zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts ( display->keyboard_shortcuts_inhibit, wl_surface, seat); - g_hash_table_insert (impl->shortcuts_inhibitors, gdk_seat, inhibitor); + g_hash_table_insert (priv->shortcuts_inhibitors, gdk_seat, inhibitor); } /* @@ -4686,6 +2952,7 @@ gdk_wayland_surface_restore_shortcuts (GdkSurface *surface, GdkSeat *gdk_seat) { GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor; inhibitor = gdk_wayland_surface_get_inhibitor (impl, gdk_seat); @@ -4693,19 +2960,24 @@ gdk_wayland_surface_restore_shortcuts (GdkSurface *surface, return; /* Not inhibitted */ zwp_keyboard_shortcuts_inhibitor_v1_destroy (inhibitor); - g_hash_table_remove (impl->shortcuts_inhibitors, gdk_seat); + g_hash_table_remove (priv->shortcuts_inhibitors, gdk_seat); } GdkSurface * create_dnd_surface (GdkDisplay *display) { GdkSurface *surface; + GdkWaylandSurface *impl; + GdkWaylandSurfacePrivate *priv; surface = _gdk_wayland_display_create_surface (display, GDK_SURFACE_TEMP, NULL, 0, 0, 100, 100); - GDK_WAYLAND_SURFACE (surface)->is_drag_surface = TRUE; + impl = GDK_WAYLAND_SURFACE (surface); + priv = gdk_wayland_surface_get_instance_private (impl); + + priv->is_drag_surface = TRUE; return surface; } @@ -4821,296 +3093,6 @@ gdk_wayland_popup_iface_init (GdkPopupInterface *iface) iface->get_position_y = gdk_wayland_popup_get_position_y; } -static void -gdk_wayland_toplevel_init (GdkWaylandToplevel *toplevel) -{ -} - -static void -gdk_wayland_toplevel_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GdkSurface *surface = GDK_SURFACE (object); - GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface); - - switch (prop_id) - { - case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE: - gdk_wayland_surface_set_title (surface, 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; - - 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; - - case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL: - gdk_wayland_surface_set_modal_hint (surface, g_value_get_boolean (value)); - g_object_notify_by_pspec (G_OBJECT (surface), 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 (G_OBJECT (surface), pspec); - break; - - case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED: - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gdk_wayland_toplevel_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GdkSurface *surface = GDK_SURFACE (object); - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface); - - switch (prop_id) - { - case LAST_PROP + GDK_TOPLEVEL_PROP_STATE: - g_value_set_flags (value, surface->state); - break; - - case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE: - g_value_set_string (value, impl->title); - break; - - case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID: - g_value_set_string (value, ""); - break; - - 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_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; - - gdk_toplevel_install_properties (object_class, 1); -} - -static void -gdk_wayland_toplevel_present (GdkToplevel *toplevel, - GdkToplevelLayout *layout) -{ - GdkSurface *surface = GDK_SURFACE (toplevel); - GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); - gboolean pending_configure = FALSE; - gboolean maximize; - gboolean fullscreen; - - if (gdk_toplevel_layout_get_maximized (layout, &maximize)) - { - if (maximize) - gdk_wayland_surface_maximize (surface); - else - gdk_wayland_surface_unmaximize (surface); - pending_configure = TRUE; - } - - if (gdk_toplevel_layout_get_fullscreen (layout, &fullscreen)) - { - if (fullscreen) - { - GdkMonitor *monitor; - - monitor = gdk_toplevel_layout_get_fullscreen_monitor (layout); - if (monitor) - gdk_wayland_surface_fullscreen_on_monitor (surface, monitor); - else - gdk_wayland_surface_fullscreen (surface); - } - else - { - gdk_wayland_surface_unfullscreen (surface); - } - pending_configure = TRUE; - } - - g_clear_pointer (&impl->toplevel.layout, gdk_toplevel_layout_unref); - impl->toplevel.layout = gdk_toplevel_layout_copy (layout); - - gdk_wayland_surface_show (surface, FALSE); - - if (!pending_configure) - { - impl->next_layout.surface_geometry_dirty = TRUE; - gdk_surface_request_layout (surface); - } -} - -static gboolean -gdk_wayland_toplevel_minimize (GdkToplevel *toplevel) -{ - gdk_wayland_surface_minimize (GDK_SURFACE (toplevel)); - - return TRUE; -} - -static gboolean -gdk_wayland_toplevel_lower (GdkToplevel *toplevel) -{ - return FALSE; -} - -static void -gdk_wayland_toplevel_focus (GdkToplevel *toplevel, - guint32 timestamp) -{ - gdk_wayland_surface_focus (GDK_SURFACE (toplevel), timestamp); -} - -static gboolean -gdk_wayland_toplevel_show_window_menu (GdkToplevel *toplevel, - GdkEvent *event) -{ - return gdk_wayland_surface_show_window_menu (GDK_SURFACE (toplevel), event); -} - -static gboolean -gdk_wayland_toplevel_supports_edge_constraints (GdkToplevel *toplevel) -{ - return gdk_wayland_surface_supports_edge_constraints (GDK_SURFACE (toplevel)); -} - -static void -inhibitor_active (void *data, - struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor) -{ - GdkToplevel *toplevel = GDK_TOPLEVEL (data); - GdkSurface *surface = GDK_SURFACE (toplevel); - - surface->shortcuts_inhibited = TRUE; - g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited"); -} - -static void -inhibitor_inactive (void *data, - struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor) -{ - GdkToplevel *toplevel = GDK_TOPLEVEL (data); - GdkSurface *surface = GDK_SURFACE (toplevel); - - surface->shortcuts_inhibited = FALSE; - g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited"); -} - -static const struct zwp_keyboard_shortcuts_inhibitor_v1_listener -zwp_keyboard_shortcuts_inhibitor_listener = { - inhibitor_active, - inhibitor_inactive, -}; - -static void -gdk_wayland_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel, - GdkEvent *event) -{ - struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor; - GdkSurface *surface = GDK_SURFACE (toplevel); - GdkWaylandSurface *impl= GDK_WAYLAND_SURFACE (surface); - GdkSeat *gdk_seat; - - if (surface->shortcuts_inhibited) - return; - - gdk_seat = gdk_surface_get_seat_from_event (surface, event); - gdk_wayland_surface_inhibit_shortcuts (surface, gdk_seat); - - inhibitor = gdk_wayland_surface_get_inhibitor (impl, gdk_seat); - if (!inhibitor) - return; - - surface->current_shortcuts_inhibited_seat = gdk_seat; - zwp_keyboard_shortcuts_inhibitor_v1_add_listener - (inhibitor, &zwp_keyboard_shortcuts_inhibitor_listener, toplevel); -} - -static void -gdk_wayland_toplevel_restore_system_shortcuts (GdkToplevel *toplevel) -{ - GdkSurface *surface = GDK_SURFACE (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"); -} - -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->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; -} - static void gdk_wayland_drag_surface_init (GdkWaylandDragSurface *surface) { @@ -5128,12 +3110,13 @@ gdk_wayland_drag_surface_present (GdkDragSurface *drag_surface, { GdkSurface *surface = GDK_SURFACE (drag_surface); GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandSurfacePrivate *priv = gdk_wayland_surface_get_instance_private (impl); gdk_wayland_surface_show (surface, FALSE); - impl->next_layout.configured_width = width; - impl->next_layout.configured_height = height; - impl->next_layout.surface_geometry_dirty = TRUE; + priv->next_layout.configured_width = width; + priv->next_layout.configured_height = height; + priv->next_layout.surface_geometry_dirty = TRUE; gdk_surface_request_layout (surface); maybe_notify_mapped (surface); diff --git a/gdk/wayland/gdksurface-wayland.h b/gdk/wayland/gdksurface-wayland.h index 8efa4be04dfbb9a351e89c5892e9557bf6497364..b631704032ba905d8b8ec2239e13aa6ea5b87577 100644 --- a/gdk/wayland/gdksurface-wayland.h +++ b/gdk/wayland/gdksurface-wayland.h @@ -22,6 +22,25 @@ #include "gdkwaylandsurface.h" +#include "gdkprivate-wayland.h" + +struct _GdkWaylandSurface +{ + GdkSurface parent_instance; +}; + +typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass; +struct _GdkWaylandSurfaceClass +{ + GdkSurfaceClass parent_class; + void (*sync) (GdkSurface*); + void (*get_window_geometry) (GdkSurface*, GdkRectangle*); + void (*configure_surface) (GdkSurface*); +}; + +#define GDK_WAYLAND_SURFACE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls), GDK_TYPE_WAYLAND_SURFACE, GdkWaylandSurfaceClass)) +#define GDK_WAYLAND_SURFACE_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), GDK_TYPE_WAYLAND_SURFACE, GdkWaylandSurfaceClass)) + G_BEGIN_DECLS void gdk_wayland_toplevel_set_dbus_properties (GdkToplevel *toplevel, @@ -38,4 +57,32 @@ void gdk_wayland_toplevel_announce_ssd (GdkTopl gboolean gdk_wayland_toplevel_inhibit_idle (GdkToplevel *toplevel); void gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel); +struct zwp_keyboard_shortcuts_inhibitor_v1 * +gdk_wayland_surface_get_inhibitor (GdkWaylandSurface *impl, + GdkSeat *gdk_seat); +void +gdk_wayland_surface_show (GdkSurface *surface, + gboolean already_mapped); + +void +gdk_wayland_surface_create_xdg_surface_resources (GdkSurface *surface); + +void +gdk_wayland_surface_get_window_geometry (GdkSurface *surface, + GdkRectangle *geometry); +void +gdk_wayland_surface_update_size (GdkSurface *surface, + int width, + int height, + int scale); + +struct xdg_surface * +gdk_wayland_surface_get_xdg_surface (GdkSurface *surface); + +struct zxdg_surface_v6 * +gdk_wayland_surface_get_zxdg_surface_v6 (GdkSurface *surface); + +struct wl_event_queue * +gdk_wayland_surface_get_event_queue (GdkSurface *surface); + G_END_DECLS diff --git a/gdk/wayland/gdktoplevel-wayland.c b/gdk/wayland/gdktoplevel-wayland.c new file mode 100644 index 0000000000000000000000000000000000000000..5e43246803fcf5c0ca38f53fda53db72b2fc1d1e --- /dev/null +++ b/gdk/wayland/gdktoplevel-wayland.c @@ -0,0 +1,2285 @@ +/* + * Copyright © 2010 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdksurface-wayland.h" +#include "gdkwaylandtoplevel.h" + +#include "gdkdeviceprivate.h" +#include "gdkdisplay-wayland.h" +#include "gdkdragsurfaceprivate.h" +#include "gdkframeclockidleprivate.h" +#include "gdkglcontext-wayland.h" +#include "gdkmonitor-wayland.h" +#include "gdkpopupprivate.h" +#include "gdkprivate-wayland.h" +#include "gdkprivate-wayland.h" +#include "gdkseat-wayland.h" +#include "gdksurfaceprivate.h" +#include "gdktoplevelprivate.h" +#include "gdkdevice-wayland-private.h" + +#include + +#include +#include +#include +#include + +#define SURFACE_IS_TOPLEVEL(surface) TRUE + +#define MAX_WL_BUFFER_SIZE (4083) /* 4096 minus header, string argument length and NUL byte */ + +typedef struct +{ + GdkWaylandSurfaceClass parent_class; +} GdkWaylandToplevelClass; + +struct _GdkWaylandToplevel +{ + GdkWaylandSurface parent_instance; + + GdkWaylandToplevel *transient_for; + + struct xdg_toplevel *xdg_toplevel; + struct zxdg_toplevel_v6 *zxdg_toplevel_v6; + struct zxdg_exported_v1 *xdg_exported; + struct org_kde_kwin_server_decoration *server_decoration; + struct gtk_surface1 *gtk_surface; + struct zxdg_imported_v1 *imported_transient_for; + + char *title; + int saved_width; + int saved_height; + + unsigned int mapped : 1; + + struct wl_output *initial_fullscreen_output; + + int last_sent_min_width; + int last_sent_min_height; + int last_sent_max_width; + int last_sent_max_height; + + GdkGeometry geometry_hints; + GdkSurfaceHints geometry_mask; + + int shadow_left; + int shadow_right; + int shadow_top; + int shadow_bottom; + + GdkToplevelLayout *layout; + + 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 { + GdkToplevelState unset_flags; + GdkToplevelState set_flags; + } initial_state; + + struct { + int width; + int height; + GdkToplevelState state; + gboolean is_resizing; + } pending; + + struct { + gboolean should_constrain; + gboolean size_is_fixed; + gboolean surface_geometry_dirty; + int configured_width; + int configured_height; + } next_layout; + + struct { + GdkWaylandToplevelExported callback; + gpointer user_data; + GDestroyNotify destroy_func; + } exported; + + struct zwp_idle_inhibitor_v1 *idle_inhibitor; + size_t idle_inhibitor_refcount; +}; + +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)) + +static void gdk_wayland_surface_sync_geometry_hints (GdkSurface *surface); +static void maybe_set_gtk_surface_dbus_properties (GdkWaylandToplevel *impl); +static void maybe_set_gtk_surface_modal (GdkSurface *surface); + +static void +gdk_wayland_surface_create_xdg_toplevel (GdkSurface *surface); +static void +gdk_wayland_surface_configure_toplevel (GdkSurface *surface); +static void +gdk_wayland_toplevel_hide (GdkSurface *surface); +static gboolean gdk_wayland_surface_is_exported (GdkWaylandToplevel *impl); +static void unset_transient_for_exported (GdkSurface *surface); + +static gboolean +is_realized_toplevel (GdkWaylandToplevel *impl) +{ + return (impl->xdg_toplevel || + impl->zxdg_toplevel_v6); +} + +static void +_gdk_wayland_surface_save_size (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (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) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + if (surface->state & (GDK_TOPLEVEL_STATE_FULLSCREEN | GDK_TOPLEVEL_STATE_MAXIMIZED)) + return; + + impl->saved_width = -1; + impl->saved_height = -1; +} + +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 +gdk_wayland_toplevel_sync (GdkSurface *surface) +{ + gdk_wayland_surface_sync_geometry_hints (surface); + GDK_WAYLAND_SURFACE_CLASS(gdk_wayland_toplevel_parent_class)->sync(surface); +} + +static void +gdk_wayland_toplevel_finalize (GObject *object) +{ + GdkWaylandToplevel *impl; + + g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (object)); + + impl = GDK_WAYLAND_TOPLEVEL (object); + + if (gdk_wayland_surface_is_exported (impl)) + gdk_wayland_toplevel_unexport_handle (GDK_TOPLEVEL (impl)); + + g_free (impl->title); + + g_free (impl->application.application_id); + g_free (impl->application.app_menu_path); + g_free (impl->application.menubar_path); + g_free (impl->application.window_object_path); + g_free (impl->application.application_object_path); + g_free (impl->application.unique_bus_name); + + G_OBJECT_CLASS(gdk_wayland_toplevel_parent_class)->finalize (object); +} + +static void +gdk_wayland_surface_sync_parent (GdkSurface *surface, + GdkSurface *parent) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + GdkWaylandDisplay *display_wayland = + GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + GdkWaylandToplevel *impl_parent = NULL; + + g_assert (parent == NULL || + gdk_surface_get_display (surface) == gdk_surface_get_display (parent)); + + if (!is_realized_toplevel (impl)) + return; + + if (impl->transient_for) + impl_parent = GDK_WAYLAND_TOPLEVEL (impl->transient_for); + else if (parent) + impl_parent = GDK_WAYLAND_TOPLEVEL (parent); + + /* XXX: Is this correct? */ + if (impl_parent && !gdk_wayland_surface_get_wl_surface (surface)) + return; + + switch (display_wayland->shell_variant) + { + case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: + { + struct xdg_toplevel *parent_toplevel; + + if (impl_parent) + parent_toplevel = impl_parent->xdg_toplevel; + else + parent_toplevel = NULL; + + xdg_toplevel_set_parent (impl->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 = impl_parent->zxdg_toplevel_v6; + else + parent_toplevel = NULL; + + zxdg_toplevel_v6_set_parent (impl->zxdg_toplevel_v6, + parent_toplevel); + break; + } + default: + g_assert_not_reached (); + } +} + +static void +gdk_wayland_surface_sync_parent_of_imported (GdkWaylandToplevel *impl) +{ + if (!gdk_wayland_surface_get_wl_surface (GDK_SURFACE (impl))) + return; + + if (!impl->imported_transient_for) + return; + + if (!is_realized_toplevel (impl)) + return; + + zxdg_imported_v1_set_parent_of (impl->imported_transient_for, + gdk_wayland_surface_get_wl_surface (GDK_SURFACE(impl))); +} + +static void +gdk_wayland_surface_sync_title (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + GdkWaylandDisplay *display_wayland = + GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + + if (!is_realized_toplevel (impl)) + return; + + if (!impl->title) + return; + + switch (display_wayland->shell_variant) + { + case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: + xdg_toplevel_set_title (impl->xdg_toplevel, + impl->title); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_set_title (impl->zxdg_toplevel_v6, + impl->title); + break; + default: + g_assert_not_reached (); + } +} + +static void +gdk_wayland_toplevel_get_window_geometry (GdkSurface *surface, + GdkRectangle *geometry) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (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_surface_set_geometry_hints (GdkWaylandSurface *impl, + const GdkGeometry *geometry, + GdkSurfaceHints geom_mask); + +static void +gdk_wayland_surface_sync_geometry_hints (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + GdkRectangle geometry; + + if (!is_realized_toplevel (impl)) + return; + + gdk_wayland_surface_get_window_geometry (surface, &geometry); + gdk_wayland_surface_set_geometry_hints (GDK_WAYLAND_SURFACE (surface), + &impl->geometry_hints, + impl->geometry_mask); +} + +static void +configure_toplevel_geometry (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + GdkDisplay *display = gdk_surface_get_display (surface); + GdkMonitor *monitor; + GdkRectangle monitor_geometry; + int bounds_width, bounds_height; + GdkToplevelSize size; + GdkToplevelLayout *layout; + GdkGeometry geometry; + GdkSurfaceHints mask; + + monitor = g_list_model_get_item (gdk_display_get_monitors (display), 0); + gdk_monitor_get_geometry (monitor, &monitor_geometry); + g_object_unref (monitor); + bounds_width = monitor_geometry.width; + bounds_height = monitor_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 = impl->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_surface_set_geometry_hints (GDK_WAYLAND_SURFACE (impl), &geometry, mask); + + if (size.shadow.is_valid) + { + impl->shadow_left = size.shadow.left; + impl->shadow_right = size.shadow.right; + impl->shadow_top = size.shadow.top; + impl->shadow_bottom = size.shadow.bottom; + } + + if (impl->next_layout.configured_width > 0 && + impl->next_layout.configured_height > 0) + { + int width, height; + + width = impl->next_layout.configured_width + + impl->shadow_left + impl->shadow_right; + height = impl->next_layout.configured_height + + impl->shadow_top + impl->shadow_bottom; + + if (impl->next_layout.should_constrain) + { + gdk_surface_constrain_size (&impl->geometry_hints, + impl->geometry_mask, + width, height, + &width, &height); + } + gdk_wayland_surface_update_size (surface, width, height, gdk_surface_get_scale_factor (surface)); + + if (!impl->next_layout.size_is_fixed) + { + impl->next_layout.should_constrain = FALSE; + impl->next_layout.configured_width = 0; + impl->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, gdk_surface_get_scale_factor (surface)); + } +} + + +static gboolean +gdk_wayland_toplevel_compute_size (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + if (impl->next_layout.surface_geometry_dirty) + { + configure_toplevel_geometry (surface); + impl->next_layout.surface_geometry_dirty = FALSE; + } + + return FALSE; +} + +static void +gdk_wayland_toplevel_request_layout (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + impl->next_layout.surface_geometry_dirty = TRUE; +} + +static void +synthesize_initial_surface_state (GdkSurface *surface, + GdkToplevelState unset_flags, + GdkToplevelState set_flags) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + impl->initial_state.unset_flags |= unset_flags; + impl->initial_state.set_flags &= ~unset_flags; + + impl->initial_state.set_flags |= set_flags; + impl->initial_state.unset_flags &= ~set_flags; +} + +static void +gdk_wayland_surface_configure_toplevel (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + GdkToplevelState new_state; + int width, height; + gboolean is_resizing; + gboolean fixed_size; + gboolean saved_size; + + new_state = impl->pending.state; + impl->pending.state = 0; + + is_resizing = impl->pending.is_resizing; + impl->pending.is_resizing = FALSE; + + fixed_size = + new_state & (GDK_TOPLEVEL_STATE_MAXIMIZED | + GDK_TOPLEVEL_STATE_FULLSCREEN | + GDK_TOPLEVEL_STATE_TILED) || + is_resizing; + + width = impl->pending.width; + height = impl->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) + { + width =impl->saved_width; + height =impl->saved_height; + } + + if (width > 0 && height > 0) + { + if (!saved_size) + { + impl->next_layout.should_constrain = TRUE; + + /* Save size for next time we get 0x0 */ + _gdk_wayland_surface_save_size (surface); + } + else if (is_resizing) + { + impl->next_layout.should_constrain = TRUE; + } + else + { + impl->next_layout.should_constrain = FALSE; + } + + impl->next_layout.size_is_fixed = fixed_size; + impl->next_layout.configured_width = width; + impl->next_layout.configured_height = height; + } + else + { + impl->next_layout.should_constrain = FALSE; + impl->next_layout.size_is_fixed = FALSE; + impl->next_layout.configured_width = 0; + impl->next_layout.configured_height = 0; + } + + gdk_surface_request_layout (surface); + + GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS, + g_message ("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_surface_queue_state_change (surface, ~0 & ~new_state, new_state); +} + +static void +gdk_wayland_surface_handle_configure_toplevel (GdkSurface *surface, + int32_t width, + int32_t height, + GdkToplevelState state) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + impl->pending.state |= state; + impl->pending.width = width; + impl->pending.height = height; +} + +static void +gdk_wayland_surface_handle_close (GdkSurface *surface) +{ + GdkDisplay *display; + GdkEvent *event; + + display = gdk_surface_get_display (surface); + + GDK_DISPLAY_NOTE (display, EVENTS, g_message ("close %p", surface)); + + event = gdk_delete_event_new (surface); + + _gdk_wayland_display_deliver_event (display, event); +} + +static void +xdg_toplevel_configure (void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *states) +{ + GdkSurface *surface = GDK_SURFACE (data); + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + uint32_t *p; + GdkToplevelState pending_state = 0; + + impl->pending.is_resizing = FALSE; + + wl_array_for_each (p, states) + { + 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: + impl->pending.is_resizing = TRUE; + break; + default: + /* Unknown state */ + break; + } + } + + gdk_wayland_surface_handle_configure_toplevel (surface, width, height, + pending_state); +} + +static void +xdg_toplevel_close (void *data, + struct xdg_toplevel *xdg_toplevel) +{ + GdkSurface *surface = GDK_SURFACE (data); + + gdk_wayland_surface_handle_close (surface); +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + xdg_toplevel_configure, + xdg_toplevel_close, +}; + +static void +create_xdg_toplevel_resources (GdkSurface *surface) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + GDK_WAYLAND_TOPLEVEL(impl)->xdg_toplevel = + xdg_surface_get_toplevel (gdk_wayland_surface_get_xdg_surface (surface)); + xdg_toplevel_add_listener (GDK_WAYLAND_TOPLEVEL(impl)->xdg_toplevel, + &xdg_toplevel_listener, + surface); +} + +static void +zxdg_toplevel_v6_configure (void *data, + struct zxdg_toplevel_v6 *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *states) +{ + GdkSurface *surface = GDK_SURFACE (data); + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + uint32_t *p; + GdkToplevelState pending_state = 0; + + impl->pending.is_resizing = FALSE; + + wl_array_for_each (p, states) + { + uint32_t state = *p; + + 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: + impl->pending.is_resizing = TRUE; + break; + default: + /* Unknown state */ + break; + } + } + + gdk_wayland_surface_handle_configure_toplevel (surface, width, height, + pending_state); +} + +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 +create_zxdg_toplevel_v6_resources (GdkSurface *surface) +{ + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + + GDK_WAYLAND_TOPLEVEL(impl)->zxdg_toplevel_v6 = + zxdg_surface_v6_get_toplevel (gdk_wayland_surface_get_zxdg_surface_v6 (surface)); + zxdg_toplevel_v6_add_listener (GDK_WAYLAND_TOPLEVEL(impl)->zxdg_toplevel_v6, + &zxdg_toplevel_v6_listener, + surface); +} + +/** + * 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 *impl; + GdkWaylandDisplay *display_wayland; + + g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); + + g_return_if_fail (application_id != NULL); + + if (GDK_SURFACE_DESTROYED (toplevel)) + return; + + impl = GDK_WAYLAND_TOPLEVEL (toplevel); + + if (!is_realized_toplevel (impl)) + return; + + display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel))); + + switch (display_wayland->shell_variant) + { + case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: + xdg_toplevel_set_app_id (impl->xdg_toplevel, + application_id); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_set_app_id (impl->zxdg_toplevel_v6, + application_id); + break; + default: + g_assert_not_reached (); + } +} + +static void +gdk_wayland_surface_create_xdg_toplevel (GdkSurface *surface) +{ + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + const char *app_id; + + gdk_surface_freeze_updates (surface); + gdk_wayland_surface_create_xdg_surface_resources (surface); + + switch (display_wayland->shell_variant) + { + case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: + create_xdg_toplevel_resources (surface); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + create_zxdg_toplevel_v6_resources (surface); + break; + default: + g_assert_not_reached (); + } + + gdk_wayland_surface_sync_parent (surface, NULL); + gdk_wayland_surface_sync_parent_of_imported (impl); + gdk_wayland_surface_sync_title (surface); + + switch (display_wayland->shell_variant) + { + case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED) + xdg_toplevel_set_maximized (impl->xdg_toplevel); + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED) + xdg_toplevel_set_minimized (impl->xdg_toplevel); + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN) + xdg_toplevel_set_fullscreen (impl->xdg_toplevel, + impl->initial_fullscreen_output); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MAXIMIZED) + zxdg_toplevel_v6_set_maximized (impl->zxdg_toplevel_v6); + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_MINIMIZED) + zxdg_toplevel_v6_set_minimized (impl->zxdg_toplevel_v6); + if (impl->initial_state.set_flags & GDK_TOPLEVEL_STATE_FULLSCREEN) + zxdg_toplevel_v6_set_fullscreen (impl->zxdg_toplevel_v6, + impl->initial_fullscreen_output); + break; + default: + g_assert_not_reached (); + } + + impl->initial_fullscreen_output = NULL; + + app_id = impl->application.application_id; + if (app_id == NULL) + app_id = g_get_prgname (); + + if (app_id == NULL) + app_id = "GTK Application"; + + gdk_wayland_toplevel_set_application_id (GDK_TOPLEVEL (impl), app_id); + + maybe_set_gtk_surface_dbus_properties (impl); + maybe_set_gtk_surface_modal (surface); + + gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "surface commit"); + wl_surface_commit (gdk_wayland_surface_get_wl_surface (surface)); +} + +void +gdk_wayland_toplevel_announce_csd (GdkToplevel *toplevel) +{ + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (toplevel))); + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (toplevel); + + g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); + + if (!display_wayland->server_decoration_manager) + return; + impl->server_decoration = + org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager, + gdk_wayland_surface_get_wl_surface (GDK_SURFACE (impl))); + if (impl->server_decoration) + org_kde_kwin_server_decoration_request_mode (impl->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 *impl = GDK_WAYLAND_TOPLEVEL (toplevel); + + g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); + + if (!display_wayland->server_decoration_manager) + return; + impl->server_decoration = + org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager, + gdk_wayland_surface_get_wl_surface (GDK_SURFACE(impl))); + if (impl->server_decoration) + org_kde_kwin_server_decoration_request_mode (impl->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 *impl = GDK_WAYLAND_TOPLEVEL (toplevel); + + g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE); + + if (!display_wayland->idle_inhibit_manager) + return FALSE; + + if (!impl->idle_inhibitor) + { + g_assert (impl->idle_inhibitor_refcount == 0); + impl->idle_inhibitor = + zwp_idle_inhibit_manager_v1_create_inhibitor (display_wayland->idle_inhibit_manager, + gdk_wayland_surface_get_wl_surface (GDK_SURFACE (impl))); + } + ++impl->idle_inhibitor_refcount; + + return TRUE; +} + +void +gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (toplevel); + + g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); + + g_assert (impl->idle_inhibitor && impl->idle_inhibitor_refcount > 0); + + if (--impl->idle_inhibitor_refcount == 0) + { + zwp_idle_inhibitor_v1_destroy (impl->idle_inhibitor); + impl->idle_inhibitor = NULL; + } +} + +static void +gdk_wayland_surface_focus (GdkSurface *surface, + guint32 timestamp) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + if (!impl->gtk_surface) + return; + + if (timestamp == GDK_CURRENT_TIME) + { + GdkWaylandDisplay *display_wayland = + GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + + if (display_wayland->startup_notification_id) + { + if (display_wayland->xdg_activation) + { + xdg_activation_v1_activate (display_wayland->xdg_activation, + display_wayland->startup_notification_id, + gdk_wayland_surface_get_wl_surface (GDK_SURFACE (impl))); + } + else if (display_wayland->gtk_shell_version >= 3) + { + gtk_surface1_request_focus (impl->gtk_surface, + display_wayland->startup_notification_id); + } + + g_clear_pointer (&display_wayland->startup_notification_id, g_free); + } + } + else + gtk_surface1_present (impl->gtk_surface, timestamp); +} + +static void +gtk_surface_configure (void *data, + struct gtk_surface1 *gtk_surface, + struct wl_array *states) +{ + GdkSurface *surface = GDK_SURFACE (data); + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + GdkToplevelState new_state = 0; + uint32_t *p; + + wl_array_for_each (p, states) + { + uint32_t state = *p; + + switch (state) + { + case GTK_SURFACE1_STATE_TILED: + new_state |= GDK_TOPLEVEL_STATE_TILED; + break; + + /* Since v2 */ + case GTK_SURFACE1_STATE_TILED_TOP: + new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_TOP_TILED); + break; + case GTK_SURFACE1_STATE_TILED_RIGHT: + new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_RIGHT_TILED); + break; + case GTK_SURFACE1_STATE_TILED_BOTTOM: + new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_BOTTOM_TILED); + break; + case GTK_SURFACE1_STATE_TILED_LEFT: + new_state |= (GDK_TOPLEVEL_STATE_TILED | GDK_TOPLEVEL_STATE_LEFT_TILED); + break; + default: + /* Unknown state */ + break; + } + } + + impl->pending.state |= new_state; +} + +static void +gtk_surface_configure_edges (void *data, + struct gtk_surface1 *gtk_surface, + struct wl_array *edge_constraints) +{ + GdkSurface *surface = GDK_SURFACE (data); + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + GdkToplevelState new_state = 0; + uint32_t *p; + + wl_array_for_each (p, edge_constraints) + { + uint32_t constraint = *p; + + switch (constraint) + { + case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_TOP: + new_state |= GDK_TOPLEVEL_STATE_TOP_RESIZABLE; + break; + case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_RIGHT: + new_state |= GDK_TOPLEVEL_STATE_RIGHT_RESIZABLE; + break; + case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_BOTTOM: + new_state |= GDK_TOPLEVEL_STATE_BOTTOM_RESIZABLE; + break; + case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_LEFT: + new_state |= GDK_TOPLEVEL_STATE_LEFT_RESIZABLE; + break; + default: + /* Unknown state */ + break; + } + } + + impl->pending.state |= new_state; +} + +static const struct gtk_surface1_listener gtk_surface_listener = { + gtk_surface_configure, + gtk_surface_configure_edges +}; + +static void +gdk_wayland_surface_init_gtk_surface (GdkWaylandToplevel *impl) +{ + GdkWaylandDisplay *display = + GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (impl))); + + if (impl->gtk_surface != NULL) + return; + if (!is_realized_toplevel (impl)) + return; + if (display->gtk_shell == NULL) + return; + + impl->gtk_surface = + gtk_shell1_get_gtk_surface (display->gtk_shell, + gdk_wayland_surface_get_wl_surface (GDK_SURFACE (impl))); + wl_proxy_set_queue ((struct wl_proxy *) impl->gtk_surface, + gdk_wayland_surface_get_event_queue (GDK_SURFACE (impl))); + gdk_wayland_surface_set_geometry_hints (GDK_WAYLAND_SURFACE(impl), + &impl->geometry_hints, + impl->geometry_mask); + gtk_surface1_add_listener (impl->gtk_surface, + >k_surface_listener, + impl); +} + +static void +maybe_set_gtk_surface_modal (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + gdk_wayland_surface_init_gtk_surface (impl); + if (impl->gtk_surface == NULL) + return; + + if (surface->modal_hint) + gtk_surface1_set_modal (impl->gtk_surface); + else + gtk_surface1_unset_modal (impl->gtk_surface); + +} + +static void +gdk_wayland_surface_set_modal_hint (GdkSurface *surface, + gboolean modal) +{ + surface->modal_hint = modal; + maybe_set_gtk_surface_modal (surface); +} + +static void +gdk_wayland_surface_set_geometry_hints (GdkWaylandSurface *surface, + const GdkGeometry *geometry, + GdkSurfaceHints geom_mask) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL(surface); + GdkWaylandDisplay *display_wayland; + int min_width, min_height; + int max_width, max_height; + + if (GDK_SURFACE_DESTROYED (impl) || + !SURFACE_IS_TOPLEVEL (impl)) + return; + + display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (impl))); + + impl->geometry_hints = *geometry; + impl->geometry_mask = geom_mask; + + if (!is_realized_toplevel (impl)) + return; + + if (geom_mask & GDK_HINT_MIN_SIZE) + { + min_width = MAX (0, (geometry->min_width - + (impl->shadow_left + impl->shadow_right))); + min_height = MAX (0, (geometry->min_height - + (impl->shadow_top + impl->shadow_bottom))); + } + else + { + min_width = 0; + min_height = 0; + } + + if (geom_mask & GDK_HINT_MAX_SIZE) + { + max_width = MAX (0, (geometry->max_width - + (impl->shadow_left + impl->shadow_right))); + max_height = MAX (0, (geometry->max_height - + (impl->shadow_top + impl->shadow_bottom))); + } + else + { + max_width = 0; + max_height = 0; + } + + if (impl->last_sent_min_width == min_width && + impl->last_sent_min_height == min_height && + impl->last_sent_max_width == max_width && + impl->last_sent_max_height == max_height) + return; + + switch (display_wayland->shell_variant) + { + case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: + xdg_toplevel_set_min_size (impl->xdg_toplevel, + min_width, min_height); + xdg_toplevel_set_max_size (impl->xdg_toplevel, + max_width, max_height); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_set_min_size (impl->zxdg_toplevel_v6, + min_width, min_height); + zxdg_toplevel_v6_set_max_size (impl->zxdg_toplevel_v6, + max_width, max_height); + break; + default: + g_assert_not_reached (); + } + + impl->last_sent_min_width = min_width; + impl->last_sent_min_height = min_height; + impl->last_sent_max_width = max_width; + impl->last_sent_max_height = max_height; +} + +static void +gdk_wayland_toplevel_set_title (GdkSurface *surface, + const char *title) +{ + GdkWaylandToplevel *impl; + const char *end; + gsize title_length; + + g_return_if_fail (title != NULL); + + if (GDK_SURFACE_DESTROYED (surface)) + return; + + impl = GDK_WAYLAND_TOPLEVEL (surface); + + if (g_strcmp0 (impl->title, title) == 0) + return; + + g_free (impl->title); + + title_length = MIN (strlen (title), MAX_WL_BUFFER_SIZE); + if (g_utf8_validate (title, title_length, &end)) + { + impl->title = g_malloc (end - title + 1); + memcpy (impl->title, title, end - title); + impl->title[end - title] = '\0'; + } + else + { + impl->title = g_utf8_make_valid (title, title_length); + g_warning ("Invalid utf8 passed to gdk_surface_set_title: '%s'", title); + } + + gdk_wayland_surface_sync_title (surface); +} + +static void +gdk_wayland_surface_set_startup_id (GdkSurface *surface, + const char *startup_id) +{ +} + +static gboolean +check_transient_for_loop (GdkWaylandToplevel *toplevel, + GdkWaylandToplevel *parent) +{ + while (parent) + { + if (parent->transient_for == toplevel) + return TRUE; + parent = parent->transient_for; + } + return FALSE; +} + +static void +gdk_wayland_toplevel_set_transient_for (GdkWaylandToplevel *toplevel, + GdkSurface *parent) +{ + g_return_if_fail (!parent || GDK_IS_WAYLAND_TOPLEVEL (parent)); + g_return_if_fail (!parent || + gdk_surface_get_display (GDK_SURFACE (toplevel)) == gdk_surface_get_display (parent)); + + if (parent) + { + GdkWaylandToplevel *parent_toplevel = GDK_WAYLAND_TOPLEVEL (parent); + + if (check_transient_for_loop (toplevel, parent_toplevel)) + { + g_warning ("Setting %p transient for %p would create a loop", + toplevel, parent); + return; + } + } + + unset_transient_for_exported (GDK_SURFACE (toplevel)); + + if (parent) + toplevel->transient_for = GDK_WAYLAND_TOPLEVEL (parent); + else + toplevel->transient_for = NULL; + + gdk_wayland_surface_sync_parent (GDK_SURFACE (toplevel), NULL); +} + +static void +gdk_wayland_surface_minimize (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + GdkWaylandDisplay *display_wayland; + + if (GDK_SURFACE_DESTROYED (surface) || + !SURFACE_IS_TOPLEVEL (surface)) + return; + + if (!is_realized_toplevel (impl)) + return; + + /* 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 (impl->xdg_toplevel); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_set_minimized (impl->zxdg_toplevel_v6); + break; + default: + g_assert_not_reached (); + } +} + +static void +gdk_wayland_surface_maximize (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + if (GDK_SURFACE_DESTROYED (surface)) + return; + + _gdk_wayland_surface_save_size (surface); + + if (is_realized_toplevel (impl)) + { + GdkWaylandDisplay *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_maximized (impl->xdg_toplevel); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_set_maximized (impl->zxdg_toplevel_v6); + break; + default: + g_assert_not_reached (); + } + } + else + { + synthesize_initial_surface_state (surface, 0, GDK_TOPLEVEL_STATE_MAXIMIZED); + } +} + +static void +gdk_wayland_surface_unmaximize (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + if (GDK_SURFACE_DESTROYED (surface)) + return; + + if (is_realized_toplevel (impl)) + { + GdkWaylandDisplay *display_wayland = + GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + + switch (display_wayland->shell_variant) + { + case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: + xdg_toplevel_unset_maximized (impl->xdg_toplevel); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_unset_maximized (impl->zxdg_toplevel_v6); + break; + default: + g_assert_not_reached (); + } + } + else + { + synthesize_initial_surface_state (surface, GDK_TOPLEVEL_STATE_MAXIMIZED, 0); + } +} + +static void +gdk_wayland_surface_fullscreen_on_monitor (GdkSurface *surface, + GdkMonitor *monitor) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + struct wl_output *output = ((GdkWaylandMonitor *)monitor)->output; + + if (GDK_SURFACE_DESTROYED (surface)) + return; + + _gdk_wayland_surface_save_size (surface); + + if (is_realized_toplevel (impl)) + { + GdkWaylandDisplay *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_fullscreen (impl->xdg_toplevel, + output); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_set_fullscreen (impl->zxdg_toplevel_v6, + output); + break; + default: + g_assert_not_reached (); + } + } + else + { + synthesize_initial_surface_state (surface, 0, GDK_TOPLEVEL_STATE_FULLSCREEN); + impl->initial_fullscreen_output = output; + } +} + +static void +gdk_wayland_surface_fullscreen (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + if (GDK_SURFACE_DESTROYED (surface)) + return; + + impl->initial_fullscreen_output = NULL; + + _gdk_wayland_surface_save_size (surface); + + if (is_realized_toplevel (impl)) + { + GdkWaylandDisplay *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_fullscreen (impl->xdg_toplevel, + NULL); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_set_fullscreen (impl->zxdg_toplevel_v6, + NULL); + break; + default: + g_assert_not_reached (); + } + } + else + { + synthesize_initial_surface_state (surface, 0, GDK_TOPLEVEL_STATE_FULLSCREEN); + } +} + +static void +gdk_wayland_surface_unfullscreen (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + if (GDK_SURFACE_DESTROYED (surface)) + return; + + impl->initial_fullscreen_output = NULL; + + if (is_realized_toplevel (impl)) + { + GdkWaylandDisplay *display_wayland = + GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + + switch (display_wayland->shell_variant) + { + case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: + xdg_toplevel_unset_fullscreen (impl->xdg_toplevel); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_unset_fullscreen (impl->zxdg_toplevel_v6); + break; + default: + g_assert_not_reached (); + } + } + else + { + synthesize_initial_surface_state (surface, 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); + GdkWaylandToplevel *impl; + GdkWaylandDisplay *display_wayland; + GdkEventSequence *sequence; + uint32_t resize_edges, serial; + + if (GDK_SURFACE_DESTROYED (surface) || + !SURFACE_IS_TOPLEVEL (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_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 (impl->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 (impl->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); + GdkWaylandToplevel *impl; + GdkWaylandDisplay *display_wayland; + GdkEventSequence *sequence; + uint32_t serial; + + if (GDK_SURFACE_DESTROYED (surface) || + !SURFACE_IS_TOPLEVEL (surface)) + return; + + impl = 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 (impl->xdg_toplevel, + gdk_wayland_device_get_wl_seat (device), + serial); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_move (impl->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 gboolean +gdk_wayland_surface_show_window_menu (GdkSurface *surface, + GdkEvent *event) +{ + GdkWaylandToplevel *impl = 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; + + seat = gdk_event_get_seat (event); + wl_seat = gdk_wayland_seat_get_wl_seat (seat); + gdk_event_get_position (event, &x, &y); + + serial = _gdk_wayland_seat_get_implicit_grab_serial (seat, event); + + switch (display_wayland->shell_variant) + { + case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL: + xdg_toplevel_show_window_menu (impl->xdg_toplevel, + wl_seat, serial, x, y); + break; + case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6: + zxdg_toplevel_v6_show_window_menu (impl->zxdg_toplevel_v6, + wl_seat, serial, x, y); + break; + default: + g_assert_not_reached (); + } + + return TRUE; +} + +static gboolean +gdk_wayland_surface_supports_edge_constraints (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + struct gtk_surface1 *gtk_surface = impl->gtk_surface; + + if (!gtk_surface) + return FALSE; + + return gtk_surface1_get_version (gtk_surface) >= GTK_SURFACE1_CONFIGURE_EDGES_SINCE_VERSION; +} + +struct gtk_surface1 * +gdk_wayland_surface_get_gtk_surface (GdkSurface *surface) +{ + g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (surface), NULL); + + return GDK_WAYLAND_TOPLEVEL (surface)->gtk_surface; +} + +static void +maybe_set_gtk_surface_dbus_properties (GdkWaylandToplevel *impl) +{ + if (impl->application.was_set) + return; + + if (impl->application.application_id == NULL && + impl->application.app_menu_path == NULL && + impl->application.menubar_path == NULL && + impl->application.window_object_path == NULL && + impl->application.application_object_path == NULL && + impl->application.unique_bus_name == NULL) + return; + + gdk_wayland_surface_init_gtk_surface (impl); + if (impl->gtk_surface == NULL) + return; + + gtk_surface1_set_dbus_properties (impl->gtk_surface, + impl->application.application_id, + impl->application.app_menu_path, + impl->application.menubar_path, + impl->application.window_object_path, + impl->application.application_object_path, + impl->application.unique_bus_name); + impl->application.was_set = TRUE; +} + +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 *impl; + + g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); + + impl = GDK_WAYLAND_TOPLEVEL (toplevel); + + impl->application.application_id = g_strdup (application_id); + impl->application.app_menu_path = g_strdup (app_menu_path); + impl->application.menubar_path = g_strdup (menubar_path); + impl->application.window_object_path = g_strdup (window_object_path); + impl->application.application_object_path = + g_strdup (application_object_path); + impl->application.unique_bus_name = g_strdup (unique_bus_name); + + maybe_set_gtk_surface_dbus_properties (impl); +} + +static void +xdg_exported_handle (void *data, + struct zxdg_exported_v1 *zxdg_exported_v1, + const char *handle) +{ + GdkToplevel *toplevel = data; + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (toplevel); + + impl->exported.callback (toplevel, handle, impl->exported.user_data); + if (impl->exported.destroy_func) + { + g_clear_pointer (&impl->exported.user_data, + impl->exported.destroy_func); + } +} + +static const struct zxdg_exported_v1_listener xdg_exported_listener = { + xdg_exported_handle +}; + +/** + * 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_surface_is_exported (GdkWaylandToplevel *impl) +{ + return !!impl->xdg_exported; +} + +/** + * 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@GdkWaylandToplevel.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) +{ + GdkWaylandToplevel *impl; + GdkWaylandDisplay *display_wayland; + GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel)); + struct zxdg_exported_v1 *xdg_exported; + + g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE); + g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE); + + impl = GDK_WAYLAND_TOPLEVEL (toplevel); + display_wayland = GDK_WAYLAND_DISPLAY (display); + + g_return_val_if_fail (!impl->xdg_exported, FALSE); + + if (!display_wayland->xdg_exporter) + { + g_warning ("Server is missing xdg_foreign support"); + return FALSE; + } + + xdg_exported = zxdg_exporter_v1_export (display_wayland->xdg_exporter, + gdk_wayland_surface_get_wl_surface (GDK_SURFACE (impl))); + zxdg_exported_v1_add_listener (xdg_exported, &xdg_exported_listener, impl); + + impl->xdg_exported = xdg_exported; + impl->exported.callback = callback; + impl->exported.user_data = user_data; + impl->exported.destroy_func = destroy_func; + + return TRUE; +} + +/** + * 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) +{ + GdkWaylandToplevel *impl; + + g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); + + impl = GDK_WAYLAND_TOPLEVEL (toplevel); + + g_return_if_fail (impl->xdg_exported); + + g_clear_pointer (&impl->xdg_exported, + zxdg_exported_v1_destroy); + if (impl->exported.destroy_func) + { + g_clear_pointer (&impl->exported.user_data, + impl->exported.destroy_func); + } +} + +static void +unset_transient_for_exported (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + g_clear_pointer (&impl->imported_transient_for, zxdg_imported_v1_destroy); +} + + +static void +xdg_imported_destroyed (void *data, + struct zxdg_imported_v1 *zxdg_imported_v1) +{ + GdkSurface *surface = data; + + unset_transient_for_exported (surface); +} + +static const struct zxdg_imported_v1_listener xdg_imported_listener = { + xdg_imported_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 gdk_wayland_toplevel_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 *impl; + GdkWaylandDisplay *display_wayland; + GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel)); + + g_return_val_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel), FALSE); + g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE); + + impl = GDK_WAYLAND_TOPLEVEL (toplevel); + display_wayland = GDK_WAYLAND_DISPLAY (display); + + if (!display_wayland->xdg_importer) + { + g_warning ("Server is missing xdg_foreign support"); + return FALSE; + } + + gdk_wayland_toplevel_set_transient_for (GDK_WAYLAND_TOPLEVEL (impl), NULL); + + impl->imported_transient_for = + zxdg_importer_v1_import (display_wayland->xdg_importer, parent_handle_str); + zxdg_imported_v1_add_listener (impl->imported_transient_for, + &xdg_imported_listener, + toplevel); + + gdk_wayland_surface_sync_parent_of_imported (impl); + + return TRUE; +} + +static void +gdk_wayland_toplevel_init (GdkWaylandToplevel *impl) +{ + impl->initial_fullscreen_output = NULL; + impl->saved_width = -1; + impl->saved_height = -1; + + gdk_wayland_toplevel_set_title (GDK_SURFACE (impl), get_default_title ()); +} + +#define LAST_PROP 1 + +static void +gdk_wayland_toplevel_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + 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 (surface, 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; + + 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; + + case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL: + gdk_wayland_surface_set_modal_hint (surface, g_value_get_boolean (value)); + g_object_notify_by_pspec (G_OBJECT (surface), 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 (G_OBJECT (surface), pspec); + break; + + case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED: + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gdk_wayland_toplevel_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdkSurface *surface = GDK_SURFACE (object); + GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface); + GdkWaylandToplevel *toplevel = GDK_WAYLAND_TOPLEVEL (surface); + + switch (prop_id) + { + case LAST_PROP + GDK_TOPLEVEL_PROP_STATE: + g_value_set_flags (value, surface->state); + break; + + case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE: + g_value_set_string (value, GDK_WAYLAND_TOPLEVEL(impl)->title); + break; + + case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID: + g_value_set_string (value, ""); + break; + + 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_class_init (GdkWaylandToplevelClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GdkSurfaceClass *surface_class = GDK_SURFACE_CLASS (class); + GdkWaylandSurfaceClass *wayland_surface_class = GDK_WAYLAND_SURFACE_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; + + surface_class->request_layout = gdk_wayland_toplevel_request_layout; + surface_class->compute_size = gdk_wayland_toplevel_compute_size; + surface_class->hide = gdk_wayland_toplevel_hide; + + wayland_surface_class->sync = gdk_wayland_toplevel_sync; + wayland_surface_class->get_window_geometry = gdk_wayland_toplevel_get_window_geometry; + wayland_surface_class->configure_surface = gdk_wayland_surface_configure_toplevel; + + gdk_toplevel_install_properties (object_class, 1); +} + +static void +gdk_wayland_surface_map_toplevel (GdkSurface *surface) +{ + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + if (impl->mapped) + return; + + gdk_wayland_surface_create_xdg_toplevel (surface); + + impl->mapped = TRUE; +} + +static void +gdk_wayland_toplevel_hide (GdkSurface *surface) { + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface)); + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + + GDK_SURFACE_CLASS (gdk_wayland_toplevel_parent_class)->hide (surface); + + if (impl->xdg_toplevel) + { + xdg_toplevel_destroy (impl->xdg_toplevel); + impl->xdg_toplevel = NULL; + } + if (impl->zxdg_toplevel_v6) + { + zxdg_toplevel_v6_destroy (impl->zxdg_toplevel_v6); + impl->zxdg_toplevel_v6 = NULL; + } + if (impl->gtk_surface) + { + if (display_wayland->gtk_shell_version >= + GTK_SURFACE1_RELEASE_SINCE_VERSION) + gtk_surface1_release (impl->gtk_surface); + else + gtk_surface1_destroy (impl->gtk_surface); + impl->gtk_surface = NULL; + impl->application.was_set = FALSE; + } + + gdk_wayland_surface_clear_saved_size (surface); + + impl->last_sent_min_width = 0; + impl->last_sent_min_height = 0; + impl->last_sent_max_width = 0; + impl->last_sent_max_height = 0; + + g_clear_pointer (&impl->layout, gdk_toplevel_layout_unref); + + unset_transient_for_exported (surface); + impl->mapped = FALSE; +} + +static void +gdk_wayland_toplevel_present (GdkToplevel *toplevel, + GdkToplevelLayout *layout) +{ + GdkSurface *surface = GDK_SURFACE (toplevel); + GdkWaylandToplevel *impl = GDK_WAYLAND_TOPLEVEL (surface); + gboolean pending_configure = FALSE; + gboolean maximize; + gboolean fullscreen; + + if (gdk_toplevel_layout_get_maximized (layout, &maximize)) + { + if (maximize) + gdk_wayland_surface_maximize (surface); + else + gdk_wayland_surface_unmaximize (surface); + pending_configure = TRUE; + } + + if (gdk_toplevel_layout_get_fullscreen (layout, &fullscreen)) + { + if (fullscreen) + { + GdkMonitor *monitor; + + monitor = gdk_toplevel_layout_get_fullscreen_monitor (layout); + if (monitor) + gdk_wayland_surface_fullscreen_on_monitor (surface, monitor); + else + gdk_wayland_surface_fullscreen (surface); + } + else + { + gdk_wayland_surface_unfullscreen (surface); + } + pending_configure = TRUE; + } + + g_clear_pointer (&impl->layout, gdk_toplevel_layout_unref); + impl->layout = gdk_toplevel_layout_copy (layout); + + gdk_wayland_surface_show (surface, FALSE); + gdk_wayland_surface_map_toplevel (surface); + + if (!pending_configure) + { + gdk_surface_request_layout (surface); + } +} + +static gboolean +gdk_wayland_toplevel_minimize (GdkToplevel *toplevel) +{ + gdk_wayland_surface_minimize (GDK_SURFACE (toplevel)); + + return TRUE; +} + +static gboolean +gdk_wayland_toplevel_lower (GdkToplevel *toplevel) +{ + return FALSE; +} + +static void +gdk_wayland_toplevel_focus (GdkToplevel *toplevel, + guint32 timestamp) +{ + gdk_wayland_surface_focus (GDK_SURFACE (toplevel), timestamp); +} + +static gboolean +gdk_wayland_toplevel_show_window_menu (GdkToplevel *toplevel, + GdkEvent *event) +{ + return gdk_wayland_surface_show_window_menu (GDK_SURFACE (toplevel), event); +} + +static gboolean +gdk_wayland_toplevel_supports_edge_constraints (GdkToplevel *toplevel) +{ + return gdk_wayland_surface_supports_edge_constraints (GDK_SURFACE (toplevel)); +} + +static void +inhibitor_active (void *data, + struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor) +{ + GdkToplevel *toplevel = GDK_TOPLEVEL (data); + GdkSurface *surface = GDK_SURFACE (toplevel); + + surface->shortcuts_inhibited = TRUE; + g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited"); +} + +static void +inhibitor_inactive (void *data, + struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor) +{ + GdkToplevel *toplevel = GDK_TOPLEVEL (data); + GdkSurface *surface = GDK_SURFACE (toplevel); + + surface->shortcuts_inhibited = FALSE; + g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited"); +} + +static const struct zwp_keyboard_shortcuts_inhibitor_v1_listener +zwp_keyboard_shortcuts_inhibitor_listener = { + inhibitor_active, + inhibitor_inactive, +}; + +static void +gdk_wayland_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel, + GdkEvent *event) +{ + struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor; + GdkSurface *surface = GDK_SURFACE (toplevel); + GdkWaylandSurface *impl= GDK_WAYLAND_SURFACE (surface); + GdkSeat *gdk_seat; + + if (surface->shortcuts_inhibited) + return; + + gdk_seat = gdk_surface_get_seat_from_event (surface, event); + gdk_wayland_surface_inhibit_shortcuts (surface, gdk_seat); + + inhibitor = gdk_wayland_surface_get_inhibitor (impl, gdk_seat); + if (!inhibitor) + return; + + surface->current_shortcuts_inhibited_seat = gdk_seat; + zwp_keyboard_shortcuts_inhibitor_v1_add_listener + (inhibitor, &zwp_keyboard_shortcuts_inhibitor_listener, toplevel); +} + +static void +gdk_wayland_toplevel_restore_system_shortcuts (GdkToplevel *toplevel) +{ + GdkSurface *surface = GDK_SURFACE (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"); +} + +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->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; +} diff --git a/gdk/wayland/gdkwayland.h b/gdk/wayland/gdkwayland.h index 4e7981a229acc855bac793bc0c8eb80db51d6422..5fb89e8d0f5ba4baed5dc1abeefcc9a469462cb3 100644 --- a/gdk/wayland/gdkwayland.h +++ b/gdk/wayland/gdkwayland.h @@ -35,6 +35,7 @@ #include #include #include +#include #undef __GDKWAYLAND_H_INSIDE__ diff --git a/gdk/wayland/gdkwaylandsurface.h b/gdk/wayland/gdkwaylandsurface.h index 851a4d5607fea1cdfde191a7fe7b5c351f8f5d1f..c94a3cbd16cb50e4b786ff2133b5f5f3f1aab2af 100644 --- a/gdk/wayland/gdkwaylandsurface.h +++ b/gdk/wayland/gdkwaylandsurface.h @@ -30,11 +30,9 @@ G_BEGIN_DECLS #ifdef GTK_COMPILATION typedef struct _GdkWaylandSurface GdkWaylandSurface; -typedef struct _GdkWaylandToplevel GdkWaylandToplevel; typedef struct _GdkWaylandPopup GdkWaylandPopup; #else typedef GdkSurface GdkWaylandSurface; -typedef GdkToplevel GdkWaylandToplevel; typedef GdkPopup GdkWaylandPopup; #endif @@ -42,10 +40,6 @@ typedef GdkPopup GdkWaylandPopup; #define GDK_WAYLAND_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_SURFACE, GdkWaylandSurface)) #define GDK_IS_WAYLAND_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_SURFACE)) -#define GDK_TYPE_WAYLAND_TOPLEVEL (gdk_wayland_toplevel_get_type()) -#define GDK_WAYLAND_TOPLEVEL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_TOPLEVEL, GdkWaylandToplevel)) -#define GDK_IS_WAYLAND_TOPLEVEL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_TOPLEVEL)) - #define GDK_TYPE_WAYLAND_POPUP (gdk_wayland_popup_get_type()) #define GDK_WAYLAND_POPUP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_POPUP, GdkWaylandPopup)) #define GDK_IS_WAYLAND_POPUP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_POPUP)) @@ -53,36 +47,12 @@ typedef GdkPopup GdkWaylandPopup; GDK_AVAILABLE_IN_ALL GType gdk_wayland_surface_get_type (void); -GDK_AVAILABLE_IN_ALL -GType gdk_wayland_toplevel_get_type (void); - GDK_AVAILABLE_IN_ALL GType gdk_wayland_popup_get_type (void); GDK_AVAILABLE_IN_ALL struct wl_surface *gdk_wayland_surface_get_wl_surface (GdkSurface *surface); -typedef void (*GdkWaylandToplevelExported) (GdkToplevel *toplevel, - const char *handle, - gpointer user_data); - -GDK_AVAILABLE_IN_ALL -gboolean gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel, - GdkWaylandToplevelExported callback, - gpointer user_data, - GDestroyNotify destroy_func); - -GDK_AVAILABLE_IN_ALL -void gdk_wayland_toplevel_unexport_handle (GdkToplevel *toplevel); - -GDK_AVAILABLE_IN_ALL -gboolean gdk_wayland_toplevel_set_transient_for_exported (GdkToplevel *toplevel, - const char *parent_handle_str); - -GDK_AVAILABLE_IN_ALL -void gdk_wayland_toplevel_set_application_id (GdkToplevel *toplevel, - const char *application_id); - G_END_DECLS #endif /* __GDK_WAYLAND_SURFACE_H__ */ diff --git a/gdk/wayland/gdkwaylandtoplevel.h b/gdk/wayland/gdkwaylandtoplevel.h new file mode 100644 index 0000000000000000000000000000000000000000..0d0c6a353bb11736148fb9490eee8408fa1149b2 --- /dev/null +++ b/gdk/wayland/gdkwaylandtoplevel.h @@ -0,0 +1,67 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2013 Jan Arne Petersen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __GDK_WAYLAND_TOPLEVEL_H__ +#define __GDK_WAYLAND_TOPLEVEL_H__ + +#if !defined (__GDKWAYLAND_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +#include + +G_BEGIN_DECLS + +#ifdef GTK_COMPILATION +typedef struct _GdkWaylandToplevel GdkWaylandToplevel; +#else +typedef GdkToplevel GdkWaylandToplevel; +#endif + +#define GDK_TYPE_WAYLAND_TOPLEVEL (gdk_wayland_toplevel_get_type()) +#define GDK_WAYLAND_TOPLEVEL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_TOPLEVEL, GdkWaylandToplevel)) +#define GDK_IS_WAYLAND_TOPLEVEL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_TOPLEVEL)) + +GDK_AVAILABLE_IN_ALL +GType gdk_wayland_toplevel_get_type (void); + +typedef void (*GdkWaylandToplevelExported) (GdkToplevel *toplevel, + const char *handle, + gpointer user_data); + +GDK_AVAILABLE_IN_ALL +gboolean gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel, + GdkWaylandToplevelExported callback, + gpointer user_data, + GDestroyNotify destroy_func); + +GDK_AVAILABLE_IN_ALL +void gdk_wayland_toplevel_unexport_handle (GdkToplevel *toplevel); + +GDK_AVAILABLE_IN_ALL +gboolean gdk_wayland_toplevel_set_transient_for_exported (GdkToplevel *toplevel, + const char *parent_handle_str); + +GDK_AVAILABLE_IN_ALL +void gdk_wayland_toplevel_set_application_id (GdkToplevel *toplevel, + const char *application_id); + +G_END_DECLS + +#endif /* __GDK_WAYLAND_TOPLEVEL_H__ */ diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build index 28a00a959b6d252b1078c7bfd1bf2c1146346209..5a30e5cd0d75e920756ac311be9e2526a80f5b1e 100644 --- a/gdk/wayland/meson.build +++ b/gdk/wayland/meson.build @@ -17,6 +17,7 @@ gdk_wayland_sources = files([ 'gdkvulkancontext-wayland.c', 'gdksurface-wayland.c', 'wm-button-layout-translation.c', + 'gdktoplevel-wayland.c', ]) gdk_wayland_public_headers = files([