diff --git a/src/MacVim/MMAppController.m b/src/MacVim/MMAppController.m index 7bafd5ecaa..dffe0772ab 100644 --- a/src/MacVim/MMAppController.m +++ b/src/MacVim/MMAppController.m @@ -126,6 +126,7 @@ typedef struct - (int)executeInLoginShell:(NSString *)path arguments:(NSArray *)args; - (void)reapChildProcesses:(id)sender; - (void)processInputQueues:(id)sender; +- (void)addVimController:(MMVimController *)vc; #ifdef MM_ENABLE_PLUGINS - (void)removePlugInMenu; @@ -1111,61 +1112,28 @@ fsEventCallback(ConstFSEventStreamRef streamRef, return nil; } -- (unsigned)connectBackend:(byref in id )backend - pid:(int)pid +- (unsigned)connectBackend:(byref in id )proxy pid:(int)pid { - //NSLog(@"Connect backend (pid=%d)", pid); - NSNumber *pidKey = [NSNumber numberWithInt:pid]; - MMVimController *vc = nil; + //NSLog(@"[%s] pid=%d", _cmd, pid); - @try { - [(NSDistantObject*)backend - setProtocolForProxy:@protocol(MMBackendProtocol)]; + [(NSDistantObject*)proxy setProtocolForProxy:@protocol(MMBackendProtocol)]; - vc = [[[MMVimController alloc] initWithBackend:backend pid:pid] - autorelease]; + // NOTE: Allocate the vim controller now but don't add it to the list of + // controllers since this is a distributed object call and as such can + // arrive at unpredictable times (e.g. while iterating the list of vim + // controllers). + // (What if input arrives before the vim controller is added to the list of + // controllers? This is not a problem since the input isn't processed + // immediately (see processInput:forIdentifier:).) + MMVimController *vc = [[MMVimController alloc] initWithBackend:proxy + pid:pid]; + [self performSelector:@selector(addVimController:) + withObject:vc + afterDelay:0]; - if (preloadPid == pid) { - // This backend was preloaded, so add it to the cache and schedule - // another vim process to be preloaded. - preloadPid = -1; - [vc setIsPreloading:YES]; - [cachedVimControllers addObject:vc]; - [self scheduleVimControllerPreloadAfterDelay:1]; + [vc release]; - return [vc identifier]; - } - - [vimControllers addObject:vc]; - - id args = [pidArguments objectForKey:pidKey]; - if (args && [NSNull null] != args) - [vc passArguments:args]; - - // HACK! MacVim does not get activated if it is launched from the - // terminal, so we forcibly activate here unless it is an untitled - // window opening. Untitled windows are treated differently, else - // MacVim would steal the focus if another app was activated while the - // untitled window was loading. - if (!args || args != [NSNull null]) - [self activateWhenNextWindowOpens]; - - if (args) - [pidArguments removeObjectForKey:pidKey]; - - return [vc identifier]; - } - - @catch (NSException *e) { - NSLog(@"Exception caught in %s: \"%@\"", _cmd, e); - - if (vc) - [vimControllers removeObject:vc]; - - [pidArguments removeObjectForKey:pidKey]; - } - - return 0; + return [vc identifier]; } - (oneway void)processInput:(in bycopy NSArray *)queue @@ -1175,8 +1143,10 @@ fsEventCallback(ConstFSEventStreamRef streamRef, // call and as such can arrive at unpredictable times. Instead, queue the // input and process it when the run loop is updated. - if (!queue) + if (!(queue && identifier)) { + NSLog(@"[%s] Bad input for identifier=%d", _cmd, identifier); return; + } NSNumber *key = [NSNumber numberWithUnsignedInt:identifier]; NSArray *q = [inputQueues objectForKey:key]; @@ -1184,7 +1154,7 @@ fsEventCallback(ConstFSEventStreamRef streamRef, q = [q arrayByAddingObjectsFromArray:queue]; [inputQueues setObject:q forKey:key]; - NSLog(@"[%s] Appending queue id=%d", _cmd, identifier); + //NSLog(@"[%s] Appending queue id=%d", _cmd, identifier); #if 0 // More debug logging info unsigned i, count = [q count]; for (i = 0; i < count; i += 2) { @@ -2200,4 +2170,36 @@ fsEventCallback(ConstFSEventStreamRef streamRef, processingFlag = 0; } +- (void)addVimController:(MMVimController *)vc +{ + int pid = [vc pid]; + NSNumber *pidKey = [NSNumber numberWithInt:pid]; + + if (preloadPid == pid) { + // This controller was preloaded, so add it to the cache and + // schedule another vim process to be preloaded. + preloadPid = -1; + [vc setIsPreloading:YES]; + [cachedVimControllers addObject:vc]; + [self scheduleVimControllerPreloadAfterDelay:1]; + } else { + [vimControllers addObject:vc]; + + id args = [pidArguments objectForKey:pidKey]; + if (args && [NSNull null] != args) + [vc passArguments:args]; + + // HACK! MacVim does not get activated if it is launched from the + // terminal, so we forcibly activate here unless it is an untitled + // window opening. Untitled windows are treated differently, else + // MacVim would steal the focus if another app was activated while the + // untitled window was loading. + if (!args || args != [NSNull null]) + [self activateWhenNextWindowOpens]; + + if (args) + [pidArguments removeObjectForKey:pidKey]; + } +} + @end // MMAppController (Private) diff --git a/src/MacVim/MMBackend.m b/src/MacVim/MMBackend.m index c316d79a21..155e3d3583 100644 --- a/src/MacVim/MMBackend.m +++ b/src/MacVim/MMBackend.m @@ -327,7 +327,6 @@ extern GuiFont gui_mch_retain_font(GuiFont font); } } - BOOL ok = NO; @try { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectionDidDie:) @@ -344,14 +343,13 @@ extern GuiFont gui_mch_retain_font(GuiFont font); int pid = [[NSProcessInfo processInfo] processIdentifier]; identifier = [appProxy connectBackend:self pid:pid]; - if (identifier != 0) - ok = YES; + return YES; } @catch (NSException *e) { NSLog(@"Exception caught when trying to connect backend: \"%@\"", e); } - return ok; + return NO; } - (BOOL)openGUIWindow diff --git a/src/MacVim/MacVim.h b/src/MacVim/MacVim.h index a81e08ef3c..0a93c1d415 100644 --- a/src/MacVim/MacVim.h +++ b/src/MacVim/MacVim.h @@ -48,9 +48,14 @@ // It handles connections between MacVim and Vim and communication from Vim to // MacVim. // +// Do not add methods to this interface without a _very_ good reason (if +// possible, instead add a new message to the *MsgID enum below and pass it via +// processInput:forIdentifier). Methods should not modify the state directly +// but should instead delay any potential modifications (see +// connectBackend:pid: and processInput:forIdentifier:). +// @protocol MMAppProtocol -- (unsigned)connectBackend:(byref in id )backend - pid:(int)pid; +- (unsigned)connectBackend:(byref in id )proxy pid:(int)pid; - (oneway void)processInput:(in bycopy NSArray *)queue forIdentifier:(unsigned)identifier; - (NSArray *)serverList;