From e452b7ac04b04d571089a332a09bc44bc83fbe2e Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sat, 10 Jun 2023 22:24:43 -0500 Subject: [PATCH] Fix macOS client/server failing to start from terminal The macOS client and server were completely unusable when run from a terminal. They blocked forever in `[NSApp run];` which was called by Sys_InitProtocolHandler(). `applicationDidFinishLaunching` was never called to exit the NSApp run loop. Use SDL's SDL_DROPFILE event to receive URLs to handle on macOS instead. This also handles URLs while the game is running (connect to new server) instead of nothing happening when clicking a link while the game is running. --- code/sdl/sdl_input.c | 26 ++++++++++++++++++++++++++ code/sys/sys_local.h | 1 - code/sys/sys_main.c | 23 +++-------------------- code/sys/sys_osx.m | 43 ------------------------------------------- 4 files changed, 29 insertions(+), 64 deletions(-) diff --git a/code/sdl/sdl_input.c b/code/sdl/sdl_input.c index 390f7b3b..1660cf75 100644 --- a/code/sdl/sdl_input.c +++ b/code/sdl/sdl_input.c @@ -1168,6 +1168,28 @@ static void IN_ProcessEvents( void ) } break; +#if defined(PROTOCOL_HANDLER) && defined(__APPLE__) + case SDL_DROPFILE: + { + char *filename = e.drop.file; + + // Handle macOS open URL event. URL protocol scheme must be set in Info.plist. + if( !Q_strncmp( filename, PROTOCOL_HANDLER ":", strlen( PROTOCOL_HANDLER ":" ) ) ) + { + char *protocolCommand = Sys_ParseProtocolUri( filename ); + + if( protocolCommand ) + { + Cbuf_ExecuteText( EXEC_APPEND, va( "%s\n", protocolCommand ) ); + free( protocolCommand ); + } + } + + SDL_free( filename ); + } + break; +#endif + default: break; } @@ -1250,6 +1272,10 @@ void IN_Init( void *windowData ) in_joystick = Cvar_Get( "in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH ); in_joystickThreshold = Cvar_Get( "joy_threshold", "0.15", CVAR_ARCHIVE ); +#if defined(PROTOCOL_HANDLER) && defined(__APPLE__) + SDL_EventState( SDL_DROPFILE, SDL_ENABLE ); +#endif + SDL_StartTextInput( ); mouseAvailable = ( in_mouse->value != 0 ); diff --git a/code/sys/sys_local.h b/code/sys/sys_local.h index cc660a71..248a51cd 100644 --- a/code/sys/sys_local.h +++ b/code/sys/sys_local.h @@ -66,6 +66,5 @@ int Sys_PID( void ); qboolean Sys_PIDIsRunning( int pid ); #ifdef PROTOCOL_HANDLER -char *Sys_InitProtocolHandler( void ); char *Sys_ParseProtocolUri( const char *uri ); #endif diff --git a/code/sys/sys_main.c b/code/sys/sys_main.c index 41bb54bd..0113920b 100644 --- a/code/sys/sys_main.c +++ b/code/sys/sys_main.c @@ -643,20 +643,6 @@ void Sys_ParseArgs( int argc, char **argv ) } #ifdef PROTOCOL_HANDLER -/* -================= -Sys_InitProtocolHandler - -See sys_osx.m for macOS implementation. -================= -*/ -#ifndef __APPLE__ -char *Sys_InitProtocolHandler( void ) -{ - return NULL; -} -#endif - /* ================= Sys_ParseProtocolUri @@ -716,9 +702,9 @@ char *Sys_ParseProtocolUri( const char *uri ) } } - bufsize = strlen( "+connect " ) + i + 1; + bufsize = strlen( "connect " ) + i + 1; out = malloc( bufsize ); - strcpy( out, "+connect " ); + strcpy( out, "connect " ); strncat( out, uri, i ); return out; } @@ -815,10 +801,6 @@ int main( int argc, char **argv ) Sys_PlatformInit( ); -#ifdef PROTOCOL_HANDLER - protocolCommand = Sys_InitProtocolHandler( ); -#endif - // Set the initial time base Sys_Milliseconds( ); @@ -865,6 +847,7 @@ int main( int argc, char **argv ) #ifdef PROTOCOL_HANDLER if ( protocolCommand != NULL ) { + Q_strcat( commandLine, sizeof( commandLine ), "+" ); Q_strcat( commandLine, sizeof( commandLine ), protocolCommand ); free( protocolCommand ); } diff --git a/code/sys/sys_osx.m b/code/sys/sys_osx.m index d7415d32..b0ecf6a5 100644 --- a/code/sys/sys_osx.m +++ b/code/sys/sys_osx.m @@ -34,10 +34,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #import #import -#ifdef PROTOCOL_HANDLER -char *protocolCommand = NULL; -#endif - /* ============== Sys_Dialog @@ -119,42 +115,3 @@ char *Sys_StripAppBundle( char *dir ) Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd)); return cwd; } - -#ifdef PROTOCOL_HANDLER - -@interface AppDelegate : NSObject -@end - -@implementation AppDelegate - -- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent -{ - NSString *input = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; - protocolCommand = Sys_ParseProtocolUri( input.UTF8String ); -} - -- (void)applicationDidFinishLaunching:(NSNotification *)notification -{ - [NSApp stop:nil]; -} - -@end - -char *Sys_InitProtocolHandler( void ) -{ - [NSApplication sharedApplication]; - - AppDelegate *appDelegate = [AppDelegate new]; - NSAppleEventManager *sharedAppleEventManager = [NSAppleEventManager new]; - [sharedAppleEventManager setEventHandler:appDelegate - andSelector:@selector(handleAppleEvent:withReplyEvent:) - forEventClass:kInternetEventClass - andEventID:kAEGetURL]; - - [NSApp setDelegate:appDelegate]; - [NSApp run]; - - return protocolCommand; -} - -#endif