diff --git a/include/SDL_syswm.h b/include/SDL_syswm.h index f7cd670cd..45f8e7540 100644 --- a/include/SDL_syswm.h +++ b/include/SDL_syswm.h @@ -298,6 +298,8 @@ struct SDL_SysWMinfo 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 */ + struct xdg_popup *xdg_popup; /**< Wayland xdg popup role */ + struct xdg_positioner *xdg_positioner; /**< Wayland xdg positioner, for popup */ } wl; #endif #if defined(SDL_VIDEO_DRIVER_MIR) /* no longer available, left for API/ABI compatibility. Remove in 2.1! */ diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index ba85c1d68..e515d9d6f 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -476,6 +476,9 @@ ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial) const uint32_t *directions_libdecor = directions; #endif + /* Hit tests shouldn't apply to xdg_popups, right? */ + SDL_assert(!WINDOW_IS_XDG_POPUP(window)); + switch (rc) { case SDL_HITTEST_DRAGGABLE: #ifdef HAVE_LIBDECOR_H diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index bce982fc6..0305c46a1 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -819,7 +819,7 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, } else if (SDL_strcmp(interface, "wl_seat") == 0) { Wayland_display_add_input(d, id, version); } else if (SDL_strcmp(interface, "xdg_wm_base") == 0) { - d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, 1); + d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, SDL_min(version, 3)); xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL); } else if (SDL_strcmp(interface, "wl_shm") == 0) { d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); @@ -924,12 +924,6 @@ Wayland_VideoInit(_THIS) /* Don't have server-side decorations? Try client-side instead. */ if (should_use_libdecor(data)) { data->shell.libdecor = libdecor_new(data->display, &libdecor_interface); - - /* If libdecor works, we don't need xdg-shell anymore. */ - if (data->shell.libdecor && data->shell.xdg) { - xdg_wm_base_destroy(data->shell.xdg); - data->shell.xdg = NULL; - } } #endif diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 7c6eb6429..9abf86834 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -25,12 +25,14 @@ #include "../SDL_sysvideo.h" #include "../../events/SDL_windowevents_c.h" +#include "../../events/SDL_mouse_c.h" #include "../SDL_egl_c.h" #include "SDL_waylandevents_c.h" #include "SDL_waylandwindow.h" #include "SDL_waylandvideo.h" #include "SDL_waylandtouch.h" #include "SDL_hints.h" +#include "SDL_events.h" #include "xdg-shell-client-protocol.h" #include "xdg-decoration-unstable-v1-client-protocol.h" @@ -318,6 +320,15 @@ SetMinMaxDimensions(SDL_Window *window, SDL_bool commit) SDL_VideoData *viddata = wind->waylandData; int min_width, min_height, max_width, max_height; + /* Pop-ups don't get to change size */ + if (WINDOW_IS_XDG_POPUP(window)) { + /* ... but we still want to commit, particularly for ShowWindow */ + if (commit) { + wl_surface_commit(wind->surface); + } + return; + } + if (window->flags & SDL_WINDOW_FULLSCREEN) { min_width = 0; min_height = 0; @@ -336,7 +347,7 @@ SetMinMaxDimensions(SDL_Window *window, SDL_bool commit) } #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -370,13 +381,22 @@ SetFullscreen(SDL_Window *window, struct wl_output *output, SDL_bool commit) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = wind->waylandData; + /* Pop-ups don't get to be fullscreened */ + if (WINDOW_IS_XDG_POPUP(window)) { + /* ... but we still want to commit, particularly for ShowWindow */ + if (commit) { + wl_surface_commit(wind->surface); + } + return; + } + /* The desktop may try to enforce min/max sizes here, so turn them off for * fullscreen and on (if applicable) for windowed */ SetMinMaxDimensions(window, SDL_FALSE); #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -609,6 +629,60 @@ static const struct xdg_toplevel_listener toplevel_listener_xdg = { handle_close_xdg_toplevel }; +static void +handle_configure_xdg_popup(void *data, + struct xdg_popup *xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + /* No-op, we don't use x/y and width/height are fixed-size */ +} + +static void +handle_done_xdg_popup(void *data, struct xdg_popup *xdg_popup) +{ + SDL_WindowData *window = (SDL_WindowData *)data; + SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0); +} + +static void +handle_repositioned_xdg_popup(void *data, + struct xdg_popup *xdg_popup, + uint32_t token) +{ + /* No-op, configure does all the work we care about */ +} + +static const struct xdg_popup_listener popup_listener_xdg = { + handle_configure_xdg_popup, + handle_done_xdg_popup, + handle_repositioned_xdg_popup +}; + +#define TOOLTIP_CURSOR_OFFSET 8 /* FIXME: Arbitrary, eyeballed from X tooltip */ + +static int +Wayland_PopupWatch(void *data, SDL_Event *event) +{ + if (event->type == SDL_MOUSEMOTION) { + SDL_Window *window = (SDL_Window *) data; + SDL_WindowData *data = window->driverdata; + + /* Coordinates might be relative to the popup, which we don't want */ + if (event->motion.windowID == data->shell_surface.xdg.roleobj.popup.parentID) { + xdg_positioner_set_offset(data->shell_surface.xdg.roleobj.popup.positioner, + event->motion.x + TOOLTIP_CURSOR_OFFSET, + event->motion.y + TOOLTIP_CURSOR_OFFSET); + xdg_popup_reposition(data->shell_surface.xdg.roleobj.popup.popup, + data->shell_surface.xdg.roleobj.popup.positioner, + 0); + } + } + return 1; +} + #ifdef HAVE_LIBDECOR_H static void decoration_frame_configure(struct libdecor_frame *frame, @@ -929,6 +1003,19 @@ static const struct wl_surface_listener surface_listener = { handle_surface_leave }; +static void +Wayland_FillEmptyShellInfo(SDL_SysWMinfo * info, const Uint32 version) +{ + info->info.wl.xdg_surface = NULL; + if (version >= SDL_VERSIONNUM(2, 0, 17)) { + info->info.wl.xdg_toplevel = NULL; + if (version >= SDL_VERSIONNUM(2, 0, 22)) { + info->info.wl.xdg_popup = NULL; + info->info.wl.xdg_positioner = NULL; + } + } +} + SDL_bool Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) { @@ -961,23 +1048,40 @@ Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) info->info.wl.egl_window = data->egl_window; #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor && data->shell_surface.libdecor.frame != NULL) { - info->info.wl.xdg_surface = libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame); - if (version >= SDL_VERSIONNUM(2, 0, 17)) { - info->info.wl.xdg_toplevel = libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame); + if (WINDOW_IS_LIBDECOR(viddata, window)) { + if (data->shell_surface.libdecor.frame != NULL) { + info->info.wl.xdg_surface = libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame); + if (version >= SDL_VERSIONNUM(2, 0, 17)) { + info->info.wl.xdg_toplevel = libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame); + if (version >= SDL_VERSIONNUM(2, 0, 22)) { + info->info.wl.xdg_popup = NULL; + info->info.wl.xdg_positioner = NULL; + } + } + } else { + /* Not mapped yet */ + Wayland_FillEmptyShellInfo(info, version); } } else #endif if (viddata->shell.xdg && data->shell_surface.xdg.surface != NULL) { info->info.wl.xdg_surface = data->shell_surface.xdg.surface; if (version >= SDL_VERSIONNUM(2, 0, 17)) { - info->info.wl.xdg_toplevel = data->shell_surface.xdg.roleobj.toplevel; + SDL_bool popup = WINDOW_IS_XDG_POPUP(window); + info->info.wl.xdg_toplevel = popup ? NULL : data->shell_surface.xdg.roleobj.toplevel; + if (version >= SDL_VERSIONNUM(2, 0, 22)) { + if (popup) { + info->info.wl.xdg_popup = data->shell_surface.xdg.roleobj.popup.popup; + info->info.wl.xdg_positioner = data->shell_surface.xdg.roleobj.popup.positioner; + } else { + info->info.wl.xdg_popup = NULL; + info->info.wl.xdg_positioner = NULL; + } + } } } else { - info->info.wl.xdg_surface = NULL; - if (version >= SDL_VERSIONNUM(2, 0, 17)) { - info->info.wl.xdg_toplevel = NULL; - } + /* Either it's not mapped yet or we don't have a shell protocol */ + Wayland_FillEmptyShellInfo(info, version); } } @@ -1002,6 +1106,10 @@ Wayland_SetWindowModalFor(_THIS, SDL_Window *modal_window, SDL_Window *parent_wi SDL_WindowData *modal_data = modal_window->driverdata; SDL_WindowData *parent_data = parent_window->driverdata; + if (WINDOW_IS_XDG_POPUP(modal_window) || WINDOW_IS_XDG_POPUP(parent_window)) { + return SDL_SetError("Modal/Parent was a popup, not a toplevel"); + } + #ifdef HAVE_LIBDECOR_H if (viddata->shell.libdecor) { if (modal_data->shell_surface.libdecor.frame == NULL) { @@ -1053,9 +1161,9 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) wl_surface_attach(data->surface, NULL, 0, 0); wl_surface_commit(data->surface); - /* Create the shell surface and map the toplevel */ + /* Create the shell surface and map the toplevel/popup */ #ifdef HAVE_LIBDECOR_H - if (c->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(c, window)) { data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor, data->surface, &libdecor_frame_interface, @@ -1073,10 +1181,42 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) xdg_surface_set_user_data(data->shell_surface.xdg.surface, data); xdg_surface_add_listener(data->shell_surface.xdg.surface, &shell_surface_listener_xdg, data); - /* !!! FIXME: add popup role */ - data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface); - xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname); - xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data); + if (WINDOW_IS_XDG_POPUP(window)) { + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Window *focused = SDL_GetMouseFocus(); + SDL_WindowData *focuseddata = focused->driverdata; + + /* This popup may be a child of another popup! */ + data->shell_surface.xdg.roleobj.popup.parentID = SDL_GetWindowID(focused); + data->shell_surface.xdg.roleobj.popup.child = NULL; + if (WINDOW_IS_XDG_POPUP(focused)) { + SDL_assert(focuseddata->shell_surface.xdg.roleobj.popup.child == NULL); + focuseddata->shell_surface.xdg.roleobj.popup.child = window; + } + + /* Set up the positioner for the popup */ + data->shell_surface.xdg.roleobj.popup.positioner = xdg_wm_base_create_positioner(c->shell.xdg); + xdg_positioner_set_offset(data->shell_surface.xdg.roleobj.popup.positioner, + mouse->x + TOOLTIP_CURSOR_OFFSET, + mouse->y + TOOLTIP_CURSOR_OFFSET); + + /* Assign the popup role */ + data->shell_surface.xdg.roleobj.popup.popup = xdg_surface_get_popup(data->shell_surface.xdg.surface, + focuseddata->shell_surface.xdg.surface, + data->shell_surface.xdg.roleobj.popup.positioner); + xdg_popup_add_listener(data->shell_surface.xdg.roleobj.popup.popup, &popup_listener_xdg, data); + + /* For tooltips, track mouse motion so it follows the cursor */ + if (window->flags & SDL_WINDOW_TOOLTIP) { + if (xdg_popup_get_version(data->shell_surface.xdg.roleobj.popup.popup) >= 3) { + SDL_AddEventWatch(Wayland_PopupWatch, window); + } + } + } else { + data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface); + xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname); + xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data); + } } /* Restore state that was set prior to this call */ @@ -1092,7 +1232,7 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) * this surface will fail. This is a new rule for xdg_shell. */ #ifdef HAVE_LIBDECOR_H - if (c->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(c, window)) { if (data->shell_surface.libdecor.frame) { while (!data->shell_surface.libdecor.initial_configure_seen) { WAYLAND_wl_display_flush(c->display); @@ -1116,7 +1256,7 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) } /* Create the window decorations */ - if (data->shell_surface.xdg.roleobj.toplevel && c->decoration_manager) { + if (!WINDOW_IS_XDG_POPUP(window) && data->shell_surface.xdg.roleobj.toplevel && c->decoration_manager) { data->server_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(c->decoration_manager, data->shell_surface.xdg.roleobj.toplevel); } } else { @@ -1129,11 +1269,11 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) * them immediately afterward. */ #ifdef HAVE_LIBDECOR_H - if (c->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(c, window)) { /* ... but don't call it redundantly for libdecor, the decorator * may not interpret a redundant call nicely and cause weird stuff to happen */ - if (window->flags & SDL_WINDOW_BORDERLESS) { + if (data->shell_surface.libdecor.frame && window->flags & SDL_WINDOW_BORDERLESS) { Wayland_SetWindowBordered(_this, window, SDL_FALSE); } } else @@ -1159,6 +1299,42 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) } } +static void +Wayland_ReleasePopup(_THIS, SDL_Window *popup) +{ + SDL_WindowData *popupdata; + + /* Basic sanity checks to weed out the weird popup closures */ + if (popup == NULL || popup->magic != &_this->window_magic) { + return; + } + popupdata = popup->driverdata; + if (popupdata == NULL) { + return; + } + + /* This may already be freed by a parent popup! */ + if (popupdata->shell_surface.xdg.roleobj.popup.popup == NULL) { + return; + } + + /* Release the child _first_, otherwise a protocol error triggers */ + if (popupdata->shell_surface.xdg.roleobj.popup.child != NULL) { + Wayland_ReleasePopup(_this, popupdata->shell_surface.xdg.roleobj.popup.child); + popupdata->shell_surface.xdg.roleobj.popup.child = NULL; + } + + if (popup->flags & SDL_WINDOW_TOOLTIP) { + if (xdg_popup_get_version(popupdata->shell_surface.xdg.roleobj.popup.popup) >= 3) { + SDL_DelEventWatch(Wayland_PopupWatch, popup); + } + } + xdg_popup_destroy(popupdata->shell_surface.xdg.roleobj.popup.popup); + xdg_positioner_destroy(popupdata->shell_surface.xdg.roleobj.popup.positioner); + popupdata->shell_surface.xdg.roleobj.popup.popup = NULL; + popupdata->shell_surface.xdg.roleobj.popup.positioner = NULL; +} + void Wayland_HideWindow(_THIS, SDL_Window *window) { SDL_VideoData *data = _this->driverdata; @@ -1170,7 +1346,7 @@ void Wayland_HideWindow(_THIS, SDL_Window *window) } #ifdef HAVE_LIBDECOR_H - if (data->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(data, window)) { if (wind->shell_surface.libdecor.frame) { libdecor_frame_unref(wind->shell_surface.libdecor.frame); wind->shell_surface.libdecor.frame = NULL; @@ -1178,7 +1354,9 @@ void Wayland_HideWindow(_THIS, SDL_Window *window) } else #endif if (data->shell.xdg) { - if (wind->shell_surface.xdg.roleobj.toplevel) { + if (WINDOW_IS_XDG_POPUP(window)) { + Wayland_ReleasePopup(_this, window); + } else if (wind->shell_surface.xdg.roleobj.toplevel) { xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel); wind->shell_surface.xdg.roleobj.toplevel = NULL; } @@ -1395,13 +1573,17 @@ Wayland_RestoreWindow(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + /* Set this flag now even if we never actually maximized, eventually * ShowWindow will take care of it along with the other window state. */ window->flags &= ~SDL_WINDOW_MAXIMIZED; #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1424,8 +1606,13 @@ Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) { SDL_WindowData *wind = window->driverdata; const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata; + + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame) { libdecor_frame_set_visibility(wind->shell_surface.libdecor.frame, bordered); } @@ -1444,7 +1631,7 @@ Wayland_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable) SDL_VideoData *data = _this->driverdata; const SDL_WindowData *wind = window->driverdata; - if (data->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(data, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1466,6 +1653,10 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + if (!(window->flags & SDL_WINDOW_RESIZABLE)) { return; } @@ -1476,7 +1667,7 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window) window->flags |= SDL_WINDOW_MAXIMIZED; #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1499,8 +1690,12 @@ Wayland_MinimizeWindow(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1721,9 +1916,14 @@ Wayland_HandleResize(SDL_Window *window, int width, int height, float scale) * It doesn't fix the first frames after resize being glitched visually, * but at least lets us not be terminated by the compositor. * Can be removed once SDL's resize logic becomes compliant. */ - if (viddata->shell.xdg && data->shell_surface.xdg.surface) { - xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, - GetWindowWidth(window), GetWindowHeight(window)); + if ( +#ifdef HAVE_LIBDECOR_H + !WINDOW_IS_LIBDECOR(viddata, window) && +#endif + viddata->shell.xdg && + data->shell_surface.xdg.surface) { + xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, + GetWindowWidth(window), GetWindowHeight(window)); } /* Update the viewport */ @@ -1753,7 +1953,7 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window) #ifdef HAVE_LIBDECOR_H /* we must not resize the window while we have a static (non-floating) size */ - if (data->shell.libdecor && + if (WINDOW_IS_LIBDECOR(data, window) && wind->shell_surface.libdecor.frame && !libdecor_frame_is_floating(wind->shell_surface.libdecor.frame)) { /* Commit the resize when we re-enter floating state */ @@ -1772,7 +1972,7 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window) } #ifdef HAVE_LIBDECOR_H - if (data->shell.libdecor && wind->shell_surface.libdecor.frame) { + if (WINDOW_IS_LIBDECOR(data, window) && wind->shell_surface.libdecor.frame) { state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window)); libdecor_frame_commit(wind->shell_surface.libdecor.frame, state, NULL); libdecor_state_free(state); @@ -1789,9 +1989,14 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window) wl_region_destroy(region); /* Update the geometry which may have been set by a hack in Wayland_HandleResize */ - if (data->shell.xdg && wind->shell_surface.xdg.surface) { - xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0, - GetWindowWidth(window), GetWindowHeight(window)); + if ( +#ifdef HAVE_LIBDECOR_H + !WINDOW_IS_LIBDECOR(data, window) && +#endif + data->shell.xdg && + wind->shell_surface.xdg.surface) { + xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0, + GetWindowWidth(window), GetWindowHeight(window)); } } @@ -1800,9 +2005,13 @@ void Wayland_SetWindowTitle(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + if (window->title != NULL) { #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index 97ae5ec8a..9ce687919 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -36,16 +36,27 @@ typedef struct { struct xdg_surface *surface; union { struct xdg_toplevel *toplevel; - struct xdg_popup *popup; + struct { + struct xdg_popup *popup; + struct xdg_positioner *positioner; + Uint32 parentID; + SDL_Window *child; + } popup; } roleobj; SDL_bool initial_configure_seen; } SDL_xdg_shell_surface; +#define WINDOW_IS_XDG_POPUP(window) \ + (window->flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU)) + #ifdef HAVE_LIBDECOR_H typedef struct { struct libdecor_frame *frame; SDL_bool initial_configure_seen; } SDL_libdecor_surface; + +#define WINDOW_IS_LIBDECOR(viddata, window) \ + (viddata->shell.libdecor && !WINDOW_IS_XDG_POPUP(window)) #endif typedef struct {