src/video/wayland/SDL_waylandwindow.c
changeset 11848 2f157c1ca383
parent 11811 5d94cb6b24d3
child 11944 295cf9910d75
     1.1 --- a/src/video/wayland/SDL_waylandwindow.c	Wed Feb 07 13:07:59 2018 -0500
     1.2 +++ b/src/video/wayland/SDL_waylandwindow.c	Wed Feb 07 13:13:55 2018 -0500
     1.3 @@ -33,15 +33,22 @@
     1.4  #include "SDL_waylanddyn.h"
     1.5  #include "SDL_hints.h"
     1.6  
     1.7 +#include "xdg-shell-unstable-v6-client-protocol.h"
     1.8 +
     1.9 +/* On modern desktops, we probably will use the xdg-shell protocol instead
    1.10 +   of wl_shell, but wl_shell might be useful on older Wayland installs that
    1.11 +   don't have the newer protocol, or embedded things that don't have a full
    1.12 +   window manager. */
    1.13 +
    1.14  static void
    1.15 -handle_ping(void *data, struct wl_shell_surface *shell_surface,
    1.16 +handle_ping_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
    1.17              uint32_t serial)
    1.18  {
    1.19      wl_shell_surface_pong(shell_surface, serial);
    1.20  }
    1.21  
    1.22  static void
    1.23 -handle_configure(void *data, struct wl_shell_surface *shell_surface,
    1.24 +handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
    1.25                   uint32_t edges, int32_t width, int32_t height)
    1.26  {
    1.27      SDL_WindowData *wind = (SDL_WindowData *)data;
    1.28 @@ -87,16 +94,94 @@
    1.29  }
    1.30  
    1.31  static void
    1.32 -handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
    1.33 +handle_popup_done_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface)
    1.34  {
    1.35  }
    1.36  
    1.37 -static const struct wl_shell_surface_listener shell_surface_listener = {
    1.38 -    handle_ping,
    1.39 -    handle_configure,
    1.40 -    handle_popup_done
    1.41 +static const struct wl_shell_surface_listener shell_surface_listener_wl = {
    1.42 +    handle_ping_wl_shell_surface,
    1.43 +    handle_configure_wl_shell_surface,
    1.44 +    handle_popup_done_wl_shell_surface
    1.45  };
    1.46  
    1.47 +
    1.48 +
    1.49 +
    1.50 +static void
    1.51 +handle_configure_zxdg_shell_surface(void *data, struct zxdg_surface_v6 *zxdg, uint32_t serial)
    1.52 +{
    1.53 +    SDL_WindowData *wind = (SDL_WindowData *)data;
    1.54 +    SDL_Window *window = wind->sdlwindow;
    1.55 +    struct wl_region *region;
    1.56 +    WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
    1.57 +
    1.58 +    region = wl_compositor_create_region(wind->waylandData->compositor);
    1.59 +    wl_region_add(region, 0, 0, window->w, window->h);
    1.60 +    wl_surface_set_opaque_region(wind->surface, region);
    1.61 +    wl_region_destroy(region);
    1.62 +    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, window->w, window->h);
    1.63 +    zxdg_surface_v6_ack_configure(zxdg, serial);
    1.64 +}
    1.65 +
    1.66 +static const struct zxdg_surface_v6_listener shell_surface_listener_zxdg = {
    1.67 +    handle_configure_zxdg_shell_surface
    1.68 +};
    1.69 +
    1.70 +
    1.71 +static void
    1.72 +handle_configure_zxdg_toplevel(void *data,
    1.73 +			  struct zxdg_toplevel_v6 *zxdg_toplevel_v6,
    1.74 +			  int32_t width,
    1.75 +			  int32_t height,
    1.76 +			  struct wl_array *states)
    1.77 +{
    1.78 +    SDL_WindowData *wind = (SDL_WindowData *)data;
    1.79 +    SDL_Window *window = wind->sdlwindow;
    1.80 +
    1.81 +    /* wl_shell_surface spec states that this is a suggestion.
    1.82 +       Ignore if less than or greater than max/min size. */
    1.83 +
    1.84 +    if (width == 0 || height == 0) {
    1.85 +        return;
    1.86 +    }
    1.87 +
    1.88 +    if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
    1.89 +        if ((window->flags & SDL_WINDOW_RESIZABLE)) {
    1.90 +            if (window->max_w > 0) {
    1.91 +                width = SDL_min(width, window->max_w);
    1.92 +            } 
    1.93 +            width = SDL_max(width, window->min_w);
    1.94 +
    1.95 +            if (window->max_h > 0) {
    1.96 +                height = SDL_min(height, window->max_h);
    1.97 +            }
    1.98 +            height = SDL_max(height, window->min_h);
    1.99 +        } else {
   1.100 +            return;
   1.101 +        }
   1.102 +    }
   1.103 +
   1.104 +    if (width == window->w && height == window->h) {
   1.105 +        return;
   1.106 +    }
   1.107 +
   1.108 +    window->w = width;
   1.109 +    window->h = height;
   1.110 +}
   1.111 +
   1.112 +static void
   1.113 +handle_close_zxdg_toplevel(void *data, struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
   1.114 +{
   1.115 +    SDL_WindowData *window = (SDL_WindowData *)data;
   1.116 +    SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
   1.117 +}
   1.118 +
   1.119 +static const struct zxdg_toplevel_v6_listener toplevel_listener_zxdg = {
   1.120 +    handle_configure_zxdg_toplevel,
   1.121 +    handle_close_zxdg_toplevel
   1.122 +};
   1.123 +
   1.124 +
   1.125  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   1.126  static void
   1.127  handle_onscreen_visibility(void *data,
   1.128 @@ -151,7 +236,7 @@
   1.129  
   1.130      info->info.wl.display = data->waylandData->display;
   1.131      info->info.wl.surface = data->surface;
   1.132 -    info->info.wl.shell_surface = data->shell_surface;
   1.133 +    info->info.wl.shell_surface = data->shell_surface.wl;
   1.134      info->subsystem = SDL_SYSWM_WAYLAND;
   1.135  
   1.136      return SDL_TRUE;
   1.137 @@ -163,18 +248,35 @@
   1.138      return 0;  /* just succeed, the real work is done elsewhere. */
   1.139  }
   1.140  
   1.141 +static void
   1.142 +SetFullscreen(_THIS, SDL_Window * window, struct wl_output *output)
   1.143 +{
   1.144 +    const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
   1.145 +    SDL_WindowData *wind = window->driverdata;
   1.146 +
   1.147 +    if (viddata->shell.zxdg) {
   1.148 +        if (output) {
   1.149 +            zxdg_toplevel_v6_set_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel, output);
   1.150 +        } else {
   1.151 +            zxdg_toplevel_v6_unset_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel);
   1.152 +        }
   1.153 +    } else {
   1.154 +        if (output) {
   1.155 +            wl_shell_surface_set_fullscreen(wind->shell_surface.wl,
   1.156 +                                            WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
   1.157 +                                            0, output);
   1.158 +        } else {
   1.159 +            wl_shell_surface_set_toplevel(wind->shell_surface.wl);
   1.160 +        }
   1.161 +    }
   1.162 +
   1.163 +    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   1.164 +}
   1.165 +
   1.166  void Wayland_ShowWindow(_THIS, SDL_Window *window)
   1.167  {
   1.168 -    SDL_WindowData *wind = window->driverdata;
   1.169 -
   1.170 -    if (window->flags & SDL_WINDOW_FULLSCREEN)
   1.171 -        wl_shell_surface_set_fullscreen(wind->shell_surface,
   1.172 -                                        WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
   1.173 -                                        0, (struct wl_output *)window->fullscreen_mode.driverdata);
   1.174 -    else
   1.175 -        wl_shell_surface_set_toplevel(wind->shell_surface);
   1.176 -
   1.177 -    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   1.178 +    struct wl_output *output = (struct wl_output *) window->fullscreen_mode.driverdata;
   1.179 +    SetFullscreen(_this, window, (window->flags & SDL_WINDOW_FULLSCREEN) ? output : NULL);
   1.180  }
   1.181  
   1.182  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   1.183 @@ -247,24 +349,20 @@
   1.184  Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
   1.185                              SDL_VideoDisplay * _display, SDL_bool fullscreen)
   1.186  {
   1.187 -    SDL_WindowData *wind = window->driverdata;
   1.188 -
   1.189 -    if (fullscreen)
   1.190 -        wl_shell_surface_set_fullscreen(wind->shell_surface,
   1.191 -                                        WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE,
   1.192 -                                        0, (struct wl_output *)_display->driverdata);
   1.193 -    else
   1.194 -        wl_shell_surface_set_toplevel(wind->shell_surface);
   1.195 -
   1.196 -    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   1.197 +    struct wl_output *output = (struct wl_output *) _display->driverdata;
   1.198 +    SetFullscreen(_this, window, fullscreen ? output : NULL);
   1.199  }
   1.200  
   1.201  void
   1.202  Wayland_RestoreWindow(_THIS, SDL_Window * window)
   1.203  {
   1.204      SDL_WindowData *wind = window->driverdata;
   1.205 +    const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
   1.206  
   1.207 -    wl_shell_surface_set_toplevel(wind->shell_surface);
   1.208 +    if (viddata->shell.zxdg) {
   1.209 +    } else {
   1.210 +        wl_shell_surface_set_toplevel(wind->shell_surface.wl);
   1.211 +    }
   1.212  
   1.213      WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   1.214  }
   1.215 @@ -273,10 +371,15 @@
   1.216  Wayland_MaximizeWindow(_THIS, SDL_Window * window)
   1.217  {
   1.218      SDL_WindowData *wind = window->driverdata;
   1.219 +    SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
   1.220  
   1.221 -    wl_shell_surface_set_maximized(wind->shell_surface, NULL);
   1.222 +    if (viddata->shell.zxdg) {
   1.223 +        zxdg_toplevel_v6_set_maximized(wind->shell_surface.zxdg.roleobj.toplevel);
   1.224 +    } else {
   1.225 +        wl_shell_surface_set_maximized(wind->shell_surface.wl, NULL);
   1.226 +    }
   1.227  
   1.228 -    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   1.229 +    WAYLAND_wl_display_flush( viddata->display );
   1.230  }
   1.231  
   1.232  int Wayland_CreateWindow(_THIS, SDL_Window *window)
   1.233 @@ -310,9 +413,18 @@
   1.234      data->surface =
   1.235          wl_compositor_create_surface(c->compositor);
   1.236      wl_surface_set_user_data(data->surface, data);
   1.237 -    data->shell_surface = wl_shell_get_shell_surface(c->shell,
   1.238 -                                                     data->surface);
   1.239 -    wl_shell_surface_set_class (data->shell_surface, c->classname);
   1.240 +
   1.241 +    if (c->shell.zxdg) {
   1.242 +        data->shell_surface.zxdg.surface = zxdg_shell_v6_get_xdg_surface(c->shell.zxdg, data->surface);
   1.243 +        /* !!! FIXME: add popup role */
   1.244 +        data->shell_surface.zxdg.roleobj.toplevel = zxdg_surface_v6_get_toplevel(data->shell_surface.zxdg.surface);
   1.245 +        zxdg_toplevel_v6_add_listener(data->shell_surface.zxdg.roleobj.toplevel, &toplevel_listener_zxdg, data);
   1.246 +        zxdg_toplevel_v6_set_app_id(data->shell_surface.zxdg.roleobj.toplevel, c->classname);
   1.247 +    } else {
   1.248 +        data->shell_surface.wl = wl_shell_get_shell_surface(c->shell.wl, data->surface);
   1.249 +        wl_shell_surface_set_class(data->shell_surface.wl, c->classname);
   1.250 +    }
   1.251 +
   1.252  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   1.253      if (c->surface_extension) {
   1.254          data->extended_surface = qt_surface_extension_get_extended_surface(
   1.255 @@ -333,10 +445,16 @@
   1.256          return SDL_SetError("failed to create a window surface");
   1.257      }
   1.258  
   1.259 -    if (data->shell_surface) {
   1.260 -        wl_shell_surface_set_user_data(data->shell_surface, data);
   1.261 -        wl_shell_surface_add_listener(data->shell_surface,
   1.262 -                                      &shell_surface_listener, data);
   1.263 +    if (c->shell.zxdg) {
   1.264 +        if (data->shell_surface.zxdg.surface) {
   1.265 +            zxdg_surface_v6_set_user_data(data->shell_surface.zxdg.surface, data);
   1.266 +            zxdg_surface_v6_add_listener(data->shell_surface.zxdg.surface, &shell_surface_listener_zxdg, data);
   1.267 +        }
   1.268 +    } else {
   1.269 +        if (data->shell_surface.wl) {
   1.270 +            wl_shell_surface_set_user_data(data->shell_surface.wl, data);
   1.271 +            wl_shell_surface_add_listener(data->shell_surface.wl, &shell_surface_listener_wl, data);
   1.272 +        }
   1.273      }
   1.274  
   1.275  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   1.276 @@ -356,6 +474,7 @@
   1.277          Wayland_input_lock_pointer(c->input);
   1.278      }
   1.279  
   1.280 +    wl_surface_commit(data->surface);
   1.281      WAYLAND_wl_display_flush(c->display);
   1.282  
   1.283      return 0;
   1.284 @@ -378,9 +497,14 @@
   1.285  void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
   1.286  {
   1.287      SDL_WindowData *wind = window->driverdata;
   1.288 +    SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
   1.289      
   1.290      if (window->title != NULL) {
   1.291 -        wl_shell_surface_set_title(wind->shell_surface, window->title);
   1.292 +        if (viddata->shell.zxdg) {
   1.293 +            zxdg_toplevel_v6_set_title(wind->shell_surface.zxdg.roleobj.toplevel, window->title);
   1.294 +        } else {
   1.295 +            wl_shell_surface_set_title(wind->shell_surface.wl, window->title);
   1.296 +        }
   1.297      }
   1.298  
   1.299      WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
   1.300 @@ -395,8 +519,18 @@
   1.301          SDL_EGL_DestroySurface(_this, wind->egl_surface);
   1.302          WAYLAND_wl_egl_window_destroy(wind->egl_window);
   1.303  
   1.304 -        if (wind->shell_surface)
   1.305 -            wl_shell_surface_destroy(wind->shell_surface);
   1.306 +        if (data->shell.zxdg) {
   1.307 +            if (wind->shell_surface.zxdg.roleobj.toplevel) {
   1.308 +                zxdg_toplevel_v6_destroy(wind->shell_surface.zxdg.roleobj.toplevel);
   1.309 +            }
   1.310 +            if (wind->shell_surface.zxdg.surface) {
   1.311 +                zxdg_surface_v6_destroy(wind->shell_surface.zxdg.surface);
   1.312 +            }
   1.313 +        } else {
   1.314 +            if (wind->shell_surface.wl) {
   1.315 +                wl_shell_surface_destroy(wind->shell_surface.wl);
   1.316 +            }
   1.317 +        }
   1.318  
   1.319  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   1.320          if (wind->extended_surface) {