Repository: electron/electron
Pull request: fix: window `accentColor` should adhere to native window behavior

Backport of #47740

See that PR for details.


Notes: Fixes an issue where the accent border was drawn on all windows regardless of the window's active focused status.

Changed files:
filename: shell/browser/api/electron_api_web_contents.cc
patch: @@ -2015,13 +2015,8 @@ void WebContents::ReadyToCommitNavigation(
   // Don't focus content in an inactive window.
   if (!owner_window())
     return;
-#if BUILDFLAG(IS_MAC)
   if (!owner_window()->IsActive())
     return;
-#else
-  if (!owner_window()->widget()->IsActive())
-    return;
-#endif
   // Don't focus content after subframe navigations.
   if (!navigation_handle->IsInMainFrame())
     return;

filename: shell/browser/native_window.h
patch: @@ -157,10 +157,10 @@ class NativeWindow : public base::SupportsUserData,
   virtual void Invalidate() = 0;
   virtual void SetTitle(const std::string& title) = 0;
   virtual std::string GetTitle() const = 0;
+  [[nodiscard]] virtual bool IsActive() const = 0;
 #if BUILDFLAG(IS_MAC)
   virtual std::string GetAlwaysOnTopLevel() const = 0;
   virtual void SetActive(bool is_key) = 0;
-  virtual bool IsActive() const = 0;
   virtual void RemoveChildFromParentWindow() = 0;
   virtual void RemoveChildWindow(NativeWindow* child) = 0;
   virtual void AttachChildren() = 0;

filename: shell/browser/native_window_views.cc
patch: @@ -424,8 +424,6 @@ 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.
@@ -1139,6 +1137,11 @@ std::string NativeWindowViews::GetTitle() const {
   return title_;
 }
 
+bool NativeWindowViews::IsActive() const {
+  views::Widget* const widget = this->widget();
+  return widget && widget->IsActive();
+}
+
 void NativeWindowViews::FlashFrame(bool flash) {
 #if BUILDFLAG(IS_WIN)
   // The Chromium's implementation has a bug stopping flash.
@@ -1704,6 +1707,12 @@ void NativeWindowViews::OnWidgetActivationChanged(views::Widget* changed_widget,
     NativeWindow::NotifyWindowBlur();
   }
 
+#if BUILDFLAG(IS_WIN)
+  // Update accent color based on activation state when no explicit color is
+  // set.
+  UpdateWindowAccentColor(active);
+#endif
+
   // Hide menu bar when window is blurred.
   if (!active && IsMenuBarAutoHide() && IsMenuBarVisible())
     SetMenuBarVisibility(false);

filename: shell/browser/native_window_views.h
patch: @@ -101,6 +101,7 @@ class NativeWindowViews : public NativeWindow,
   void Invalidate() override;
   void SetTitle(const std::string& title) override;
   std::string GetTitle() const override;
+  [[nodiscard]] bool IsActive() const override;
   void FlashFrame(bool flash) override;
   void SetSkipTaskbar(bool skip) override;
   void SetExcludedFromShownWindowsMenu(bool excluded) override {}
@@ -210,7 +211,7 @@ class NativeWindowViews : public NativeWindow,
   void ResetWindowControls();
   void SetRoundedCorners(bool rounded);
   void SetForwardMouseMessages(bool forward);
-  void UpdateWindowAccentColor();
+  void UpdateWindowAccentColor(bool active);
   static LRESULT CALLBACK SubclassProc(HWND hwnd,
                                        UINT msg,
                                        WPARAM w_param,

filename: shell/browser/native_window_views_win.cc
patch: @@ -499,15 +499,15 @@ bool NativeWindowViews::PreHandleMSG(UINT message,
       return false;
     }
     case WM_DWMCOLORIZATIONCOLORCHANGED: {
-      UpdateWindowAccentColor();
+      UpdateWindowAccentColor(IsActive());
       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();
+          UpdateWindowAccentColor(IsActive());
       }
       return false;
     }
@@ -570,7 +570,7 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
   }
 }
 
-void NativeWindowViews::UpdateWindowAccentColor() {
+void NativeWindowViews::UpdateWindowAccentColor(bool active) {
   if (base::win::GetVersion() < base::win::Version::WIN11)
     return;
 
@@ -589,7 +589,7 @@ void NativeWindowViews::UpdateWindowAccentColor() {
     should_apply_accent = std::get<bool>(accent_color_);
   } else if (std::holds_alternative<std::monostate>(accent_color_)) {
     // If no explicit color was set, default to the system accent color.
-    should_apply_accent = IsAccentColorOnTitleBarsEnabled();
+    should_apply_accent = IsAccentColorOnTitleBarsEnabled() && active;
   }
 
   // Use system accent color as fallback if no explicit color was set.