diff --git a/src/video/wayland/SDL_waylanddyn.h b/src/video/wayland/SDL_waylanddyn.h index 998a3809dcd7e..41c8bf908d6b4 100644 --- a/src/video/wayland/SDL_waylanddyn.h +++ b/src/video/wayland/SDL_waylanddyn.h @@ -165,6 +165,7 @@ extern void SDL_WAYLAND_UnloadSymbols(void); #define libdecor_frame_is_floating (*WAYLAND_libdecor_frame_is_floating) #define libdecor_frame_set_parent (*WAYLAND_libdecor_frame_set_parent) #define libdecor_frame_show_window_menu (*WAYLAND_libdecor_frame_show_window_menu) +#define libdecor_frame_get_wm_capabilities (*WAYLAND_libdecor_frame_get_wm_capabilities) #define libdecor_frame_get_xdg_surface (*WAYLAND_libdecor_frame_get_xdg_surface) #define libdecor_frame_get_xdg_toplevel (*WAYLAND_libdecor_frame_get_xdg_toplevel) #define libdecor_frame_translate_coordinate (*WAYLAND_libdecor_frame_translate_coordinate) diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 9f72d03c1dd5d..1de96fbf2efcc 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -638,7 +638,7 @@ static bool ProcessHitTest(SDL_WindowData *window_data, switch (window_data->hit_test_result) { case SDL_HITTEST_DRAGGABLE: #ifdef HAVE_LIBDECOR_H - if (window_data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (window_data->shell_surface.libdecor.frame) { libdecor_frame_move(window_data->shell_surface.libdecor.frame, seat, @@ -646,9 +646,9 @@ static bool ProcessHitTest(SDL_WindowData *window_data, } } else #endif - if (window_data->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { - if (window_data->shell_surface.xdg.roleobj.toplevel) { - xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel, + if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { + if (window_data->shell_surface.xdg.toplevel.xdg_toplevel) { + xdg_toplevel_move(window_data->shell_surface.xdg.toplevel.xdg_toplevel, seat, serial); } @@ -664,7 +664,7 @@ static bool ProcessHitTest(SDL_WindowData *window_data, case SDL_HITTEST_RESIZE_BOTTOMLEFT: case SDL_HITTEST_RESIZE_LEFT: #ifdef HAVE_LIBDECOR_H - if (window_data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (window_data->shell_surface.libdecor.frame) { libdecor_frame_resize(window_data->shell_surface.libdecor.frame, seat, @@ -673,9 +673,9 @@ static bool ProcessHitTest(SDL_WindowData *window_data, } } else #endif - if (window_data->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { - if (window_data->shell_surface.xdg.roleobj.toplevel) { - xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel, + if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { + if (window_data->shell_surface.xdg.toplevel.xdg_toplevel) { + xdg_toplevel_resize(window_data->shell_surface.xdg.toplevel.xdg_toplevel, seat, serial, directions[window_data->hit_test_result - SDL_HITTEST_RESIZE_TOPLEFT]); diff --git a/src/video/wayland/SDL_waylandopengles.c b/src/video/wayland/SDL_waylandopengles.c index 1e720e0e45c53..b2f320f5f99f4 100644 --- a/src/video/wayland/SDL_waylandopengles.c +++ b/src/video/wayland/SDL_waylandopengles.c @@ -115,8 +115,8 @@ bool Wayland_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) * FIXME: Request EGL_WAYLAND_swap_buffers_with_timeout. * -flibit */ - if (data->surface_status != WAYLAND_SURFACE_STATUS_SHOWN && - data->surface_status != WAYLAND_SURFACE_STATUS_WAITING_FOR_FRAME) { + if (data->shell_surface_status != WAYLAND_SHELL_SURFACE_STATUS_SHOWN && + data->shell_surface_status != WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) { return true; } @@ -134,7 +134,7 @@ bool Wayland_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) } // Control swap interval ourselves. See comments on Wayland_GLES_SetSwapInterval - if (swap_interval != 0 && data->surface_status == WAYLAND_SURFACE_STATUS_SHOWN) { + if (swap_interval != 0 && data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_SHOWN) { SDL_VideoData *videodata = _this->internal; struct wl_display *display = videodata->display; // 20hz, so we'll progress even if throttled to zero. diff --git a/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h index 6cd9a655897e2..341e80511b919 100644 --- a/src/video/wayland/SDL_waylandsym.h +++ b/src/video/wayland/SDL_waylandsym.h @@ -228,6 +228,10 @@ SDL_WAYLAND_SYM_OPT(void, libdecor_frame_get_max_content_size, (const struct lib int *)) #endif +#if defined(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR) || SDL_LIBDECOR_CHECK_VERSION(0, 3, 0) +SDL_WAYLAND_SYM_OPT(enum libdecor_wm_capabilities, libdecor_frame_get_wm_capabilities, (struct libdecor_frame *)) +#endif + #endif #undef SDL_WAYLAND_MODULE diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 60cfa76fa5840..5beafb0a87092 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -176,7 +176,7 @@ static void SetMinMaxDimensions(SDL_Window *window) } #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (!wind->shell_surface.libdecor.initial_configure_seen || !wind->shell_surface.libdecor.frame) { return; // Can't do anything yet, wait for ShowWindow } @@ -193,14 +193,14 @@ static void SetMinMaxDimensions(SDL_Window *window) } } else #endif - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { - if (wind->shell_surface.xdg.roleobj.toplevel == NULL) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { + if (wind->shell_surface.xdg.toplevel.xdg_toplevel == NULL) { return; // Can't do anything yet, wait for ShowWindow } - xdg_toplevel_set_min_size(wind->shell_surface.xdg.roleobj.toplevel, + xdg_toplevel_set_min_size(wind->shell_surface.xdg.toplevel.xdg_toplevel, min_width, min_height); - xdg_toplevel_set_max_size(wind->shell_surface.xdg.roleobj.toplevel, + xdg_toplevel_set_max_size(wind->shell_surface.xdg.toplevel.xdg_toplevel, max_width, max_height); } @@ -247,7 +247,7 @@ static void AdjustPopupOffset(SDL_Window *popup, int *x, int *y) { // Adjust the popup positioning, if necessary #ifdef HAVE_LIBDECOR_H - if (popup->parent->internal->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (popup->parent->internal->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { int adj_x, adj_y; libdecor_frame_translate_coordinate(popup->parent->internal->shell_surface.libdecor.frame, *x, *y, &adj_x, &adj_y); @@ -261,9 +261,9 @@ static void RepositionPopup(SDL_Window *window, bool use_current_position) { SDL_WindowData *wind = window->internal; - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_POPUP && - wind->shell_surface.xdg.roleobj.popup.positioner && - xdg_popup_get_version(wind->shell_surface.xdg.roleobj.popup.popup) >= XDG_POPUP_REPOSITION_SINCE_VERSION) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP && + wind->shell_surface.xdg.popup.xdg_positioner && + xdg_popup_get_version(wind->shell_surface.xdg.popup.xdg_popup) >= XDG_POPUP_REPOSITION_SINCE_VERSION) { int x = use_current_position ? window->x : window->floating.x; int y = use_current_position ? window->y : window->floating.y; @@ -273,11 +273,11 @@ static void RepositionPopup(SDL_Window *window, bool use_current_position) y = PixelToPoint(window->parent, y); } AdjustPopupOffset(window, &x, &y); - xdg_positioner_set_anchor_rect(wind->shell_surface.xdg.roleobj.popup.positioner, 0, 0, window->parent->internal->current.logical_width, window->parent->internal->current.logical_height); - xdg_positioner_set_size(wind->shell_surface.xdg.roleobj.popup.positioner, wind->current.logical_width, wind->current.logical_height); - xdg_positioner_set_offset(wind->shell_surface.xdg.roleobj.popup.positioner, x, y); - xdg_popup_reposition(wind->shell_surface.xdg.roleobj.popup.popup, - wind->shell_surface.xdg.roleobj.popup.positioner, + xdg_positioner_set_anchor_rect(wind->shell_surface.xdg.popup.xdg_positioner, 0, 0, window->parent->internal->current.logical_width, window->parent->internal->current.logical_height); + xdg_positioner_set_size(wind->shell_surface.xdg.popup.xdg_positioner, wind->current.logical_width, wind->current.logical_height); + xdg_positioner_set_offset(wind->shell_surface.xdg.popup.xdg_positioner, x, y); + xdg_popup_reposition(wind->shell_surface.xdg.popup.xdg_popup, + wind->shell_surface.xdg.popup.xdg_positioner, 0); } } @@ -297,7 +297,7 @@ static void SetSurfaceOpaqueRegion(SDL_WindowData *wind, bool is_opaque) } } -static void ConfigureWindowGeometry(SDL_Window *window) +static bool ConfigureWindowGeometry(SDL_Window *window) { SDL_WindowData *data = window->internal; const double scale_factor = GetWindowScale(window); @@ -306,6 +306,17 @@ static void ConfigureWindowGeometry(SDL_Window *window) int window_width, window_height; bool window_size_changed; + // Throttle interactive resize events to once per refresh cycle to prevent lag. + if (data->resizing) { + data->resizing = false; + + if (data->drop_interactive_resizes) { + return false; + } else { + data->drop_interactive_resizes = true; + } + } + // Set the drawable backbuffer size. GetBufferSize(window, &data->current.pixel_width, &data->current.pixel_height); const bool buffer_size_changed = data->current.pixel_width != old_pixel_width || @@ -413,7 +424,7 @@ static void ConfigureWindowGeometry(SDL_Window *window) * aren't supported to avoid a potential protocol violation if a buffer * with an old size is committed. */ - if (!data->viewport && data->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL && data->shell_surface.xdg.surface) { + if (!data->viewport && data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL && data->shell_surface.xdg.surface) { xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, data->current.logical_width, data->current.logical_height); } @@ -444,7 +455,7 @@ static void ConfigureWindowGeometry(SDL_Window *window) * * The occlusion state is immediately set again afterward, if necessary. */ - if (data->surface_status == WAYLAND_SURFACE_STATUS_SHOWN) { + if (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_SHOWN) { if ((buffer_size_changed || window_size_changed) || (!data->suspended && (window->flags & SDL_WINDOW_OCCLUDED))) { SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_EXPOSED, 0, 0); @@ -454,6 +465,8 @@ static void ConfigureWindowGeometry(SDL_Window *window) SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_OCCLUDED, 0, 0); } } + + return true; } static void CommitLibdecorFrame(SDL_Window *window) @@ -461,7 +474,7 @@ static void CommitLibdecorFrame(SDL_Window *window) #ifdef HAVE_LIBDECOR_H SDL_WindowData *wind = window->internal; - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR && wind->shell_surface.libdecor.frame) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR && wind->shell_surface.libdecor.frame) { struct libdecor_state *state = libdecor_state_new(wind->current.logical_width, wind->current.logical_height); libdecor_frame_commit(wind->shell_surface.libdecor.frame, state, NULL); libdecor_state_free(state); @@ -553,7 +566,7 @@ static void Wayland_move_window(SDL_Window *window) if (wind->last_displayID != displays[i]) { wind->last_displayID = displays[i]; - if (wind->shell_surface_type != WAYLAND_SURFACE_XDG_POPUP) { + if (wind->shell_surface_type != WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) { SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, display->x, display->y); SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_DISPLAY_CHANGED, wind->last_displayID, 0); } @@ -571,7 +584,7 @@ static void SetFullscreen(SDL_Window *window, struct wl_output *output) SDL_VideoData *viddata = wind->waylandData; #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (!wind->shell_surface.libdecor.frame) { return; // Can't do anything yet, wait for ShowWindow } @@ -588,8 +601,8 @@ static void SetFullscreen(SDL_Window *window, struct wl_output *output) } } else #endif - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { - if (wind->shell_surface.xdg.roleobj.toplevel == NULL) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { + if (wind->shell_surface.xdg.toplevel.xdg_toplevel == NULL) { return; // Can't do anything yet, wait for ShowWindow } @@ -599,9 +612,9 @@ static void SetFullscreen(SDL_Window *window, struct wl_output *output) Wayland_SetWindowResizable(SDL_GetVideoDevice(), window, true); wl_surface_commit(wind->surface); - xdg_toplevel_set_fullscreen(wind->shell_surface.xdg.roleobj.toplevel, output); + xdg_toplevel_set_fullscreen(wind->shell_surface.xdg.toplevel.xdg_toplevel, output); } else { - xdg_toplevel_unset_fullscreen(wind->shell_surface.xdg.roleobj.toplevel); + xdg_toplevel_unset_fullscreen(wind->shell_surface.xdg.toplevel.xdg_toplevel); } } @@ -666,12 +679,14 @@ static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time wl_surface_damage(wind->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32); } - if (wind->surface_status == WAYLAND_SURFACE_STATUS_WAITING_FOR_FRAME) { - wind->surface_status = WAYLAND_SURFACE_STATUS_SHOWN; + wind->drop_interactive_resizes = false; + + if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) { + wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_SHOWN; // If any child windows are waiting on this window to be shown, show them now for (SDL_Window *w = wind->sdlwindow->first_child; w; w = w->next_sibling) { - if (w->internal->surface_status == WAYLAND_SURFACE_STATUS_SHOW_PENDING) { + if (w->internal->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_SHOW_PENDING) { Wayland_ShowWindow(SDL_GetVideoDevice(), w); } else if (w->internal->reparenting_required) { Wayland_SetWindowParent(SDL_GetVideoDevice(), w, w->parent); @@ -720,8 +735,9 @@ static void handle_configure_xdg_shell_surface(void *data, struct xdg_surface *x SDL_WindowData *wind = (SDL_WindowData *)data; SDL_Window *window = wind->sdlwindow; - ConfigureWindowGeometry(window); - xdg_surface_ack_configure(xdg, serial); + if (ConfigureWindowGeometry(window)) { + xdg_surface_ack_configure(xdg, serial); + } wind->shell_surface.xdg.initial_configure_seen = true; } @@ -745,6 +761,7 @@ static void handle_configure_xdg_toplevel(void *data, bool floating = true; bool tiled = false; bool active = false; + bool resizing = false; bool suspended = false; wl_array_for_each (state, states) { switch (*state) { @@ -756,6 +773,9 @@ static void handle_configure_xdg_toplevel(void *data, maximized = true; floating = false; break; + case XDG_TOPLEVEL_STATE_RESIZING: + resizing = true; + break; case XDG_TOPLEVEL_STATE_ACTIVATED: active = true; break; @@ -931,9 +951,10 @@ static void handle_configure_xdg_toplevel(void *data, wind->suspended = suspended; wind->active = active; window->tiled = tiled; + wind->resizing = resizing; - if (wind->surface_status == WAYLAND_SURFACE_STATUS_WAITING_FOR_CONFIGURE) { - wind->surface_status = WAYLAND_SURFACE_STATUS_WAITING_FOR_FRAME; + if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) { + wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME; } } @@ -950,11 +971,33 @@ static void handle_xdg_configure_toplevel_bounds(void *data, // NOP } -void handle_xdg_toplevel_wm_capabilities(void *data, - struct xdg_toplevel *xdg_toplevel, - struct wl_array *capabilities) +static void handle_xdg_toplevel_wm_capabilities(void *data, + struct xdg_toplevel *xdg_toplevel, + struct wl_array *capabilities) { - // NOP + SDL_WindowData *wind = (SDL_WindowData *)data; + enum xdg_toplevel_wm_capabilities *wm_cap; + + wind->wm_caps = 0; + + wl_array_for_each (wm_cap, capabilities) { + switch (*wm_cap) { + case XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU: + wind->wm_caps |= WAYLAND_WM_CAPS_WINDOW_MENU; + break; + case XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE: + wind->wm_caps |= WAYLAND_WM_CAPS_MAXIMIZE; + break; + case XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN: + wind->wm_caps |= WAYLAND_WM_CAPS_FULLSCREEN; + break; + case XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE: + wind->wm_caps |= WAYLAND_WM_CAPS_MINIMIZE; + break; + default: + break; + } + } } static const struct xdg_toplevel_listener toplevel_listener_xdg = { @@ -991,8 +1034,8 @@ static void handle_configure_xdg_popup(void *data, SDL_SendWindowEvent(wind->sdlwindow, SDL_EVENT_WINDOW_MOVED, x, y); - if (wind->surface_status == WAYLAND_SURFACE_STATUS_WAITING_FOR_CONFIGURE) { - wind->surface_status = WAYLAND_SURFACE_STATUS_WAITING_FOR_FRAME; + if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) { + wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME; } } @@ -1041,7 +1084,7 @@ static void handle_configure_zxdg_decoration(void *data, Wayland_HideWindow(device, window); SDL_zero(internal->shell_surface); - internal->shell_surface_type = WAYLAND_SURFACE_LIBDECOR; + internal->shell_surface_type = WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR; Wayland_ShowWindow(device, window); } @@ -1099,7 +1142,6 @@ static void decoration_frame_configure(struct libdecor_frame *frame, { SDL_WindowData *wind = (SDL_WindowData *)user_data; SDL_Window *window = wind->sdlwindow; - struct libdecor_state *state; enum libdecor_window_state window_state; int width, height; @@ -1110,7 +1152,7 @@ static void decoration_frame_configure(struct libdecor_frame *frame, bool maximized = false; bool tiled = false; bool suspended = false; - bool floating; + bool resizing = false; static const enum libdecor_window_state tiled_states = (LIBDECOR_WINDOW_STATE_TILED_LEFT | LIBDECOR_WINDOW_STATE_TILED_RIGHT | LIBDECOR_WINDOW_STATE_TILED_TOP | LIBDECOR_WINDOW_STATE_TILED_BOTTOM); @@ -1123,9 +1165,12 @@ static void decoration_frame_configure(struct libdecor_frame *frame, tiled = (window_state & tiled_states) != 0; #if SDL_LIBDECOR_CHECK_VERSION(0, 2, 0) suspended = (window_state & LIBDECOR_WINDOW_STATE_SUSPENDED) != 0; +#endif +#if SDL_LIBDECOR_CHECK_VERSION(0, 3, 0) + resizing = (window_state & LIBDECOR_WINDOW_STATE_RESIZING) != 0; #endif } - floating = !(fullscreen || maximized || tiled); + const bool floating = !(fullscreen || maximized || tiled); UpdateWindowFullscreen(window, fullscreen); @@ -1295,21 +1340,40 @@ static void decoration_frame_configure(struct libdecor_frame *frame, wind->suspended = suspended; wind->active = active; window->tiled = tiled; + wind->resizing = resizing; - // Calculate the new window geometry - ConfigureWindowGeometry(window); + // Update the window manager capabilities. +#if SDL_LIBDECOR_CHECK_VERSION(0, 3, 0) + enum libdecor_wm_capabilities caps; +#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR + if (libdecor_frame_get_wm_capabilities) { + caps = libdecor_frame_get_wm_capabilities(wind->shell_surface.libdecor.frame); +#else + caps = libdecor_frame_get_wm_capabilities(wind->shell_surface.libdecor.frame); + { +#endif + wind->wm_caps = 0; + wind->wm_caps |= caps & LIBDECOR_WM_CAPABILITIES_WINDOW_MENU ? WAYLAND_WM_CAPS_WINDOW_MENU : 0; + wind->wm_caps |= caps & LIBDECOR_WM_CAPABILITIES_MAXIMIZE ? WAYLAND_WM_CAPS_MAXIMIZE : 0; + wind->wm_caps |= caps & LIBDECOR_WM_CAPABILITIES_FULLSCREEN ? WAYLAND_WM_CAPS_FULLSCREEN : 0; + wind->wm_caps |= caps & LIBDECOR_WM_CAPABILITIES_MINIMIZE ? WAYLAND_WM_CAPS_MINIMIZE : 0; + } +#endif - // ... then commit the changes on the libdecor side. - state = libdecor_state_new(wind->current.logical_width, wind->current.logical_height); - libdecor_frame_commit(frame, state, configuration); - libdecor_state_free(state); + // Calculate the new window geometry + if (ConfigureWindowGeometry(window)) { + // ... then commit the changes on the libdecor side. + struct libdecor_state *state = libdecor_state_new(wind->current.logical_width, wind->current.logical_height); + libdecor_frame_commit(frame, state, configuration); + libdecor_state_free(state); + } if (!wind->shell_surface.libdecor.initial_configure_seen) { LibdecorGetMinContentSize(frame, &wind->system_limits.min_width, &wind->system_limits.min_height); wind->shell_surface.libdecor.initial_configure_seen = true; } - if (wind->surface_status == WAYLAND_SURFACE_STATUS_WAITING_FOR_CONFIGURE) { - wind->surface_status = WAYLAND_SURFACE_STATUS_WAITING_FOR_FRAME; + if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) { + wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME; } /* Update the resize capability if this config event was the result of the @@ -1335,7 +1399,7 @@ static void decoration_frame_commit(struct libdecor_frame *frame, void *user_dat * commit a frame to trigger an update of the decoration surfaces. */ SDL_WindowData *wind = (SDL_WindowData *)user_data; - if (!wind->suspended && wind->surface_status == WAYLAND_SURFACE_STATUS_SHOWN) { + if (!wind->suspended && wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_SHOWN) { SDL_SendWindowEvent(wind->sdlwindow, SDL_EVENT_WINDOW_EXPOSED, 0, 0); } } @@ -1573,12 +1637,12 @@ static struct xdg_toplevel *GetToplevelForWindow(SDL_WindowData *wind) * internally anyways). */ #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR && wind->shell_surface.libdecor.frame) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR && wind->shell_surface.libdecor.frame) { return libdecor_frame_get_xdg_toplevel(wind->shell_surface.libdecor.frame); } else #endif - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL && wind->shell_surface.xdg.roleobj.toplevel) { - return wind->shell_surface.xdg.roleobj.toplevel; + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL && wind->shell_surface.xdg.toplevel.xdg_toplevel) { + return wind->shell_surface.xdg.toplevel.xdg_toplevel; } } @@ -1592,7 +1656,7 @@ bool Wayland_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Win child_data->reparenting_required = false; - if (parent_data && parent_data->surface_status != WAYLAND_SURFACE_STATUS_SHOWN) { + if (parent_data && parent_data->shell_surface_status != WAYLAND_SHELL_SURFACE_STATUS_SHOWN) { // Need to wait for the parent to become mapped, or it's the same as setting a null parent. child_data->reparenting_required = true; return true; @@ -1614,7 +1678,7 @@ bool Wayland_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool mod SDL_WindowData *data = window->internal; SDL_WindowData *parent_data = window->parent->internal; - if (parent_data->surface_status != WAYLAND_SURFACE_STATUS_SHOWN) { + if (parent_data->shell_surface_status != WAYLAND_SHELL_SURFACE_STATUS_SHOWN) { // Need to wait for the parent to become mapped before changing modal status. data->reparenting_required = true; return true; @@ -1678,7 +1742,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) SDL_PropertiesID props = SDL_GetWindowProperties(window); // Custom surfaces don't get toplevels and are always considered 'shown'; nothing to do here. - if (data->shell_surface_type == WAYLAND_SURFACE_CUSTOM) { + if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_CUSTOM) { return; } @@ -1691,8 +1755,8 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) * be shown when the parent is in the shown state. */ if (window->parent) { - if (window->parent->internal->surface_status != WAYLAND_SURFACE_STATUS_SHOWN) { - data->surface_status = WAYLAND_SURFACE_STATUS_SHOW_PENDING; + if (window->parent->internal->shell_surface_status != WAYLAND_SHELL_SURFACE_STATUS_SHOWN) { + data->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_SHOW_PENDING; return; } } @@ -1704,7 +1768,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) WAYLAND_wl_display_roundtrip(c->display); } - data->surface_status = WAYLAND_SURFACE_STATUS_WAITING_FOR_CONFIGURE; + data->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE; /* Detach any previous buffers before resetting everything, otherwise when * calling this a second time you'll get an annoying protocol error! @@ -1725,7 +1789,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) // Create the shell surface and map the toplevel/popup #ifdef HAVE_LIBDECOR_H - if (data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor, data->surface, &libdecor_frame_interface, @@ -1752,13 +1816,13 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) } } else #endif - if (data->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL || data->shell_surface_type == WAYLAND_SURFACE_XDG_POPUP) { + if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL || data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) { data->shell_surface.xdg.surface = xdg_wm_base_get_xdg_surface(c->shell.xdg, data->surface); 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); SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, data->shell_surface.xdg.surface); - if (data->shell_surface_type == WAYLAND_SURFACE_XDG_POPUP) { + if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) { SDL_Window *parent = window->parent; SDL_WindowData *parent_data = parent->internal; struct xdg_surface *parent_xdg_surface = NULL; @@ -1766,23 +1830,23 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) // Configure the popup parameters #ifdef HAVE_LIBDECOR_H - if (parent_data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (parent_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { parent_xdg_surface = libdecor_frame_get_xdg_surface(parent_data->shell_surface.libdecor.frame); } else #endif - if (parent_data->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL || - parent_data->shell_surface_type == WAYLAND_SURFACE_XDG_POPUP) { + if (parent_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL || + parent_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) { parent_xdg_surface = parent_data->shell_surface.xdg.surface; } // Set up the positioner for the popup and configure the constraints - data->shell_surface.xdg.roleobj.popup.positioner = xdg_wm_base_create_positioner(c->shell.xdg); - xdg_positioner_set_anchor(data->shell_surface.xdg.roleobj.popup.positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); - xdg_positioner_set_anchor_rect(data->shell_surface.xdg.roleobj.popup.positioner, 0, 0, parent->internal->current.logical_width, parent->internal->current.logical_width); - xdg_positioner_set_constraint_adjustment(data->shell_surface.xdg.roleobj.popup.positioner, + data->shell_surface.xdg.popup.xdg_positioner = xdg_wm_base_create_positioner(c->shell.xdg); + xdg_positioner_set_anchor(data->shell_surface.xdg.popup.xdg_positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); + xdg_positioner_set_anchor_rect(data->shell_surface.xdg.popup.xdg_positioner, 0, 0, parent->internal->current.logical_width, parent->internal->current.logical_width); + xdg_positioner_set_constraint_adjustment(data->shell_surface.xdg.popup.xdg_positioner, XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); - xdg_positioner_set_gravity(data->shell_surface.xdg.roleobj.popup.positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); - xdg_positioner_set_size(data->shell_surface.xdg.roleobj.popup.positioner, data->current.logical_width, data->current.logical_height); + xdg_positioner_set_gravity(data->shell_surface.xdg.popup.xdg_positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); + xdg_positioner_set_size(data->shell_surface.xdg.popup.xdg_positioner, data->current.logical_width, data->current.logical_height); // Set the popup initial position position_x = window->x; @@ -1793,13 +1857,13 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) position_y = PixelToPoint(window->parent, position_y); } AdjustPopupOffset(window, &position_x, &position_y); - xdg_positioner_set_offset(data->shell_surface.xdg.roleobj.popup.positioner, position_x, position_y); + xdg_positioner_set_offset(data->shell_surface.xdg.popup.xdg_positioner, position_x, position_y); // Assign the popup role - data->shell_surface.xdg.roleobj.popup.popup = xdg_surface_get_popup(data->shell_surface.xdg.surface, + data->shell_surface.xdg.popup.xdg_popup = xdg_surface_get_popup(data->shell_surface.xdg.surface, parent_xdg_surface, - data->shell_surface.xdg.roleobj.popup.positioner); - xdg_popup_add_listener(data->shell_surface.xdg.roleobj.popup.popup, &popup_listener_xdg, data); + data->shell_surface.xdg.popup.xdg_positioner); + xdg_popup_add_listener(data->shell_surface.xdg.popup.xdg_popup, &popup_listener_xdg, data); if (window->flags & SDL_WINDOW_TOOLTIP) { struct wl_region *region; @@ -1815,12 +1879,12 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) } } - SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_POPUP_POINTER, data->shell_surface.xdg.roleobj.popup.popup); - SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_POSITIONER_POINTER, data->shell_surface.xdg.roleobj.popup.positioner); + SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_POPUP_POINTER, data->shell_surface.xdg.popup.xdg_popup); + SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_POSITIONER_POINTER, data->shell_surface.xdg.popup.xdg_positioner); } 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, data->app_id); - xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data); + data->shell_surface.xdg.toplevel.xdg_toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface); + xdg_toplevel_set_app_id(data->shell_surface.xdg.toplevel.xdg_toplevel, data->app_id); + xdg_toplevel_add_listener(data->shell_surface.xdg.toplevel.xdg_toplevel, &toplevel_listener_xdg, data); if (c->zxdg_exporter_v2) { data->exported = zxdg_exporter_v2_export_toplevel(c->zxdg_exporter_v2, data->surface); @@ -1829,11 +1893,11 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) if (c->xdg_toplevel_icon_manager_v1 && data->xdg_toplevel_icon_v1) { xdg_toplevel_icon_manager_v1_set_icon(_this->internal->xdg_toplevel_icon_manager_v1, - data->shell_surface.xdg.roleobj.toplevel, + data->shell_surface.xdg.toplevel.xdg_toplevel, data->xdg_toplevel_icon_v1); } - SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, data->shell_surface.xdg.roleobj.toplevel); + SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, data->shell_surface.xdg.toplevel.xdg_toplevel); } } @@ -1850,7 +1914,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) * this surface will fail. This is a new rule for xdg_shell. */ #ifdef HAVE_LIBDECOR_H - if (data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (data->shell_surface.libdecor.frame) { while (!data->shell_surface.libdecor.initial_configure_seen) { WAYLAND_wl_display_flush(c->display); @@ -1859,7 +1923,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) } } else #endif - if (data->shell_surface_type == WAYLAND_SURFACE_XDG_POPUP || data->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { + if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP || data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { /* Unlike libdecor we need to call this explicitly to prevent a deadlock. * libdecor will call this as part of their configure event! * -flibit @@ -1873,8 +1937,8 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) } // Create the window decorations - if (data->shell_surface_type != WAYLAND_SURFACE_XDG_POPUP && 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); + if (data->shell_surface_type != WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP && data->shell_surface.xdg.toplevel.xdg_toplevel && c->decoration_manager) { + data->server_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(c->decoration_manager, data->shell_surface.xdg.toplevel.xdg_toplevel); zxdg_toplevel_decoration_v1_add_listener(data->server_decoration, &decoration_listener, window); @@ -1893,7 +1957,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) * them immediately afterward. */ #ifdef HAVE_LIBDECOR_H - if (data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { // Libdecor plugins can enforce minimum window sizes, so adjust if the initial window size is too small. if (window->windowed.w < data->system_limits.min_width || window->windowed.h < data->system_limits.min_height) { @@ -1933,7 +1997,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) wl_callback_add_listener(cb, &show_hide_sync_listener, (void*)((uintptr_t)window->id)); // Send an exposure event to signal that the client should draw. - if (data->surface_status == WAYLAND_SURFACE_STATUS_WAITING_FOR_FRAME) { + if (data->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) { SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_EXPOSED, 0, 0); } } @@ -1952,7 +2016,7 @@ static void Wayland_ReleasePopup(SDL_VideoDevice *_this, SDL_Window *popup) } // This may already be freed by a parent popup! - if (popupdata->shell_surface.xdg.roleobj.popup.popup == NULL) { + if (popupdata->shell_surface.xdg.popup.xdg_popup == NULL) { return; } @@ -1969,10 +2033,10 @@ static void Wayland_ReleasePopup(SDL_VideoDevice *_this, SDL_Window *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; + xdg_popup_destroy(popupdata->shell_surface.xdg.popup.xdg_popup); + xdg_positioner_destroy(popupdata->shell_surface.xdg.popup.xdg_positioner); + popupdata->shell_surface.xdg.popup.xdg_popup = NULL; + popupdata->shell_surface.xdg.popup.xdg_positioner = NULL; SDL_PropertiesID props = SDL_GetWindowProperties(popup); SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_POPUP_POINTER, NULL); @@ -1986,7 +2050,7 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) SDL_PropertiesID props = SDL_GetWindowProperties(window); // Custom surfaces have nothing to destroy and are always considered to be 'shown'; nothing to do here. - if (wind->shell_surface_type == WAYLAND_SURFACE_CUSTOM) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_CUSTOM) { return; } @@ -1997,7 +2061,7 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) WAYLAND_wl_display_roundtrip(data->display); } - wind->surface_status = WAYLAND_SURFACE_STATUS_HIDDEN; + wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_HIDDEN; if (wind->server_decoration) { zxdg_toplevel_decoration_v1_destroy(wind->server_decoration); @@ -2005,7 +2069,7 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) } // Be sure to detach after this is done, otherwise ShowWindow crashes! - if (wind->shell_surface_type != WAYLAND_SURFACE_XDG_POPUP) { + if (wind->shell_surface_type != WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) { wl_surface_attach(wind->surface, NULL, 0, 0); wl_surface_commit(wind->surface); } @@ -2024,7 +2088,7 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) } #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (wind->shell_surface.libdecor.frame) { libdecor_frame_unref(wind->shell_surface.libdecor.frame); wind->shell_surface.libdecor.frame = NULL; @@ -2034,11 +2098,11 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) } } else #endif - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_POPUP) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) { 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; + } else if (wind->shell_surface.xdg.toplevel.xdg_toplevel) { + xdg_toplevel_destroy(wind->shell_surface.xdg.toplevel.xdg_toplevel); + wind->shell_surface.xdg.toplevel.xdg_toplevel = NULL; SDL_SetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, NULL); } if (wind->shell_surface.xdg.surface) { @@ -2146,7 +2210,7 @@ SDL_FullscreenResult Wayland_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Win struct wl_output *output = display->internal->output; // Custom surfaces have no toplevel to make fullscreen. - if (wind->shell_surface_type == WAYLAND_SURFACE_CUSTOM) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_CUSTOM) { return SDL_FULLSCREEN_FAILED; } @@ -2205,7 +2269,7 @@ void Wayland_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window) SDL_WindowData *wind = window->internal; #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (!wind->shell_surface.libdecor.frame) { return; // Can't do anything yet, wait for ShowWindow } @@ -2213,11 +2277,11 @@ void Wayland_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window) } else #endif // Note that xdg-shell does NOT provide a way to unset minimize! - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { - if (wind->shell_surface.xdg.roleobj.toplevel == NULL) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { + if (wind->shell_surface.xdg.toplevel.xdg_toplevel == NULL) { return; // Can't do anything yet, wait for ShowWindow } - xdg_toplevel_unset_maximized(wind->shell_surface.xdg.roleobj.toplevel); + xdg_toplevel_unset_maximized(wind->shell_surface.xdg.toplevel.xdg_toplevel); } } @@ -2227,13 +2291,13 @@ void Wayland_SetWindowBordered(SDL_VideoDevice *_this, SDL_Window *window, bool const SDL_VideoData *viddata = (const SDL_VideoData *)_this->internal; #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (wind->shell_surface.libdecor.frame) { libdecor_frame_set_visibility(wind->shell_surface.libdecor.frame, bordered); } } else #endif - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { if ((viddata->decoration_manager) && (wind->server_decoration)) { const enum zxdg_toplevel_decoration_v1_mode mode = bordered ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; zxdg_toplevel_decoration_v1_set_mode(wind->server_decoration, mode); @@ -2246,7 +2310,7 @@ void Wayland_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool #ifdef HAVE_LIBDECOR_H const SDL_WindowData *wind = window->internal; - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (!wind->shell_surface.libdecor.frame) { return; // Can't do anything yet, wait for ShowWindow } @@ -2277,7 +2341,7 @@ void Wayland_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window) } #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (!wind->shell_surface.libdecor.frame) { return; // Can't do anything yet, wait for ShowWindow } @@ -2287,14 +2351,14 @@ void Wayland_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window) libdecor_frame_set_maximized(wind->shell_surface.libdecor.frame); } else #endif - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { - if (wind->shell_surface.xdg.roleobj.toplevel == NULL) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { + if (wind->shell_surface.xdg.toplevel.xdg_toplevel == NULL) { return; // Can't do anything yet, wait for ShowWindow } // Commit to preserve any pending size data. wl_surface_commit(wind->surface); - xdg_toplevel_set_maximized(wind->shell_surface.xdg.roleobj.toplevel); + xdg_toplevel_set_maximized(wind->shell_surface.xdg.toplevel.xdg_toplevel); } ++wind->maximized_deadline_count; @@ -2306,9 +2370,12 @@ void Wayland_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window) { SDL_WindowData *wind = window->internal; - // TODO: Check compositor capabilities to see if minimizing is supported + if (!(wind->wm_caps & WAYLAND_WM_CAPS_MINIMIZE)) { + return; + } + #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (!wind->shell_surface.libdecor.frame) { return; // Can't do anything yet, wait for ShowWindow } @@ -2316,11 +2383,11 @@ void Wayland_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window) SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0); } else #endif - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { - if (wind->shell_surface.xdg.roleobj.toplevel == NULL) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { + if (wind->shell_surface.xdg.toplevel.xdg_toplevel == NULL) { return; // Can't do anything yet, wait for ShowWindow } - xdg_toplevel_set_minimized(wind->shell_surface.xdg.roleobj.toplevel); + xdg_toplevel_set_minimized(wind->shell_surface.xdg.toplevel.xdg_toplevel); SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0); } } @@ -2395,6 +2462,9 @@ bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper data->waylandData = c; data->sdlwindow = window; + // Default to all capabilities + data->wm_caps = WAYLAND_WM_CAPS_ALL; + data->scale_factor = 1.0; if (SDL_WINDOW_IS_POPUP(window)) { @@ -2524,20 +2594,20 @@ bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper if (!custom_surface_role) { #ifdef HAVE_LIBDECOR_H if (c->shell.libdecor && !SDL_WINDOW_IS_POPUP(window)) { - data->shell_surface_type = WAYLAND_SURFACE_LIBDECOR; + data->shell_surface_type = WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR; } else #endif if (c->shell.xdg) { if (SDL_WINDOW_IS_POPUP(window)) { - data->shell_surface_type = WAYLAND_SURFACE_XDG_POPUP; + data->shell_surface_type = WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP; } else { - data->shell_surface_type = WAYLAND_SURFACE_XDG_TOPLEVEL; + data->shell_surface_type = WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL; } } // All other cases will be WAYLAND_SURFACE_UNKNOWN } else { // Roleless and external surfaces are always considered to be in the shown state by the backend. - data->shell_surface_type = WAYLAND_SURFACE_CUSTOM; - data->surface_status = WAYLAND_SURFACE_STATUS_SHOWN; + data->shell_surface_type = WAYLAND_SHELL_SURFACE_TYPE_CUSTOM; + data->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_SHOWN; } if (SDL_GetHintBoolean(SDL_HINT_VIDEO_DOUBLE_BUFFER, false)) { @@ -2571,15 +2641,15 @@ bool Wayland_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window) SDL_WindowData *wind = window->internal; // Only popup windows can be positioned relative to the parent. - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_POPUP) { - if (wind->shell_surface.xdg.roleobj.popup.popup && - xdg_popup_get_version(wind->shell_surface.xdg.roleobj.popup.popup) < XDG_POPUP_REPOSITION_SINCE_VERSION) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP) { + if (wind->shell_surface.xdg.popup.xdg_popup && + xdg_popup_get_version(wind->shell_surface.xdg.popup.xdg_popup) < XDG_POPUP_REPOSITION_SINCE_VERSION) { return SDL_Unsupported(); } RepositionPopup(window, false); return true; - } else if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR || wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { + } else if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR || wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { const int x = window->floating.x; const int y = window->floating.y; @@ -2630,7 +2700,7 @@ void Wayland_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) FlushPendingEvents(window); if (!(window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED)) || - wind->shell_surface_type == WAYLAND_SURFACE_CUSTOM) { + wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_CUSTOM) { if (!wind->scale_to_display) { wind->requested.logical_width = window->floating.w; wind->requested.logical_height = window->floating.h; @@ -2700,12 +2770,12 @@ void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window) const char *title = window->title ? window->title : ""; #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR && wind->shell_surface.libdecor.frame) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR && wind->shell_surface.libdecor.frame) { libdecor_frame_set_title(wind->shell_surface.libdecor.frame, title); } else #endif - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL && wind->shell_surface.xdg.roleobj.toplevel) { - xdg_toplevel_set_title(wind->shell_surface.xdg.roleobj.toplevel, title); + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL && wind->shell_surface.xdg.toplevel.xdg_toplevel) { + xdg_toplevel_set_title(wind->shell_surface.xdg.toplevel.xdg_toplevel, title); } } @@ -2739,12 +2809,12 @@ bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surfa xdg_toplevel_icon_v1_add_buffer(wind->xdg_toplevel_icon_v1, wind->icon.wl_buffer, 1); #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR && wind->shell_surface.libdecor.frame) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR && wind->shell_surface.libdecor.frame) { toplevel = libdecor_frame_get_xdg_toplevel(wind->shell_surface.libdecor.frame); } else #endif - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL && wind->shell_surface.xdg.roleobj.toplevel) { - toplevel = wind->shell_surface.xdg.roleobj.toplevel; + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL && wind->shell_surface.xdg.toplevel.xdg_toplevel) { + toplevel = wind->shell_surface.xdg.toplevel.xdg_toplevel; } if (toplevel) { @@ -2775,15 +2845,15 @@ void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y) } #ifdef HAVE_LIBDECOR_H - if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) { + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { if (wind->shell_surface.libdecor.frame) { libdecor_frame_show_window_menu(wind->shell_surface.libdecor.frame, wind->waylandData->input->seat, wind->waylandData->input->last_implicit_grab_serial, x, y); } } else #endif - if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) { - if (wind->shell_surface.xdg.roleobj.toplevel) { - xdg_toplevel_show_window_menu(wind->shell_surface.xdg.roleobj.toplevel, wind->waylandData->input->seat, wind->waylandData->input->last_implicit_grab_serial, x, y); + if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) { + if (wind->shell_surface.xdg.toplevel.xdg_toplevel) { + xdg_toplevel_show_window_menu(wind->shell_surface.xdg.toplevel.xdg_toplevel, wind->waylandData->input->seat, wind->waylandData->input->last_implicit_grab_serial, x, y); } } } diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index 7260575762885..4cf0ceec99e9a 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -56,32 +56,47 @@ struct SDL_WindowData struct xdg_surface *surface; union { - struct xdg_toplevel *toplevel; struct { - struct xdg_popup *popup; - struct xdg_positioner *positioner; + struct xdg_toplevel *xdg_toplevel; + } toplevel; + struct + { + struct xdg_popup *xdg_popup; + struct xdg_positioner *xdg_positioner; } popup; - } roleobj; + }; bool initial_configure_seen; } xdg; } shell_surface; enum { - WAYLAND_SURFACE_UNKNOWN = 0, - WAYLAND_SURFACE_XDG_TOPLEVEL, - WAYLAND_SURFACE_XDG_POPUP, - WAYLAND_SURFACE_LIBDECOR, - WAYLAND_SURFACE_CUSTOM + WAYLAND_SHELL_SURFACE_TYPE_UNKNOWN = 0, + WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL, + WAYLAND_SHELL_SURFACE_TYPE_XDG_POPUP, + WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR, + WAYLAND_SHELL_SURFACE_TYPE_CUSTOM } shell_surface_type; enum { - WAYLAND_SURFACE_STATUS_HIDDEN = 0, - WAYLAND_SURFACE_STATUS_WAITING_FOR_CONFIGURE, - WAYLAND_SURFACE_STATUS_WAITING_FOR_FRAME, - WAYLAND_SURFACE_STATUS_SHOW_PENDING, - WAYLAND_SURFACE_STATUS_SHOWN - } surface_status; + WAYLAND_SHELL_SURFACE_STATUS_HIDDEN = 0, + WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE, + WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME, + WAYLAND_SHELL_SURFACE_STATUS_SHOW_PENDING, + WAYLAND_SHELL_SURFACE_STATUS_SHOWN + } shell_surface_status; + enum + { + WAYLAND_WM_CAPS_WINDOW_MENU = 0x01, + WAYLAND_WM_CAPS_MAXIMIZE = 0x02, + WAYLAND_WM_CAPS_FULLSCREEN = 0x04, + WAYLAND_WM_CAPS_MINIMIZE = 0x08, + + WAYLAND_WM_CAPS_ALL = WAYLAND_WM_CAPS_WINDOW_MENU | + WAYLAND_WM_CAPS_MAXIMIZE | + WAYLAND_WM_CAPS_FULLSCREEN | + WAYLAND_WM_CAPS_MINIMIZE + } wm_caps; struct wl_egl_window *egl_window; struct SDL_WaylandInput *keyboard_device; @@ -165,7 +180,9 @@ struct SDL_WindowData Uint64 last_focus_event_time_ns; bool floating; bool suspended; + bool resizing; bool active; + bool drop_interactive_resizes; bool is_fullscreen; bool fullscreen_exclusive; bool drop_fullscreen_requests;