wayland: Don't destroy the wl_surface on hide()

We want to keep the wl_surface around, because surfaces create their
resources on construct and keep them until destroyed. See the HWND ond
Windows and the XWindow on X11.

This is relevant for graphics resources, where we want to have access
to the VkSurface and eglSurface while the GdkSurface is hidden.
We also want these surfaces to be permanent and not change during the
lifetime of the GdkSurface.

What we can - and must - destroy however are the xdg surfaces, because
those handle visibility on screen.
And we also need to ensure no buffer is attached, so that during the
next creation of the xdg surface we don't get a protocol error.
This commit is contained in:
Benjamin Otte 2023-04-13 03:33:59 +02:00
parent 891242920e
commit 5d3cec5441
5 changed files with 136 additions and 150 deletions

View File

@ -127,9 +127,6 @@ gdk_wayland_drag_surface_present (GdkDragSurface *drag_surface,
GdkSurface *surface = GDK_SURFACE (drag_surface);
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
if (!impl->display_server.wl_surface)
gdk_wayland_surface_create_wl_surface (surface);
impl->next_layout.configured_width = width;
impl->next_layout.configured_height = height;
impl->next_layout.surface_geometry_dirty = TRUE;

View File

@ -1289,11 +1289,6 @@ show_popup (GdkWaylandPopup *wayland_popup,
int height,
GdkPopupLayout *layout)
{
GdkWaylandSurface *wayland_surface = GDK_WAYLAND_SURFACE (wayland_popup);
if (!wayland_surface->display_server.wl_surface)
gdk_wayland_surface_create_wl_surface (GDK_SURFACE (wayland_popup));
if (wayland_popup->thaw_upon_show)
{
wayland_popup->thaw_upon_show = FALSE;

View File

@ -104,7 +104,6 @@ struct _GdkWaylandSurfaceClass
#define GDK_WAYLAND_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WAYLAND_SURFACE, GdkWaylandSurfaceClass))
void gdk_wayland_surface_create_wl_surface (GdkSurface *surface);
void gdk_wayland_surface_update_size (GdkSurface *surface,
int32_t width,
int32_t height,

View File

@ -481,102 +481,6 @@ gdk_wayland_surface_update_scale (GdkSurface *surface)
&GDK_FRACTIONAL_SCALE_INIT_INT (scale));
}
GdkSurface *
_gdk_wayland_display_create_surface (GdkDisplay *display,
GdkSurfaceType surface_type,
GdkSurface *parent,
int x,
int y,
int width,
int height)
{
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
GdkSurface *surface;
GdkFrameClock *frame_clock;
if (parent)
frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
else
frame_clock = _gdk_frame_clock_idle_new ();
switch (surface_type)
{
case GDK_SURFACE_TOPLEVEL:
g_warn_if_fail (parent == NULL);
surface = g_object_new (GDK_TYPE_WAYLAND_TOPLEVEL,
"display", display,
"frame-clock", frame_clock,
"title", get_default_title (),
NULL);
display_wayland->toplevels = g_list_prepend (display_wayland->toplevels, surface);
break;
case GDK_SURFACE_POPUP:
g_warn_if_fail (parent != NULL);
surface = g_object_new (GDK_TYPE_WAYLAND_POPUP,
"parent", parent,
"display", display,
"frame-clock", frame_clock,
NULL);
break;
case GDK_SURFACE_DRAG:
g_warn_if_fail (parent == NULL);
surface = g_object_new (GDK_TYPE_WAYLAND_DRAG_SURFACE,
"display", display,
"frame-clock", frame_clock,
NULL);
break;
default:
g_assert_not_reached ();
break;
}
if (width > 65535)
{
g_warning ("Native Surfaces wider than 65535 pixels are not supported");
width = 65535;
}
if (height > 65535)
{
g_warning ("Native Surfaces taller than 65535 pixels are not supported");
height = 65535;
}
surface->x = x;
surface->y = y;
surface->width = width;
surface->height = height;
g_object_ref (surface);
/* More likely to be right than just assuming 1 */
if (wl_compositor_get_version (display_wayland->compositor) >= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
{
GdkMonitor *monitor = g_list_model_get_item (gdk_display_get_monitors (display), 0);
if (monitor)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
guint32 monitor_scale = gdk_monitor_get_scale_factor (monitor);
if (monitor_scale != 1)
{
impl->scale = GDK_FRACTIONAL_SCALE_INIT_INT (monitor_scale);
impl->buffer_scale_dirty = TRUE;
}
g_object_unref (monitor);
}
}
gdk_wayland_surface_create_wl_surface (surface);
g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), surface);
g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), surface);
g_object_unref (frame_clock);
return surface;
}
void
gdk_wayland_surface_attach_image (GdkSurface *surface,
cairo_surface_t *cairo_surface,
@ -883,7 +787,7 @@ static const struct wl_surface_listener surface_listener = {
surface_leave
};
void
static void
gdk_wayland_surface_create_wl_surface (GdkSurface *surface)
{
GdkWaylandSurface *self = GDK_WAYLAND_SURFACE (surface);
@ -921,6 +825,102 @@ gdk_wayland_surface_destroy_wl_surface (GdkWaylandSurface *self)
g_clear_pointer (&self->display_server.outputs, g_slist_free);
}
GdkSurface *
_gdk_wayland_display_create_surface (GdkDisplay *display,
GdkSurfaceType surface_type,
GdkSurface *parent,
int x,
int y,
int width,
int height)
{
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
GdkSurface *surface;
GdkFrameClock *frame_clock;
if (parent)
frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
else
frame_clock = _gdk_frame_clock_idle_new ();
switch (surface_type)
{
case GDK_SURFACE_TOPLEVEL:
g_warn_if_fail (parent == NULL);
surface = g_object_new (GDK_TYPE_WAYLAND_TOPLEVEL,
"display", display,
"frame-clock", frame_clock,
"title", get_default_title (),
NULL);
display_wayland->toplevels = g_list_prepend (display_wayland->toplevels, surface);
break;
case GDK_SURFACE_POPUP:
g_warn_if_fail (parent != NULL);
surface = g_object_new (GDK_TYPE_WAYLAND_POPUP,
"parent", parent,
"display", display,
"frame-clock", frame_clock,
NULL);
break;
case GDK_SURFACE_DRAG:
g_warn_if_fail (parent == NULL);
surface = g_object_new (GDK_TYPE_WAYLAND_DRAG_SURFACE,
"display", display,
"frame-clock", frame_clock,
NULL);
break;
default:
g_assert_not_reached ();
break;
}
if (width > 65535)
{
g_warning ("Native Surfaces wider than 65535 pixels are not supported");
width = 65535;
}
if (height > 65535)
{
g_warning ("Native Surfaces taller than 65535 pixels are not supported");
height = 65535;
}
surface->x = x;
surface->y = y;
surface->width = width;
surface->height = height;
g_object_ref (surface);
/* More likely to be right than just assuming 1 */
if (wl_compositor_get_version (display_wayland->compositor) >= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
{
GdkMonitor *monitor = g_list_model_get_item (gdk_display_get_monitors (display), 0);
if (monitor)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
guint32 monitor_scale = gdk_monitor_get_scale_factor (monitor);
if (monitor_scale != 1)
{
impl->scale = GDK_FRACTIONAL_SCALE_INIT_INT (monitor_scale);
impl->buffer_scale_dirty = TRUE;
}
g_object_unref (monitor);
}
}
gdk_wayland_surface_create_wl_surface (surface);
g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), surface);
g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), surface);
g_object_unref (frame_clock);
return surface;
}
static void
maybe_notify_mapped (GdkSurface *surface)
{
@ -1048,53 +1048,49 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
if (!impl->mapped)
return;
unmap_popups_for_surface (surface);
if (impl->display_server.wl_surface)
if (impl->display_server.egl_window)
{
if (impl->display_server.egl_window)
{
gdk_surface_set_egl_native_window (surface, NULL);
wl_egl_window_destroy (impl->display_server.egl_window);
impl->display_server.egl_window = NULL;
}
impl->awaiting_frame = FALSE;
if (impl->awaiting_frame_frozen)
{
impl->awaiting_frame_frozen = FALSE;
gdk_surface_thaw_updates (surface);
}
GDK_WAYLAND_SURFACE_GET_CLASS (impl)->hide_surface (impl);
if (impl->display_server.xdg_surface)
{
xdg_surface_destroy (impl->display_server.xdg_surface);
impl->display_server.xdg_surface = NULL;
if (!impl->initial_configure_received)
gdk_surface_thaw_updates (surface);
else
impl->initial_configure_received = FALSE;
}
if (impl->display_server.zxdg_surface_v6)
{
g_clear_pointer (&impl->display_server.zxdg_surface_v6, zxdg_surface_v6_destroy);
if (!impl->initial_configure_received)
gdk_surface_thaw_updates (surface);
else
impl->initial_configure_received = FALSE;
}
gdk_wayland_surface_destroy_wl_surface (impl);
gdk_surface_set_egl_native_window (surface, NULL);
wl_egl_window_destroy (impl->display_server.egl_window);
impl->display_server.egl_window = NULL;
}
impl->awaiting_frame = FALSE;
if (impl->awaiting_frame_frozen)
{
impl->awaiting_frame_frozen = FALSE;
gdk_surface_thaw_updates (surface);
}
GDK_WAYLAND_SURFACE_GET_CLASS (impl)->hide_surface (impl);
if (impl->display_server.xdg_surface)
{
xdg_surface_destroy (impl->display_server.xdg_surface);
impl->display_server.xdg_surface = NULL;
if (!impl->initial_configure_received)
gdk_surface_thaw_updates (surface);
else
impl->initial_configure_received = FALSE;
}
if (impl->display_server.zxdg_surface_v6)
{
g_clear_pointer (&impl->display_server.zxdg_surface_v6, zxdg_surface_v6_destroy);
if (!impl->initial_configure_received)
gdk_surface_thaw_updates (surface);
else
impl->initial_configure_received = FALSE;
}
wl_surface_attach (impl->display_server.wl_surface, NULL, 0, 0);
wl_surface_commit (impl->display_server.wl_surface);
impl->has_uncommitted_ack_configure = FALSE;
impl->input_region_dirty = TRUE;
impl->opaque_region_dirty = TRUE;
impl->viewport_dirty = TRUE;
if (!gdk_fractional_scale_equal (&impl->scale, &GDK_FRACTIONAL_SCALE_INIT_INT (1)))
impl->buffer_scale_dirty = TRUE;
impl->last_sent_window_geometry = (GdkRectangle) { 0 };
impl->mapped = FALSE;
@ -1235,6 +1231,8 @@ gdk_wayland_surface_destroy (GdkSurface *surface,
gdk_wayland_surface_hide_surface (surface);
gdk_wayland_surface_destroy_wl_surface (GDK_WAYLAND_SURFACE(surface));
frame_clock = gdk_surface_get_frame_clock (surface);
g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface);
g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_after_paint, surface);

View File

@ -1526,9 +1526,6 @@ gdk_wayland_toplevel_show (GdkWaylandToplevel *toplevel)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (toplevel);
if (!impl->display_server.wl_surface)
gdk_wayland_surface_create_wl_surface (GDK_SURFACE (impl));
if (impl->mapped)
return;