mirror of
https://github.com/electron/electron.git
synced 2026-01-08 23:18:06 -05:00
fix: abnormal behavior of windows background material (#47386)
* fix: abnormal behavior of windows background material Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> * chore: update patches * fix: setting background material after init --------- Co-authored-by: zoy <zoy-l@outlook.com> Co-authored-by: patchup[bot] <73610968+patchup[bot]@users.noreply.github.com>
This commit is contained in:
@@ -850,8 +850,8 @@ void BaseWindow::SetVibrancy(v8::Isolate* isolate,
|
||||
window_->SetVibrancy(type, animation_duration_ms);
|
||||
}
|
||||
|
||||
void BaseWindow::SetBackgroundMaterial(const std::string& material_type) {
|
||||
window_->SetBackgroundMaterial(material_type);
|
||||
void BaseWindow::SetBackgroundMaterial(const std::string& material) {
|
||||
window_->SetBackgroundMaterial(material);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
|
||||
@@ -196,7 +196,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
|
||||
virtual void SetVibrancy(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> value,
|
||||
gin_helper::Arguments* args);
|
||||
void SetBackgroundMaterial(const std::string& vibrancy);
|
||||
virtual void SetBackgroundMaterial(const std::string& material);
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
std::string GetAlwaysOnTopLevel() const;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shell/browser/api/electron_api_browser_window.h"
|
||||
|
||||
#include "base/containers/fixed_flat_set.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_owner_delegate.h" // nogncheck
|
||||
#include "content/browser/web_contents/web_contents_impl.h" // nogncheck
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
@@ -247,6 +248,18 @@ void BrowserWindow::SetBackgroundColor(const std::string& color_name) {
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserWindow::SetBackgroundMaterial(const std::string& material) {
|
||||
BaseWindow::SetBackgroundMaterial(material);
|
||||
static constexpr auto materialTypes =
|
||||
base::MakeFixedFlatSet<std::string_view>({"tabbed", "mica", "acrylic"});
|
||||
|
||||
if (materialTypes.contains(material)) {
|
||||
SetBackgroundColor(ToRGBAHex(SK_ColorTRANSPARENT));
|
||||
} else if (material == "none") {
|
||||
SetBackgroundColor(ToRGBAHex(SK_ColorWHITE));
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserWindow::FocusOnWebView() {
|
||||
web_contents()->GetRenderViewHost()->GetWidget()->Focus();
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ class BrowserWindow : public BaseWindow,
|
||||
void Focus() override;
|
||||
void Blur() override;
|
||||
void SetBackgroundColor(const std::string& color_name) override;
|
||||
void SetBackgroundMaterial(const std::string& material) override;
|
||||
void OnWindowShow() override;
|
||||
void OnWindowHide() override;
|
||||
|
||||
|
||||
@@ -233,6 +233,10 @@ class NativeWindow : public base::SupportsUserData,
|
||||
// Vibrancy API
|
||||
virtual void SetVibrancy(const std::string& type, int duration);
|
||||
|
||||
const std::string& background_material() const {
|
||||
return background_material_;
|
||||
}
|
||||
|
||||
virtual void SetBackgroundMaterial(const std::string& type);
|
||||
|
||||
// Traffic Light API
|
||||
|
||||
@@ -80,6 +80,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/browser/ui/win/electron_desktop_window_tree_host_win.h"
|
||||
#include "shell/common/color_util.h"
|
||||
#include "skia/ext/skia_utils_win.h"
|
||||
#include "ui/display/win/screen_win.h"
|
||||
@@ -352,6 +353,7 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
|
||||
if (!has_frame()) {
|
||||
// Set Window style so that we get a minimize and maximize animation when
|
||||
// frameless.
|
||||
|
||||
DWORD frame_style = WS_CAPTION | WS_OVERLAPPED;
|
||||
if (resizable_)
|
||||
frame_style |= WS_THICKFRAME;
|
||||
@@ -683,13 +685,7 @@ void NativeWindowViews::SetEnabledInternal(bool enable) {
|
||||
|
||||
void NativeWindowViews::Maximize() {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
if (IsTranslucent()) {
|
||||
// Semi-transparent windows with backgroundMaterial not set to 'none', and
|
||||
// not fully transparent, require manual handling of rounded corners when
|
||||
// maximized.
|
||||
if (rounded_corner_)
|
||||
SetRoundedCorners(false);
|
||||
|
||||
if (transparent()) {
|
||||
restore_bounds_ = GetBounds();
|
||||
auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(
|
||||
GetNativeWindow());
|
||||
@@ -713,15 +709,10 @@ void NativeWindowViews::Unmaximize() {
|
||||
return;
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
if (IsTranslucent()) {
|
||||
if (transparent()) {
|
||||
SetBounds(restore_bounds_, false);
|
||||
NotifyWindowUnmaximize();
|
||||
if (transparent()) {
|
||||
UpdateThickFrame();
|
||||
}
|
||||
if (rounded_corner_) {
|
||||
SetRoundedCorners(true);
|
||||
}
|
||||
UpdateThickFrame();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -738,7 +729,7 @@ bool NativeWindowViews::IsMaximized() const {
|
||||
return true;
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
if (IsTranslucent() && !IsMinimized()) {
|
||||
if (transparent() && !IsMinimized()) {
|
||||
// If the window is the same dimensions and placement as the
|
||||
// display, we consider it maximized.
|
||||
auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(
|
||||
@@ -760,15 +751,10 @@ void NativeWindowViews::Minimize() {
|
||||
|
||||
void NativeWindowViews::Restore() {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
if (IsMaximized() && IsTranslucent()) {
|
||||
if (IsMaximized() && transparent()) {
|
||||
SetBounds(restore_bounds_, false);
|
||||
NotifyWindowRestore();
|
||||
if (transparent()) {
|
||||
UpdateThickFrame();
|
||||
}
|
||||
if (rounded_corner_) {
|
||||
SetRoundedCorners(true);
|
||||
}
|
||||
UpdateThickFrame();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -914,7 +900,7 @@ gfx::Size NativeWindowViews::GetContentSize() const {
|
||||
|
||||
gfx::Rect NativeWindowViews::GetNormalBounds() const {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
if (IsMaximized() && IsTranslucent())
|
||||
if (IsMaximized() && transparent())
|
||||
return restore_bounds_;
|
||||
#endif
|
||||
return widget()->GetRestoredBounds();
|
||||
@@ -1555,25 +1541,53 @@ void NativeWindowViews::SetBackgroundMaterial(const std::string& material) {
|
||||
return;
|
||||
|
||||
DWM_SYSTEMBACKDROP_TYPE backdrop_type = GetBackdropFromString(material);
|
||||
HRESULT result =
|
||||
DwmSetWindowAttribute(GetAcceleratedWidget(), DWMWA_SYSTEMBACKDROP_TYPE,
|
||||
&backdrop_type, sizeof(backdrop_type));
|
||||
const bool is_translucent = backdrop_type != DWMSBT_NONE &&
|
||||
backdrop_type != DWMSBT_AUTO && !has_frame();
|
||||
|
||||
HWND hwnd = GetAcceleratedWidget();
|
||||
|
||||
// We need to update margins ourselves since Chromium won't.
|
||||
// See: ui/views/widget/widget_hwnd_utils.cc#157
|
||||
// See: src/ui/views/win/hwnd_message_handler.cc#1793
|
||||
MARGINS m = {0, 0, 0, 0};
|
||||
if (is_translucent)
|
||||
m = {-1, -1, -1, -1};
|
||||
|
||||
HRESULT result = DwmExtendFrameIntoClientArea(hwnd, &m);
|
||||
if (FAILED(result))
|
||||
LOG(WARNING) << "Failed to extend frame into client area";
|
||||
|
||||
result = DwmSetWindowAttribute(hwnd, DWMWA_SYSTEMBACKDROP_TYPE,
|
||||
&backdrop_type, sizeof(backdrop_type));
|
||||
if (FAILED(result))
|
||||
LOG(WARNING) << "Failed to set background material to " << material;
|
||||
|
||||
auto* desktop_window_tree_host =
|
||||
static_cast<ElectronDesktopWindowTreeHostWin*>(
|
||||
GetNativeWindow()->GetHost());
|
||||
|
||||
// Synchronize the internal state; otherwise, the background material may not
|
||||
// work properly.
|
||||
if (desktop_window_tree_host) {
|
||||
desktop_window_tree_host->SetIsTranslucent(is_translucent);
|
||||
}
|
||||
|
||||
auto* desktop_native_widget_aura =
|
||||
static_cast<ElectronDesktopNativeWidgetAura*>(widget()->native_widget());
|
||||
desktop_native_widget_aura->UpdateWindowTransparency();
|
||||
|
||||
// For frameless windows with a background material set, we also need to
|
||||
// remove the caption color so it doesn't render a caption bar (since the
|
||||
// window is frameless)
|
||||
COLORREF caption_color = DWMWA_COLOR_DEFAULT;
|
||||
if (backdrop_type != DWMSBT_NONE && backdrop_type != DWMSBT_AUTO &&
|
||||
!has_frame()) {
|
||||
caption_color = DWMWA_COLOR_NONE;
|
||||
}
|
||||
result = DwmSetWindowAttribute(GetAcceleratedWidget(), DWMWA_CAPTION_COLOR,
|
||||
&caption_color, sizeof(caption_color));
|
||||
|
||||
COLORREF caption_color =
|
||||
is_translucent ? DWMWA_COLOR_NONE : DWMWA_COLOR_DEFAULT;
|
||||
result = DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, &caption_color,
|
||||
sizeof(caption_color));
|
||||
if (FAILED(result))
|
||||
LOG(WARNING) << "Failed to set caption color to transparent";
|
||||
|
||||
// Activate the non-client area of the window
|
||||
DefWindowProc(hwnd, WM_NCACTIVATE, TRUE, has_frame() ? 0 : -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1901,7 +1915,7 @@ ui::mojom::WindowShowState NativeWindowViews::GetRestoredState() {
|
||||
if (IsMaximized()) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// Restore maximized state for windows that are not translucent.
|
||||
if (!IsTranslucent()) {
|
||||
if (!transparent()) {
|
||||
return ui::mojom::WindowShowState::kMaximized;
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -64,7 +64,16 @@ bool ElectronDesktopWindowTreeHostWin::GetDwmFrameInsetsInPixels(
|
||||
gfx::Insets* insets) const {
|
||||
// Set DWMFrameInsets to prevent maximized frameless window from bleeding
|
||||
// into other monitors.
|
||||
|
||||
if (IsMaximized() && !native_window_view_->has_frame()) {
|
||||
// We avoid doing this when the window is translucent (e.g. using
|
||||
// backgroundMaterial effects), because setting zero insets can interfere
|
||||
// with DWM rendering of blur or acrylic, potentially causing visual
|
||||
// glitches.
|
||||
const std::string& bg_material = native_window_view_->background_material();
|
||||
if (!bg_material.empty() && bg_material != "none") {
|
||||
return false;
|
||||
}
|
||||
// This would be equivalent to calling:
|
||||
// DwmExtendFrameIntoClientArea({0, 0, 0, 0});
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user