wayland: fix resizing and fullscreen toggling
authorSebastian Krzyszkowiak <dos@dosowisko.net>
Wed, 07 Nov 2018 01:08:35 +0100
changeset 1240028303fca62bd
parent 12399 2ea6e539b218
child 12401 77433beaf97a
wayland: fix resizing and fullscreen toggling
For starters, we need to correctly respond to 0,0 configure after unsetting
fullscreen. Also, turns out that there should be no drawing calls at all
in between eglSwapBuffers and wl_egl_window_resize, as otherwise EGL can
already allocate a wrongly sized buffer for a next frame, so handle those
together.
src/video/wayland/SDL_waylandopengles.c
src/video/wayland/SDL_waylandwindow.c
src/video/wayland/SDL_waylandwindow.h
     1.1 --- a/src/video/wayland/SDL_waylandopengles.c	Tue Nov 06 23:45:50 2018 +0300
     1.2 +++ b/src/video/wayland/SDL_waylandopengles.c	Wed Nov 07 01:08:35 2018 +0100
     1.3 @@ -22,12 +22,17 @@
     1.4  
     1.5  #if SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL
     1.6  
     1.7 +#include "../SDL_sysvideo.h"
     1.8 +#include "../../events/SDL_windowevents_c.h"
     1.9  #include "SDL_waylandvideo.h"
    1.10  #include "SDL_waylandopengles.h"
    1.11  #include "SDL_waylandwindow.h"
    1.12  #include "SDL_waylandevents_c.h"
    1.13  #include "SDL_waylanddyn.h"
    1.14  
    1.15 +#include "xdg-shell-client-protocol.h"
    1.16 +#include "xdg-shell-unstable-v6-client-protocol.h"
    1.17 +
    1.18  /* EGL implementation of SDL OpenGL ES support */
    1.19  
    1.20  int
    1.21 @@ -57,10 +62,37 @@
    1.22  int
    1.23  Wayland_GLES_SwapWindow(_THIS, SDL_Window *window)
    1.24  {
    1.25 -    if (SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface) < 0) {
    1.26 +    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    1.27 +    struct wl_region *region;
    1.28 +
    1.29 +    if (SDL_EGL_SwapBuffers(_this, data->egl_surface) < 0) {
    1.30          return -1;
    1.31      }
    1.32 -    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
    1.33 +
    1.34 +    // Wayland-EGL forbids drawing calls in-between SwapBuffers and wl_egl_window_resize
    1.35 +    if (data->resize.pending) {
    1.36 +        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, data->resize.width, data->resize.height);
    1.37 +        window->w = data->resize.width;
    1.38 +        window->h = data->resize.height;
    1.39 +
    1.40 +        WAYLAND_wl_egl_window_resize(data->egl_window, window->w, window->h, 0, 0);
    1.41 +
    1.42 +        if (data->waylandData->shell.xdg) {
    1.43 +           xdg_surface_ack_configure(data->shell_surface.xdg.surface, data->resize.serial);
    1.44 +        } else if (data->waylandData->shell.zxdg) {
    1.45 +           zxdg_surface_v6_ack_configure(data->shell_surface.zxdg.surface, data->resize.serial);
    1.46 +        }
    1.47 +
    1.48 +        region = wl_compositor_create_region(data->waylandData->compositor);
    1.49 +        wl_region_add(region, 0, 0, window->w, window->h);
    1.50 +        wl_surface_set_opaque_region(data->surface, region);
    1.51 +        wl_region_destroy(region);
    1.52 +
    1.53 +        data->resize.pending = SDL_FALSE;
    1.54 +    }
    1.55 +
    1.56 +    WAYLAND_wl_display_flush( data->waylandData->display );
    1.57 +
    1.58      return 0;
    1.59  }
    1.60  
     2.1 --- a/src/video/wayland/SDL_waylandwindow.c	Tue Nov 06 23:45:50 2018 +0300
     2.2 +++ b/src/video/wayland/SDL_waylandwindow.c	Wed Nov 07 01:08:35 2018 +0100
     2.3 @@ -55,7 +55,6 @@
     2.4  {
     2.5      SDL_WindowData *wind = (SDL_WindowData *)data;
     2.6      SDL_Window *window = wind->sdlwindow;
     2.7 -    struct wl_region *region;
     2.8  
     2.9      /* wl_shell_surface spec states that this is a suggestion.
    2.10         Ignore if less than or greater than max/min size. */
    2.11 @@ -68,7 +67,7 @@
    2.12          if ((window->flags & SDL_WINDOW_RESIZABLE)) {
    2.13              if (window->max_w > 0) {
    2.14                  width = SDL_min(width, window->max_w);
    2.15 -            } 
    2.16 +            }
    2.17              width = SDL_max(width, window->min_w);
    2.18  
    2.19              if (window->max_h > 0) {
    2.20 @@ -80,15 +79,9 @@
    2.21          }
    2.22      }
    2.23  
    2.24 -    WAYLAND_wl_egl_window_resize(wind->egl_window, width, height, 0, 0);
    2.25 -    region = wl_compositor_create_region(wind->waylandData->compositor);
    2.26 -    wl_region_add(region, 0, 0, width, height);
    2.27 -    wl_surface_set_opaque_region(wind->surface, region);
    2.28 -    wl_region_destroy(region);
    2.29 -
    2.30 -    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height);
    2.31 -    window->w = width;
    2.32 -    window->h = height;
    2.33 +    wind->resize.width = width;
    2.34 +    wind->resize.height = height;
    2.35 +    wind->resize.pending = SDL_TRUE;
    2.36  }
    2.37  
    2.38  static void
    2.39 @@ -112,15 +105,25 @@
    2.40      SDL_Window *window = wind->sdlwindow;
    2.41      struct wl_region *region;
    2.42  
    2.43 -    wind->shell_surface.zxdg.initial_configure_seen = SDL_TRUE;
    2.44 +    if (!wind->shell_surface.zxdg.initial_configure_seen) {
    2.45 +        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, wind->resize.width, wind->resize.height);
    2.46 +        window->w = wind->resize.width;
    2.47 +        window->h = wind->resize.height;
    2.48  
    2.49 -    WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
    2.50 +        WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
    2.51  
    2.52 -    region = wl_compositor_create_region(wind->waylandData->compositor);
    2.53 -    wl_region_add(region, 0, 0, window->w, window->h);
    2.54 -    wl_surface_set_opaque_region(wind->surface, region);
    2.55 -    wl_region_destroy(region);
    2.56 -    zxdg_surface_v6_ack_configure(zxdg, serial);
    2.57 +        zxdg_surface_v6_ack_configure(zxdg, serial);
    2.58 +
    2.59 +        region = wl_compositor_create_region(wind->waylandData->compositor);
    2.60 +        wl_region_add(region, 0, 0, window->w, window->h);
    2.61 +        wl_surface_set_opaque_region(wind->surface, region);
    2.62 +        wl_region_destroy(region);
    2.63 +
    2.64 +        wind->shell_surface.zxdg.initial_configure_seen = SDL_TRUE;
    2.65 +    } else {
    2.66 +        wind->resize.pending = SDL_TRUE;
    2.67 +        wind->resize.serial = serial;
    2.68 +    }
    2.69  }
    2.70  
    2.71  static const struct zxdg_surface_v6_listener shell_surface_listener_zxdg = {
    2.72 @@ -138,18 +141,27 @@
    2.73      SDL_WindowData *wind = (SDL_WindowData *)data;
    2.74      SDL_Window *window = wind->sdlwindow;
    2.75  
    2.76 -    /* wl_shell_surface spec states that this is a suggestion.
    2.77 -       Ignore if less than or greater than max/min size. */
    2.78 -
    2.79 -    if (width == 0 || height == 0) {
    2.80 -        return;
    2.81 +    enum zxdg_toplevel_v6_state *state;
    2.82 +    SDL_bool fullscreen = SDL_FALSE;
    2.83 +    wl_array_for_each(state, states) {
    2.84 +        if (*state == ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN) {
    2.85 +            fullscreen = SDL_TRUE;
    2.86 +        }
    2.87      }
    2.88  
    2.89 -    if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
    2.90 +    if (!fullscreen) {
    2.91 +        if (width == 0 || height == 0) {
    2.92 +            width = window->windowed.w;
    2.93 +            height = window->windowed.h;
    2.94 +        }
    2.95 +
    2.96 +        /* zxdg_toplevel spec states that this is a suggestion.
    2.97 +           Ignore if less than or greater than max/min size. */
    2.98 +
    2.99          if ((window->flags & SDL_WINDOW_RESIZABLE)) {
   2.100              if (window->max_w > 0) {
   2.101                  width = SDL_min(width, window->max_w);
   2.102 -            } 
   2.103 +            }
   2.104              width = SDL_max(width, window->min_w);
   2.105  
   2.106              if (window->max_h > 0) {
   2.107 @@ -157,13 +169,20 @@
   2.108              }
   2.109              height = SDL_max(height, window->min_h);
   2.110          } else {
   2.111 +            wind->resize.width = window->w;
   2.112 +            wind->resize.height = window->h;
   2.113              return;
   2.114          }
   2.115      }
   2.116  
   2.117 -    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height);
   2.118 -    window->w = width;
   2.119 -    window->h = height;
   2.120 +    if (width == 0 || height == 0) {
   2.121 +        wind->resize.width = window->w;
   2.122 +        wind->resize.height = window->h;
   2.123 +        return;
   2.124 +    }
   2.125 +
   2.126 +    wind->resize.width = width;
   2.127 +    wind->resize.height = height;
   2.128  }
   2.129  
   2.130  static void
   2.131 @@ -187,15 +206,25 @@
   2.132      SDL_Window *window = wind->sdlwindow;
   2.133      struct wl_region *region;
   2.134  
   2.135 -    wind->shell_surface.xdg.initial_configure_seen = SDL_TRUE;
   2.136 +    if (!wind->shell_surface.xdg.initial_configure_seen) {
   2.137 +        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, wind->resize.width, wind->resize.height);
   2.138 +        window->w = wind->resize.width;
   2.139 +        window->h = wind->resize.height;
   2.140  
   2.141 -    WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
   2.142 +        WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
   2.143  
   2.144 -    region = wl_compositor_create_region(wind->waylandData->compositor);
   2.145 -    wl_region_add(region, 0, 0, window->w, window->h);
   2.146 -    wl_surface_set_opaque_region(wind->surface, region);
   2.147 -    wl_region_destroy(region);
   2.148 -    xdg_surface_ack_configure(xdg, serial);
   2.149 +        xdg_surface_ack_configure(xdg, serial);
   2.150 +
   2.151 +        region = wl_compositor_create_region(wind->waylandData->compositor);
   2.152 +        wl_region_add(region, 0, 0, window->w, window->h);
   2.153 +        wl_surface_set_opaque_region(wind->surface, region);
   2.154 +        wl_region_destroy(region);
   2.155 +
   2.156 +        wind->shell_surface.xdg.initial_configure_seen = SDL_TRUE;
   2.157 +    } else {
   2.158 +        wind->resize.pending = SDL_TRUE;
   2.159 +        wind->resize.serial = serial;
   2.160 +    }
   2.161  }
   2.162  
   2.163  static const struct xdg_surface_listener shell_surface_listener_xdg = {
   2.164 @@ -213,18 +242,27 @@
   2.165      SDL_WindowData *wind = (SDL_WindowData *)data;
   2.166      SDL_Window *window = wind->sdlwindow;
   2.167  
   2.168 -    /* wl_shell_surface spec states that this is a suggestion.
   2.169 -       Ignore if less than or greater than max/min size. */
   2.170 +    enum xdg_toplevel_state *state;
   2.171 +    SDL_bool fullscreen = SDL_FALSE;
   2.172 +    wl_array_for_each(state, states) {
   2.173 +        if (*state == XDG_TOPLEVEL_STATE_FULLSCREEN) {
   2.174 +            fullscreen = SDL_TRUE;
   2.175 +        }
   2.176 +     }
   2.177  
   2.178 -    if (width == 0 || height == 0) {
   2.179 -        return;
   2.180 -    }
   2.181 +    if (!fullscreen) {
   2.182 +        if (width == 0 || height == 0) {
   2.183 +            width = window->windowed.w;
   2.184 +            height = window->windowed.h;
   2.185 +        }
   2.186  
   2.187 -    if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
   2.188 +        /* xdg_toplevel spec states that this is a suggestion.
   2.189 +           Ignore if less than or greater than max/min size. */
   2.190 +
   2.191          if ((window->flags & SDL_WINDOW_RESIZABLE)) {
   2.192              if (window->max_w > 0) {
   2.193                  width = SDL_min(width, window->max_w);
   2.194 -            } 
   2.195 +            }
   2.196              width = SDL_max(width, window->min_w);
   2.197  
   2.198              if (window->max_h > 0) {
   2.199 @@ -232,17 +270,20 @@
   2.200              }
   2.201              height = SDL_max(height, window->min_h);
   2.202          } else {
   2.203 +            wind->resize.width = window->w;
   2.204 +            wind->resize.height = window->h;
   2.205              return;
   2.206          }
   2.207      }
   2.208  
   2.209 -    if (width == window->w && height == window->h) {
   2.210 +    if (width == 0 || height == 0) {
   2.211 +        wind->resize.width = window->w;
   2.212 +        wind->resize.height = window->h;
   2.213          return;
   2.214      }
   2.215  
   2.216 -    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height);
   2.217 -    window->w = width;
   2.218 -    window->h = height;
   2.219 +    wind->resize.width = width;
   2.220 +    wind->resize.height = height;
   2.221  }
   2.222  
   2.223  static void
   2.224 @@ -508,6 +549,8 @@
   2.225      data->waylandData = c;
   2.226      data->sdlwindow = window;
   2.227  
   2.228 +    data->resize.pending = SDL_FALSE;
   2.229 +
   2.230      data->surface =
   2.231          wl_compositor_create_surface(c->compositor);
   2.232      wl_surface_set_user_data(data->surface, data);
     3.1 --- a/src/video/wayland/SDL_waylandwindow.h	Tue Nov 06 23:45:50 2018 +0300
     3.2 +++ b/src/video/wayland/SDL_waylandwindow.h	Wed Nov 07 01:08:35 2018 +0100
     3.3 @@ -66,7 +66,13 @@
     3.4  
     3.5  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
     3.6      struct qt_extended_surface *extended_surface;
     3.7 -#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */    
     3.8 +#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
     3.9 +
    3.10 +    struct {
    3.11 +        SDL_bool pending;
    3.12 +        uint32_t serial;
    3.13 +        int width, height;
    3.14 +    } resize;
    3.15  } SDL_WindowData;
    3.16  
    3.17  extern void Wayland_ShowWindow(_THIS, SDL_Window *window);