From adad7dcae09292adc4a0bf429fa75eafb21dbff3 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Sun, 6 Apr 2025 12:29:41 -0400
Subject: [PATCH] x11/wayland: Ignore redundant restore and fullscreen leave
requests when showing the window
The window may be initially maximized or made fullscreen by the window manager for various reasons, such as automatically declaring a window that precisely fills the usable desktop space as maximized, or a "kiosk-mode" automatically making the window fullscreen.
Don't redundantly make restored or unset fullscreen calls when initially showing a window, or the expected state can be unset.
---
src/video/wayland/SDL_waylandwindow.c | 14 ++++++++++++++
src/video/wayland/SDL_waylandwindow.h | 1 +
src/video/x11/SDL_x11events.c | 3 +++
src/video/x11/SDL_x11window.c | 9 +++++++++
src/video/x11/SDL_x11window.h | 1 +
5 files changed, 28 insertions(+)
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index 523d2e4bb29bd..1fea144e17032 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -2055,6 +2055,10 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
struct wl_callback *cb = wl_display_sync(_this->internal->display);
wl_callback_add_listener(cb, &show_hide_sync_listener, (void*)((uintptr_t)window->id));
+ data->showing_window = true;
+ SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_SHOWN, 0, 0);
+ data->showing_window = false;
+
// Send an exposure event to signal that the client should draw.
if (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_EXPOSED, 0, 0);
@@ -2277,6 +2281,11 @@ SDL_FullscreenResult Wayland_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Win
return SDL_FULLSCREEN_FAILED;
}
+ // Drop fullscreen leave requests when showing the window.
+ if (wind->showing_window && fullscreen == SDL_FULLSCREEN_OP_LEAVE) {
+ return SDL_FULLSCREEN_SUCCEEDED;
+ }
+
if (wind->show_hide_sync_required) {
WAYLAND_wl_display_roundtrip(_this->internal->display);
}
@@ -2331,6 +2340,11 @@ void Wayland_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *wind = window->internal;
+ // Drop restore requests when showing the window.
+ if (wind->showing_window) {
+ return;
+ }
+
// Not currently fullscreen or maximized, and no state pending; nothing to do.
if (!(window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED)) &&
!wind->fullscreen_deadline_count && !wind->maximized_restored_deadline_count) {
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index 619fd79e6d7d5..ee27f337b8805 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -198,6 +198,7 @@ struct SDL_WindowData
bool is_fullscreen;
bool fullscreen_exclusive;
bool drop_fullscreen_requests;
+ bool showing_window;
bool fullscreen_was_positioned;
bool show_hide_sync_required;
bool scale_to_display;
diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c
index 43d6dd72833d8..96bf8c7a1b68d 100644
--- a/src/video/x11/SDL_x11events.c
+++ b/src/video/x11/SDL_x11events.c
@@ -508,6 +508,7 @@ static void X11_DispatchMapNotify(SDL_WindowData *data)
SDL_Window *window = data->window;
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_SHOWN, 0, 0);
+ data->was_shown = true;
// This may be sent when restoring a minimized window.
if (window->flags & SDL_WINDOW_MINIMIZED) {
@@ -528,6 +529,8 @@ static void X11_DispatchUnmapNotify(SDL_WindowData *data)
if (!window->is_hiding) {
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_OCCLUDED, 0, 0);
+ } else {
+ SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_HIDDEN, 0, 0);
}
}
diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c
index d88487627e817..ca340953ede37 100644
--- a/src/video/x11/SDL_x11window.c
+++ b/src/video/x11/SDL_x11window.c
@@ -1773,6 +1773,11 @@ void X11_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
void X11_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
+ // Don't restore the window the first time it is being shown.
+ if (!window->internal->was_shown) {
+ return;
+ }
+
if (window->internal->pending_operation & (X11_PENDING_OP_FULLSCREEN | X11_PENDING_OP_MAXIMIZE | X11_PENDING_OP_MINIMIZE)) {
SDL_SyncWindow(window);
}
@@ -1807,6 +1812,10 @@ static SDL_FullscreenResult X11_SetWindowFullscreenViaWM(SDL_VideoDevice *_this,
Atom _NET_WM_STATE = data->videodata->atoms._NET_WM_STATE;
Atom _NET_WM_STATE_FULLSCREEN = data->videodata->atoms._NET_WM_STATE_FULLSCREEN;
+ if (!data->was_shown && fullscreen == SDL_FULLSCREEN_OP_LEAVE) {
+ return SDL_FULLSCREEN_SUCCEEDED;
+ }
+
if (X11_IsWindowMapped(_this, window)) {
XEvent e;
diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h
index f1a73ab592480..2d7b3239d37a1 100644
--- a/src/video/x11/SDL_x11window.h
+++ b/src/video/x11/SDL_x11window.h
@@ -115,6 +115,7 @@ struct SDL_WindowData
bool previous_borders_nonzero;
bool toggle_borders;
bool fullscreen_borders_forced_on;
+ bool was_shown;
SDL_HitTestResult hit_test_result;
XPoint xim_spot;