Skip to content

Commit 62741fb

Browse files
committed
wayland: Commit client specified floating viewport dimensions before entering fixed-size states
Otherwise, the compositor may restore the window to the old dimensions when transitioning from a fixed-sized state to floating.
1 parent 93b4aa4 commit 62741fb

File tree

2 files changed

+59
-38
lines changed

2 files changed

+59
-38
lines changed

src/video/wayland/SDL_waylandwindow.c

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -656,43 +656,46 @@ static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time
656656
{
657657
SDL_WindowData *wind = (SDL_WindowData *)data;
658658

659-
/* XXX: This is needed to work around an Nvidia egl-wayland bug due to buffer coordinates
660-
* being used with wl_surface_damage, which causes part of the output to not be
661-
* updated when using a viewport with an output region larger than the source region.
662-
*/
663-
if (wl_compositor_get_version(wind->waylandData->compositor) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) {
664-
wl_surface_damage_buffer(wind->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32);
665-
} else {
666-
wl_surface_damage(wind->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32);
667-
}
668-
669659
wind->drop_interactive_resizes = false;
660+
wind->pending_client_viewport_dimensions = false;
670661

671-
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) {
672-
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_SHOWN;
673-
674-
// If any child windows are waiting on this window to be shown, show them now
675-
for (SDL_Window *w = wind->sdlwindow->first_child; w; w = w->next_sibling) {
676-
if (w->internal->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_SHOW_PENDING) {
677-
Wayland_ShowWindow(SDL_GetVideoDevice(), w);
678-
} else if (w->internal->reparenting_required) {
679-
Wayland_SetWindowParent(SDL_GetVideoDevice(), w, w->parent);
680-
if (w->flags & SDL_WINDOW_MODAL) {
681-
Wayland_SetWindowModal(SDL_GetVideoDevice(), w, true);
662+
if (!(wind->sdlwindow->flags & SDL_WINDOW_EXTERNAL)) {
663+
/* XXX: This is needed to work around an Nvidia egl-wayland bug due to buffer coordinates
664+
* being used with wl_surface_damage, which causes part of the output to not be
665+
* updated when using a viewport with an output region larger than the source region.
666+
*/
667+
if (wl_compositor_get_version(wind->waylandData->compositor) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) {
668+
wl_surface_damage_buffer(wind->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32);
669+
} else {
670+
wl_surface_damage(wind->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32);
671+
}
672+
673+
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) {
674+
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_SHOWN;
675+
676+
// If any child windows are waiting on this window to be shown, show them now
677+
for (SDL_Window *w = wind->sdlwindow->first_child; w; w = w->next_sibling) {
678+
if (w->internal->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_SHOW_PENDING) {
679+
Wayland_ShowWindow(SDL_GetVideoDevice(), w);
680+
} else if (w->internal->reparenting_required) {
681+
Wayland_SetWindowParent(SDL_GetVideoDevice(), w, w->parent);
682+
if (w->flags & SDL_WINDOW_MODAL) {
683+
Wayland_SetWindowModal(SDL_GetVideoDevice(), w, true);
684+
}
682685
}
683686
}
684-
}
685687

686-
/* If the window was initially set to the suspended state, send the occluded event now,
687-
* as we don't want to mark the window as occluded until at least one frame has been submitted.
688-
*/
689-
if (wind->suspended) {
690-
SDL_SendWindowEvent(wind->sdlwindow, SDL_EVENT_WINDOW_OCCLUDED, 0, 0);
688+
/* If the window was initially set to the suspended state, send the occluded event now,
689+
* as we don't want to mark the window as occluded until at least one frame has been submitted.
690+
*/
691+
if (wind->suspended) {
692+
SDL_SendWindowEvent(wind->sdlwindow, SDL_EVENT_WINDOW_OCCLUDED, 0, 0);
693+
}
691694
}
692695
}
693696

694697
wl_callback_destroy(cb);
695-
wind->surface_frame_callback = wl_surface_frame(wind->surface);
698+
wind->surface_frame_callback = wl_surface_frame(wind->surface_wrapper);
696699
wl_callback_add_listener(wind->surface_frame_callback, &surface_frame_listener, data);
697700
}
698701

@@ -2331,6 +2334,13 @@ SDL_FullscreenResult Wayland_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Win
23312334
output = NULL;
23322335
}
23332336
}
2337+
2338+
// Commit to preserve any pending client viewport dimensions before entering fullscreen.
2339+
if (fullscreen == SDL_FULLSCREEN_OP_ENTER && !(window->flags & SDL_WINDOW_MAXIMIZED) &&
2340+
wind->pending_client_viewport_dimensions) {
2341+
wind->pending_client_viewport_dimensions = false;
2342+
wl_surface_commit(wind->surface);
2343+
}
23342344
SetFullscreen(window, output, !!fullscreen);
23352345
} else if (wind->is_fullscreen) {
23362346
/*
@@ -2459,8 +2469,11 @@ void Wayland_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
24592469
return; // Can't do anything yet, wait for ShowWindow
24602470
}
24612471

2462-
// Commit to preserve any pending size data.
2463-
wl_surface_commit(wind->surface);
2472+
// Commit to preserve any pending viewport size data.
2473+
if (wind->pending_client_viewport_dimensions) {
2474+
wind->pending_client_viewport_dimensions = false;
2475+
wl_surface_commit(wind->surface);
2476+
}
24642477
libdecor_frame_set_maximized(wind->shell_surface.libdecor.frame);
24652478

24662479
++wind->window_state_deadline_count;
@@ -2473,8 +2486,11 @@ void Wayland_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
24732486
return; // Can't do anything yet, wait for ShowWindow
24742487
}
24752488

2476-
// Commit to preserve any pending size data.
2477-
wl_surface_commit(wind->surface);
2489+
// Commit to preserve any pending viewport size data.
2490+
if (wind->pending_client_viewport_dimensions) {
2491+
wind->pending_client_viewport_dimensions = false;
2492+
wl_surface_commit(wind->surface);
2493+
}
24782494
xdg_toplevel_set_maximized(wind->shell_surface.xdg.toplevel.xdg_toplevel);
24792495

24802496
++wind->window_state_deadline_count;
@@ -2716,12 +2732,10 @@ bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper
27162732
wl_callback_add_listener(data->gles_swap_frame_callback, &gles_swap_frame_listener, data);
27172733
}
27182734

2719-
// No frame callback on external surfaces as it may already have one attached.
2720-
if (!external_surface) {
2721-
// Fire a callback when the compositor wants a new frame to set the surface damage region.
2722-
data->surface_frame_callback = wl_surface_frame(data->surface);
2723-
wl_callback_add_listener(data->surface_frame_callback, &surface_frame_listener, data);
2724-
}
2735+
// Fire a callback when the compositor wants a new frame.
2736+
data->surface_wrapper = WAYLAND_wl_proxy_create_wrapper(data->surface);
2737+
data->surface_frame_callback = wl_surface_frame(data->surface_wrapper);
2738+
wl_callback_add_listener(data->surface_frame_callback, &surface_frame_listener, data);
27252739

27262740
if (window->flags & SDL_WINDOW_TRANSPARENT) {
27272741
if (_this->gl_config.alpha_size == 0) {
@@ -2853,6 +2867,11 @@ void Wayland_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
28532867
wind->requested.pixel_height = window->pending.h;
28542868
}
28552869

2870+
if (wind->requested.logical_width != wind->current.logical_width ||
2871+
wind->requested.logical_height != wind->current.logical_height) {
2872+
wind->pending_client_viewport_dimensions = true;
2873+
}
2874+
28562875
ConfigureWindowGeometry(window);
28572876
} else {
28582877
// Can't resize the window.

src/video/wayland/SDL_waylandwindow.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct SDL_WindowData
3535
SDL_Window *sdlwindow;
3636
SDL_VideoData *waylandData;
3737
struct wl_surface *surface;
38+
struct wl_surface *surface_wrapper;
3839
struct wl_callback *gles_swap_frame_callback;
3940
struct wl_event_queue *gles_swap_frame_event_queue;
4041
struct wl_surface *gles_swap_frame_surface_wrapper;
@@ -202,6 +203,7 @@ struct SDL_WindowData
202203
bool suspended;
203204
bool resizing;
204205
bool active;
206+
bool pending_client_viewport_dimensions;
205207
bool drop_interactive_resizes;
206208
bool is_fullscreen;
207209
bool fullscreen_exclusive;

0 commit comments

Comments
 (0)