Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support Mica/Acrylic on Windows #38163

Merged
merged 2 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/api/browser-window.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
codebytere marked this conversation as resolved.
Show resolved Hide resolved

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
Expand Down
3 changes: 3 additions & 0 deletions docs/api/structures/browser-window-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions shell/browser/api/electron_api_base_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,10 @@ void BaseWindow::SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> 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();
Expand Down Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions shell/browser/api/electron_api_base_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
bool IsVisibleOnAllWorkspaces();
void SetAutoHideCursor(bool auto_hide);
virtual void SetVibrancy(v8::Isolate* isolate, v8::Local<v8::Value> value);
void SetBackgroundMaterial(const std::string& vibrancy);

#if BUILDFLAG(IS_MAC)
std::string GetAlwaysOnTopLevel();
Expand Down
7 changes: 7 additions & 0 deletions shell/browser/native_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
codebytere marked this conversation as resolved.
Show resolved Hide resolved
SetBackgroundMaterial(material);
}
#endif
std::string color;
if (options.Get(options::kBackgroundColor, &color)) {
Expand Down Expand Up @@ -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<gin_helper::PersistentDictionary> items) {}

Expand Down
2 changes: 2 additions & 0 deletions shell/browser/native_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,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;
Expand Down
30 changes: 30 additions & 0 deletions shell/browser/native_window_views.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "shell/browser/native_window_views.h"

#if BUILDFLAG(IS_WIN)
#include <dwmapi.h>
#include <wrl/client.h>
#endif

Expand Down Expand Up @@ -68,6 +69,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"
Expand All @@ -82,6 +84,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
Expand Down Expand Up @@ -1378,6 +1393,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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this surface an error to the user rather than silent termination ?

Copy link
Member Author

@codebytere codebytere May 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't for comparable version-gated features like this - historically it's just been clearly noted in docs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think silently failing is fine here


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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User facing error instead of LOG ?

Copy link
Member Author

@codebytere codebytere May 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also open to that, but we don't have a clear convention there either really 🤔 for dark mode for example we don't surface a user facing error:

TrySetWindowTheme(hWnd, dark);

Beyond that - we don't really get a good error message from the call sadly, so all we'd really be able to say is "it failed"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we set this in the constructor we can't safely have a user facing error afaik anyway. I think the LOG is fine here. We shouldn't fail to construct a window just because the DWM call got lost

#endif
}

void NativeWindowViews::SetVisibleOnAllWorkspaces(
bool visible,
bool visibleOnFullScreen,
Expand Down
1 change: 1 addition & 0 deletions shell/browser/native_window_views.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,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,
Expand Down
3 changes: 3 additions & 0 deletions shell/common/options_switches.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
1 change: 1 addition & 0 deletions shell/common/options_switches.h
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down