macOS: Colored Titlebar and WM Client-Side Decorations API - GSoC 2024 #123982

Open
Jonas Holzman wants to merge 49 commits from Brainzman/blender:gsoc-simple-titlebar-csd into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
Member

As part of the GSoC 2024 project Improvements to the Blender macOS User Interface Experience, this pull request implements custom colored titlebar window decorations on macOS, following the Blender theme colors, as well as a basic GHOST API for enabling and implementing custom client-side window decorations on other systems.

Screenshots

Main.png

Blender Dark Theme

BlenderDark.png

Blender Light Theme

BlenderLight.png

Nordic Gold Theme (link)

NordicGold.png

Video Demo with different windows/themes


Featured themes can be found on the Blender Extensions Platform

Titlebar blending with Editor header

Technical Notes

Titlebar Text Color

The original goal was to let the Blender themes not only dictate the macOS titlebar background color, but also its foreground/text color. However, modifying the titlebar text color on macOS proved to be tricky and impractical, as it either required the use of Objective-C reflection / private APIs, or recreating an entirely new titlebar view from scratch, with both solutions proving themselves to be relatively unreliable, not future-proof, and prone to breaking on macOS updates.

Thus, the chosen solution was to instead stick to the default macOS titlebar text color, and set it to either use its dark or light appearance variant depending on the current theme. This solution better guarantees that we stick to the overall macOS style and guidelines, and is also used by other GUI frameworks and softwares such as Qt or IntelliJ IDEs. Since Blender does not tag its themes as being light or dark, the titlebar background color is used to determine which variant to apply, using its HSV value component.

For implementation on other systems, the GHOST setTitlebarCSDColors API function still expose both the titlebar background and text color as arguments, with the macOS implementation only using the background color.

Slight titlebar flash on theme change

Due to small timing differences in drawing updates, the titlebar may sometimes briefly flash on theme changes due to it updating a few frames after the window content view, as can be sometimes seen in the first demo video. While I have been able to reduce the issue by making the titlebar update more consistently with the main content view, I haven't looked into achieving perfect synchronization yet, which would require lower-level work that's out of scope for this PR, and would be better part of a separate project to allow proper redraw synchronization on theme change.

New WM Decoration API Overview

// WM_api.hh - line 381-396

/** Client-Side Window Decorations (CSD). */
/* Flags for WM_window_decoration_set_style().
 * NOTE: To be kept in sync with GHOST_TWindowDecorationFlags. */
enum eWM_DecorationStyleFlag {
  /** No Decorations / System Decorations. */
  WM_DECORATION_NONE = 0,
  /** Custom Colored Titlebar. */
  WM_DECORATION_COLORED_TITLEBAR = (1 << 0),
};
ENUM_OPERATORS(eWM_DecorationStyleFlag, WM_DECORATION_COLORED_TITLEBAR)

/* Get/set decoration style flags. */
eWM_DecorationStyleFlag WM_window_decoration_get_style(const wmWindow *win);
void WM_window_decoration_set_style(const wmWindow *win, eWM_DecorationStyleFlag style_flags);
/* Apply decorations to the window using the current flags and settings from the current theme.
 * The screen parameter is optional, and can be passed for enhanced theme settings parsing. */
void WM_window_decoration_apply(const wmWindow *win, const bScreen *screen = nullptr);

The main idea behind this new API is for it to be as light and simple as possible, and for decorations to be tied to windows, not global state. Multiple decoration flags can be set on each windows (via WM_window_decoration_set_style), which can also depend on the current theme (see wm_window_decoration_parse_theme, called by WM_decoration_apply).

To keep this API as platform independent as possible, decoration style flags and settings are stored in the base GHOST_Window class. This means that to implement this decoration on another backend, the only thing that needs to be done is to override the applyDecoration() function on the target backend, see the existing macOS implementation in GHOST_WindowCocoa.mm.

