diff --git a/include/SDL_syswm.h b/include/SDL_syswm.h index 18f6873299..f421bec0e2 100644 --- a/include/SDL_syswm.h +++ b/include/SDL_syswm.h @@ -294,7 +294,7 @@ struct SDL_SysWMinfo { struct wl_display *display; /**< Wayland display */ struct wl_surface *surface; /**< Wayland surface */ - void *shell_surface; /**< DEPRECATED Wayland shell_surface (window manager handle) */ + struct wl_shell_surface *shell_surface; /**< DEPRECATED Wayland shell_surface (window manager handle) */ struct wl_egl_window *egl_window; /**< Wayland EGL window (native window) */ struct xdg_surface *xdg_surface; /**< Wayland xdg surface (window manager handle) */ struct xdg_toplevel *xdg_toplevel; /**< Wayland xdg toplevel role */ diff --git a/src/video/wayland/SDL_waylanddyn.h b/src/video/wayland/SDL_waylanddyn.h index e86375ac94..e38dda4e12 100644 --- a/src/video/wayland/SDL_waylanddyn.h +++ b/src/video/wayland/SDL_waylanddyn.h @@ -111,11 +111,13 @@ void SDL_WAYLAND_UnloadSymbols(void); #define wl_shm_pool_interface (*WAYLAND_wl_shm_pool_interface) #define wl_buffer_interface (*WAYLAND_wl_buffer_interface) #define wl_registry_interface (*WAYLAND_wl_registry_interface) +#define wl_shell_surface_interface (*WAYLAND_wl_shell_surface_interface) #define wl_region_interface (*WAYLAND_wl_region_interface) #define wl_pointer_interface (*WAYLAND_wl_pointer_interface) #define wl_keyboard_interface (*WAYLAND_wl_keyboard_interface) #define wl_compositor_interface (*WAYLAND_wl_compositor_interface) #define wl_output_interface (*WAYLAND_wl_output_interface) +#define wl_shell_interface (*WAYLAND_wl_shell_interface) #define wl_shm_interface (*WAYLAND_wl_shm_interface) #define wl_data_device_interface (*WAYLAND_wl_data_device_interface) #define wl_data_offer_interface (*WAYLAND_wl_data_offer_interface) diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 496bb5e8fe..233c0eba5e 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -543,6 +543,10 @@ static SDL_bool ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial) input->seat, serial); } + } else { + if (window_data->shell_surface.wl) { + wl_shell_surface_move(window_data->shell_surface.wl, input->seat, serial); + } } return SDL_TRUE; @@ -568,6 +572,10 @@ static SDL_bool ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial) serial, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]); } + } else { + if (window_data->shell_surface.wl) { + wl_shell_surface_resize(window_data->shell_surface.wl, input->seat, serial, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]); + } } return SDL_TRUE; diff --git a/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h index 13fc0d8a7f..79902819ca 100644 --- a/src/video/wayland/SDL_waylandsym.h +++ b/src/video/wayland/SDL_waylandsym.h @@ -101,11 +101,13 @@ SDL_WAYLAND_INTERFACE(wl_surface_interface) SDL_WAYLAND_INTERFACE(wl_shm_pool_interface) SDL_WAYLAND_INTERFACE(wl_buffer_interface) SDL_WAYLAND_INTERFACE(wl_registry_interface) +SDL_WAYLAND_INTERFACE(wl_shell_surface_interface) SDL_WAYLAND_INTERFACE(wl_region_interface) SDL_WAYLAND_INTERFACE(wl_pointer_interface) SDL_WAYLAND_INTERFACE(wl_keyboard_interface) SDL_WAYLAND_INTERFACE(wl_compositor_interface) SDL_WAYLAND_INTERFACE(wl_output_interface) +SDL_WAYLAND_INTERFACE(wl_shell_interface) SDL_WAYLAND_INTERFACE(wl_shm_interface) SDL_WAYLAND_INTERFACE(wl_data_device_interface) SDL_WAYLAND_INTERFACE(wl_data_source_interface) diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 0549520d61..18d23f898e 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -847,6 +847,8 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint } else if (SDL_strcmp(interface, "xdg_wm_base") == 0) { d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, SDL_min(version, 5)); xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL); + } else if (SDL_strcmp(interface, "wl_shell") == 0) { + d->shell.wl = wl_registry_bind(d->registry, id, &wl_shell_interface, 1); } else if (SDL_strcmp(interface, "wl_shm") == 0) { d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); } else if (SDL_strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) { @@ -1098,6 +1100,11 @@ static void Wayland_VideoCleanup(_THIS) data->shm = NULL; } + if (data->shell.wl) { + wl_shell_destroy(data->shell.wl); + data->shell.wl = NULL; + } + if (data->shell.xdg) { xdg_wm_base_destroy(data->shell.xdg); data->shell.xdg = NULL; diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index 13e9b35ee8..c468b4a05c 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -64,6 +64,7 @@ typedef struct struct { struct xdg_wm_base *xdg; + struct wl_shell *wl; #ifdef HAVE_LIBDECOR_H struct libdecor *libdecor; #endif diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index d208c1ab26..ede8b4de6b 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -385,6 +385,20 @@ static void SetFullscreen(SDL_Window *window, struct wl_output *output) } else { xdg_toplevel_unset_fullscreen(wind->shell_surface.xdg.roleobj.toplevel); } + } else { + if (wind->shell_surface.wl == NULL) { + return; /* Can't do anything yet, wait for ShowWindow */ + } + + wl_surface_commit(wind->surface); + + if (output) { + wl_shell_surface_set_fullscreen(wind->shell_surface.wl, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + 0, output); + } else { + wl_shell_surface_set_toplevel(wind->shell_surface.wl); + } } } @@ -480,6 +494,62 @@ static const struct wl_callback_listener gles_swap_frame_listener = { static void Wayland_HandleResize(SDL_Window *window, int width, int height, float scale); +/* On modern desktops, we probably will use the xdg-shell protocol instead + of wl_shell, but wl_shell might be useful on older Wayland installs that + don't have the newer protocol, or embedded things that don't have a full + window manager. */ + +static void +handle_ping_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface, + uint32_t serial) +{ + wl_shell_surface_pong(shell_surface, serial); +} + +static void +handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface, + uint32_t edges, int32_t width, int32_t height) +{ + SDL_WindowData *wind = (SDL_WindowData *)data; + SDL_Window *window = wind->sdlwindow; + + /* wl_shell_surface spec states that this is a suggestion. + Ignore if less than or greater than max/min size. */ + + if (width == 0 || height == 0) { + return; + } + + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + if ((window->flags & SDL_WINDOW_RESIZABLE)) { + if (window->max_w > 0) { + width = SDL_min(width, window->max_w); + } + width = SDL_max(width, window->min_w); + + if (window->max_h > 0) { + height = SDL_min(height, window->max_h); + } + height = SDL_max(height, window->min_h); + } else { + return; + } + } + + Wayland_HandleResize(window, width, height, wind->scale_factor); +} + +static void +handle_popup_done_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface) +{ +} + +static const struct wl_shell_surface_listener shell_surface_listener_wl = { + handle_ping_wl_shell_surface, + handle_configure_wl_shell_surface, + handle_popup_done_wl_shell_surface +}; + static void handle_configure_xdg_shell_surface(void *data, struct xdg_surface *xdg, uint32_t serial) { SDL_WindowData *wind = (SDL_WindowData *)data; @@ -1359,6 +1429,11 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) SetMinMaxDimensions(window, SDL_FALSE); } + } else { + data->shell_surface.wl = wl_shell_get_shell_surface(c->shell.wl, data->surface); + wl_shell_surface_set_class(data->shell_surface.wl, c->classname); + wl_shell_surface_set_user_data(data->shell_surface.wl, data); + wl_shell_surface_add_listener(data->shell_surface.wl, &shell_surface_listener_wl, data); } /* Restore state that was set prior to this call */ @@ -1532,6 +1607,11 @@ void Wayland_HideWindow(_THIS, SDL_Window *window) xdg_surface_destroy(wind->shell_surface.xdg.surface); wind->shell_surface.xdg.surface = NULL; } + } else { + if (wind->shell_surface.wl) { + wl_shell_surface_destroy(wind->shell_surface.wl); + wind->shell_surface.wl = NULL; + } } /* @@ -1812,6 +1892,11 @@ void Wayland_RestoreWindow(_THIS, SDL_Window *window) return; /* Can't do anything yet, wait for ShowWindow */ } xdg_toplevel_unset_maximized(wind->shell_surface.xdg.roleobj.toplevel); + } else { + if (wind->shell_surface.wl == NULL) { + return; /* Can't do anything yet, wait for ShowWindow */ + } + wl_shell_surface_set_toplevel(wind->shell_surface.wl); } WAYLAND_wl_display_roundtrip(viddata->display); @@ -1891,6 +1976,11 @@ void Wayland_MaximizeWindow(_THIS, SDL_Window *window) return; /* Can't do anything yet, wait for ShowWindow */ } xdg_toplevel_set_maximized(wind->shell_surface.xdg.roleobj.toplevel); + } else { + if (wind->shell_surface.wl == NULL) { + return; /* Can't do anything yet, wait for ShowWindow */ + } + wl_shell_surface_set_maximized(wind->shell_surface.wl, NULL); } WAYLAND_wl_display_roundtrip(viddata->display); @@ -2205,6 +2295,11 @@ void Wayland_SetWindowTitle(_THIS, SDL_Window *window) return; /* Can't do anything yet, wait for ShowWindow */ } xdg_toplevel_set_title(wind->shell_surface.xdg.roleobj.toplevel, title); + } else { + if (wind->shell_surface.wl == NULL) { + return; /* Can'd do anything yet, wait for ShowWindow */ + } + wl_shell_surface_set_title(wind->shell_surface.wl, title); } WAYLAND_wl_display_flush(viddata->display); diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index 618fd21cf1..c21bcca07c 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -68,6 +68,7 @@ typedef struct } roleobj; SDL_bool initial_configure_seen; } xdg; + struct wl_shell_surface *wl; } shell_surface; enum {