diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp index 9a916f9bd1b..99bbf9109ec 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cpp +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -173,35 +173,24 @@ static GHOST_TWindowState gwl_window_state_get(const GWL_Window *win) return GHOST_kWindowStateNormal; } -static bool gwl_window_state_set(GWL_Window *win, const GHOST_TWindowState state) +#ifdef WITH_GHOST_WAYLAND_LIBDECOR +/** + * \note Keep in sync with #gwl_window_state_set_for_xdg. + */ +static bool gwl_window_state_set_for_libdecor(struct libdecor_frame *frame, + const GHOST_TWindowState state, + const GHOST_TWindowState state_current) { - const GHOST_TWindowState state_current = gwl_window_state_get(win); switch (state) { case GHOST_kWindowStateNormal: /* Unset states. */ switch (state_current) { case GHOST_kWindowStateMaximized: { -#ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (use_libdecor) { - libdecor_frame_unset_maximized(win->libdecor->frame); - } - else -#endif - { - xdg_toplevel_unset_maximized(win->xdg_decor->toplevel); - } + libdecor_frame_unset_maximized(frame); break; } case GHOST_kWindowStateFullScreen: { -#ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (use_libdecor) { - libdecor_frame_unset_fullscreen(win->libdecor->frame); - } - else -#endif - { - xdg_toplevel_unset_fullscreen(win->xdg_decor->toplevel); - } + libdecor_frame_unset_fullscreen(frame); break; } default: { @@ -210,46 +199,83 @@ static bool gwl_window_state_set(GWL_Window *win, const GHOST_TWindowState state } break; case GHOST_kWindowStateMaximized: { -#ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (use_libdecor) { - libdecor_frame_set_maximized(win->libdecor->frame); - } - else -#endif - { - xdg_toplevel_set_maximized(win->xdg_decor->toplevel); - } + libdecor_frame_set_maximized(frame); break; } case GHOST_kWindowStateMinimized: { -#ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (use_libdecor) { - libdecor_frame_set_minimized(win->libdecor->frame); - } - else -#endif - { - xdg_toplevel_set_minimized(win->xdg_decor->toplevel); - } + libdecor_frame_set_minimized(frame); break; } case GHOST_kWindowStateFullScreen: { -#ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (use_libdecor) { - libdecor_frame_set_fullscreen(win->libdecor->frame, nullptr); - } - else -#endif - { - xdg_toplevel_set_fullscreen(win->xdg_decor->toplevel, nullptr); - } + libdecor_frame_set_fullscreen(frame, nullptr); break; } case GHOST_kWindowStateEmbedded: { - return GHOST_kFailure; + return false; } } - return GHOST_kSuccess; + return true; +} + +#endif /* WITH_GHOST_WAYLAND_LIBDECOR */ + +/** + * \note Keep in sync with #gwl_window_state_set_for_libdecor. + */ +static bool gwl_window_state_set_for_xdg(struct xdg_toplevel *toplevel, + const GHOST_TWindowState state, + const GHOST_TWindowState state_current) +{ + switch (state) { + case GHOST_kWindowStateNormal: + /* Unset states. */ + switch (state_current) { + case GHOST_kWindowStateMaximized: { + xdg_toplevel_unset_maximized(toplevel); + break; + } + case GHOST_kWindowStateFullScreen: { + xdg_toplevel_unset_fullscreen(toplevel); + break; + } + default: { + break; + } + } + break; + case GHOST_kWindowStateMaximized: { + xdg_toplevel_set_maximized(toplevel); + break; + } + case GHOST_kWindowStateMinimized: { + xdg_toplevel_set_minimized(toplevel); + break; + } + case GHOST_kWindowStateFullScreen: { + xdg_toplevel_set_fullscreen(toplevel, nullptr); + break; + } + case GHOST_kWindowStateEmbedded: { + return false; + } + } + return true; +} + +static bool gwl_window_state_set(GWL_Window *win, const GHOST_TWindowState state) +{ + const GHOST_TWindowState state_current = gwl_window_state_get(win); + bool result; +#ifdef WITH_GHOST_WAYLAND_LIBDECOR + if (use_libdecor) { + result = gwl_window_state_set_for_libdecor(win->libdecor->frame, state, state_current); + } + else +#endif + { + result = gwl_window_state_set_for_xdg(win->xdg_decor->toplevel, state, state_current); + } + return result; } /** \} */ @@ -856,26 +882,23 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, wl_surface_commit(window_->wl_surface); wl_display_roundtrip(system_->wl_display()); -#ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (use_libdecor) { - WGL_LibDecor_Window &decor = *window_->libdecor; - /* It's important not to return until the window is configured or - * calls to `setState` from Blender will crash `libdecor`. */ - while (!decor.configured) { - if (libdecor_dispatch(system_->libdecor_context(), 0) < 0) { - break; - } - } - } -#endif - #ifdef GHOST_OPENGL_ALPHA setOpaque(); #endif /* Causes a glitch with `libdecor` for some reason. */ #ifdef WITH_GHOST_WAYLAND_LIBDECOR - if (use_libdecor == false) + if (use_libdecor) { + /* Additional round-trip is needed to ensure `xdg_toplevel` is set. */ + wl_display_roundtrip(system_->wl_display()); + + /* NOTE: LIBDECOR requires the window to be created & configured before the state can be set. + * Workaround this by using the underlying `xdg_toplevel` */ + WGL_LibDecor_Window &decor = *window_->libdecor; + struct xdg_toplevel *toplevel = libdecor_frame_get_xdg_toplevel(decor.frame); + gwl_window_state_set_for_xdg(toplevel, state, GHOST_kWindowStateNormal); + } + else #endif { gwl_window_state_set(window_, state); diff --git a/intern/wayland_dynload/extern/wayland_dynload_libdecor.h b/intern/wayland_dynload/extern/wayland_dynload_libdecor.h index 9dcecb4d876..0f5459491c0 100644 --- a/intern/wayland_dynload/extern/wayland_dynload_libdecor.h +++ b/intern/wayland_dynload/extern/wayland_dynload_libdecor.h @@ -19,6 +19,7 @@ WAYLAND_DYNLOAD_FN(libdecor_configuration_get_window_state) WAYLAND_DYNLOAD_FN(libdecor_decorate) WAYLAND_DYNLOAD_FN(libdecor_dispatch) WAYLAND_DYNLOAD_FN(libdecor_frame_commit) +WAYLAND_DYNLOAD_FN(libdecor_frame_get_xdg_toplevel) WAYLAND_DYNLOAD_FN(libdecor_frame_map) WAYLAND_DYNLOAD_FN(libdecor_frame_set_app_id) WAYLAND_DYNLOAD_FN(libdecor_frame_set_fullscreen) @@ -73,6 +74,7 @@ struct WaylandDynload_Libdecor { void WL_DYN_FN(libdecor_frame_commit)(struct libdecor_frame *frame, struct libdecor_state *state, struct libdecor_configuration *configuration); + struct xdg_toplevel *WL_DYN_FN(libdecor_frame_get_xdg_toplevel)(struct libdecor_frame *frame); void WL_DYN_FN(libdecor_frame_map)(struct libdecor_frame *frame); void WL_DYN_FN(libdecor_frame_set_app_id)(struct libdecor_frame *frame, const char *app_id); void WL_DYN_FN(libdecor_frame_set_fullscreen)(struct libdecor_frame *frame, @@ -108,6 +110,8 @@ struct WaylandDynload_Libdecor { # define libdecor_dispatch(...) (*wayland_dynload_libdecor.libdecor_dispatch)(__VA_ARGS__) # define libdecor_frame_commit(...) \ (*wayland_dynload_libdecor.libdecor_frame_commit)(__VA_ARGS__) +# define libdecor_frame_get_xdg_toplevel(...) \ + (*wayland_dynload_libdecor.libdecor_frame_get_xdg_toplevel)(__VA_ARGS__) # define libdecor_frame_map(...) (*wayland_dynload_libdecor.libdecor_frame_map)(__VA_ARGS__) # define libdecor_frame_set_app_id(...) \ (*wayland_dynload_libdecor.libdecor_frame_set_app_id)(__VA_ARGS__)