As part of the GSoC 2024 project [Improvements to the Blender macOS User Interface Experience](https://devtalk.blender.org/t/gsoc-2024-proposal-improvements-to-the-blender-macos-user-interface-experience/34022), this pull request implements custom colored titlebar window decorations on macOS, following the Blender theme colors, as well as a basic GHOST API for enabling and implementing custom client-side window decorations on other systems. ### Screenshots ![Main.png](/attachments/0a40f347-4dbe-487e-98bd-931b1dbabddf) #### Blender Dark Theme ![BlenderDark.png](/attachments/851e3724-3206-429a-ac74-ad1d1d93306c) #### Blender Light Theme ![BlenderLight.png](/attachments/0f6a638f-1cb1-45e0-95c5-b23bd58c9a3a) #### Nordic Gold Theme (*[link](https://extensions.blender.org/themes/nordic-gold/)*) ![NordicGold.png](/attachments/779815a1-6a30-40a7-be3f-c96644e11566) ### Video Demo with different windows/themes <video src="/attachments/cdf9b5d0-4586-412e-a843-da2499df34ba" title="MixedDemo.mp4" controls></video> *Featured themes can be found on the Blender Extensions Platform* ### Titlebar blending with Editor header <video src="/attachments/39c254eb-8656-4b45-9359-14944d2c3dab" title="TitlebarEditorBlending2.mp4" controls></video> ### Technical Notes #### Titlebar Text Color The original goal was to let the Blender themes not only dictate the macOS titlebar background color, but also its foreground/text color. However, modifying the titlebar text color on macOS proved to be tricky and impractical, as it either required the use of Objective-C reflection / private APIs, or recreating an entirely new titlebar view from scratch, with both solutions proving themselves to be relatively unreliable, not future-proof, and prone to breaking on macOS updates. Thus, the chosen solution was to instead stick to the default macOS titlebar text color, and set it to either use its dark or light appearance variant depending on the current theme. This solution better guarantees that we stick to the overall macOS style and guidelines, and is also used by other GUI frameworks and softwares such as Qt or IntelliJ IDEs. Since Blender does not tag its themes as being light or dark, the titlebar background color is used to determine which variant to apply, using its HSV value component. <video src="/attachments/89ac6542-5fb1-4273-8dfa-8190d15bca7e" title="TitleTextColoring.mp4" controls></video> For implementation on other systems, the GHOST `setTitlebarCSDColors` API function still expose both the titlebar background and text color as arguments, with the macOS implementation only using the background color. #### Slight titlebar flash on theme change Due to small timing differences in drawing updates, the titlebar may sometimes briefly flash on theme changes due to it updating a few frames after the window content view, as can be sometimes seen in the first demo video. While I have been able to reduce the issue by making the titlebar update more consistently with the main content view, I haven't looked into achieving perfect synchronization yet, which would require lower-level work that's out of scope for this PR, and would be better part of a separate project to allow proper redraw synchronization on theme change. #### New WM Decoration API Overview ```cpp // WM_api.hh - line 381-396 /** Client-Side Window Decorations (CSD). */ /* Flags for WM_window_decoration_set_style(). * NOTE: To be kept in sync with GHOST_TWindowDecorationFlags. */ enum eWM_DecorationStyleFlag { /** No Decorations / System Decorations. */ WM_DECORATION_NONE = 0, /** Custom Colored Titlebar. */ WM_DECORATION_COLORED_TITLEBAR = (1 << 0), }; ENUM_OPERATORS(eWM_DecorationStyleFlag, WM_DECORATION_COLORED_TITLEBAR) /* Get/set decoration style flags. */ eWM_DecorationStyleFlag WM_window_decoration_get_style(const wmWindow *win); void WM_window_decoration_set_style(const wmWindow *win, eWM_DecorationStyleFlag style_flags); /* Apply decorations to the window using the current flags and settings from the current theme. * The screen parameter is optional, and can be passed for enhanced theme settings parsing. */ void WM_window_decoration_apply(const wmWindow *win, const bScreen *screen = nullptr); ``` The main idea behind this new API is for it to be as light and simple as possible, and for decorations to be tied to windows, not global state. Multiple decoration flags can be set on each windows (via `WM_window_decoration_set_style`), which can also depend on the current theme (see `wm_window_decoration_parse_theme`, called by `WM_decoration_apply`). To keep this API as platform independent as possible, decoration style flags and settings are stored in the base `GHOST_Window` class. This means that to implement this decoration on another backend, the only thing that needs to be done is to override the `applyDecoration()` function on the target backend, see the existing macOS implementation in `GHOST_WindowCocoa.mm`.
Jonas Holzman added 11 commits 2024-07-01 07:59:57 +02:00
Simple cleaned-up initial proof of concept
Using a simple NSView overlayed on top of the topbar space that forward
mouseDrag events (and not clicks, as to preserve the ability to interact
with the topbar) to the macOS window manager.
This reverts commit f5a4e5e649.
This commit adds a basic interface for enabling/disable client-side
window decoration on a GHOST window, decoupled from window creation.

Window decorations are for now only applied to main windows, using a
check in `wm_window_ghostwindow_ensure` to see if the window should
contain global areas (topbar/statusbar)
Exception for the View 3D editor which has a transparent header, in
which case use the window background color instead
Jonas Holzman requested review from Raul Fernandez Hernandez 2024-07-01 08:00:16 +02:00
Jonas Holzman requested review from Julian Eisel 2024-07-01 08:00:16 +02:00
Jonas Holzman added 1 commit 2024-07-01 08:28:40 +02:00
Pablo Vazquez added the
Interest
User Interface
label 2024-07-01 10:34:59 +02:00
Jonas Holzman changed title from WIP: macOS Colored Titlebar Client-Side Decorations - GSoC 2024 to macOS: Colored Titlebar Client-Side Decorations - GSoC 2024 2024-07-01 10:53:28 +02:00
Iliya Katushenock added this to the User Interface project 2024-07-01 11:55:39 +02:00
Raul Fernandez Hernandez approved these changes 2024-07-01 21:32:35 +02:00
Member

Very nice!

Very nice!
Jonas Holzman added 2 commits 2024-07-02 00:01:54 +02:00
In the case of floating windows with multiples editors/areas, the window
titlebar would switch to the header color of whichever area was last
focused. Fixed by only applying the area header color to the titlebar
on single editor floating windows, and falling back to the header color
of the default space (SPACE_PROPERTIES) for multi-area windows otherwise.
Jonas Holzman added 1 commit 2024-07-02 00:05:41 +02:00
Sietse Brouwer reviewed 2024-07-02 12:42:58 +02:00
Sietse Brouwer left a comment
Member

Nice indeed! Now I know what GSoC stands for: Great Summer of Color 🌈

I'm learning about the Cocoa side of GHOST things, so I took the liberty to take a look at your code. I marked a few tiny things I spotted.

Nice indeed! Now I know what GSoC stands for: Great Summer of Color 🌈 I'm learning about the Cocoa side of GHOST things, so I took the liberty to take a look at your code. I marked a few tiny things I spotted.
@ -596,2 +596,4 @@
extern GHOST_TSuccess GHOST_SetPath(GHOST_WindowHandle windowhandle, const char *filepath);
/**
* Enable or disable custom client-side window decorations
Member

Silly nitpick, but the style guide tells us to end comments with a full stop.
Applies here and several other places.

Silly nitpick, but the style guide tells us [to end comments with a full stop](https://developer.blender.org/docs/handbook/guidelines/c_cpp/#comments). Applies here and several other places.
Brainzman marked this conversation as resolved
@ -598,0 +599,4 @@
* Enable or disable custom client-side window decorations
* \param useCSD: Whether to use custom client-side window decorations
*/
extern void GHOST_SetUseCSD(GHOST_WindowHandle windowhandle, bool useCSD);
Member

The abbreviation CSD is a bit cryptic, I think. In the context of this PR I understand it, but when I would come across WM_window_set_use_csd(win, true) in the wild, I wouldn't know what it meant.
Perhaps something less technical, more functional, like CustomDecorations?

And a question: is it meant that users have a choice to use custom decorations, e.g. in the Preferences? As far as I can see, m_useCSD is now always set to true for all windows Blender is creating. So it could be omitted. But perhaps that's not true in the broader scope of plans.

The abbreviation `CSD` is a bit cryptic, I think. In the context of this PR I understand it, but when I would come across `WM_window_set_use_csd(win, true)` in the wild, I wouldn't know what it meant. Perhaps something less technical, more functional, like `CustomDecorations`? And a question: is it meant that users have a choice to use custom decorations, e.g. in the Preferences? As far as I can see, `m_useCSD` is now always set to `true` for all windows Blender is creating. So it could be omitted. But perhaps that's not true in the broader scope of plans.
SietseB marked this conversation as resolved
@ -598,0 +607,4 @@
* \param tbTitleTextCol: Titlebar title text color
*/
extern void GHOST_SetTitlebarCSDColors(GHOST_WindowHandle windowhandle,
const float tbBackgroundCol[4],
Member

Second nitpick: better full variable names like backgroundColor than tbBackgroundCol. The 'title bar' part is implied by the function.

Second nitpick: better full variable names like `backgroundColor` than `tbBackgroundCol`. The 'title bar' part is implied by the function.
Brainzman marked this conversation as resolved
@ -312,6 +325,7 @@ class GHOST_WindowCocoa : public GHOST_Window {
bool m_immediateDraw;
bool m_debug_context; // for debug messages during context setup
bool m_is_dialog;
bool m_use_decoration;
Member

Is this one used?

Is this one used?
Brainzman marked this conversation as resolved
@ -2740,0 +2757,4 @@
/**
* Return whether the window should contain global areas (topbar/statusbar)
*/
bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
Member

Third nitpick: you can use const here, so const bScreen *screen =.

Third nitpick: you can use `const` here, so ` const bScreen *screen =`.
Brainzman marked this conversation as resolved
Jonas Holzman added 4 commits 2024-07-07 11:52:35 +02:00
Author
Member

@SietseB Thanks for the feedback! I addressed them in the commits above. Regarding the CSD abbreviation, while it does look a bit cryptic without context, it's important to highlight that this function refers to Client-Side Decorations. To which CSD is the common acronym (see Wikipedia). This also importantly underlines that we're interacting with the OS Window Manager, drawing outside our window bounds.

While I would prefer to be as clear as possible, GHOST_SetUseClientSideDecorations and GHOST_SetTitlebarClientSideDecorationsColor feel too verbose, and dropping the ClientSide part might be more confusing, as I feel like that would implicitly refer to in-window decorations. In any case, the Doxygen header comments do provide descriptions of the functions, but if you feel like that's not enough, I can search for another solution/clearer and shorter names.

Regarding the m_useCSD flag, this is mainly to give the Window Manager code control over CSDs, which could serve to conditionally disable them in the future, or only enable them on specific windows on certain platforms. For example the initial implementation of this PR used to disable them for main windows on macOS, which is way easier to do directly from the WM code, than to try to make checks from the GHOST code.

@SietseB Thanks for the feedback! I addressed them in the commits above. Regarding the CSD abbreviation, while it does look a bit cryptic without context, it's important to highlight that this function refers to *Client-Side* Decorations. To which CSD is the common acronym (see [Wikipedia](https://en.wikipedia.org/wiki/Client-side_decoration)). This also importantly underlines that we're interacting with the OS Window Manager, drawing outside our window bounds. While I would prefer to be as clear as possible, `GHOST_SetUseClientSideDecorations` and `GHOST_SetTitlebarClientSideDecorationsColor` feel too verbose, and dropping the `ClientSide` part might be more confusing, as I feel like that would implicitly refer to in-window decorations. In any case, the Doxygen header comments do provide descriptions of the functions, but if you feel like that's not enough, I can search for another solution/clearer and shorter names. Regarding the `m_useCSD` flag, this is mainly to give the Window Manager code control over CSDs, which could serve to conditionally disable them in the future, or only enable them on specific windows on certain platforms. For example the initial implementation of this PR used to disable them for main windows on macOS, which is way easier to do directly from the WM code, than to try to make checks from the GHOST code.
Member

So m_useCSD is indeed part of a bigger/future plan, I already thought so. So that's fine as it is 👍

And I fully understand your considerations around the CSD naming. Writing it in full, well, yeah – your tea will be cold before you finish reading 😄 Perhaps adding a little comment in wm_windows.cc to clarify? To keep that file readable without hovering or clicking to definitions in header files.
Just a tiny idea, I leave it up to you.

So `m_useCSD` is indeed part of a bigger/future plan, I already thought so. So that's fine as it is 👍 And I fully understand your considerations around the CSD naming. Writing it in full, well, yeah – your tea will be cold before you finish reading 😄 Perhaps adding a little comment [in `wm_windows.cc`](https://projects.blender.org/Brainzman/blender/src/commit/edb521e84f4d0f619e40b92a67d6e18ca4497bf9/source/blender/windowmanager/intern/wm_window.cc#L878) to clarify? To keep that file readable without hovering or clicking to definitions in header files. Just a tiny idea, I leave it up to you.
Jonas Holzman added 1 commit 2024-07-10 18:41:03 +02:00
Feedback: Specified CSD acronym in comments
All checks were successful
buildbot/vexp-code-patch-linux-x86_64 Build done.
buildbot/vexp-code-patch-windows-amd64 Build done.
buildbot/vexp-code-patch-coordinator Build done.
52a12849ea
Author
Member

You're right that a small comment in wm_windows.cc won't hurt, I also specified the CSD acronym in the description of GHOST functions to make it a bit clearer. Thanks for the overall feedback! :)

You're right that a small comment in `wm_windows.cc` won't hurt, I also specified the CSD acronym in the description of GHOST functions to make it a bit clearer. Thanks for the overall feedback! :)
Member

@blender-bot package

@blender-bot package
Member

Package build started. Download here when ready.

Package build started. [Download here](https://builder.blender.org/download/patch/PR123982) when ready.
Jonas Holzman added 2 commits 2024-07-24 16:31:15 +02:00
Added GHOST and WM Capability Flags
All checks were successful
buildbot/vexp-code-patch-lint Build done.
buildbot/vexp-code-patch-darwin-x86_64 Build done.
buildbot/vexp-code-patch-darwin-arm64 Build done.
buildbot/vexp-code-patch-linux-x86_64 Build done.
buildbot/vexp-code-patch-windows-amd64 Build done.
buildbot/vexp-code-patch-coordinator Build done.
46ae36522a
Member

@blender-bot package

@blender-bot package
Member

Package build started. Download here when ready.

Package build started. [Download here](https://builder.blender.org/download/patch/PR123982) when ready.
Julian Eisel requested changes 2024-07-30 17:03:10 +02:00
@ -596,2 +596,4 @@
extern GHOST_TSuccess GHOST_SetPath(GHOST_WindowHandle windowhandle, const char *filepath);
/**
* Enable or disable custom client-side window decorations (CSD).
Member

Not a big fan of naming this "CSD". I generally prefer avoiding abbreviations since they can be ambiguous (can mean different things depending on context). I also find that names can often be avoided and the intention/behavior can be described more directly, which makes the API more user friendly.
Also this isn't really connected yet to full client side decorations as we do them on Linux with Wayland. So using "CSD" here can be misleading too.

I'd propose to name this GHOST_SetWindowDecorationStyle() and let it take an enum like:

enum class GHOST_WindowDecorationStyle {
  System,
  CustomTitleBar,
};

I find this expresses things better.

Not a big fan of naming this "CSD". I generally prefer avoiding abbreviations since they can be ambiguous (can mean different things depending on context). I also find that names can often be avoided and the intention/behavior can be described more directly, which makes the API more user friendly. Also this isn't really connected yet to full client side decorations as we do them on Linux with Wayland. So using "CSD" here can be misleading too. I'd propose to name this `GHOST_SetWindowDecorationStyle()` and let it take an enum like: ```cpp enum class GHOST_WindowDecorationStyle { System, CustomTitleBar, }; ``` I find this expresses things better.
Brainzman marked this conversation as resolved
@ -518,0 +517,4 @@
const char area_spacetype = area ? area->spacetype : 0;
/* Set client-side window decoration titlebar colors. */
if (at->regionid == RGN_TYPE_WINDOW) {
Member

Don't think this function is the right place for this logic. It is run for every region for every redraw. I think the NC_WINDOW in ED_screen_do_listen could handle this. A NC_WINDOW notifier is sent on every theme change. I'd also put this into a separate function, so it's clear that this is all doing a specific task.

Don't think this function is the right place for this logic. It is run for every region for every redraw. I think the `NC_WINDOW` in `ED_screen_do_listen` could handle this. A `NC_WINDOW` notifier is sent on every theme change. I'd also put this into a separate function, so it's clear that this is all doing a specific task.
Brainzman marked this conversation as resolved
@ -2730,6 +2749,18 @@ bool WM_window_is_maximized(const wmWindow *win)
return win->windowstate == GHOST_kWindowStateMaximized;
}
bool WM_window_has_global_areas(const wmWindow *win)
Member

The name suggests that this checks if the window has in fact global areas. What it actually checks if it should have them. Suggest WM_window_should_have_global_areas().

The name suggests that this checks if the window has in fact global areas. What it actually checks if it _should_ have them. Suggest `WM_window_should_have_global_areas()`.
Brainzman marked this conversation as resolved
Jonas Holzman added 6 commits 2024-08-07 04:02:50 +02:00
Jonas Holzman added 1 commit 2024-08-07 04:04:47 +02:00
Jonas Holzman added 3 commits 2024-08-09 03:34:12 +02:00
Just using the header color and discarding the Alpha is actually
a much simpler, cleaner and better looking solution, which works with
more themes (Like novelty themes using non-transparent View3D headers
and high-contrast viewport backgrounds)
Jonas Holzman added 1 commit 2024-08-12 16:56:11 +02:00
Jonas Holzman force-pushed gsoc-simple-titlebar-csd from a1fc6fb18c to 7ce368fe4b 2024-08-13 21:33:42 +02:00 Compare
Jonas Holzman added 4 commits 2024-08-18 17:51:38 +02:00
This removes `WM_window_decoration_set_titlebar_colors` in favor of
setting decoration directly in `WM_window_parse_theme`, which then
forward the decoration setting to GHOST via a `GHOST_DecorationSettings`
struct, stored in the base `GHOST_Window` class
Jonas Holzman added 2 commits 2024-08-18 18:50:39 +02:00
Jonas Holzman added 1 commit 2024-08-18 19:32:27 +02:00
Author
Member

After much refactoring and refinements, this Pull Request now features a new WM Client-Side Decorations API, a deliverable of this GSoC project.

WM Decoration API Overview

// WM_api.hh - line 381-396

/** Client-Side Window Decorations (CSD). */
/* Flags for WM_window_decoration_set_style().
 * NOTE: To be kept in sync with GHOST_TWindowDecorationFlags. */
enum eWM_DecorationStyleFlag {
  /** No Decorations / System Decorations. */
  WM_DECORATION_NONE = 0,
  /** Custom Colored Titlebar. */
  WM_DECORATION_COLORED_TITLEBAR = (1 << 0),
};
ENUM_OPERATORS(eWM_DecorationStyleFlag, WM_DECORATION_COLORED_TITLEBAR)

/* Get/set decoration style flags. */
eWM_DecorationStyleFlag WM_window_decoration_get_style(const wmWindow *win);
void WM_window_decoration_set_style(const wmWindow *win, eWM_DecorationStyleFlag style_flags);
/* Apply decorations to the window using the current flags and settings from the current theme.
 * The screen parameter is optional, and can be passed for enhanced theme settings parsing. */
void WM_window_decoration_apply(const wmWindow *win, const bScreen *screen = nullptr);

The main idea behind this API is for it to be as light and simple as possible, and for decorations to be tied to windows, not global state. Multiple decoration flags can be set on each windows (via WM_window_decoration_set_style), which can also depend on the current theme (see wm_window_decoration_parse_theme, called by WM_decoration_apply).

To keep this API as platform independent as possible, decoration style flags and settings are stored in the base GHOST_Window class. This means that to implement this decoration on another backend, the only thing that needs to be done is to override the applyDecoration() function on the target backend, see the existing macOS implementation in GHOST_WindowCocoa.mm (cc @Harley if you're interested)

Other refactors / improvements since review include:

  • Better update logic, based on Window and screen update notifications
  • Better colored titlebar theme parsing logic, removing the special cases for a more uniform / theme-independent result
  • Lots of logic, style and naming cleanups
After much refactoring and refinements, this Pull Request now features a new WM Client-Side Decorations API, a deliverable of this GSoC project. ### WM Decoration API Overview ```cpp // WM_api.hh - line 381-396 /** Client-Side Window Decorations (CSD). */ /* Flags for WM_window_decoration_set_style(). * NOTE: To be kept in sync with GHOST_TWindowDecorationFlags. */ enum eWM_DecorationStyleFlag { /** No Decorations / System Decorations. */ WM_DECORATION_NONE = 0, /** Custom Colored Titlebar. */ WM_DECORATION_COLORED_TITLEBAR = (1 << 0), }; ENUM_OPERATORS(eWM_DecorationStyleFlag, WM_DECORATION_COLORED_TITLEBAR) /* Get/set decoration style flags. */ eWM_DecorationStyleFlag WM_window_decoration_get_style(const wmWindow *win); void WM_window_decoration_set_style(const wmWindow *win, eWM_DecorationStyleFlag style_flags); /* Apply decorations to the window using the current flags and settings from the current theme. * The screen parameter is optional, and can be passed for enhanced theme settings parsing. */ void WM_window_decoration_apply(const wmWindow *win, const bScreen *screen = nullptr); ``` The main idea behind this API is for it to be as light and simple as possible, and for decorations to be tied to windows, not global state. Multiple decoration flags can be set on each windows (via `WM_window_decoration_set_style`), which can also depend on the current theme (see `wm_window_decoration_parse_theme`, called by `WM_decoration_apply`). To keep this API as platform independent as possible, decoration style flags and settings are stored in the base `GHOST_Window` class. This means that to implement this decoration on another backend, the only thing that needs to be done is to override the `applyDecoration()` function on the target backend, see the existing macOS implementation in `GHOST_WindowCocoa.mm` (cc @Harley if you're interested) Other refactors / improvements since review include: - Better update logic, based on Window and screen update notifications - Better colored titlebar theme parsing logic, removing the special cases for a more uniform / theme-independent result - Lots of logic, style and naming cleanups
Jonas Holzman added 1 commit 2024-08-18 19:44:08 +02:00
Jonas Holzman added 1 commit 2024-08-18 19:49:21 +02:00
Member

This works great on Windows 11 (prior versions can't set an exact titlebar color).

I just removed GHOST_kCapabilityClientSideWindowDecorations from that getCapabilities list, then made an applyDecoration like this:

GHOST_TSuccess GHOST_WindowWin32::applyDecoration()
{
  if (m_windowDecorationFlags & GHOST_kDecorationColoredTitleBar) {
    const float *color = m_windowDecorationSettings.colored_titlebar_bg_color;
    const COLORREF colorref = RGB(
        char(color[0] * 255.0f), char(color[1] * 255.0f), char(color[2] * 255.0f));
    if (!SUCCEEDED(DwmSetWindowAttribute(
            m_hWnd, DWMWINDOWATTRIBUTE::DWMWA_CAPTION_COLOR, &colorref, sizeof(colorref))))
    {
      return GHOST_kFailure;
    }
  }
  return GHOST_kSuccess;
}

Like on Mac I wouldn't want to set the caption text color because the OS does a good job of setting a contrasting color and dims it when the window is not active.

The colors match perfectly.

image

I especially like how it looks for the Preferences window.

image

This works great on Windows 11 (prior versions can't set an exact titlebar color). I just removed GHOST_kCapabilityClientSideWindowDecorations from that getCapabilities list, then made an applyDecoration like this: ``` GHOST_TSuccess GHOST_WindowWin32::applyDecoration() { if (m_windowDecorationFlags & GHOST_kDecorationColoredTitleBar) { const float *color = m_windowDecorationSettings.colored_titlebar_bg_color; const COLORREF colorref = RGB( char(color[0] * 255.0f), char(color[1] * 255.0f), char(color[2] * 255.0f)); if (!SUCCEEDED(DwmSetWindowAttribute( m_hWnd, DWMWINDOWATTRIBUTE::DWMWA_CAPTION_COLOR, &colorref, sizeof(colorref)))) { return GHOST_kFailure; } } return GHOST_kSuccess; } ``` Like on Mac I wouldn't want to set the caption text color because the OS does a good job of setting a contrasting color and dims it when the window is not active. The colors match perfectly. ![image](/attachments/77831b23-53e7-4c1e-9867-f5460e770bd3) I especially like how it looks for the Preferences window. ![image](/attachments/2f907472-4483-46b5-bf8e-568623dea443)
Author
Member

Oooh this looks amazing! Thank you so much for taking the time to implement it! I'm so glad you were able to port this to Windows with this little code

Oooh this looks amazing! Thank you so much for taking the time to implement it! I'm so glad you were able to port this to Windows with this little code
Jonas Holzman added 2 commits 2024-08-19 23:51:39 +02:00
Inspired by Harley Windows port code, don't even know why I didn't
go for a raw pointer in the first place. I guess I thought a little
too hard about this.
Jonas Holzman added 2 commits 2024-09-22 23:59:02 +02:00
Small tweak for consistency with the Objective-C refactor
Some checks failed
buildbot/vexp-code-patch-lint Build done.
buildbot/vexp-code-patch-darwin-arm64 Build done.
buildbot/vexp-code-patch-darwin-x86_64 Build done.
buildbot/vexp-code-patch-coordinator Build done.
997ca97630
Jonas Holzman changed title from macOS: Colored Titlebar Client-Side Decorations - GSoC 2024 to macOS: Colored Titlebar and WM Client-Side Decorations API - GSoC 2024 2024-09-23 00:00:35 +02:00
Author
Member

@JulianEisel Hey there, I very slightly tweaked this PR to be consistent with the now merged in Objective-C refactor and updated its title, it should all be ready for final review now.

@JulianEisel Hey there, I very slightly tweaked this PR to be consistent with the now merged in [Objective-C refactor](https://projects.blender.org/blender/blender/issues/126772) and updated its title, it should all be ready for final review now.
Jonas Holzman requested review from Julian Eisel 2024-09-23 00:01:06 +02:00
First-time contributor

@blender-bot package

@blender-bot package
Member

Only blender organization members with write access can start builds. See documentation for details.

Only blender organization members with write access can start builds. See [documentation](https://projects.blender.org/infrastructure/blender-bot/src/branch/main/README.md) for details.
First-time contributor

Nice work! Could organization members review and merge it into the main branch?

Nice work! Could organization members review and merge it into the main branch?

@hologerry Julian is busy finishng up Brush Assets for 4.3. This patch is not a target for 4.3, thus it has to wait.

But the community at large is welcome to help with the code review (and testing). I will kick a new build.

@hologerry Julian is busy finishng up Brush Assets for 4.3. This patch is not a target for 4.3, thus it has to wait. But the community at large is welcome to help with the code review (and testing). I will kick a new build.

@blender-bot package macos

@blender-bot package macos
Member

Package build started. Download here when ready.

Package build started. [Download here](https://builder.blender.org/download/patch/PR123982) when ready.
First-time contributor

@dfelinto Thanks!

@dfelinto Thanks!
Some checks failed
buildbot/vexp-code-patch-lint Build done.
buildbot/vexp-code-patch-darwin-arm64 Build done.
buildbot/vexp-code-patch-darwin-x86_64 Build done.
buildbot/vexp-code-patch-coordinator Build done.
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u gsoc-simple-titlebar-csd:Brainzman-gsoc-simple-titlebar-csd
git checkout Brainzman-gsoc-simple-titlebar-csd
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset System
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Viewport & EEVEE
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Asset Browser Project
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Module
Viewport & EEVEE
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Severity
High
Severity
Low
Severity
Normal
Severity
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
10 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#123982
No description provided.