macOS: Colored Titlebar and WM Window Decoration Styles API - GSoC 2024
As part of the GSoC 2024 project "Improvements to the Blender macOS User Interface Experience" [1], this patch implements colored titlebar window decorations on macOS, based on the current Blender theme colors. Additionally, this patch introduces a new WM/GHOST API for implementing and enabling custom decoration styles on any system/desktop environment that support customizing window decorations. [1]: https://devtalk.blender.org/t/gsoc-2024-proposal-improvements-to-the-blender-macos-user-interface-experience/34022) Pull Request: https://projects.blender.org/blender/blender/pulls/123982
This commit is contained in:
@@ -593,6 +593,31 @@ extern char *GHOST_GetTitle(GHOST_WindowHandle windowhandle);
|
|||||||
*/
|
*/
|
||||||
extern GHOST_TSuccess GHOST_SetPath(GHOST_WindowHandle windowhandle, const char *filepath);
|
extern GHOST_TSuccess GHOST_SetPath(GHOST_WindowHandle windowhandle, const char *filepath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current window decoration style flags.
|
||||||
|
*/
|
||||||
|
extern GHOST_TWindowDecorationStyleFlags GHOST_GetWindowDecorationStyleFlags(
|
||||||
|
GHOST_WindowHandle windowhandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the window decoration style flags.
|
||||||
|
* \param styleFlags: Window decoration style flags.
|
||||||
|
*/
|
||||||
|
extern void GHOST_SetWindowDecorationStyleFlags(GHOST_WindowHandle windowhandle,
|
||||||
|
GHOST_TWindowDecorationStyleFlags styleFlags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the window decoration style settings.
|
||||||
|
* \param decorationSettings: Window decoration style settings.
|
||||||
|
*/
|
||||||
|
extern void GHOST_SetWindowDecorationStyleSettings(
|
||||||
|
GHOST_WindowHandle windowhandle, GHOST_WindowDecorationStyleSettings decorationSettings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the window decoration style using the current flags and settings.
|
||||||
|
*/
|
||||||
|
extern GHOST_TSuccess GHOST_ApplyWindowDecorationStyle(GHOST_WindowHandle windowhandle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the window rectangle dimensions.
|
* Returns the window rectangle dimensions.
|
||||||
* These are screen coordinates.
|
* These are screen coordinates.
|
||||||
|
|||||||
@@ -87,6 +87,29 @@ class GHOST_IWindow {
|
|||||||
*/
|
*/
|
||||||
virtual GHOST_TSuccess setPath(const char *filepath) = 0;
|
virtual GHOST_TSuccess setPath(const char *filepath) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current window decoration style flags.
|
||||||
|
*/
|
||||||
|
virtual GHOST_TWindowDecorationStyleFlags getWindowDecorationStyleFlags() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the window decoration style flags.
|
||||||
|
* \param styleFlags: Window decoration style flags.
|
||||||
|
*/
|
||||||
|
virtual void setWindowDecorationStyleFlags(GHOST_TWindowDecorationStyleFlags styleFlags) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the window decoration style settings.
|
||||||
|
* \param decorationSettings: Window decoration style settings.
|
||||||
|
*/
|
||||||
|
virtual void setWindowDecorationStyleSettings(
|
||||||
|
GHOST_WindowDecorationStyleSettings decorationSettings) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the window decoration style using the current flags and settings.
|
||||||
|
*/
|
||||||
|
virtual GHOST_TSuccess applyWindowDecorationStyle() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the window rectangle dimensions.
|
* Returns the window rectangle dimensions.
|
||||||
* These are screen coordinates.
|
* These are screen coordinates.
|
||||||
|
|||||||
@@ -119,6 +119,10 @@ typedef enum {
|
|||||||
* Support detecting the physical trackpad direction.
|
* Support detecting the physical trackpad direction.
|
||||||
*/
|
*/
|
||||||
GHOST_kCapabilityTrackpadPhysicalDirection = (1 << 7),
|
GHOST_kCapabilityTrackpadPhysicalDirection = (1 << 7),
|
||||||
|
/**
|
||||||
|
* Support for window decoration styles.
|
||||||
|
*/
|
||||||
|
GHOST_kCapabilityWindowDecorationStyles = (1 << 8),
|
||||||
} GHOST_TCapabilityFlag;
|
} GHOST_TCapabilityFlag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,7 +133,8 @@ typedef enum {
|
|||||||
(GHOST_kCapabilityCursorWarp | GHOST_kCapabilityWindowPosition | \
|
(GHOST_kCapabilityCursorWarp | GHOST_kCapabilityWindowPosition | \
|
||||||
GHOST_kCapabilityPrimaryClipboard | GHOST_kCapabilityGPUReadFrontBuffer | \
|
GHOST_kCapabilityPrimaryClipboard | GHOST_kCapabilityGPUReadFrontBuffer | \
|
||||||
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityDesktopSample | \
|
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityDesktopSample | \
|
||||||
GHOST_kCapabilityInputIME | GHOST_kCapabilityTrackpadPhysicalDirection)
|
GHOST_kCapabilityInputIME | GHOST_kCapabilityTrackpadPhysicalDirection | \
|
||||||
|
GHOST_kCapabilityWindowDecorationStyles)
|
||||||
|
|
||||||
/* Xtilt and Ytilt represent how much the pen is tilted away from
|
/* Xtilt and Ytilt represent how much the pen is tilted away from
|
||||||
* vertically upright in either the X or Y direction, with X and Y the
|
* vertically upright in either the X or Y direction, with X and Y the
|
||||||
@@ -694,6 +699,11 @@ typedef enum {
|
|||||||
/* Can be extended as needed. */
|
/* Can be extended as needed. */
|
||||||
} GHOST_TUserSpecialDirTypes;
|
} GHOST_TUserSpecialDirTypes;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GHOST_kDecorationNone = 0,
|
||||||
|
GHOST_kDecorationColoredTitleBar = (1 << 0),
|
||||||
|
} GHOST_TWindowDecorationStyleFlags;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/** Number of pixels on a line. */
|
/** Number of pixels on a line. */
|
||||||
uint32_t xPixels;
|
uint32_t xPixels;
|
||||||
@@ -720,6 +730,11 @@ typedef struct {
|
|||||||
GHOST_GPUDevice preferred_device;
|
GHOST_GPUDevice preferred_device;
|
||||||
} GHOST_GPUSettings;
|
} GHOST_GPUSettings;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float colored_titlebar_bg_color[3];
|
||||||
|
float colored_titlebar_fg_color[3];
|
||||||
|
} GHOST_WindowDecorationStyleSettings;
|
||||||
|
|
||||||
#ifdef WITH_VULKAN_BACKEND
|
#ifdef WITH_VULKAN_BACKEND
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/** Image handle to the image that will be presented to the user. */
|
/** Image handle to the image that will be presented to the user. */
|
||||||
|
|||||||
@@ -606,6 +606,33 @@ GHOST_TSuccess GHOST_SetPath(GHOST_WindowHandle windowhandle, const char *filepa
|
|||||||
return window->setPath(filepath);
|
return window->setPath(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GHOST_TWindowDecorationStyleFlags GHOST_GetWindowDecorationStyleFlags(
|
||||||
|
GHOST_WindowHandle windowhandle)
|
||||||
|
{
|
||||||
|
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
|
||||||
|
return window->getWindowDecorationStyleFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GHOST_SetWindowDecorationStyleFlags(GHOST_WindowHandle windowhandle,
|
||||||
|
GHOST_TWindowDecorationStyleFlags styleFlags)
|
||||||
|
{
|
||||||
|
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
|
||||||
|
window->setWindowDecorationStyleFlags(styleFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GHOST_SetWindowDecorationStyleSettings(GHOST_WindowHandle windowhandle,
|
||||||
|
GHOST_WindowDecorationStyleSettings decorationSettings)
|
||||||
|
{
|
||||||
|
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
|
||||||
|
window->setWindowDecorationStyleSettings(decorationSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
GHOST_TSuccess GHOST_ApplyWindowDecorationStyle(GHOST_WindowHandle windowhandle)
|
||||||
|
{
|
||||||
|
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
|
||||||
|
return window->applyWindowDecorationStyle();
|
||||||
|
}
|
||||||
|
|
||||||
GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle)
|
GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle)
|
||||||
{
|
{
|
||||||
const GHOST_IWindow *window = (const GHOST_IWindow *)windowhandle;
|
const GHOST_IWindow *window = (const GHOST_IWindow *)windowhandle;
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ class GHOST_SystemHeadless : public GHOST_System {
|
|||||||
~(GHOST_kCapabilityWindowPosition | GHOST_kCapabilityCursorWarp |
|
~(GHOST_kCapabilityWindowPosition | GHOST_kCapabilityCursorWarp |
|
||||||
GHOST_kCapabilityPrimaryClipboard |
|
GHOST_kCapabilityPrimaryClipboard |
|
||||||
GHOST_kCapabilityDesktopSample |
|
GHOST_kCapabilityDesktopSample |
|
||||||
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityInputIME));
|
GHOST_kCapabilityClipboardImages | GHOST_kCapabilityInputIME |
|
||||||
|
GHOST_kCapabilityWindowDecorationStyles));
|
||||||
}
|
}
|
||||||
char *getClipboard(bool /*selection*/) const override
|
char *getClipboard(bool /*selection*/) const override
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -791,7 +791,9 @@ GHOST_TCapabilityFlag GHOST_SystemSDL::getCapabilities() const
|
|||||||
/* This SDL back-end has not yet implemented image copy/paste. */
|
/* This SDL back-end has not yet implemented image copy/paste. */
|
||||||
GHOST_kCapabilityClipboardImages |
|
GHOST_kCapabilityClipboardImages |
|
||||||
/* No support yet for IME input methods. */
|
/* No support yet for IME input methods. */
|
||||||
GHOST_kCapabilityInputIME));
|
GHOST_kCapabilityInputIME |
|
||||||
|
/* No support for window decoration styles. */
|
||||||
|
GHOST_kCapabilityWindowDecorationStyles));
|
||||||
}
|
}
|
||||||
|
|
||||||
char *GHOST_SystemSDL::getClipboard(bool /*selection*/) const
|
char *GHOST_SystemSDL::getClipboard(bool /*selection*/) const
|
||||||
|
|||||||
@@ -8730,6 +8730,10 @@ GHOST_TCapabilityFlag GHOST_SystemWayland::getCapabilities() const
|
|||||||
GHOST_kCapabilityGPUReadFrontBuffer |
|
GHOST_kCapabilityGPUReadFrontBuffer |
|
||||||
/* This WAYLAND back-end has not yet implemented desktop color sample. */
|
/* This WAYLAND back-end has not yet implemented desktop color sample. */
|
||||||
GHOST_kCapabilityDesktopSample |
|
GHOST_kCapabilityDesktopSample |
|
||||||
|
/* This WAYLAND back-end doesn't have support for window decoration styles.
|
||||||
|
* In all likelihood, this back-end will eventually need to support client-side
|
||||||
|
* decorations, see #113795. */
|
||||||
|
GHOST_kCapabilityWindowDecorationStyles |
|
||||||
/* This flag will eventually be removed. */
|
/* This flag will eventually be removed. */
|
||||||
((has_wl_trackpad_physical_direction == 1) ?
|
((has_wl_trackpad_physical_direction == 1) ?
|
||||||
0 :
|
0 :
|
||||||
|
|||||||
@@ -586,7 +586,10 @@ GHOST_TCapabilityFlag GHOST_SystemWin32::getCapabilities() const
|
|||||||
return GHOST_TCapabilityFlag(GHOST_CAPABILITY_FLAG_ALL &
|
return GHOST_TCapabilityFlag(GHOST_CAPABILITY_FLAG_ALL &
|
||||||
~(
|
~(
|
||||||
/* WIN32 has no support for a primary selection clipboard. */
|
/* WIN32 has no support for a primary selection clipboard. */
|
||||||
GHOST_kCapabilityPrimaryClipboard));
|
GHOST_kCapabilityPrimaryClipboard |
|
||||||
|
/* This WIN32 backend has not yet implemented support for window
|
||||||
|
* decoration styles. */
|
||||||
|
GHOST_kCapabilityWindowDecorationStyles));
|
||||||
}
|
}
|
||||||
|
|
||||||
GHOST_TSuccess GHOST_SystemWin32::init()
|
GHOST_TSuccess GHOST_SystemWin32::init()
|
||||||
|
|||||||
@@ -1817,7 +1817,9 @@ GHOST_TCapabilityFlag GHOST_SystemX11::getCapabilities() const
|
|||||||
/* No support yet for image copy/paste. */
|
/* No support yet for image copy/paste. */
|
||||||
GHOST_kCapabilityClipboardImages |
|
GHOST_kCapabilityClipboardImages |
|
||||||
/* No support yet for IME input methods. */
|
/* No support yet for IME input methods. */
|
||||||
GHOST_kCapabilityInputIME));
|
GHOST_kCapabilityInputIME |
|
||||||
|
/* No support for window decoration styles. */
|
||||||
|
GHOST_kCapabilityWindowDecorationStyles));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GHOST_SystemX11::addDirtyWindow(GHOST_WindowX11 *bad_wind)
|
void GHOST_SystemX11::addDirtyWindow(GHOST_WindowX11 *bad_wind)
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ GHOST_Window::GHOST_Window(uint32_t width,
|
|||||||
m_progressBarVisible(false),
|
m_progressBarVisible(false),
|
||||||
m_canAcceptDragOperation(false),
|
m_canAcceptDragOperation(false),
|
||||||
m_isUnsavedChanges(false),
|
m_isUnsavedChanges(false),
|
||||||
|
m_windowDecorationStyleFlags(GHOST_kDecorationNone),
|
||||||
|
m_windowDecorationStyleSettings(),
|
||||||
m_wantStereoVisual(wantStereoVisual),
|
m_wantStereoVisual(wantStereoVisual),
|
||||||
m_nativePixelSize(1.0f),
|
m_nativePixelSize(1.0f),
|
||||||
m_context(new GHOST_ContextNone(false))
|
m_context(new GHOST_ContextNone(false))
|
||||||
@@ -55,6 +57,22 @@ void *GHOST_Window::getOSWindow() const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GHOST_TWindowDecorationStyleFlags GHOST_Window::getWindowDecorationStyleFlags()
|
||||||
|
{
|
||||||
|
return m_windowDecorationStyleFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GHOST_Window::setWindowDecorationStyleFlags(GHOST_TWindowDecorationStyleFlags styleFlags)
|
||||||
|
{
|
||||||
|
m_windowDecorationStyleFlags = styleFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GHOST_Window::setWindowDecorationStyleSettings(
|
||||||
|
GHOST_WindowDecorationStyleSettings decorationSettings)
|
||||||
|
{
|
||||||
|
m_windowDecorationStyleSettings = decorationSettings;
|
||||||
|
}
|
||||||
|
|
||||||
GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType type)
|
GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType type)
|
||||||
{
|
{
|
||||||
if (type != m_drawingContextType) {
|
if (type != m_drawingContextType) {
|
||||||
|
|||||||
@@ -89,6 +89,33 @@ class GHOST_Window : public GHOST_IWindow {
|
|||||||
return GHOST_kFailure;
|
return GHOST_kFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current window decoration style flags.
|
||||||
|
*/
|
||||||
|
virtual GHOST_TWindowDecorationStyleFlags getWindowDecorationStyleFlags() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the window decoration style flags.
|
||||||
|
* \param styleFlags: Window decoration style flags.
|
||||||
|
*/
|
||||||
|
virtual void setWindowDecorationStyleFlags(
|
||||||
|
GHOST_TWindowDecorationStyleFlags styleFlags) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the window decoration style settings.
|
||||||
|
* \param decorationSettings: Window decoration style settings.
|
||||||
|
*/
|
||||||
|
virtual void setWindowDecorationStyleSettings(
|
||||||
|
GHOST_WindowDecorationStyleSettings decorationSettings) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the window decoration style using the current flags and settings.
|
||||||
|
*/
|
||||||
|
virtual GHOST_TSuccess applyWindowDecorationStyle() override
|
||||||
|
{
|
||||||
|
return GHOST_kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current cursor shape.
|
* Returns the current cursor shape.
|
||||||
* \return The current cursor shape.
|
* \return The current cursor shape.
|
||||||
@@ -410,6 +437,10 @@ class GHOST_Window : public GHOST_IWindow {
|
|||||||
/** Stores whether this is a full screen window. */
|
/** Stores whether this is a full screen window. */
|
||||||
bool m_fullScreen;
|
bool m_fullScreen;
|
||||||
|
|
||||||
|
/** Window Decoration Styles. */
|
||||||
|
GHOST_TWindowDecorationStyleFlags m_windowDecorationStyleFlags;
|
||||||
|
GHOST_WindowDecorationStyleSettings m_windowDecorationStyleSettings;
|
||||||
|
|
||||||
/** Whether to attempt to initialize a context with a stereo frame-buffer. */
|
/** Whether to attempt to initialize a context with a stereo frame-buffer. */
|
||||||
bool m_wantStereoVisual;
|
bool m_wantStereoVisual;
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,11 @@ class GHOST_WindowCocoa : public GHOST_Window {
|
|||||||
*/
|
*/
|
||||||
GHOST_TSuccess setPath(const char *filepath) override;
|
GHOST_TSuccess setPath(const char *filepath) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the window decoration style using the current flags and settings.
|
||||||
|
*/
|
||||||
|
GHOST_TSuccess applyWindowDecorationStyle() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the window rectangle dimensions.
|
* Returns the window rectangle dimensions.
|
||||||
* The dimensions are given in screen coordinates that are
|
* The dimensions are given in screen coordinates that are
|
||||||
|
|||||||
@@ -565,6 +565,38 @@ GHOST_TSuccess GHOST_WindowCocoa::setPath(const char *filepath)
|
|||||||
return GHOST_kSuccess;
|
return GHOST_kSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GHOST_TSuccess GHOST_WindowCocoa::applyWindowDecorationStyle()
|
||||||
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
if (m_windowDecorationStyleFlags & GHOST_kDecorationColoredTitleBar) {
|
||||||
|
const float *background_color = m_windowDecorationStyleSettings.colored_titlebar_bg_color;
|
||||||
|
|
||||||
|
/* Titlebar background color. */
|
||||||
|
m_window.backgroundColor = [NSColor colorWithRed:background_color[0]
|
||||||
|
green:background_color[1]
|
||||||
|
blue:background_color[2]
|
||||||
|
alpha:1.0];
|
||||||
|
|
||||||
|
/* Titlebar foreground color.
|
||||||
|
* Use the value component of the titlebar background's HSV representation to determine
|
||||||
|
* whether we should use the macOS dark or light titlebar text appearance. With values below
|
||||||
|
* 0.5 considered as dark themes, and values above 0.5 considered as light themes.
|
||||||
|
*/
|
||||||
|
const float hsv_v = MAX(background_color[0], MAX(background_color[1], background_color[2]));
|
||||||
|
|
||||||
|
const NSAppearanceName win_appearance = hsv_v > 0.5 ? NSAppearanceNameVibrantLight :
|
||||||
|
NSAppearanceNameVibrantDark;
|
||||||
|
|
||||||
|
m_window.appearance = [NSAppearance appearanceNamed:win_appearance];
|
||||||
|
m_window.titlebarAppearsTransparent = YES;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_window.titlebarAppearsTransparent = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GHOST_kSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect &bounds) const
|
void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect &bounds) const
|
||||||
{
|
{
|
||||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid");
|
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid");
|
||||||
|
|||||||
@@ -2720,6 +2720,13 @@ void ED_area_newspace(bContext *C, ScrArea *area, int type, const bool skip_regi
|
|||||||
WM_window_title(CTX_wm_manager(C), CTX_wm_window(C));
|
WM_window_title(CTX_wm_manager(C), CTX_wm_window(C));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If window decoration styles are supported, send a notification to re-apply them. */
|
||||||
|
/* TODO: The `bl_animation_keyframing` test fails here if WM_capabilities_flags is called in
|
||||||
|
* background mode. Remove the !G.background check once the test has been fixed. */
|
||||||
|
if (!G.background && WM_capabilities_flag() & WM_CAPABILITY_WINDOW_DECORATION_STYLES) {
|
||||||
|
WM_event_add_notifier(C, NC_WINDOW, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
/* also redraw when re-used */
|
/* also redraw when re-used */
|
||||||
ED_area_tag_redraw(area);
|
ED_area_tag_redraw(area);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -660,10 +660,16 @@ void ED_screen_do_listen(bContext *C, const wmNotifier *note)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NC_WINDOW:
|
case NC_WINDOW:
|
||||||
|
if (WM_capabilities_flag() & WM_CAPABILITY_WINDOW_DECORATION_STYLES) {
|
||||||
|
WM_window_apply_decoration_style(win, screen);
|
||||||
|
}
|
||||||
screen->do_draw = true;
|
screen->do_draw = true;
|
||||||
break;
|
break;
|
||||||
case NC_SCREEN:
|
case NC_SCREEN:
|
||||||
if (note->action == NA_EDITED) {
|
if (note->action == NA_EDITED) {
|
||||||
|
if (WM_capabilities_flag() & WM_CAPABILITY_WINDOW_DECORATION_STYLES) {
|
||||||
|
WM_window_apply_decoration_style(win, screen);
|
||||||
|
}
|
||||||
screen->do_draw = screen->do_refresh = true;
|
screen->do_draw = screen->do_refresh = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1312,7 +1318,7 @@ void ED_screen_global_areas_refresh(wmWindow *win)
|
|||||||
{
|
{
|
||||||
/* Don't create global area for child and temporary windows. */
|
/* Don't create global area for child and temporary windows. */
|
||||||
bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
|
bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
|
||||||
if ((win->parent != nullptr) || screen->temp) {
|
if (!WM_window_is_main_top_level(win)) {
|
||||||
if (win->global_areas.areabase.first) {
|
if (win->global_areas.areabase.first) {
|
||||||
screen->do_refresh = true;
|
screen->do_refresh = true;
|
||||||
BKE_screen_area_map_free(&win->global_areas);
|
BKE_screen_area_map_free(&win->global_areas);
|
||||||
|
|||||||
@@ -185,10 +185,12 @@ enum eWM_CapabilitiesFlag {
|
|||||||
WM_CAPABILITY_INPUT_IME = (1 << 6),
|
WM_CAPABILITY_INPUT_IME = (1 << 6),
|
||||||
/** Trackpad physical scroll detection. */
|
/** Trackpad physical scroll detection. */
|
||||||
WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION = (1 << 7),
|
WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION = (1 << 7),
|
||||||
|
/** Support for window decoration styles. */
|
||||||
|
WM_CAPABILITY_WINDOW_DECORATION_STYLES = (1 << 8),
|
||||||
/** The initial value, indicates the value needs to be set by inspecting GHOST. */
|
/** The initial value, indicates the value needs to be set by inspecting GHOST. */
|
||||||
WM_CAPABILITY_INITIALIZED = (1u << 31),
|
WM_CAPABILITY_INITIALIZED = (1u << 31),
|
||||||
};
|
};
|
||||||
ENUM_OPERATORS(eWM_CapabilitiesFlag, WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION)
|
ENUM_OPERATORS(eWM_CapabilitiesFlag, WM_CAPABILITY_WINDOW_DECORATION_STYLES)
|
||||||
|
|
||||||
eWM_CapabilitiesFlag WM_capabilities_flag();
|
eWM_CapabilitiesFlag WM_capabilities_flag();
|
||||||
|
|
||||||
@@ -284,6 +286,7 @@ void WM_window_rect_calc(const wmWindow *win, rcti *r_rect);
|
|||||||
* \note Depends on #UI_SCALE_FAC. Should that be outdated, call #WM_window_set_dpi first.
|
* \note Depends on #UI_SCALE_FAC. Should that be outdated, call #WM_window_set_dpi first.
|
||||||
*/
|
*/
|
||||||
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect);
|
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect);
|
||||||
|
bool WM_window_is_main_top_level(const wmWindow *win);
|
||||||
bool WM_window_is_fullscreen(const wmWindow *win);
|
bool WM_window_is_fullscreen(const wmWindow *win);
|
||||||
bool WM_window_is_maximized(const wmWindow *win);
|
bool WM_window_is_maximized(const wmWindow *win);
|
||||||
|
|
||||||
@@ -374,6 +377,29 @@ void WM_window_title(wmWindowManager *wm, wmWindow *win, const char *title = nul
|
|||||||
|
|
||||||
bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check);
|
bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check);
|
||||||
|
|
||||||
|
/* Window Decoration Styles. */
|
||||||
|
|
||||||
|
/* Flags for #WM_window_decoration_set_style().
|
||||||
|
* NOTE: To be kept in sync with #GHOST_TWindowDecorationFlags. */
|
||||||
|
enum eWM_WindowDecorationStyleFlag {
|
||||||
|
/** No decoration styling. */
|
||||||
|
WM_WINDOW_DECORATION_STYLE_NONE = 0,
|
||||||
|
/** Colored Titlebar. */
|
||||||
|
WM_WINDOW_DECORATION_STYLE_COLORED_TITLEBAR = (1 << 0),
|
||||||
|
};
|
||||||
|
ENUM_OPERATORS(eWM_WindowDecorationStyleFlag, WM_WINDOW_DECORATION_STYLE_COLORED_TITLEBAR)
|
||||||
|
|
||||||
|
/* Get/set window decoration style flags. */
|
||||||
|
eWM_WindowDecorationStyleFlag WM_window_get_decoration_style_flags(const wmWindow *win);
|
||||||
|
void WM_window_set_decoration_style_flags(const wmWindow *win,
|
||||||
|
eWM_WindowDecorationStyleFlag style_flags);
|
||||||
|
/* Apply the window decoration style using the current style flags and by parsing style
|
||||||
|
* settings from the current Blender theme.
|
||||||
|
* The screen parameter is optional, and can be passed for enhanced theme parsing.
|
||||||
|
* NOTE: Avoid calling this function directly, prefer sending an NC_WINDOW WM notification instead.
|
||||||
|
*/
|
||||||
|
void WM_window_apply_decoration_style(const wmWindow *win, const bScreen *screen = nullptr);
|
||||||
|
|
||||||
/* `wm_files.cc`. */
|
/* `wm_files.cc`. */
|
||||||
|
|
||||||
void WM_file_autoexec_init(const char *filepath);
|
void WM_file_autoexec_init(const char *filepath);
|
||||||
|
|||||||
@@ -598,6 +598,72 @@ void WM_window_set_dpi(const wmWindow *win)
|
|||||||
U.widget_unit = int(roundf(18.0f * U.scale_factor)) + (2 * pixelsize);
|
U.widget_unit = int(roundf(18.0f * U.scale_factor)) + (2 * pixelsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eWM_WindowDecorationStyleFlag WM_window_get_decoration_style_flags(const wmWindow *win)
|
||||||
|
{
|
||||||
|
const GHOST_TWindowDecorationStyleFlags ghost_style_flags = GHOST_GetWindowDecorationStyleFlags(
|
||||||
|
static_cast<GHOST_WindowHandle>(win->ghostwin));
|
||||||
|
|
||||||
|
eWM_WindowDecorationStyleFlag wm_style_flags = WM_WINDOW_DECORATION_STYLE_NONE;
|
||||||
|
|
||||||
|
if (ghost_style_flags & GHOST_kDecorationColoredTitleBar) {
|
||||||
|
wm_style_flags |= WM_WINDOW_DECORATION_STYLE_COLORED_TITLEBAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wm_style_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WM_window_set_decoration_style_flags(const wmWindow *win,
|
||||||
|
eWM_WindowDecorationStyleFlag style_flags)
|
||||||
|
{
|
||||||
|
unsigned int ghost_style_flags = GHOST_kDecorationNone;
|
||||||
|
|
||||||
|
if (style_flags & WM_WINDOW_DECORATION_STYLE_COLORED_TITLEBAR) {
|
||||||
|
ghost_style_flags |= GHOST_kDecorationColoredTitleBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
GHOST_SetWindowDecorationStyleFlags(
|
||||||
|
static_cast<GHOST_WindowHandle>(win->ghostwin),
|
||||||
|
static_cast<GHOST_TWindowDecorationStyleFlags>(ghost_style_flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wm_window_decoration_style_set_from_theme(const wmWindow *win, const bScreen *screen)
|
||||||
|
{
|
||||||
|
/* Set the decoration style settings from the current theme colors.
|
||||||
|
* NOTE: screen may be null. In which case, only the window is used as a theme provider. */
|
||||||
|
GHOST_WindowDecorationStyleSettings decoration_settings = {};
|
||||||
|
|
||||||
|
/* Colored Titlebar Decoration. */
|
||||||
|
/* For main windows, use the topbar color. */
|
||||||
|
if (WM_window_is_main_top_level(win)) {
|
||||||
|
UI_SetTheme(SPACE_TOPBAR, RGN_TYPE_HEADER);
|
||||||
|
}
|
||||||
|
/* For single editor floating windows, use the editor header color. */
|
||||||
|
else if (screen && BLI_listbase_is_single(&screen->areabase)) {
|
||||||
|
const ScrArea *main_area = static_cast<ScrArea *>(screen->areabase.first);
|
||||||
|
UI_SetTheme(main_area->spacetype, RGN_TYPE_HEADER);
|
||||||
|
}
|
||||||
|
/* For floating window with multiple editors/areas, use the default space color. */
|
||||||
|
else {
|
||||||
|
UI_SetTheme(0, RGN_TYPE_WINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
float titlebar_bg_color[3], titlebar_fg_color[3];
|
||||||
|
UI_GetThemeColor3fv(TH_BACK, titlebar_bg_color);
|
||||||
|
UI_GetThemeColor3fv(TH_BUTBACK_TEXT, titlebar_fg_color);
|
||||||
|
copy_v3_v3(decoration_settings.colored_titlebar_bg_color, titlebar_bg_color);
|
||||||
|
copy_v3_v3(decoration_settings.colored_titlebar_fg_color, titlebar_fg_color);
|
||||||
|
|
||||||
|
GHOST_SetWindowDecorationStyleSettings(static_cast<GHOST_WindowHandle>(win->ghostwin),
|
||||||
|
decoration_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WM_window_apply_decoration_style(const wmWindow *win, const bScreen *screen)
|
||||||
|
{
|
||||||
|
BLI_assert(WM_capabilities_flag() & WM_CAPABILITY_WINDOW_DECORATION_STYLES);
|
||||||
|
wm_window_decoration_style_set_from_theme(win, screen);
|
||||||
|
GHOST_ApplyWindowDecorationStyle(static_cast<GHOST_WindowHandle>(win->ghostwin));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When windows are activated, simulate modifier press/release to match the current state of
|
* When windows are activated, simulate modifier press/release to match the current state of
|
||||||
* held modifier keys, see #40317.
|
* held modifier keys, see #40317.
|
||||||
@@ -857,6 +923,12 @@ static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, boo
|
|||||||
wm_window_ensure_eventstate(win);
|
wm_window_ensure_eventstate(win);
|
||||||
|
|
||||||
WM_window_set_dpi(win);
|
WM_window_set_dpi(win);
|
||||||
|
|
||||||
|
if (WM_capabilities_flag() & WM_CAPABILITY_WINDOW_DECORATION_STYLES) {
|
||||||
|
/* Only decoration style we have for now. */
|
||||||
|
WM_window_set_decoration_style_flags(win, WM_WINDOW_DECORATION_STYLE_COLORED_TITLEBAR);
|
||||||
|
WM_window_apply_decoration_style(win);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add key-map handlers (1 handler for all keys in map!). */
|
/* Add key-map handlers (1 handler for all keys in map!). */
|
||||||
@@ -2174,6 +2246,9 @@ eWM_CapabilitiesFlag WM_capabilities_flag()
|
|||||||
if (ghost_flag & GHOST_kCapabilityTrackpadPhysicalDirection) {
|
if (ghost_flag & GHOST_kCapabilityTrackpadPhysicalDirection) {
|
||||||
flag |= WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION;
|
flag |= WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION;
|
||||||
}
|
}
|
||||||
|
if (ghost_flag & GHOST_kCapabilityWindowDecorationStyles) {
|
||||||
|
flag |= WM_CAPABILITY_WINDOW_DECORATION_STYLES;
|
||||||
|
}
|
||||||
|
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
@@ -2808,6 +2883,19 @@ bool WM_window_is_maximized(const wmWindow *win)
|
|||||||
return win->windowstate == GHOST_kWindowStateMaximized;
|
return win->windowstate == GHOST_kWindowStateMaximized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WM_window_is_main_top_level(const wmWindow *win)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Return whether the window is a main/top-level window. In which case it is expected to contain
|
||||||
|
* global areas (topbar/statusbar).
|
||||||
|
*/
|
||||||
|
const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
|
||||||
|
if ((win->parent != nullptr) || screen->temp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|||||||
Reference in New Issue
Block a user