diff -r c9d9e7ec5bf6 src/video/wayland/SDL_waylanddyn.c --- a/src/video/wayland/SDL_waylanddyn.c Fri Jan 29 23:32:42 2021 +0100 +++ b/src/video/wayland/SDL_waylanddyn.c Sat Jan 30 02:16:09 2021 -0500 @@ -47,12 +47,16 @@ #ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON #define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON NULL #endif +#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECORATION +#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECORATION NULL +#endif static waylanddynlib waylandlibs[] = { {NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC}, {NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL}, {NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR}, - {NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON} + {NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON}, + {NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECORATION} }; static void * diff -r c9d9e7ec5bf6 src/video/wayland/SDL_waylanddyn.h --- a/src/video/wayland/SDL_waylanddyn.h Fri Jan 29 23:32:42 2021 +0100 +++ b/src/video/wayland/SDL_waylanddyn.h Sat Jan 30 02:16:09 2021 -0500 @@ -81,6 +81,8 @@ #define wl_proxy_add_listener (*WAYLAND_wl_proxy_add_listener) #define wl_proxy_marshal_constructor (*WAYLAND_wl_proxy_marshal_constructor) #define wl_proxy_marshal_constructor_versioned (*WAYLAND_wl_proxy_marshal_constructor_versioned) +#define wl_proxy_set_tag (*WAYLAND_wl_proxy_set_tag) +#define wl_proxy_get_tag (*WAYLAND_wl_proxy_get_tag) #define wl_seat_interface (*WAYLAND_wl_seat_interface) #define wl_surface_interface (*WAYLAND_wl_surface_interface) @@ -100,6 +102,24 @@ #define wl_data_source_interface (*WAYLAND_wl_data_source_interface) #define wl_data_device_manager_interface (*WAYLAND_wl_data_device_manager_interface) +#define libdecor_unref (*WAYLAND_libdecor_unref) +#define libdecor_new (*WAYLAND_libdecor_new) +#define libdecor_decorate (*WAYLAND_libdecor_decorate) +#define libdecor_frame_unref (*WAYLAND_libdecor_frame_unref) +#define libdecor_frame_set_title (*WAYLAND_libdecor_frame_set_title) +#define libdecor_frame_set_app_id (*WAYLAND_libdecor_frame_set_app_id) +#define libdecor_frame_resize (*WAYLAND_libdecor_frame_resize) +#define libdecor_frame_move (*WAYLAND_libdecor_frame_move) +#define libdecor_frame_commit (*WAYLAND_libdecor_frame_commit) +#define libdecor_frame_set_minimized (*WAYLAND_libdecor_frame_set_minimized) +#define libdecor_frame_set_maximized (*WAYLAND_libdecor_frame_set_maximized) +#define libdecor_frame_set_fullscreen (*WAYLAND_libdecor_frame_set_fullscreen) +#define libdecor_frame_unset_fullscreen (*WAYLAND_libdecor_frame_unset_fullscreen) +#define libdecor_frame_map (*WAYLAND_libdecor_frame_map) +#define libdecor_state_new (*WAYLAND_libdecor_state_new) +#define libdecor_state_free (*WAYLAND_libdecor_state_free) +#define libdecor_configuration_get_content_size (*WAYLAND_libdecor_configuration_get_content_size) + #endif /* SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC */ #include "wayland-client-protocol.h" diff -r c9d9e7ec5bf6 src/video/wayland/SDL_waylandevents.c --- a/src/video/wayland/SDL_waylandevents.c Fri Jan 29 23:32:42 2021 +0100 +++ b/src/video/wayland/SDL_waylandevents.c Sat Jan 30 02:16:09 2021 -0500 @@ -314,6 +314,11 @@ return; } + /* check that this surface belongs to one of the SDL windows */ + if (!SDL_WAYLAND_own_surface(surface)) { + return; + } + /* This handler will be called twice in Wayland 1.4 * Once for the window surface which has valid user data * and again for the mouse cursor surface which does not have valid user data @@ -369,12 +374,17 @@ WL_SHELL_SURFACE_RESIZE_*), but the values are the same. */ const uint32_t *directions_zxdg = directions_wl; + /* ditto for libdecoration. FIXME libdecoration: Right...? Please...? */ + const uint32_t *directions_libdecoration = directions_wl; + switch (rc) { case SDL_HITTEST_DRAGGABLE: if (input->display->shell.xdg) { xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial); } else if (input->display->shell.zxdg) { zxdg_toplevel_v6_move(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial); + } else if (input->display->shell.libdecoration) { + libdecor_frame_move(window_data->shell_surface.libdecoration.frame, input->seat, serial); } else { wl_shell_surface_move(window_data->shell_surface.wl, input->seat, serial); } @@ -392,6 +402,8 @@ xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]); } else if (input->display->shell.zxdg) { zxdg_toplevel_v6_resize(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]); + } else if (input->display->shell.libdecoration) { + libdecor_frame_resize(window_data->shell_surface.libdecoration.frame, input->seat, serial, directions_libdecoration[rc - SDL_HITTEST_RESIZE_TOPLEFT]); } else { wl_shell_surface_resize(window_data->shell_surface.wl, input->seat, serial, directions_wl[rc - SDL_HITTEST_RESIZE_TOPLEFT]); } diff -r c9d9e7ec5bf6 src/video/wayland/SDL_waylandsym.h --- a/src/video/wayland/SDL_waylandsym.h Fri Jan 29 23:32:42 2021 +0100 +++ b/src/video/wayland/SDL_waylandsym.h Sat Jan 30 02:16:09 2021 -0500 @@ -71,6 +71,10 @@ SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_10) SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor_versioned, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...)) +SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_18) +SDL_WAYLAND_SYM(void, wl_proxy_set_tag, (struct wl_proxy *, const char * const *)) +SDL_WAYLAND_SYM(const char * const *, wl_proxy_get_tag, (struct wl_proxy *)) + SDL_WAYLAND_INTERFACE(wl_seat_interface) SDL_WAYLAND_INTERFACE(wl_surface_interface) SDL_WAYLAND_INTERFACE(wl_shm_pool_interface) @@ -119,6 +123,39 @@ xkb_layout_index_t latched_layout,\ xkb_layout_index_t locked_layout) ) +SDL_WAYLAND_MODULE(WAYLAND_LIBDECORATION) +SDL_WAYLAND_SYM(void, libdecor_unref, (struct libdecor *)) +SDL_WAYLAND_SYM(struct libdecor *, libdecor_new, (struct wl_display *, struct libdecor_interface *)) +SDL_WAYLAND_SYM(struct libdecor_frame *, libdecor_decorate, (struct libdecor *,\ + struct wl_surface *,\ + struct libdecor_frame_interface *,\ + void *)) +SDL_WAYLAND_SYM(void, libdecor_frame_unref, (struct libdecor_frame *)) +SDL_WAYLAND_SYM(void, libdecor_frame_set_title, (struct libdecor_frame *, const char *)) +SDL_WAYLAND_SYM(void, libdecor_frame_set_app_id, (struct libdecor_frame *, const char *)) +SDL_WAYLAND_SYM(void, libdecor_frame_resize, (struct libdecor_frame *,\ + struct wl_seat *,\ + uint32_t,\ + enum libdecor_resize_edge)) +SDL_WAYLAND_SYM(void, libdecor_frame_move, (struct libdecor_frame *,\ + struct wl_seat *,\ + uint32_t)) +SDL_WAYLAND_SYM(void, libdecor_frame_commit, (struct libdecor_frame *,\ + struct libdecor_state *,\ + struct libdecor_configuration *)) +SDL_WAYLAND_SYM(void, libdecor_frame_set_minimized, (struct libdecor_frame *)) +SDL_WAYLAND_SYM(void, libdecor_frame_set_maximized, (struct libdecor_frame *)) +SDL_WAYLAND_SYM(void, libdecor_frame_set_fullscreen, (struct libdecor_frame *, struct wl_output *)) +SDL_WAYLAND_SYM(void, libdecor_frame_unset_fullscreen, (struct libdecor_frame *)) +SDL_WAYLAND_SYM(void, libdecor_frame_map, (struct libdecor_frame *)) +SDL_WAYLAND_SYM(struct libdecor_state *, libdecor_state_new, (int, int)) +SDL_WAYLAND_SYM(void, libdecor_state_free, (struct libdecor_state *)) +/* FIXME libdecoration: bool? in C? >:| */ +SDL_WAYLAND_SYM(uint8_t, libdecor_configuration_get_content_size, (struct libdecor_configuration *,\ + struct libdecor_frame *,\ + int *,\ + int *)) + #undef SDL_WAYLAND_MODULE #undef SDL_WAYLAND_SYM #undef SDL_WAYLAND_INTERFACE diff -r c9d9e7ec5bf6 src/video/wayland/SDL_waylandvideo.c --- a/src/video/wayland/SDL_waylandvideo.c Fri Jan 29 23:32:42 2021 +0100 +++ b/src/video/wayland/SDL_waylandvideo.c Sat Jan 30 02:16:09 2021 -0500 @@ -371,6 +371,19 @@ static void +libdecoration_error(struct libdecor *context, + enum libdecor_error error, + const char *message) +{ + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "libdecoration error (%d): %s\n", error, message); +} + +static const struct libdecor_interface libdecoration_interface = { + libdecoration_error, +}; + + +static void display_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) { @@ -457,6 +470,9 @@ Wayland_InitMouse(); + /* FIXME libdecoration: Shouldn't we check for other types first? */ + data->shell.libdecoration = libdecor_new(data->display, &libdecoration_interface); + /* Get the surface class name, usually the name of the application */ data->classname = get_classname(); @@ -503,6 +519,11 @@ display->desktop_mode.driverdata = NULL; } + /* FIXME libdecoration: Same issue as libdecor_new but on the other side */ + if (data->shell.libdecoration) { + libdecor_unref(data->shell.libdecoration); + } + Wayland_display_destroy_input(data); Wayland_display_destroy_pointer_constraints(data); Wayland_display_destroy_relative_pointer_manager(data); diff -r c9d9e7ec5bf6 src/video/wayland/SDL_waylandvideo.h --- a/src/video/wayland/SDL_waylandvideo.h Fri Jan 29 23:32:42 2021 +0100 +++ b/src/video/wayland/SDL_waylandvideo.h Sat Jan 30 02:16:09 2021 -0500 @@ -39,6 +39,15 @@ #include "../../core/linux/SDL_dbus.h" +/* FIXME libdecoration: Somewhere we're going to need this, and it needs to be + * early enough to where SDL_waylanddyn.h won't spew warnings when the SDL + * Vulkan headers eventually include it. + */ +#ifdef HAVE_LIBDECORATION_H +#include +#endif + + struct xkb_context; struct SDL_WaylandInput; @@ -60,6 +69,7 @@ struct xdg_wm_base *xdg; struct zxdg_shell_v6 *zxdg; struct wl_shell *wl; + struct libdecor *libdecoration; } shell; struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; struct zwp_pointer_constraints_v1 *pointer_constraints; diff -r c9d9e7ec5bf6 src/video/wayland/SDL_waylandwindow.c --- a/src/video/wayland/SDL_waylandwindow.c Fri Jan 29 23:32:42 2021 +0100 +++ b/src/video/wayland/SDL_waylandwindow.c Sat Jan 30 02:16:09 2021 -0500 @@ -39,6 +39,16 @@ #include "org-kde-kwin-server-decoration-manager-client-protocol.h" #include "idle-inhibit-unstable-v1-client-protocol.h" +static const char *SDL_WAYLAND_surface_tag = "sdl-window"; + +SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface) +{ + if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) { + return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag; + } + return SDL_TRUE; /* For older clients we have to assume this is us... */ +} + static float get_window_scale_factor(SDL_Window *window) { return ((SDL_WindowData*)window->driverdata)->scale_factor; } @@ -61,6 +71,12 @@ } else { zxdg_toplevel_v6_unset_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel); } + } else if (viddata->shell.libdecoration) { + if (output) { + libdecor_frame_set_fullscreen(wind->shell_surface.libdecoration.frame, output); + } else { + libdecor_frame_unset_fullscreen(wind->shell_surface.libdecoration.frame); + } } else { if (output) { wl_shell_surface_set_fullscreen(wind->shell_surface.wl, @@ -372,6 +388,61 @@ +static void +libdecoration_frame_configure(struct libdecor_frame *frame, + struct libdecor_configuration *configuration, + void *user_data) +{ + SDL_WindowData *wind = user_data; + SDL_Window *window = wind->sdlwindow; + int width, height; + struct libdecor_state *state; + + /* window size */ + if (!libdecor_configuration_get_content_size(configuration, frame, + &width, &height)) { + width = window->w; + height = window->h; + } + + wind->resize.width = width; + wind->resize.height = height; + + wind->resize.pending = SDL_TRUE; + wind->resize.configure = SDL_TRUE; + Wayland_HandlePendingResize(window); + wind->shell_surface.libdecoration.initial_configure_seen = SDL_TRUE; + + window->w = wind->resize.width; + window->h = wind->resize.height; + + state = libdecor_state_new(width, height); + libdecor_frame_commit(frame, state, configuration); + libdecor_state_free(state); +} + +static void +libdecoration_frame_close(struct libdecor_frame *frame, + void *user_data) +{ + SDL_SendWindowEvent(((SDL_WindowData *)user_data)->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0); +} + +static void +libdecoration_frame_commit(void *user_data) +{ + /* No-op */ +} + +static struct libdecor_frame_interface libdecoration_frame_interface = { + libdecoration_frame_configure, + libdecoration_frame_close, + libdecoration_frame_commit, +}; + + + + #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH static void handle_onscreen_visibility(void *data, @@ -625,6 +696,7 @@ const enum org_kde_kwin_server_decoration_manager_mode mode = bordered ? ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER : ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE; org_kde_kwin_server_decoration_request_mode(wind->kwin_server_decoration, mode); } + /* FIXME libdecoration: Implement toggling decorations */ } void @@ -647,6 +719,8 @@ xdg_toplevel_set_maximized(wind->shell_surface.xdg.roleobj.toplevel); } else if (viddata->shell.zxdg) { zxdg_toplevel_v6_set_maximized(wind->shell_surface.zxdg.roleobj.toplevel); + } else if (viddata->shell.libdecoration) { + libdecor_frame_set_maximized(wind->shell_surface.libdecoration.frame); } else { wl_shell_surface_set_maximized(wind->shell_surface.wl, NULL); } @@ -664,6 +738,8 @@ xdg_toplevel_set_minimized(wind->shell_surface.xdg.roleobj.toplevel); } else if (viddata->shell.zxdg) { zxdg_toplevel_v6_set_minimized(wind->shell_surface.zxdg.roleobj.toplevel); + } else if (viddata->shell.libdecoration) { + libdecor_frame_set_minimized(wind->shell_surface.libdecoration.frame); } WAYLAND_wl_display_flush(viddata->display); @@ -747,6 +823,10 @@ wl_compositor_create_surface(c->compositor); wl_surface_add_listener(data->surface, &surface_listener, data); + if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) { + wl_proxy_set_tag((struct wl_proxy *)data->surface, &SDL_WAYLAND_surface_tag); + } + if (c->shell.xdg) { data->shell_surface.xdg.surface = xdg_wm_base_get_xdg_surface(c->shell.xdg, data->surface); /* !!! FIXME: add popup role */ @@ -759,6 +839,17 @@ data->shell_surface.zxdg.roleobj.toplevel = zxdg_surface_v6_get_toplevel(data->shell_surface.zxdg.surface); zxdg_toplevel_v6_add_listener(data->shell_surface.zxdg.roleobj.toplevel, &toplevel_listener_zxdg, data); zxdg_toplevel_v6_set_app_id(data->shell_surface.zxdg.roleobj.toplevel, c->classname); + } else if (c->shell.libdecoration) { + data->shell_surface.libdecoration.frame = libdecor_decorate(c->shell.libdecoration, + data->surface, + &libdecoration_frame_interface, + data); + if (data->shell_surface.libdecoration.frame == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Failed to create libdecoration frame!"); + } else { + libdecor_frame_set_app_id(data->shell_surface.libdecoration.frame, c->classname); + libdecor_frame_map(data->shell_surface.libdecoration.frame); + } } 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); @@ -855,6 +946,13 @@ WAYLAND_wl_display_dispatch(c->display); } } + } else if (c->shell.libdecoration) { + if (data->shell_surface.libdecoration.frame) { + while (!data->shell_surface.libdecoration.initial_configure_seen) { + WAYLAND_wl_display_flush(c->display); + WAYLAND_wl_display_dispatch(c->display); + } + } } /* We may need to create an idle inhibitor for this new window */ @@ -930,6 +1028,8 @@ xdg_toplevel_set_title(wind->shell_surface.xdg.roleobj.toplevel, window->title); } else if (viddata->shell.zxdg) { zxdg_toplevel_v6_set_title(wind->shell_surface.zxdg.roleobj.toplevel, window->title); + } else if (viddata->shell.libdecoration) { + libdecor_frame_set_title(wind->shell_surface.libdecoration.frame, window->title); } else { wl_shell_surface_set_title(wind->shell_surface.wl, window->title); } @@ -1015,6 +1115,10 @@ if (wind->shell_surface.zxdg.surface) { zxdg_surface_v6_destroy(wind->shell_surface.zxdg.surface); } + } else if (data->shell.libdecoration) { + if (wind->shell_surface.libdecoration.frame) { + libdecor_frame_unref(wind->shell_surface.libdecoration.frame); + } } else { if (wind->shell_surface.wl) { wl_shell_surface_destroy(wind->shell_surface.wl); diff -r c9d9e7ec5bf6 src/video/wayland/SDL_waylandwindow.h --- a/src/video/wayland/SDL_waylandwindow.h Fri Jan 29 23:32:42 2021 +0100 +++ b/src/video/wayland/SDL_waylandwindow.h Sat Jan 30 02:16:09 2021 -0500 @@ -51,12 +51,18 @@ } SDL_xdg_shell_surface; typedef struct { + struct libdecor_frame *frame; + SDL_bool initial_configure_seen; +} SDL_libdecoration_surface; + +typedef struct { SDL_Window *sdlwindow; SDL_VideoData *waylandData; struct wl_surface *surface; union { SDL_xdg_shell_surface xdg; SDL_zxdg_shell_surface zxdg; + SDL_libdecoration_surface libdecoration; struct wl_shell_surface *wl; } shell_surface; struct wl_egl_window *egl_window; @@ -108,6 +114,8 @@ extern void Wayland_HandlePendingResize(SDL_Window *window); +extern SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface); + #endif /* SDL_waylandwindow_h_ */ /* vi: set ts=4 sw=4 expandtab: */