wayland: Queue the surface frame callback after the initial commit

Some compositors may dispatch this too early, during the initial empty commit, when subsurfaces are attached to a toplevel window, but a buffer has yet to be committed to the parent surface. Don't set the frame callback until the initial empty commit is done, so it will be called when the actual parent surface frame is committed.

(cherry picked from commit e3393e6304)
This commit is contained in:
Frank Praznik
2026-05-06 11:30:15 -04:00
parent b42dbd8ecb
commit d2999a4047

View File

@@ -2015,7 +2015,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
wl_surface_commit(data->surface);
}
// Make sure the window can't be resized to 0 or it can be spuriously closed by the window manager.
// Make sure the window can't be resized to 0, or it can be spuriously closed by the window manager.
data->system_limits.min_width = SDL_max(data->system_limits.min_width, 1);
data->system_limits.min_height = SDL_max(data->system_limits.min_height, 1);
@@ -2058,6 +2058,13 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
}
}
// No frame callback on an external surface, as it may already have one attached.
if (!(window->flags & SDL_WINDOW_EXTERNAL)) {
// Fire a callback when the compositor wants a new frame.
data->surface_frame_callback = wl_surface_frame(data->surface);
wl_callback_add_listener(data->surface_frame_callback, &surface_frame_listener, data);
}
data->show_hide_sync_required = true;
struct wl_callback *cb = wl_display_sync(_this->internal->display);
wl_callback_add_listener(cb, &show_hide_sync_listener, (void*)((uintptr_t)window->id));
@@ -2124,6 +2131,11 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_HIDDEN;
if (wind->surface_frame_callback) {
wl_callback_destroy(wind->surface_frame_callback);
wind->surface_frame_callback = NULL;
}
if (wind->server_decoration) {
zxdg_toplevel_decoration_v1_destroy(wind->server_decoration);
wind->server_decoration = NULL;
@@ -2654,13 +2666,6 @@ bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper
wl_callback_add_listener(data->gles_swap_frame_callback, &gles_swap_frame_listener, data);
}
// No frame callback on external surfaces as it may already have one attached.
if (!external_surface) {
// Fire a callback when the compositor wants a new frame to set the surface damage region.
data->surface_frame_callback = wl_surface_frame(data->surface);
wl_callback_add_listener(data->surface_frame_callback, &surface_frame_listener, data);
}
if (window->flags & SDL_WINDOW_TRANSPARENT) {
if (_this->gl_config.alpha_size == 0) {
_this->gl_config.alpha_size = 8;
@@ -3127,10 +3132,6 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
WAYLAND_wl_event_queue_destroy(wind->gles_swap_frame_event_queue);
}
if (wind->surface_frame_callback) {
wl_callback_destroy(wind->surface_frame_callback);
}
if (!(window->flags & SDL_WINDOW_EXTERNAL)) {
wl_surface_destroy(wind->surface);
} else {