GHOST/Wayland: improve workaround for libdecor setting the window state

libdecor has a workaround where creating the window would loop until
the windows configure callback ran.

Simplify this workaround by setting the initial state on the underlying
xdg_toplevel struct.

Also correct mixup between bool / GHOST_TSuccess types.
This commit is contained in:
Campbell Barton 2022-11-16 10:45:56 +11:00
parent 9f0e9f36be
commit aee5fcc120
2 changed files with 90 additions and 63 deletions

View File

@ -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);

View File

@ -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__)