mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
Do not modify frontend state in DO calls
In particular, delay all state changes that used to be made inside connectBackend:pid such add adding vim controllers to the vimControllers array.
This commit is contained in:
@@ -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 <MMBackendProtocol>)backend
|
||||
pid:(int)pid
|
||||
- (unsigned)connectBackend:(byref in id <MMBackendProtocol>)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)
|
||||
|
||||
@@ -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
|
||||
|
||||
+7
-2
@@ -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 <MMBackendProtocol>)backend
|
||||
pid:(int)pid;
|
||||
- (unsigned)connectBackend:(byref in id <MMBackendProtocol>)proxy pid:(int)pid;
|
||||
- (oneway void)processInput:(in bycopy NSArray *)queue
|
||||
forIdentifier:(unsigned)identifier;
|
||||
- (NSArray *)serverList;
|
||||
|
||||
Reference in New Issue
Block a user