wayland: Enable compositor fullscreen toggling

The compositor can toggle the fullscreen state (via a hotkey or otherwise), so the internal SDL state must be updated accordingly when it does.

When toggling fullscreen via the compositor, SDL will attempt to use the last fullscreen flag explicitly set. If no flag was previously set, SDL_WINDOW_FULLSCREEN will be used if a window video mode was set, otherwise SDL_WINDOW_FULLSCREEN_DESKTOP will be used. If the previous flag was SDL_WINDOW_FULLSCREEN and the window video mode was cleared, it will revert to SDL_WINDOW_FULLSCREEN_DESKTOP.
This commit is contained in:
Frank Praznik 2022-09-03 12:37:02 -04:00 committed by Sam Lantinga
parent 31979e2d98
commit 707b561f97
2 changed files with 81 additions and 33 deletions

View File

@ -44,6 +44,8 @@
#include <libdecor.h> #include <libdecor.h>
#endif #endif
#define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)
SDL_FORCE_INLINE SDL_bool SDL_FORCE_INLINE SDL_bool
EGLTransparencyEnabled() EGLTransparencyEnabled()
{ {
@ -448,6 +450,54 @@ SetFullscreen(SDL_Window *window, struct wl_output *output, SDL_bool commit)
} }
} }
static void
UpdateWindowFullscreen(SDL_Window *window, SDL_bool fullscreen)
{
SDL_WindowData *wind = (SDL_WindowData*)window->driverdata;
if (fullscreen) {
if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
/*
* If the window was never previously made full screen, check if a particular
* fullscreen mode has been set for the window. If one is found, use SDL_WINDOW_FULLSCREEN,
* otherwise, use SDL_WINDOW_FULLSCREEN_DESKTOP.
*
* If the previous flag was SDL_WINDOW_FULLSCREEN, make sure a mode is still set,
* otherwise, fall back to SDL_WINDOW_FULLSCREEN_DESKTOP.
*/
if (!wind->fullscreen_flags) {
if (window->fullscreen_mode.w && window->fullscreen_mode.h) {
wind->fullscreen_flags = SDL_WINDOW_FULLSCREEN;
} else {
wind->fullscreen_flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
}
} else if (wind->fullscreen_flags != SDL_WINDOW_FULLSCREEN_DESKTOP &&
(!window->fullscreen_mode.w || !window->fullscreen_mode.h)) {
wind->fullscreen_flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
}
wind->is_fullscreen = SDL_TRUE;
wind->in_fullscreen_transition = SDL_TRUE;
SDL_SetWindowFullscreen(window, wind->fullscreen_flags);
wind->in_fullscreen_transition = SDL_FALSE;
SetMinMaxDimensions(window, SDL_FALSE);
}
} else {
/* Don't change the fullscreen flags if the window is hidden or being hidden. */
if (!window->is_hiding && !(window->flags & SDL_WINDOW_HIDDEN)) {
if (window->flags & SDL_WINDOW_FULLSCREEN) {
wind->is_fullscreen = SDL_FALSE;
wind->in_fullscreen_transition = SDL_TRUE;
SDL_SetWindowFullscreen(window, 0);
wind->in_fullscreen_transition = SDL_FALSE;
SetMinMaxDimensions(window, SDL_FALSE);
}
}
}
}
static const struct wl_callback_listener surface_damage_frame_listener; static const struct wl_callback_listener surface_damage_frame_listener;
static void static void
@ -545,30 +595,9 @@ handle_configure_xdg_toplevel(void *data,
driverdata = (SDL_WaylandOutputData *) SDL_GetDisplayForWindow(window)->driverdata; driverdata = (SDL_WaylandOutputData *) SDL_GetDisplayForWindow(window)->driverdata;
UpdateWindowFullscreen(window, fullscreen);
if (!fullscreen) { if (!fullscreen) {
if (window->flags & SDL_WINDOW_FULLSCREEN) {
/* Foolishly do what the compositor says here. If it's wrong, don't
* blame us, we were explicitly instructed to do this.
*
* UPDATE: Nope, we can't actually do that, the compositor may give
* us a completely stateless, sizeless configure, with which we have
* to enforce our own state anyway.
*/
if (width != 0 && height != 0 && (window->w != width || window->h != height)) {
window->w = width;
window->h = height;
wind->needs_resize_event = SDL_TRUE;
}
/* This part is good though. */
if ((window->flags & SDL_WINDOW_ALLOW_HIGHDPI) && !FloatEqual(wind->scale_factor, driverdata->scale_factor)) {
wind->scale_factor = driverdata->scale_factor;
wind->needs_resize_event = SDL_TRUE;
}
return;
}
if (width == 0 || height == 0) { if (width == 0 || height == 0) {
/* This usually happens when we're being restored from a /* This usually happens when we're being restored from a
* non-floating state, so use the cached floating size here. * non-floating state, so use the cached floating size here.
@ -781,19 +810,19 @@ decoration_frame_configure(struct libdecor_frame *frame,
driverdata = (SDL_WaylandOutputData *) SDL_GetDisplayForWindow(window)->driverdata; driverdata = (SDL_WaylandOutputData *) SDL_GetDisplayForWindow(window)->driverdata;
UpdateWindowFullscreen(window, fullscreen);
if (!fullscreen) { if (!fullscreen) {
/* Always send a maximized/restore event; if the event is redundant it will /* Always send a maximized/restore event; if the event is redundant it will
* automatically be discarded (see src/events/SDL_windowevents.c) * automatically be discarded (see src/events/SDL_windowevents.c)
* *
* No, we do not get minimize events from libdecor. * No, we do not get minimize events from libdecor.
*/ */
if (!fullscreen) { SDL_SendWindowEvent(window,
SDL_SendWindowEvent(window, maximized ?
maximized ? SDL_WINDOWEVENT_MAXIMIZED :
SDL_WINDOWEVENT_MAXIMIZED : SDL_WINDOWEVENT_RESTORED,
SDL_WINDOWEVENT_RESTORED, 0, 0);
0, 0);
}
} }
/* Similar to maximized/restore events above, send focus events too! */ /* Similar to maximized/restore events above, send focus events too! */
@ -1630,12 +1659,28 @@ void
Wayland_SetWindowFullscreen(_THIS, SDL_Window * window, Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
SDL_VideoDisplay * _display, SDL_bool fullscreen) SDL_VideoDisplay * _display, SDL_bool fullscreen)
{ {
SDL_WindowData *wind = (SDL_WindowData*) window->driverdata;
struct wl_output *output = ((SDL_WaylandOutputData*) _display->driverdata)->output; struct wl_output *output = ((SDL_WaylandOutputData*) _display->driverdata)->output;
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
SetFullscreen(window, fullscreen ? output : NULL, SDL_TRUE);
/* Roundtrip required to receive the updated window dimensions */ /* Called from within a configure event, drop it. */
WAYLAND_wl_display_roundtrip(viddata->display); if (wind->in_fullscreen_transition) {
return;
}
/* Save the last fullscreen flags for future requests by the compositor. */
if (fullscreen) {
wind->fullscreen_flags = window->flags & FULLSCREEN_MASK;
}
/* Don't send redundant fullscreen set/unset events. */
if (wind->is_fullscreen != fullscreen) {
wind->is_fullscreen = fullscreen;
SetFullscreen(window, fullscreen ? output : NULL, SDL_TRUE);
/* Roundtrip required to receive the updated window dimensions */
WAYLAND_wl_display_roundtrip(viddata->display);
}
} }
void void

View File

@ -107,6 +107,9 @@ typedef struct {
SDL_Rect viewport_rect; SDL_Rect viewport_rect;
SDL_bool needs_resize_event; SDL_bool needs_resize_event;
SDL_bool floating_resize_pending; SDL_bool floating_resize_pending;
SDL_bool is_fullscreen;
SDL_bool in_fullscreen_transition;
Uint32 fullscreen_flags;
} SDL_WindowData; } SDL_WindowData;
extern void Wayland_ShowWindow(_THIS, SDL_Window *window); extern void Wayland_ShowWindow(_THIS, SDL_Window *window);