Repository: electron/electron
Pull request: fix: titlebar incorrectly displayed on frameless windows

#### Description of Change

Fixes #39959.

- Fixes a bug where Mica background won't work without the `transparent: true` setting
- Fixes a bug where a title bar is displayed on frameless windows

[A patch was added](https://github.com/electron/electron/pull/39708/) to fix Mica backgrounds on frameless windows, but it caused a side-effect in which a title bar gets displayed on frameless transparent windows.

This happens because, after the patch, `WM_NCACTIVATE` would be dispatched to `DefWindowProc` for frameless transparent windows. While this is necessary to make Mica work on these windows, it would cause an incorrect title bar to also be displayed.

To fix this, we are setting -1 as the lParam of `DefWindowProc`, which seems to prevent the non-client area from being displayed on window activation/deactivation:

> When a visual style is not active for this window, this parameter is a handle to an optional update region for the nonclient area of the window. If this parameter is set to -1, [DefWindowProc](https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-defwindowproca) does not repaint the nonclient area to reflect the state change.


|            | Transparent: False, Mica | Transparent: True, Frame: False, Mica | Transparent: True, Frame: True, Mica | Transparent: True, Frame: False, No Mica |
|------------|:------------------:|:--------------------------------:|:-------------------------------------:|:------------------------------------------:|
| **Mica Before** |       ❌       |              ❌              |                ✅                 |                      -                     |
| **Mica After**  |       ✅        |              ❌              |                ✅                 |                      -                     |
| **Title Bar Before** |          -         |              ❌              |                ✅                 |                 ❌                     |
| **Title Bar After**  |          -         |              ✅              |                ✅                 |                 ✅                     |




#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [ ] tests are [changed or added](https://github.com/electron/electron/blob/main/docs/development/testing.md)
- [x] relevant documentation, tutorials, templates and examples are changed or added
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: fix incorrect title bar shown on frameless transparent windows


Changed files:
filename: patches/chromium/fix_activate_background_material_on_windows.patch
patch: @@ -1,19 +1,23 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: clavin <clavin@electronjs.org>
-Date: Wed, 30 Aug 2023 18:15:36 -0700
+Date: Mon, 11 Dec 2023 20:43:34 -0300
 Subject: fix: activate background material on windows
 
 This patch adds a condition to the HWND message handler to allow windows
 with translucent background materials to become activated.
 
+It also ensures the lParam of WM_NCACTIVATE is set to -1 so as to not repaint
+the client area, which can lead to a title bar incorrectly being displayed in
+frameless windows.
+
 This patch likely can't be upstreamed as-is, as Chromium doesn't have
 this use case in mind currently.
 
 diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
-index 23905a6b7f739ff3c6f391f984527ef5d2ed0bd9..ee72bad1b884677b02cc2f86ea307742e5528bad 100644
+index 23905a6b7f739ff3c6f391f984527ef5d2ed0bd9..aed8894a5514fddfc8d15b8fb4ae611fa4493b6f 100644
 --- a/ui/views/win/hwnd_message_handler.cc
 +++ b/ui/views/win/hwnd_message_handler.cc
-@@ -901,7 +901,7 @@ void HWNDMessageHandler::FrameTypeChanged() {
+@@ -901,13 +901,13 @@ void HWNDMessageHandler::FrameTypeChanged() {
  
  void HWNDMessageHandler::PaintAsActiveChanged() {
    if (!delegate_->HasNonClientView() || !delegate_->CanActivate() ||
@@ -22,3 +26,34 @@ index 23905a6b7f739ff3c6f391f984527ef5d2ed0bd9..ee72bad1b884677b02cc2f86ea307742
        (delegate_->GetFrameMode() == FrameMode::CUSTOM_DRAWN)) {
      return;
    }
+ 
+   DefWindowProcWithRedrawLock(WM_NCACTIVATE, delegate_->ShouldPaintAsActive(),
+-                              0);
++                              delegate_->HasFrame() ? 0 : -1);
+ }
+ 
+ void HWNDMessageHandler::SetWindowIcons(const gfx::ImageSkia& window_icon,
+@@ -2254,17 +2254,18 @@ LRESULT HWNDMessageHandler::OnNCActivate(UINT message,
+   if (IsVisible())
+     delegate_->SchedulePaint();
+ 
+-  // Calling DefWindowProc is only necessary if there's a system frame being
+-  // drawn. Otherwise it can draw an incorrect title bar and cause visual
+-  // corruption.
+-  if (!delegate_->HasFrame() ||
++  // If the window is translucent, it may have the Mica background.
++  // In that case, it's necessary to call |DefWindowProc|, but we can
++  // pass -1 in the lParam to prevent any non-client area elements from
++  // being displayed.
++  if ((!delegate_->HasFrame() && !is_translucent_) ||
+       delegate_->GetFrameMode() == FrameMode::CUSTOM_DRAWN) {
+     SetMsgHandled(TRUE);
+     return TRUE;
+   }
+ 
+   return DefWindowProcWithRedrawLock(WM_NCACTIVATE, paint_as_active || active,
+-                                     0);
++                                     delegate_->HasFrame() ? 0 : -1);
+ }
+ 
+ LRESULT HWNDMessageHandler::OnNCCalcSize(BOOL mode, LPARAM l_param) {

filename: shell/browser/ui/win/electron_desktop_window_tree_host_win.cc
patch: @@ -135,12 +135,12 @@ void ElectronDesktopWindowTreeHostWin::OnNativeThemeUpdated(
 
 bool ElectronDesktopWindowTreeHostWin::ShouldWindowContentsBeTransparent()
     const {
-  // Window should be marked as opaque if no transparency setting has been set,
-  // otherwise videos rendered in the window will trigger a DirectComposition
-  // redraw for every frame.
+  // Window should be marked as opaque if no transparency setting has been
+  // set, otherwise animations or videos rendered in the window will trigger a
+  // DirectComposition redraw for every frame.
   // https://github.com/electron/electron/pull/39895
   return native_window_view_->GetOpacity() < 1.0 ||
-         native_window_view_->transparent();
+         native_window_view_->IsTranslucent();
 }
 
 }  // namespace electron