feat: support customizing window accent color on Windows (#47537)
* fix: support window accent color in frameless windows Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> * refactor: allow customization Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> * Update docs/api/structures/base-window-options.md Co-authored-by: Will Anderson <andersonw@dropbox.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> --------- Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
This commit is contained in:
parent
be53277b54
commit
75cda9e16b
5 changed files with 107 additions and 0 deletions
|
@ -95,6 +95,7 @@
|
|||
* `color` String (optional) _Windows_ _Linux_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color.
|
||||
* `symbolColor` String (optional) _Windows_ _Linux_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color.
|
||||
* `height` Integer (optional) - The height of the title bar and Window Controls Overlay in pixels. Default is system height.
|
||||
* `accentColor` boolean | string (optional) _Windows_ - The accent color for the window. By default, follows user preference in System Settings. Set to `false` to explicitly disable, or set the color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. Alpha values will be ignored.
|
||||
* `trafficLightPosition` [Point](point.md) (optional) _macOS_ -
|
||||
Set a custom position for the traffic light buttons in frameless windows.
|
||||
* `roundedCorners` boolean (optional) _macOS_ _Windows_ - Whether frameless window
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
#include "base/win/windows_version.h"
|
||||
#include "shell/browser/ui/views/win_frame_view.h"
|
||||
#include "shell/browser/ui/win/electron_desktop_native_widget_aura.h"
|
||||
#include "shell/common/color_util.h"
|
||||
#include "skia/ext/skia_utils_win.h"
|
||||
#include "ui/display/win/screen_win.h"
|
||||
#include "ui/gfx/color_utils.h"
|
||||
|
@ -214,6 +215,14 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
|
|||
|
||||
overlay_button_color_ = color_utils::GetSysSkColor(COLOR_BTNFACE);
|
||||
overlay_symbol_color_ = color_utils::GetSysSkColor(COLOR_BTNTEXT);
|
||||
|
||||
bool accent_color = true;
|
||||
std::string accent_color_string;
|
||||
if (options.Get(options::kAccentColor, &accent_color_string)) {
|
||||
accent_color_ = ParseCSSColor(accent_color_string);
|
||||
} else if (options.Get(options::kAccentColor, &accent_color)) {
|
||||
accent_color_ = accent_color;
|
||||
}
|
||||
#endif
|
||||
|
||||
v8::Local<v8::Value> titlebar_overlay;
|
||||
|
@ -430,6 +439,8 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
|
|||
last_window_state_ = ui::mojom::WindowShowState::kFullscreen;
|
||||
else
|
||||
last_window_state_ = ui::mojom::WindowShowState::kNormal;
|
||||
|
||||
UpdateWindowAccentColor();
|
||||
#endif
|
||||
|
||||
// Listen to mouse events.
|
||||
|
|
|
@ -209,6 +209,7 @@ class NativeWindowViews : public NativeWindow,
|
|||
void ResetWindowControls();
|
||||
void SetRoundedCorners(bool rounded);
|
||||
void SetForwardMouseMessages(bool forward);
|
||||
void UpdateWindowAccentColor();
|
||||
static LRESULT CALLBACK SubclassProc(HWND hwnd,
|
||||
UINT msg,
|
||||
WPARAM w_param,
|
||||
|
@ -305,6 +306,8 @@ class NativeWindowViews : public NativeWindow,
|
|||
// Whether the window is currently being moved.
|
||||
bool is_moving_ = false;
|
||||
|
||||
std::variant<bool, SkColor> accent_color_ = true;
|
||||
|
||||
std::optional<gfx::Rect> pending_bounds_change_;
|
||||
|
||||
// The message ID of the "TaskbarCreated" message, sent to us when we need to
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <wrl/client.h>
|
||||
|
||||
#include "base/win/atl.h" // Must be before UIAutomationCore.h
|
||||
#include "base/win/registry.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
|
@ -28,6 +29,53 @@ namespace electron {
|
|||
|
||||
namespace {
|
||||
|
||||
void SetWindowBorderAndCaptionColor(HWND hwnd, COLORREF color) {
|
||||
if (base::win::GetVersion() < base::win::Version::WIN11)
|
||||
return;
|
||||
|
||||
HRESULT result =
|
||||
DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, &color, sizeof(color));
|
||||
|
||||
if (FAILED(result))
|
||||
LOG(WARNING) << "Failed to set caption color";
|
||||
|
||||
result =
|
||||
DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, &color, sizeof(color));
|
||||
|
||||
if (FAILED(result))
|
||||
LOG(WARNING) << "Failed to set border color";
|
||||
}
|
||||
|
||||
std::optional<DWORD> GetAccentColor() {
|
||||
base::win::RegKey key;
|
||||
if (key.Open(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\DWM",
|
||||
KEY_READ) != ERROR_SUCCESS) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
DWORD accent_color = 0;
|
||||
if (key.ReadValueDW(L"AccentColor", &accent_color) != ERROR_SUCCESS) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return accent_color;
|
||||
}
|
||||
|
||||
bool IsAccentColorOnTitleBarsEnabled() {
|
||||
base::win::RegKey key;
|
||||
if (key.Open(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\DWM",
|
||||
KEY_READ) != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD enabled = 0;
|
||||
if (key.ReadValueDW(L"ColorPrevalence", &enabled) != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return enabled != 0;
|
||||
}
|
||||
|
||||
// Convert Win32 WM_QUERYENDSESSIONS to strings.
|
||||
const std::vector<std::string> EndSessionToStringVec(LPARAM end_session_id) {
|
||||
std::vector<std::string> params;
|
||||
|
@ -450,6 +498,19 @@ bool NativeWindowViews::PreHandleMSG(UINT message,
|
|||
}
|
||||
return false;
|
||||
}
|
||||
case WM_DWMCOLORIZATIONCOLORCHANGED: {
|
||||
UpdateWindowAccentColor();
|
||||
return false;
|
||||
}
|
||||
case WM_SETTINGCHANGE: {
|
||||
if (l_param) {
|
||||
const wchar_t* setting_name = reinterpret_cast<const wchar_t*>(l_param);
|
||||
std::wstring setting_str(setting_name);
|
||||
if (setting_str == L"ImmersiveColorSet")
|
||||
UpdateWindowAccentColor();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
|
@ -509,6 +570,35 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
|
|||
}
|
||||
}
|
||||
|
||||
void NativeWindowViews::UpdateWindowAccentColor() {
|
||||
if (base::win::GetVersion() < base::win::Version::WIN11)
|
||||
return;
|
||||
|
||||
if (!IsAccentColorOnTitleBarsEnabled())
|
||||
return;
|
||||
|
||||
COLORREF border_color;
|
||||
if (std::holds_alternative<bool>(accent_color_)) {
|
||||
// Don't set accent color if the user has disabled it.
|
||||
if (!std::get<bool>(accent_color_))
|
||||
return;
|
||||
|
||||
std::optional<DWORD> accent_color = GetAccentColor();
|
||||
if (!accent_color.has_value())
|
||||
return;
|
||||
|
||||
border_color =
|
||||
RGB(GetRValue(accent_color.value()), GetGValue(accent_color.value()),
|
||||
GetBValue(accent_color.value()));
|
||||
} else {
|
||||
SkColor color = std::get<SkColor>(accent_color_);
|
||||
border_color =
|
||||
RGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
|
||||
}
|
||||
|
||||
SetWindowBorderAndCaptionColor(GetAcceleratedWidget(), border_color);
|
||||
}
|
||||
|
||||
void NativeWindowViews::ResetWindowControls() {
|
||||
// If a given window was minimized and has since been
|
||||
// unminimized (restored/maximized), ensure the WCO buttons
|
||||
|
|
|
@ -123,6 +123,8 @@ inline constexpr std::string_view kRoundedCorners = "roundedCorners";
|
|||
|
||||
inline constexpr std::string_view ktitleBarOverlay = "titleBarOverlay";
|
||||
|
||||
inline constexpr std::string_view kAccentColor = "accentColor";
|
||||
|
||||
// The color to use as the theme and symbol colors respectively for Window
|
||||
// Controls Overlay if enabled on Windows.
|
||||
inline constexpr std::string_view kOverlayButtonColor = "color";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue