Core: add --no-window-frame command line option

Add a command line option to load Blender without a window frame.

Currently this is only used on Wayland, enabled for WITH_UI_TESTS since
attempting to load LIBDECOR caused the tests to crash on start on Fedora.
For tests there is no need to use LIBDECOR, so disable the window frame.
This can also be used by users who don't want to use the X11 fallback if
LIBDECOR can't be found.

Ref !147716
This commit is contained in:
Campbell Barton
2025-10-13 09:47:07 +00:00
parent d79a23e6b9
commit 3349b97987
12 changed files with 97 additions and 6 deletions

View File

@@ -1007,6 +1007,13 @@ extern GHOST_TCapabilityFlag GHOST_GetCapabilities(void);
*/
extern void GHOST_SetBacktraceHandler(GHOST_TBacktraceFn backtrace_fn);
/**
* When `use_window_frame` is false, don't show window frames.
*
* \note This must run before the system is created.
*/
extern void GHOST_UseWindowFrame(bool use_window_frame);
/**
* Focus window after opening, or put them in the background.
*/

View File

@@ -150,6 +150,9 @@ class GHOST_ISystem {
static GHOST_TBacktraceFn getBacktraceFn();
static void setBacktraceFn(GHOST_TBacktraceFn backtrace_fn);
static bool getUseWindowFrame();
static void setUseWindowFrame(bool use_window_frame);
protected:
/**
* Constructor.
@@ -541,5 +544,14 @@ class GHOST_ISystem {
/** Function to call that sets the back-trace. */
static GHOST_TBacktraceFn backtrace_fn_;
/**
* When false, don't use window frame.
*
* \note This needs to be set before system initialization
* to avoid loading LIBDECOR libraries (which can crash).
* If LIBDECOR is removed, this could be set on window creation instead.
*/
static bool use_window_frame_;
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_ISystem")
};

View File

@@ -965,6 +965,11 @@ void GHOST_SetBacktraceHandler(GHOST_TBacktraceFn backtrace_fn)
GHOST_ISystem::setBacktraceFn(backtrace_fn);
}
void GHOST_UseWindowFrame(bool use_window_frame)
{
GHOST_ISystem::setUseWindowFrame(use_window_frame);
}
void GHOST_UseWindowFocus(bool use_focus)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();

View File

@@ -39,6 +39,8 @@ const char *GHOST_ISystem::system_backend_id_ = nullptr;
GHOST_TBacktraceFn GHOST_ISystem::backtrace_fn_ = nullptr;
bool GHOST_ISystem::use_window_frame_ = true;
GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose, [[maybe_unused]] bool background)
{
@@ -53,12 +55,13 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose, [[maybe_unused]] bool b
GHOST_TSuccess success;
if (!system_) {
const bool use_window_frame = GHOST_ISystem::getUseWindowFrame();
#if defined(WITH_HEADLESS)
/* Pass. */
#elif defined(WITH_GHOST_WAYLAND)
# if defined(WITH_GHOST_WAYLAND_DYNLOAD)
const bool has_wayland_libraries = ghost_wl_dynload_libraries_init();
const bool has_wayland_libraries = ghost_wl_dynload_libraries_init(use_window_frame);
# else
const bool has_wayland_libraries = true;
# endif
@@ -261,3 +264,13 @@ void GHOST_ISystem::setBacktraceFn(GHOST_TBacktraceFn backtrace_fn)
{
GHOST_ISystem::backtrace_fn_ = backtrace_fn;
}
bool GHOST_ISystem::getUseWindowFrame()
{
return GHOST_ISystem::use_window_frame_;
}
void GHOST_ISystem::setUseWindowFrame(bool use_window_frame)
{
GHOST_ISystem::use_window_frame_ = use_window_frame;
}

View File

@@ -1548,6 +1548,11 @@ struct GWL_Display {
*/
bool background = false;
/**
* Show window decorations, otherwise all windows are frame-less.
*/
bool use_window_frame = false;
/* Threaded event handling. */
#ifdef USE_EVENT_BACKGROUND_THREAD
/**
@@ -7609,8 +7614,12 @@ GHOST_SystemWayland::GHOST_SystemWayland(const bool background)
wl_log_set_handler_client(background ? ghost_wayland_log_handler_background :
ghost_wayland_log_handler);
const bool use_window_frame = GHOST_ISystem::getUseWindowFrame();
display_->system = this;
display_->background = background;
display_->use_window_frame = use_window_frame;
/* Connect to the Wayland server. */
display_->wl.display = wl_display_connect(nullptr);
@@ -7641,7 +7650,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(const bool background)
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
bool libdecor_required = false;
{
if (use_window_frame) {
const char *xdg_current_desktop = [] {
/* Account for VSCode overriding this value (TSK!), see: #133921. */
const char *key = "ORIGINAL_XDG_CURRENT_DESKTOP";
@@ -9359,6 +9368,11 @@ GHOST_TimerManager *GHOST_SystemWayland::ghost_timer_manager()
}
#endif
bool GHOST_SystemWayland::use_window_frame_get()
{
return display_->use_window_frame;
}
/** \} */
/* -------------------------------------------------------------------- */
@@ -9870,7 +9884,7 @@ bool GHOST_SystemWayland::use_libdecor_runtime()
#endif
#ifdef WITH_GHOST_WAYLAND_DYNLOAD
bool ghost_wl_dynload_libraries_init()
bool ghost_wl_dynload_libraries_init(const bool use_window_frame)
{
# ifdef WITH_GHOST_X11
/* When running in WAYLAND, let the user know when a missing library is the only reason
@@ -9891,7 +9905,11 @@ bool ghost_wl_dynload_libraries_init()
)
{
# ifdef WITH_GHOST_WAYLAND_LIBDECOR
has_libdecor = wayland_dynload_libdecor_init(verbose); /* `libdecor-0`. */
if (use_window_frame) {
has_libdecor = wayland_dynload_libdecor_init(verbose); /* `libdecor-0`. */
}
# else
(void)use_window_frame;
# endif
return true;
}

View File

@@ -86,7 +86,7 @@ int gwl_window_scale_int_from(const GWL_WindowScaleParams &scale_params, int val
* Return true when all required WAYLAND libraries are present,
* Performs dynamic loading when `WITH_GHOST_WAYLAND_DYNLOAD` is in use.
*/
bool ghost_wl_dynload_libraries_init();
bool ghost_wl_dynload_libraries_init(bool use_window_frame);
void ghost_wl_dynload_libraries_exit();
#endif
@@ -280,6 +280,8 @@ class GHOST_SystemWayland : public GHOST_System {
bool completed) const;
void ime_end(const GHOST_WindowWayland *win) const;
bool use_window_frame_get();
static const char *xdg_app_id_get();
/* WAYLAND utility functions. */

View File

@@ -1867,12 +1867,16 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
GWL_XDG_Decor_Window &decor = *window_->xdg_decor;
if (system_->xdg_decor_manager_get()) {
const bool use_window_frame = system_->use_window_frame_get();
decor.toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
system_->xdg_decor_manager_get(), decor.toplevel);
zxdg_toplevel_decoration_v1_add_listener(
decor.toplevel_decor, &xdg_toplevel_decoration_v1_listener, window_);
/* Request client side decorations as a way of disabling decorations. */
zxdg_toplevel_decoration_v1_set_mode(decor.toplevel_decor,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
use_window_frame ?
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE :
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
}
/* Commit needed to so configure callback runs. */