Repository: electron/electron
Pull request: fix: prevent traffic light buttons flashing on deminiaturize

#### Description of Change

Fixes https://github.com/electron/electron/issues/50099

When a window with a custom `trafficLightPosition` is minimized and restored, macOS re-layouts the title bar container during the deminiaturize animation, causing the traffic light buttons to briefly appear at their default position before being repositioned.

Fix this by hiding the buttons container in `windowWillMiniaturize` and restoring them (with a redraw to the correct position) in `windowDidDeminiaturize`.

Tested with https://gist.github.com/rubywwwilde/031350b7c4d91f5afc0e2cff51bb6173

Fixes #50099

#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] PR description included
- [x] I have built and tested this PR
- [x] `npm test` passes
- [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: Fixed an issue where traffic light buttons would flash at position (0,0) when restoring a window with a custom `trafficLightPosition` from minimization on macOS.

Changed files:
filename: shell/browser/native_window_mac.h
patch: @@ -172,6 +172,12 @@ class NativeWindowMac : public NativeWindow,
   void NotifyWindowDidFailToEnterFullScreen();
   void NotifyWindowWillLeaveFullScreen();
 
+  // Hide/show traffic light buttons around miniaturize/deminiaturize to
+  // prevent them from flashing at the default position during the restore
+  // animation when a custom trafficLightPosition is configured.
+  void HideTrafficLights();
+  void RestoreTrafficLights();
+
   // Cleanup observers when window is getting closed. Note that the destructor
   // can be called much later after window gets closed, so we should not do
   // cleanup in destructor.

filename: shell/browser/native_window_mac.mm
patch: @@ -1535,6 +1535,18 @@ static bool FromV8(v8::Isolate* isolate,
     [buttons_proxy_ redraw];
 }
 
+void NativeWindowMac::HideTrafficLights() {
+  if (buttons_proxy_)
+    [buttons_proxy_ setVisible:NO];
+}
+
+void NativeWindowMac::RestoreTrafficLights() {
+  if (buttons_proxy_ && window_button_visibility_.value_or(true)) {
+    [buttons_proxy_ redraw];
+    [buttons_proxy_ setVisible:YES];
+  }
+}
+
 // In simpleFullScreen mode, update the frame for new bounds.
 void NativeWindowMac::UpdateFrame() {
   NSWindow* window = GetNativeWindow().GetNativeNSWindow();

filename: shell/browser/ui/cocoa/electron_ns_window_delegate.mm
patch: @@ -256,6 +256,10 @@ - (void)windowWillMiniaturize:(NSNotification*)notification {
   shell_->SetWindowLevel(NSNormalWindowLevel);
   shell_->UpdateWindowOriginalFrame();
   shell_->DetachChildren();
+  // Hide the traffic light buttons container before miniaturize so that
+  // when the window is restored, macOS does not render the buttons at
+  // their default position during the deminiaturize animation.
+  shell_->HideTrafficLights();
 }
 
 - (void)windowDidMiniaturize:(NSNotification*)notification {
@@ -273,6 +277,10 @@ - (void)windowDidDeminiaturize:(NSNotification*)notification {
   shell_->set_wants_to_be_visible(true);
   shell_->AttachChildren();
   shell_->SetWindowLevel(level_);
+  // Reposition traffic light buttons and make them visible again.
+  // They were hidden in windowWillMiniaturize to prevent a flash at
+  // the default (0,0) position during the restore animation.
+  shell_->RestoreTrafficLights();
   shell_->NotifyWindowRestore();
 }