From 4b5144a31d65f4fc35df76a3201be0f3f1f7658b Mon Sep 17 00:00:00 2001 From: ztancrell Date: Sat, 17 Oct 2026 07:59:09 -0400 Subject: [PATCH] Fix Riot Client crashes on sign-in buttons and file dialogs The Riot Client (Electron) aborted with unrecognized selectors in Cocotron's AppKit: - -[NSOpenPanel setShowsTagField:]: Electron sets it on every file dialog. Add the missing NSSavePanel setters it uses (showsTagField, nameFieldLabel, extensionHidden, canSelectHiddenExtension) as no-ops, and implement beginWithCompletionHandler: and beginSheetModalForWindow:completionHandler: by running the panel modally and calling the handler (the old stub never called it). - -[MacWorkspace openURLs:withAppBundleIdentifier:options: additionalEventParamDescriptor:launchIdentifiers:]: used by shell.openExternal for the third-party sign-in buttons. Open each URL through openURL: (LaunchServices). Fixes #28 Co-Authored-By: Claude Opus 5.5 --- patches/cocotron.patch | 100 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/patches/cocotron.patch b/patches/cocotron.patch index 899b568..96258f2 100644 --- a/patches/cocotron.patch +++ b/patches/cocotron.patch @@ -2069,7 +2069,7 @@ index d545120a..b2845478 100644 + (BOOL) allowsAutomaticWindowTabbing { diff --git a/AppKit/NSWorkspace.m b/AppKit/NSWorkspace.m -index ad5e4f9d..dbd997aa 100644 +index ad5e4f9d..6e9cb1c9 100644 --- a/AppKit/NSWorkspace.m +++ b/AppKit/NSWorkspace.m @@ -20,9 +20,58 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ @@ -2131,7 +2131,7 @@ index ad5e4f9d..dbd997aa 100644 NSString *const NSWorkspaceWillPowerOffNotification = @"NSWorkspaceWillPowerOffNotification"; -@@ -161,6 +210,24 @@ NSNotificationName NSWorkspaceWillUnmountNotification = @"NSWorkspaceWillUnmount +@@ -161,6 +210,41 @@ NSNotificationName NSWorkspaceWillUnmountNotification = @"NSWorkspaceWillUnmount return 0; } @@ -2152,11 +2152,28 @@ index ad5e4f9d..dbd997aa 100644 + } + }); +} ++ ++/* Electron's shell.openExternal({activate: false}) (Riot's "Sign in with Google") uses this ++ * pre-10.15 form. Launch options and the bundle identifier are ignored: the host decides ++ * which application opens the URL. */ ++- (BOOL) openURLs: (NSArray *) urls ++ withAppBundleIdentifier: (NSString *) bundleIdentifier ++ options: (NSUInteger) options ++ additionalEventParamDescriptor: (NSAppleEventDescriptor *) descriptor ++ launchIdentifiers: (NSArray **) identifiers ++{ ++ BOOL opened = [urls count] > 0; ++ for (NSURL *url in urls) ++ opened = [self openURL: url] && opened; ++ if (identifiers != NULL) ++ *identifiers = nil; ++ return opened; ++} + - (BOOL) selectFile: (NSString *) path inFileViewerRootedAtPath: (NSString *) rootedAtPath { -@@ -317,16 +384,3 @@ NSNotificationName NSWorkspaceWillUnmountNotification = @"NSWorkspaceWillUnmount +@@ -317,16 +401,3 @@ NSNotificationName NSWorkspaceWillUnmountNotification = @"NSWorkspaceWillUnmount } @end @@ -10367,3 +10384,80 @@ index 00000000..19cd9ea9 +- (instancetype) init; + +@end +diff --git a/AppKit/NSSavePanel.subproj/NSSavePanel.m b/AppKit/NSSavePanel.subproj/NSSavePanel.m +index 50c3d59e..5872e594 100644 +--- a/AppKit/NSSavePanel.subproj/NSSavePanel.m ++++ b/AppKit/NSSavePanel.subproj/NSSavePanel.m +@@ -124,8 +124,48 @@ static NSSavePanel *_newPanel = nil; + [NSApp stopModalWithCode: NSCancelButton]; + } + ++// Electron (Riot Client UI) opens its file dialogs through these and waits ++// for the handler; run the panel modally and report the result. + - (void) beginWithCompletionHandler: (void (^)(NSModalResponse result)) handler { +- NSUnimplementedMethod(); ++ NSModalResponse result = [self runModal]; ++ if (handler) ++ handler(result); ++} ++ ++- (void) beginSheetModalForWindow: (NSWindow *) window ++ completionHandler: (void (^)(NSModalResponse result)) handler ++{ ++ [self beginWithCompletionHandler: handler]; ++} ++ ++// Electron sets these unconditionally; Cocotron's panel has no tag field, ++// name label or extension toggle, so they are accepted and ignored. ++- (void) setNameFieldLabel: (NSString *) label { ++} ++ ++- (NSString *) nameFieldLabel { ++ return nil; ++} ++ ++- (void) setShowsTagField: (BOOL) flag { ++} ++ ++- (BOOL) showsTagField { ++ return NO; ++} ++ ++- (void) setExtensionHidden: (BOOL) flag { ++} ++ ++- (BOOL) isExtensionHidden { ++ return NO; ++} ++ ++- (void) setCanSelectHiddenExtension: (BOOL) flag { ++} ++ ++- (BOOL) canSelectHiddenExtension { ++ return NO; + } + + - (NSInteger) runModalForDirectory: (NSString *) directory +diff --git a/AppKit/include/AppKit/NSSavePanel.h b/AppKit/include/AppKit/NSSavePanel.h +index 53bacc46..3c6adfb7 100644 +--- a/AppKit/include/AppKit/NSSavePanel.h ++++ b/AppKit/include/AppKit/NSSavePanel.h +@@ -88,6 +88,18 @@ enum { + - (void) setPrompt: (NSString *) message; + - (NSString *) prompt; + ++- (void) setNameFieldLabel: (NSString *) label; ++- (NSString *) nameFieldLabel; ++- (void) setShowsTagField: (BOOL) flag; ++- (BOOL) showsTagField; ++- (void) setExtensionHidden: (BOOL) flag; ++- (BOOL) isExtensionHidden; ++- (void) setCanSelectHiddenExtension: (BOOL) flag; ++- (BOOL) canSelectHiddenExtension; ++ ++- (void) beginSheetModalForWindow: (NSWindow *) window ++ completionHandler: (void (^)(NSModalResponse result)) handler; ++ + - (void) beginSheetForDirectory: (NSString *) path + file: (NSString *) name + modalForWindow: (NSWindow *) docWindow