Repository: electron/electron
Pull request: fix: crash after `win.showAllTabs()` new tab

#### Description of Change

Closes https://github.com/electron/electron/issues/49819.

Round 2.

Fixes a macOS crash when creating a new tab from the tab overview (`new-window-for-tab`) on newer AppKit builds.

The crash happens in private visual tab picker animation paths where AppKit can build constraints from invalid/nil anchors. This change swizzles NSVisualTabPickerGridView’s s`tartGridAnimation:completionHandler:` and immediately runs the completion handler, avoiding the crash animation path while preserving behavior. Alternative possible approach was to swallow the exception, but i think this is a more targeted approach.

cc @nmggithub 

#### 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 a macOS crash when creating a new tab from the tab overview.

Changed files:
filename: shell/browser/ui/cocoa/electron_ns_window.mm
patch: @@ -35,6 +35,41 @@ - (void)cr_mouseDownOnFrameView:(NSEvent*)event;
 
 typedef void (*MouseDownImpl)(id, SEL, NSEvent*);
 
+// Work around an Apple bug where the visual tab picker's
+// grid animation creates NSLayoutConstraints against nil layout anchors,
+// crashing in NSVisualTabPickerShadowTileView. This happens when a new tabbed
+// window is created while the tab picker is open — the "+" tile (and possibly
+// others) have broken internal state. Rather than patching individual tile
+// animation methods, short-circuit the entire grid animation by swizzling
+// NSVisualTabPickerGridView's -startGridAnimation:completionHandler: to
+// immediately invoke the completion handler without running the animation.
+typedef void (*StartGridAnimationIMP)(id, SEL, id, id);
+static StartGridAnimationIMP g_orig_startGridAnimation = nullptr;
+
+static void Patched_startGridAnimation(id self,
+                                       SEL _cmd,
+                                       id animation,
+                                       void (^completionHandler)(void)) {
+  if (completionHandler)
+    completionHandler();
+}
+
+static void SwizzleTabPickerGridAnimation() {
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    Class cls = NSClassFromString(@"NSVisualTabPickerGridView");
+    if (!cls)
+      return;
+    SEL sel = @selector(startGridAnimation:completionHandler:);
+    Method method = class_getInstanceMethod(cls, sel);
+    if (!method)
+      return;
+    g_orig_startGridAnimation =
+        (StartGridAnimationIMP)method_getImplementation(method);
+    method_setImplementation(method, (IMP)Patched_startGridAnimation);
+  });
+}
+
 namespace {
 MouseDownImpl g_nsthemeframe_mousedown;
 MouseDownImpl g_nsnextstepframe_mousedown;
@@ -125,6 +160,7 @@ @implementation ElectronNSWindow
 
 - (id)initWithShell:(electron::NativeWindowMac*)shell
           styleMask:(NSUInteger)styleMask {
+  SwizzleTabPickerGridAnimation();
   if ((self = [super initWithContentRect:ui::kWindowSizeDeterminedLater
                                styleMask:styleMask
                                  backing:NSBackingStoreBuffered