Skip to content

Commit 940d919

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 f29c94a commit 940d919

File tree

2 files changed

+63
-38
lines changed

2 files changed

+63
-38
lines changed

src/video/wayland/SDL_waylandwindow.c

Lines changed: 61 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;
661+
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;
670675

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);
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

@@ -2334,6 +2337,13 @@ SDL_FullscreenResult Wayland_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Win
23342337
output = NULL;
23352338
}
23362339
}
2340+
2341+
// Commit to preserve any pending client viewport dimensions before entering fullscreen.
2342+
if (fullscreen == SDL_FULLSCREEN_OP_ENTER && !(window->flags & SDL_WINDOW_MAXIMIZED) &&
2343+
wind->pending_client_viewport_dimensions) {
2344+
wind->pending_client_viewport_dimensions = false;
2345+
wl_surface_commit(wind->surface);
2346+
}
23372347
SetFullscreen(window, output, !!fullscreen);
23382348
} else if (wind->is_fullscreen) {
23392349
/*
@@ -2462,8 +2472,11 @@ void Wayland_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
24622472
return; // Can't do anything yet, wait for ShowWindow
24632473
}
24642474

2465-
// Commit to preserve any pending size data.
2466-
wl_surface_commit(wind->surface);
2475+
// Commit to preserve any pending viewport size data.
2476+
if (wind->pending_client_viewport_dimensions) {
2477+
wind->pending_client_viewport_dimensions = false;
2478+
wl_surface_commit(wind->surface);
2479+
}
24672480
libdecor_frame_set_maximized(wind->shell_surface.libdecor.frame);
24682481

24692482
++wind->window_state_deadline_count;
@@ -2476,8 +2489,11 @@ void Wayland_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
24762489
return; // Can't do anything yet, wait for ShowWindow
24772490
}
24782491

2479-
// Commit to preserve any pending size data.
2480-
wl_surface_commit(wind->surface);
2492+
// Commit to preserve any pending viewport size data.
2493+
if (wind->pending_client_viewport_dimensions) {
2494+
wind->pending_client_viewport_dimensions = false;
2495+
wl_surface_commit(wind->surface);
2496+
}
24812497
xdg_toplevel_set_maximized(wind->shell_surface.xdg.toplevel.xdg_toplevel);
24822498

24832499
++wind->window_state_deadline_count;
@@ -2719,12 +2735,10 @@ bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper
27192735
wl_callback_add_listener(data->gles_swap_frame_callback, &gles_swap_frame_listener, data);
27202736
}
27212737

2722-
// No frame callback on external surfaces as it may already have one attached.
2723-
if (!external_surface) {
2724-
// Fire a callback when the compositor wants a new frame to set the surface damage region.
2725-
data->surface_frame_callback = wl_surface_frame(data->surface);
2726-
wl_callback_add_listener(data->surface_frame_callback, &surface_frame_listener, data);
2727-
}
2738+
// Fire a callback when the compositor wants a new frame.
2739+
data->surface_wrapper = WAYLAND_wl_proxy_create_wrapper(data->surface);
2740+
data->surface_frame_callback = wl_surface_frame(data->surface_wrapper);
2741+
wl_callback_add_listener(data->surface_frame_callback, &surface_frame_listener, data);
27282742

27292743
if (window->flags & SDL_WINDOW_TRANSPARENT) {
27302744
if (_this->gl_config.alpha_size == 0) {
@@ -2856,6 +2870,11 @@ void Wayland_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
28562870
wind->requested.pixel_height = window->pending.h;
28572871
}
28582872

2873+
if (wind->requested.logical_width != wind->current.logical_width ||
2874+
wind->requested.logical_height != wind->current.logical_height) {
2875+
wind->pending_client_viewport_dimensions = true;
2876+
}
2877+
28592878
ConfigureWindowGeometry(window);
28602879
} else {
28612880
// Can't resize the window.
@@ -3203,6 +3222,10 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
32033222
wl_callback_destroy(wind->surface_frame_callback);
32043223
}
32053224

3225+
if (wind->surface_wrapper) {
3226+
WAYLAND_wl_proxy_wrapper_destroy(wind->surface_wrapper);
3227+
}
3228+
32063229
if (!(window->flags & SDL_WINDOW_EXTERNAL)) {
32073230
wl_surface_destroy(wind->surface);
32083231
} else {

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)