From e19500fa03bf08af1466dac5dbca39f1b4281d9c Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 15 May 2023 22:31:57 +0200 Subject: [PATCH] feat: support Mica/Acrylic on Windows (#38163) * feat: support Mica/Acrylic on Windows * chore: feedback from review --- docs/api/browser-window.md | 15 ++++++++++ docs/api/structures/browser-window-options.md | 3 ++ shell/browser/api/electron_api_base_window.cc | 5 ++++ shell/browser/api/electron_api_base_window.h | 1 + shell/browser/native_window.cc | 7 +++++ shell/browser/native_window.h | 2 ++ shell/browser/native_window_views.cc | 30 +++++++++++++++++++ shell/browser/native_window_views.h | 1 + shell/common/options_switches.cc | 3 ++ shell/common/options_switches.h | 1 + 10 files changed, 68 insertions(+) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index ee206597bb41..177a3395a776 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -1557,6 +1557,21 @@ will remove the vibrancy effect on the window. Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been deprecated and will be removed in an upcoming version of macOS. +#### `win.setBackgroundMaterial(material)` _Windows_ + +* `material` string + * `auto` - Let the Desktop Window Manager (DWM) automatically decide the system-drawn backdrop material for this window. This is the default. + * `none` - Don't draw any system backdrop. + * `mica` - Draw the backdrop material effect corresponding to a long-lived window. + * `acrylic` - Draw the backdrop material effect corresponding to a transient window. + * `tabbed` - Draw the backdrop material effect corresponding to a window with a tabbed title bar. + +This method sets the browser window's system-drawn background material, including behind the non-client area. + +See the [Windows documentation](https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type) for more details. + +**Note:** This method is only supported on Windows 11 22H2 and up. + #### `win.setWindowButtonPosition(position)` _macOS_ * `position` [Point](structures/point.md) | null diff --git a/docs/api/structures/browser-window-options.md b/docs/api/structures/browser-window-options.md index fafefa9ccf9e..64204ba470ea 100644 --- a/docs/api/structures/browser-window-options.md +++ b/docs/api/structures/browser-window-options.md @@ -110,6 +110,9 @@ `tooltip`, `content`, `under-window`, or `under-page`. Please note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` are deprecated and have been removed in macOS Catalina (10.15). +* `backgroundMaterial` string (optional) _Windows_ - Set the window's + system-drawn background material, including behind the non-client area. + Can be `auto`, `none`, `mica`, `acrylic` or `tabbed`. See [win.setBackgroundMaterial](../browser-window.md#winsetbackgroundmaterialmaterial-windows) for more information. * `zoomToPageWidth` boolean (optional) _macOS_ - Controls the behavior on macOS when option-clicking the green stoplight button on the toolbar or by clicking the Window > Zoom menu item. If `true`, the window will grow to diff --git a/shell/browser/api/electron_api_base_window.cc b/shell/browser/api/electron_api_base_window.cc index fdbe58cf2be3..0ef53104ecdd 100644 --- a/shell/browser/api/electron_api_base_window.cc +++ b/shell/browser/api/electron_api_base_window.cc @@ -864,6 +864,10 @@ void BaseWindow::SetVibrancy(v8::Isolate* isolate, v8::Local value) { window_->SetVibrancy(type); } +void BaseWindow::SetBackgroundMaterial(const std::string& material_type) { + window_->SetBackgroundMaterial(material_type); +} + #if BUILDFLAG(IS_MAC) std::string BaseWindow::GetAlwaysOnTopLevel() { return window_->GetAlwaysOnTopLevel(); @@ -1267,6 +1271,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate, .SetMethod("setAutoHideCursor", &BaseWindow::SetAutoHideCursor) #endif .SetMethod("setVibrancy", &BaseWindow::SetVibrancy) + .SetMethod("setBackgroundMaterial", &BaseWindow::SetBackgroundMaterial) #if BUILDFLAG(IS_MAC) .SetMethod("isHiddenInMissionControl", diff --git a/shell/browser/api/electron_api_base_window.h b/shell/browser/api/electron_api_base_window.h index 28207f1e5793..f95ca67d3005 100644 --- a/shell/browser/api/electron_api_base_window.h +++ b/shell/browser/api/electron_api_base_window.h @@ -190,6 +190,7 @@ class BaseWindow : public gin_helper::TrackableObject, bool IsVisibleOnAllWorkspaces(); void SetAutoHideCursor(bool auto_hide); virtual void SetVibrancy(v8::Isolate* isolate, v8::Local value); + void SetBackgroundMaterial(const std::string& vibrancy); #if BUILDFLAG(IS_MAC) std::string GetAlwaysOnTopLevel(); diff --git a/shell/browser/native_window.cc b/shell/browser/native_window.cc index ce7186bb4994..1477f4e7e595 100644 --- a/shell/browser/native_window.cc +++ b/shell/browser/native_window.cc @@ -249,6 +249,11 @@ void NativeWindow::InitFromOptions(const gin_helper::Dictionary& options) { if (options.Get(options::kVibrancyType, &type)) { SetVibrancy(type); } +#elif BUILDFLAG(IS_WIN) + std::string material; + if (options.Get(options::kBackgroundMaterial, &material)) { + SetBackgroundMaterial(material); + } #endif std::string color; if (options.Get(options::kBackgroundColor, &color)) { @@ -445,6 +450,8 @@ bool NativeWindow::AddTabbedWindow(NativeWindow* window) { void NativeWindow::SetVibrancy(const std::string& type) {} +void NativeWindow::SetBackgroundMaterial(const std::string& type) {} + void NativeWindow::SetTouchBar( std::vector items) {} diff --git a/shell/browser/native_window.h b/shell/browser/native_window.h index ce5d1a7b62d1..098fa2fcf457 100644 --- a/shell/browser/native_window.h +++ b/shell/browser/native_window.h @@ -216,6 +216,8 @@ class NativeWindow : public base::SupportsUserData, // Vibrancy API virtual void SetVibrancy(const std::string& type); + virtual void SetBackgroundMaterial(const std::string& type); + // Traffic Light API #if BUILDFLAG(IS_MAC) virtual void SetWindowButtonVisibility(bool visible) = 0; diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc index 3511d7ba1503..e92247f2a0d7 100644 --- a/shell/browser/native_window_views.cc +++ b/shell/browser/native_window_views.cc @@ -5,6 +5,7 @@ #include "shell/browser/native_window_views.h" #if BUILDFLAG(IS_WIN) +#include #include #endif @@ -69,6 +70,7 @@ #elif BUILDFLAG(IS_WIN) #include "base/win/win_util.h" +#include "base/win/windows_version.h" #include "content/public/common/color_parser.h" #include "shell/browser/ui/views/win_frame_view.h" #include "shell/browser/ui/win/electron_desktop_native_widget_aura.h" @@ -83,6 +85,19 @@ namespace electron { #if BUILDFLAG(IS_WIN) +DWM_SYSTEMBACKDROP_TYPE GetBackdropFromString(const std::string& material) { + if (material == "none") { + return DWMSBT_NONE; + } else if (material == "acrylic") { + return DWMSBT_TRANSIENTWINDOW; + } else if (material == "mica") { + return DWMSBT_MAINWINDOW; + } else if (material == "tabbed") { + return DWMSBT_TABBEDWINDOW; + } + return DWMSBT_AUTO; +} + // Similar to the ones in display::win::ScreenWin, but with rounded values // These help to avoid problems that arise from unresizable windows where the // original ceil()-ed values can cause calculation errors, since converting @@ -1379,6 +1394,21 @@ bool NativeWindowViews::IsMenuBarVisible() { return root_view_->IsMenuBarVisible(); } +void NativeWindowViews::SetBackgroundMaterial(const std::string& material) { +#if BUILDFLAG(IS_WIN) + // DWMWA_USE_HOSTBACKDROPBRUSH is only supported on Windows 11 22H2 and up. + if (base::win::GetVersion() < base::win::Version::WIN11_22H2) + return; + + DWM_SYSTEMBACKDROP_TYPE backdrop_type = GetBackdropFromString(material); + HRESULT result = + DwmSetWindowAttribute(GetAcceleratedWidget(), DWMWA_SYSTEMBACKDROP_TYPE, + &backdrop_type, sizeof(backdrop_type)); + if (FAILED(result)) + LOG(WARNING) << "Failed to set background material to " << material; +#endif +} + void NativeWindowViews::SetVisibleOnAllWorkspaces( bool visible, bool visibleOnFullScreen, diff --git a/shell/browser/native_window_views.h b/shell/browser/native_window_views.h index 2961072ed4a1..a84e17c265b3 100644 --- a/shell/browser/native_window_views.h +++ b/shell/browser/native_window_views.h @@ -138,6 +138,7 @@ class NativeWindowViews : public NativeWindow, bool IsMenuBarAutoHide() override; void SetMenuBarVisibility(bool visible) override; bool IsMenuBarVisible() override; + void SetBackgroundMaterial(const std::string& type) override; void SetVisibleOnAllWorkspaces(bool visible, bool visibleOnFullScreen, diff --git a/shell/common/options_switches.cc b/shell/common/options_switches.cc index a50ea98c1e78..57b66f2e2d31 100644 --- a/shell/common/options_switches.cc +++ b/shell/common/options_switches.cc @@ -110,6 +110,9 @@ const char kWebPreferences[] = "webPreferences"; // Add a vibrancy effect to the browser window const char kVibrancyType[] = "vibrancy"; +// Add a vibrancy effect to the browser window. +const char kBackgroundMaterial[] = "backgroundMaterial"; + // Specify how the material appearance should reflect window activity state on // macOS. const char kVisualEffectState[] = "visualEffectState"; diff --git a/shell/common/options_switches.h b/shell/common/options_switches.h index 46f966f879c5..b0199569dbca 100644 --- a/shell/common/options_switches.h +++ b/shell/common/options_switches.h @@ -55,6 +55,7 @@ extern const char kOpacity[]; extern const char kFocusable[]; extern const char kWebPreferences[]; extern const char kVibrancyType[]; +extern const char kBackgroundMaterial[]; extern const char kVisualEffectState[]; extern const char kTrafficLightPosition[]; extern const char kRoundedCorners[];