Repository: electron/electron
Pull request: fix: handle missing `NativeWindowMac` in `ElectronNSWindow`

#### Description of Change

Closes https://github.com/electron/electron/issues/47679.
Refs https://github.com/electron/electron/pull/44628

Fixes an issue where certain operations performed in a window close callback could trigger a crash. After https://github.com/electron/electron/pull/44628 it's possible for `ElectronNSWindow` to outlive `shell_` and thus we should check that it's not `nullptr` prior to use.

#### 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
- [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 certain operations performed in a window close callback could trigger a crash.


Changed files:
filename: shell/browser/ui/cocoa/electron_ns_window.mm
patch: @@ -173,18 +173,16 @@ - (void)cleanup {
 }
 
 - (id)accessibilityFocusedUIElement {
-  views::Widget* widget = shell_->widget();
-  id superFocus = [super accessibilityFocusedUIElement];
-  if (!widget || shell_->IsFocused())
-    return superFocus;
+  if (!shell_ || !shell_->widget() || shell_->IsFocused())
+    return [super accessibilityFocusedUIElement];
   return nil;
 }
 - (NSRect)originalContentRectForFrameRect:(NSRect)frameRect {
   return [super contentRectForFrameRect:frameRect];
 }
 
 - (NSTouchBar*)makeTouchBar {
-  if (shell_->touch_bar())
+  if (shell_ && shell_->touch_bar())
     return [shell_->touch_bar() makeTouchBar];
   else
     return nil;
@@ -214,7 +212,8 @@ - (void)sendEvent:(NSEvent*)event {
 }
 
 - (void)rotateWithEvent:(NSEvent*)event {
-  shell_->NotifyWindowRotateGesture(event.rotation);
+  if (shell_)
+    shell_->NotifyWindowRotateGesture(event.rotation);
 }
 
 - (NSRect)contentRectForFrameRect:(NSRect)frameRect {
@@ -238,7 +237,7 @@ - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen*)screen {
     //
     // If there's no frame, put the window wherever the developer
     // wanted it to go
-    if (shell_->has_frame()) {
+    if (shell_ && shell_->has_frame()) {
       result.size = frameRect.size;
     } else {
       result = frameRect;
@@ -285,7 +284,7 @@ - (id)accessibilityAttributeValue:(NSString*)attribute {
 }
 
 - (NSString*)accessibilityTitle {
-  return base::SysUTF8ToNSString(shell_->GetTitle());
+  return base::SysUTF8ToNSString(shell_ ? shell_->GetTitle() : "");
 }
 
 - (BOOL)canBecomeMainWindow {
@@ -305,7 +304,7 @@ - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
   // support closing a window without title we need to manually do menu item
   // validation. This code path is used by the "roundedCorners" option.
   if ([item action] == @selector(performClose:))
-    return shell_->IsClosable();
+    return shell_ && shell_->IsClosable();
   return [super validateUserInterfaceItem:item];
 }
 
@@ -325,7 +324,8 @@ - (void)disableHeadlessMode {
     // shown, but we don't want the headless behavior of allowing the window to
     // be placed unconstrained.
     self.isHeadless = false;
-    shell_->widget()->DisableHeadlessMode();
+    if (shell_->widget())
+      shell_->widget()->DisableHeadlessMode();
   }
 }
 
@@ -375,6 +375,9 @@ - (void)performClose:(id)sender {
 }
 
 - (BOOL)toggleFullScreenMode:(id)sender {
+  if (!shell_)
+    return NO;
+
   bool is_simple_fs = shell_->IsSimpleFullScreen();
   bool always_simple_fs = shell_->always_simple_fullscreen();
 
@@ -408,11 +411,13 @@ - (BOOL)toggleFullScreenMode:(id)sender {
 }
 
 - (void)performMiniaturize:(id)sender {
-  if (shell_->title_bar_style() ==
-      electron::NativeWindowMac::TitleBarStyle::kCustomButtonsOnHover)
+  if (shell_ &&
+      shell_->title_bar_style() ==
+          electron::NativeWindowMac::TitleBarStyle::kCustomButtonsOnHover) {
     [self miniaturize:self];
-  else
+  } else {
     [super performMiniaturize:sender];
+  }
 }
 
 @end