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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index 78d6c1b..7abdcc4 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -44,6 +44,8 @@
#include <libdecor.h>
#endif
+#define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)
+
SDL_FORCE_INLINE SDL_bool
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 void
@@ -545,30 +595,9 @@ handle_configure_xdg_toplevel(void *data,
driverdata = (SDL_WaylandOutputData *) SDL_GetDisplayForWindow(window)->driverdata;
- 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;
- }
+ UpdateWindowFullscreen(window, fullscreen);
+ if (!fullscreen) {
if (width == 0 || height == 0) {
/* This usually happens when we're being restored from a
* 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;
+ UpdateWindowFullscreen(window, fullscreen);
+
if (!fullscreen) {
/* Always send a maximized/restore event; if the event is redundant it will
* automatically be discarded (see src/events/SDL_windowevents.c)
*
* No, we do not get minimize events from libdecor.
*/
- if (!fullscreen) {
- SDL_SendWindowEvent(window,
- maximized ?
- SDL_WINDOWEVENT_MAXIMIZED :
- SDL_WINDOWEVENT_RESTORED,
- 0, 0);
- }
+ SDL_SendWindowEvent(window,
+ maximized ?
+ SDL_WINDOWEVENT_MAXIMIZED :
+ SDL_WINDOWEVENT_RESTORED,
+ 0, 0);
}
/* Similar to maximized/restore events above, send focus events too! */
@@ -1630,12 +1659,28 @@ void
Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
SDL_VideoDisplay * _display, SDL_bool fullscreen)
{
+ SDL_WindowData *wind = (SDL_WindowData*) window->driverdata;
struct wl_output *output = ((SDL_WaylandOutputData*) _display->driverdata)->output;
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
- SetFullscreen(window, fullscreen ? output : NULL, SDL_TRUE);
- /* Roundtrip required to receive the updated window dimensions */
- WAYLAND_wl_display_roundtrip(viddata->display);
+ /* Called from within a configure event, drop it. */
+ 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
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index 5413c95..a1ba0fe 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -107,6 +107,9 @@ typedef struct {
SDL_Rect viewport_rect;
SDL_bool needs_resize_event;
SDL_bool floating_resize_pending;
+ SDL_bool is_fullscreen;
+ SDL_bool in_fullscreen_transition;
+ Uint32 fullscreen_flags;
} SDL_WindowData;
extern void Wayland_ShowWindow(_THIS, SDL_Window *window);