diff --git a/MMAppController.h b/MMAppController.h index 5bcbf1ea48..680330882e 100644 --- a/MMAppController.h +++ b/MMAppController.h @@ -9,10 +9,15 @@ */ #import +#import "MacVim.h" -@interface MMAppController : NSObject { +@interface MMAppController : NSObject +#if MM_USE_DO + +#endif +{ NSPort *receivePort; NSMutableArray *vimControllers; unsigned terminateNowCount; diff --git a/MMAppController.m b/MMAppController.m index 08c1e9c199..83bfe49afb 100644 --- a/MMAppController.m +++ b/MMAppController.m @@ -10,7 +10,6 @@ #import "MMAppController.h" #import "MMVimController.h" -#import "MacVim.h" @@ -21,6 +20,20 @@ if ((self = [super init])) { vimControllers = [NSMutableArray new]; +#if MM_USE_DO + // NOTE! If the name of the connection changes here it must also be + // updated in MMBackend.m. + NSConnection *connection = [NSConnection defaultConnection]; + NSString *name = [NSString stringWithFormat:@"%@-connection", + [[NSBundle mainBundle] bundleIdentifier]]; + //NSLog(@"Registering connection with name '%@'", name); + if ([connection registerName:name]) { + [connection setRootObject:self]; + } else { + NSLog(@"WARNING: Failed to register connection with name '%@'", + name); + } +#else // Init named port for VimTasks to connect to receivePort = [NSMachPort new]; [receivePort setDelegate:self]; @@ -37,6 +50,7 @@ name:portName]) { NSLog(@"WARNING: Failed to start mach bootstrap server"); } +#endif } return self; @@ -46,7 +60,9 @@ { //NSLog(@"MMAppController dealloc"); +#if !MM_USE_DO [receivePort release]; +#endif [vimControllers release]; [super dealloc]; @@ -86,6 +102,38 @@ - (NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *)sender { +#if MM_USE_DO + int reply = NSTerminateNow; + BOOL modifiedBuffers = NO; + + unsigned i, count = [vimControllers count]; + for (i = 0; i < count; ++i) { + MMVimController *controller = [vimControllers objectAtIndex:i]; + id proxy = [controller backendProxy]; + if (proxy && [proxy checkForModifiedBuffers]) { + modifiedBuffers = YES; + break; + } + } + + if (modifiedBuffers) { + NSAlert *alert = [[NSAlert alloc] init]; + [alert addButtonWithTitle:@"Quit"]; + [alert addButtonWithTitle:@"Cancel"]; + [alert setMessageText:@"Quit without saving?"]; + [alert setInformativeText:@"There are modified buffers, " + " if you quit now all changes will be lost. Quit anyway?"]; + [alert setAlertStyle:NSWarningAlertStyle]; + + if ([alert runModal] != NSAlertFirstButtonReturn) { + reply = NSTerminateCancel; + } + + [alert release]; + } + + return reply; +#else int reply = NSTerminateNow; // HACK! Send message to all vim tasks asking if they have modified @@ -136,6 +184,7 @@ } return reply; +#endif } - (void)applicationWillTerminate:(NSNotification *)aNotification @@ -145,6 +194,7 @@ [self autorelease]; } +#if !MM_USE_DO - (void)handlePortMessage:(NSPortMessage *)portMessage { unsigned msgid = [portMessage msgid]; @@ -163,6 +213,7 @@ NSLog(@"WARNING: Unknown message received (msgid=%d)", msgid); } } +#endif - (void)removeVimController:(id)controller { @@ -179,4 +230,22 @@ [NSTask launchedTaskWithLaunchPath:path arguments:args]; } +#if MM_USE_DO +- (byref id )connectBackend: + (byref in id )backend; +{ + //NSLog(@"Frontend got connection request from backend...adding new " + // "MMVimController"); + + [(NSDistantObject*)backend + setProtocolForProxy:@protocol(MMBackendProtocol)]; + + MMVimController *wc = [[[MMVimController alloc] initWithBackend:backend] + autorelease]; + [vimControllers addObject:wc]; + + return wc; +} +#endif + @end diff --git a/MMBackend.h b/MMBackend.h index 5f2aa7265d..5e28c6b525 100644 --- a/MMBackend.h +++ b/MMBackend.h @@ -9,15 +9,25 @@ */ #import +#import "MacVim.h" -@interface MMBackend : NSObject { +@interface MMBackend : NSObject +#if MM_USE_DO + +#endif +{ NSMutableArray *queue; NSMutableData *drawData; - NSData *replyData; +#if MM_USE_DO + NSConnection *connection; + id frontendProxy; +#else NSPort *sendPort; NSPort *receivePort; + NSData *replyData; +#endif NSDictionary *colorDict; BOOL inputReceived; BOOL receivedKillTaskMsg; diff --git a/MMBackend.m b/MMBackend.m index 50c809f39b..2456ff1d4b 100644 --- a/MMBackend.m +++ b/MMBackend.m @@ -9,7 +9,6 @@ */ #import "MMBackend.h" -#import "MacVim.h" #import "vim.h" @@ -21,9 +20,13 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); @interface MMBackend (Private) +- (void)handleMessage:(int)msgid data:(NSData *)data; + (NSDictionary *)specialKeys; - (void)handleKeyDown:(NSString *)key modifiers:(int)mods; - (void)queueMessage:(int)msgid data:(NSData *)data; +#if MM_USE_DO +- (void)connectionDidDie:(NSNotification *)notification; +#endif @end @@ -51,10 +54,17 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); - (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [queue release]; [drawData release]; +#if MM_USE_DO + [frontendProxy release]; + [connection release]; +#else [sendPort release]; [receivePort release]; +#endif [colorDict release]; [super dealloc]; @@ -78,6 +88,14 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); - (BOOL)checkin { +#if MM_USE_DO + // NOTE! If the name of the connection changes here it must also be + // updated in MMAppController.m. + NSString *name = [NSString stringWithFormat:@"%@-connection", + [[NSBundle mainBundle] bundleIdentifier]]; + connection = [NSConnection connectionWithRegisteredName:name host:nil]; + if (!connection) +#else // NOTE! If the name of the port changes here it must also be updated in // MMAppController.m. NSString *portName = [NSString stringWithFormat:@"%@-taskport", @@ -85,7 +103,9 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); NSPort *port = [[[NSMachBootstrapServer sharedInstance] portForName:portName host:nil] retain]; - if (!port) { + if (!port) +#endif + { #if 0 NSString *path = [[NSBundle mainBundle] bundlePath]; if (![[NSWorkspace sharedWorkspace] launchApplication:path]) { @@ -113,20 +133,52 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); // returns a valid port. Also set a time-out date so that we don't get // stuck doing this forever. NSDate *timeOutDate = [NSDate dateWithTimeIntervalSinceNow:15]; - while (!port && - NSOrderedDescending == [timeOutDate compare:[NSDate date]]) { + while ( +#if MM_USE_DO + !connection +#else + !port +#endif + && NSOrderedDescending == [timeOutDate compare:[NSDate date]]) + { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]; - port = [[NSMachBootstrapServer sharedInstance] portForName:portName]; +#if MM_USE_DO + connection = [NSConnection connectionWithRegisteredName:name + host:nil]; +#else + port = [[NSMachBootstrapServer sharedInstance] + portForName:portName]; +#endif } - if (!port) { +#if MM_USE_DO + if (!connection) +#else + if (!port) +#endif + { NSLog(@"WARNING: Timed-out waiting for GUI to launch."); return NO; } } +#if MM_USE_DO + id proxy = [connection rootProxy]; + [proxy setProtocolForProxy:@protocol(MMAppProtocol)]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(connectionDidDie:) + name:NSConnectionDidDieNotification object:connection]; + + frontendProxy = [(NSDistantObject*)[proxy connectBackend:self] retain]; + if (frontendProxy) { + [frontendProxy setProtocolForProxy:@protocol(MMAppProtocol)]; + } + + return connection && frontendProxy; +#else receivePort = [NSMachPort new]; [receivePort setDelegate:self]; @@ -137,10 +189,12 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); receivePort:receivePort wait:YES]; return YES; +#endif } - (BOOL)openVimWindowWithRows:(int)rows columns:(int)cols { +#if !MM_USE_DO if (!sendPort) { #if 0 // TODO: Wait until connected---maybe time out at some point? @@ -165,6 +219,7 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); } #endif } +#endif // !MM_USE_DO NSMutableData *data = [NSMutableData data]; @@ -276,19 +331,25 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); // TODO: Come up with a better way to handle the insertion point. [self updateInsertionPoint]; +#if MM_USE_DO + [frontendProxy processCommandQueue:queue]; +#else [NSPortMessage sendMessage:FlushQueueMsgID withSendPort:sendPort components:queue wait:YES]; +#endif [queue removeAllObjects]; } } - (BOOL)waitForInput:(int)milliseconds { +#if !MM_USE_DO if (![receivePort isValid]) { // This should only happen if the GUI crashes. NSLog(@"ERROR: The receive port is no longer valid, quitting..."); getout(0); } +#endif NSDate *date = milliseconds > 0 ? [NSDate dateWithTimeIntervalSinceNow:.001*milliseconds] : @@ -308,10 +369,18 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); - (void)exit { +#if MM_USE_DO + // By invalidating the NSConnection the MMWindowController immediately + // finds out that the connection is down and as a result + // [MMWindowController connectionDidDie:] is invoked. + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [connection invalidate]; +#else if (!receivedKillTaskMsg) { [NSPortMessage sendMessage:TaskExitedMsgID withSendPort:sendPort receivePort:receivePort wait:YES]; } +#endif } - (void)selectTab:(int)index @@ -388,6 +457,9 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); - (char *)browseForFileInDirectory:(char *)dir title:(char *)title saving:(int)saving { +#if MM_USE_DO + return nil; +#else //NSLog(@"browseForFileInDirectory:%s title:%s saving:%d", dir, title, // saving); @@ -430,6 +502,7 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); [replyData release]; replyData = nil; return (char*)s; +#endif // MM_USE_DO } - (void)updateInsertionPoint @@ -665,6 +738,27 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); return INVALCOLOR; } +#if MM_USE_DO +- (oneway void)processInput:(int)msgid data:(in NSData *)data +{ + [self handleMessage:msgid data:data]; + inputReceived = YES; +} + +- (BOOL)checkForModifiedBuffers +{ + buf_T *buf; + for (buf = firstbuf; buf != NULL; buf = buf->b_next) { + if (bufIsChanged(buf)) { + return YES; + } + } + + return NO; +} + +#else // MM_USE_DO + - (void)handlePortMessage:(NSPortMessage *)portMessage { unsigned msgid = [portMessage msgid]; @@ -672,17 +766,48 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); if (ConnectedMsgID == msgid) { sendPort = [[portMessage sendPort] retain]; //NSLog(@"VimTask connected to MMVimController."); - } else if (KillTaskMsgID == msgid) { + } else if (TaskShouldTerminateMsgID == msgid) { + int reply = TerminateReplyYesMsgID; + buf_T *buf; + for (buf = firstbuf; buf != NULL; buf = buf->b_next) { + if (bufIsChanged(buf)) { + reply = TerminateReplyNoMsgID; + break; + } + } + + //NSLog(@"TaskShouldTerminateMsgID = %s", + // reply == TerminateReplyYesMsgID ? "YES" : "NO"); + + [NSPortMessage sendMessage:reply withSendPort:[portMessage sendPort] + wait:YES]; + } else { + NSArray *components = [portMessage components]; + NSData *data = [components count] > 0 ? + [components objectAtIndex:0] : nil; + [self handleMessage:msgid data:data]; + } +} +#endif // MM_USE_DO + +@end // MMBackend + + + +@implementation MMBackend (Private) + +- (void)handleMessage:(int)msgid data:(NSData *)data +{ + if (KillTaskMsgID == msgid) { //NSLog(@"VimTask received kill message; exiting now."); // Set this flag here so that exit does not send TaskExitedMsgID back // to MMVimController. receivedKillTaskMsg = YES; getout(0); } else if (InsertTextMsgID == msgid) { - if (![[portMessage components] count]) return; - NSString *key = [[NSString alloc] - initWithData:[[portMessage components] objectAtIndex:0] - encoding:NSUTF8StringEncoding]; + if (!data) return; + NSString *key = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; //NSLog(@"insert text: %@ (hex=%x)", key, [key characterAtIndex:0]); add_to_input_buf((char_u*)[key UTF8String], [key lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); @@ -690,8 +815,8 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); inputReceived = YES; } else if (KeyDownMsgID == msgid || CmdKeyMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + if (!data) return; + const void *bytes = [data bytes]; int mods = *((int*)bytes); bytes += sizeof(int); int len = *((int*)bytes); bytes += sizeof(int); NSString *key = [[NSString alloc] initWithBytes:bytes length:len @@ -703,15 +828,15 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); [key release]; inputReceived = YES; } else if (SelectTabMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + if (!data) return; + const void *bytes = [data bytes]; int idx = *((int*)bytes) + 1; //NSLog(@"Selecting tab %d", idx); send_tabline_event(idx); inputReceived = YES; } else if (CloseTabMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + if (!data) return; + const void *bytes = [data bytes]; int idx = *((int*)bytes) + 1; //NSLog(@"Closing tab %d", idx); send_tabline_menu_event(idx, TABLINE_MENU_CLOSE); @@ -721,8 +846,8 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); send_tabline_menu_event(0, TABLINE_MENU_NEW); inputReceived = YES; } else if (DraggedTabMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + if (!data) return; + const void *bytes = [data bytes]; // NOTE! The destination index is 0 based, so do not add 1 to make it 1 // based. int idx = *((int*)bytes); @@ -743,8 +868,8 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); tabpage_move(idx); #endif } else if (ScrollWheelMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + if (!data) return; + const void *bytes = [data bytes]; int row = *((int*)bytes); bytes += sizeof(int); int col = *((int*)bytes); bytes += sizeof(int); @@ -759,8 +884,8 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); gui_send_mouse_event(button, col, row, NO, flags); inputReceived = YES; } else if (MouseDownMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + if (!data) return; + const void *bytes = [data bytes]; int row = *((int*)bytes); bytes += sizeof(int); int col = *((int*)bytes); bytes += sizeof(int); @@ -775,8 +900,8 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); inputReceived = YES; } else if (MouseUpMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + if (!data) return; + const void *bytes = [data bytes]; int row = *((int*)bytes); bytes += sizeof(int); int col = *((int*)bytes); bytes += sizeof(int); @@ -787,8 +912,8 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); gui_send_mouse_event(MOUSE_RELEASE, col, row, NO, flags); inputReceived = YES; } else if (MouseDraggedMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + if (!data) return; + const void *bytes = [data bytes]; int row = *((int*)bytes); bytes += sizeof(int); int col = *((int*)bytes); bytes += sizeof(int); @@ -798,21 +923,25 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); gui_send_mouse_event(MOUSE_DRAG, col, row, NO, flags); inputReceived = YES; - } else if (BrowseForFileReplyMsgID == msgid) { - if (![[portMessage components] count]) return; + } +#if !MM_USE_DO + else if (BrowseForFileReplyMsgID == msgid) { + if (!data) return; [replyData release]; - replyData = [[[portMessage components] objectAtIndex:0] copy]; - } else if (SetTextDimensionsMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + replyData = [data copy]; + } +#endif + else if (SetTextDimensionsMsgID == msgid) { + if (!data) return; + const void *bytes = [data bytes]; int rows = *((int*)bytes); bytes += sizeof(int); int cols = *((int*)bytes); bytes += sizeof(int); //NSLog(@"[VimTask] Resizing shell to %dx%d.", cols, rows); gui_resize_shell(cols, rows); } else if (ExecuteMenuMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + if (!data) return; + const void *bytes = [data bytes]; int tag = *((int*)bytes); bytes += sizeof(int); vimmenu_T *menu = (vimmenu_T*)tag; @@ -821,24 +950,9 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); gui_menu_cb(menu); inputReceived = YES; } - } else if (TaskShouldTerminateMsgID == msgid) { - int reply = TerminateReplyYesMsgID; - buf_T *buf; - for (buf = firstbuf; buf != NULL; buf = buf->b_next) { - if (bufIsChanged(buf)) { - reply = TerminateReplyNoMsgID; - break; - } - } - - //NSLog(@"TaskShouldTerminateMsgID = %s", - // reply == TerminateReplyYesMsgID ? "YES" : "NO"); - - [NSPortMessage sendMessage:reply withSendPort:[portMessage sendPort] - wait:YES]; } else if (ScrollbarEventMsgID == msgid) { - if (![[portMessage components] count]) return; - const void *bytes = [[[portMessage components] objectAtIndex:0] bytes]; + if (!data) return; + const void *bytes = [data bytes]; long ident = *((long*)bytes); bytes += sizeof(long); int hitPart = *((int*)bytes); bytes += sizeof(int); float fval = *((float*)bytes); bytes += sizeof(float); @@ -900,18 +1014,13 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); inputReceived = YES; } + } else if (VimShouldCloseMsgID == msgid) { + gui_shell_closed(); } else { NSLog(@"WARNING: Unknown message received (msgid=%d)", msgid); } } - -@end // MMBackend - - - -@implementation MMBackend (Private) - + (NSDictionary *)specialKeys { static NSDictionary *specialKeys = nil; @@ -1002,6 +1111,19 @@ static int eventButtonNumberToVimMouseButton(int buttonNumber); [queue addObject:[NSData data]]; } +#if MM_USE_DO +- (void)connectionDidDie:(NSNotification *)notification +{ + // If the main connection to MacVim is lost this means that MacVim was + // either quit (by the user chosing Quit on the MacVim menu), or it has + // crashed. In either case our only option is to quit now. + // TODO: Write backup file? + + //NSLog(@"A Vim process lots its connection to MacVim; quitting."); + getout(0); +} +#endif // MM_USE_DO + @end // MMBackend (Private) diff --git a/MMTextStorage.m b/MMTextStorage.m index d4fd08ac72..13315018ef 100644 --- a/MMTextStorage.m +++ b/MMTextStorage.m @@ -54,6 +54,8 @@ - (void)dealloc { + //NSLog(@"%@ %s", [self className], _cmd); + [emptyRowString release]; //[paragraphStyle release]; [font release]; diff --git a/MMTextView.h b/MMTextView.h index 04905f1d26..6acdb8843b 100644 --- a/MMTextView.h +++ b/MMTextView.h @@ -12,15 +12,9 @@ @interface MMTextView : NSTextView { - BOOL ownsTextStorage; - int tabpageIdx; - NSPort *sendPort; BOOL shouldDrawInsertionPoint; } -- (id)initWithPort:(NSPort *)port frame:(NSRect)frame - textContainer:(NSTextContainer *)tc; -- (MMTextView *)initWithFrame:(NSRect)frame port:(NSPort *)port; - (void)setShouldDrawInsertionPoint:(BOOL)enable; @end diff --git a/MMTextView.m b/MMTextView.m index 4c990489fa..fbe3990c77 100644 --- a/MMTextView.m +++ b/MMTextView.m @@ -10,80 +10,22 @@ #import "MMTextView.h" #import "MMTextStorage.h" -#import "MacVim.h" #import "MMWindowController.h" +#import "MMVimController.h" +#import "MacVim.h" @interface MMTextView (Private) - (BOOL)convertPoint:(NSPoint)point toRow:(int *)row column:(int *)column; - (void)dispatchKeyEvent:(NSEvent *)event; +- (MMVimController *)vimController; @end @implementation MMTextView -- (id)initWithPort:(NSPort *)port frame:(NSRect)frame - textContainer:(NSTextContainer *)tc -{ - if ((self = [super initWithFrame:frame textContainer:tc])) { - sendPort = [port retain]; - } - - return self; -} - -- (MMTextView *)initWithFrame:(NSRect)frame port:(NSPort *)port -{ - MMTextStorage *ts = [[MMTextStorage alloc] init]; - NSLayoutManager *lm = [[NSLayoutManager alloc] init]; - NSTextContainer *tc = [[NSTextContainer alloc] initWithContainerSize: - NSMakeSize(1.0e7,1.0e7)]; - - [tc setWidthTracksTextView:NO]; - [tc setHeightTracksTextView:NO]; - [tc setLineFragmentPadding:0]; - - [ts addLayoutManager:lm]; - [lm addTextContainer:tc]; - - [tc release]; - [lm release]; - - // HACK! Where should i get these values from? - // TODO: get values from frame - [ts setMaxRows:24 columns:80]; - - if ((self = [super initWithFrame:frame textContainer:tc])) { - ownsTextStorage = YES; - //[self setRichText:NO]; - sendPort = [port retain]; - } else { - ownsTextStorage = NO; - [ts release]; - } - - return self; -} - - -- (void)dealloc -{ - // BUG! The reference count of the text view will never reach 0 unless - // release is explicitly called on the text storage; so this code is - // meaningless. - if (ownsTextStorage) { - [[self textContainer] setTextView:nil]; - [[self textStorage] release]; - ownsTextStorage = NO; - } - - [sendPort release]; - - [super dealloc]; -} - - (void)setShouldDrawInsertionPoint:(BOOL)enable { shouldDrawInsertionPoint = enable; @@ -122,9 +64,9 @@ [NSCursor setHiddenUntilMouseMoves:YES]; - [NSPortMessage sendMessage:InsertTextMsgID withSendPort:sendPort - data:[string dataUsingEncoding:NSUTF8StringEncoding] - wait:NO]; + [[self vimController] sendMessage:InsertTextMsgID + data:[string dataUsingEncoding:NSUTF8StringEncoding] + wait:NO]; } @@ -174,8 +116,7 @@ [data appendBytes:&len length:sizeof(int)]; [data appendBytes:[string UTF8String] length:len]; - [NSPortMessage sendMessage:CmdKeyMsgID withSendPort:sendPort data:data - wait:NO]; + [[self vimController] sendMessage:CmdKeyMsgID data:data wait:NO]; return YES; } @@ -220,8 +161,7 @@ [data appendBytes:&flags length:sizeof(int)]; [data appendBytes:&dy length:sizeof(float)]; - [NSPortMessage sendMessage:ScrollWheelMsgID withSendPort:sendPort - data:data wait:NO]; + [[self vimController] sendMessage:ScrollWheelMsgID data:data wait:NO]; } - (void)mouseDown:(NSEvent *)event @@ -242,8 +182,7 @@ [data appendBytes:&flags length:sizeof(int)]; [data appendBytes:&count length:sizeof(int)]; - [NSPortMessage sendMessage:MouseDownMsgID withSendPort:sendPort - data:data wait:NO]; + [[self vimController] sendMessage:MouseDownMsgID data:data wait:NO]; } - (void)rightMouseDown:(NSEvent *)event @@ -270,8 +209,7 @@ [data appendBytes:&col length:sizeof(int)]; [data appendBytes:&flags length:sizeof(int)]; - [NSPortMessage sendMessage:MouseUpMsgID withSendPort:sendPort - data:data wait:NO]; + [[self vimController] sendMessage:MouseUpMsgID data:data wait:NO]; } - (void)rightMouseUp:(NSEvent *)event @@ -298,8 +236,7 @@ [data appendBytes:&col length:sizeof(int)]; [data appendBytes:&flags length:sizeof(int)]; - [NSPortMessage sendMessage:MouseDraggedMsgID withSendPort:sendPort - data:data wait:NO]; + [[self vimController] sendMessage:MouseDraggedMsgID data:data wait:NO]; } - (void)rightMouseDragged:(NSEvent *)event @@ -393,9 +330,17 @@ [NSCursor setHiddenUntilMouseMoves:YES]; - [NSPortMessage sendMessage:KeyDownMsgID withSendPort:sendPort data:data - wait:NO]; + [[self vimController] sendMessage:KeyDownMsgID data:data wait:NO]; } } +- (MMVimController *)vimController +{ + id windowController = [[self window] windowController]; + + // TODO: Make sure 'windowController' is a MMWindowController before type + // casting. + return [(MMWindowController*)windowController vimController]; +} + @end // MMTextView (Private) diff --git a/MMVimController.h b/MMVimController.h index 19da37f264..5917d474ff 100644 --- a/MMVimController.h +++ b/MMVimController.h @@ -9,15 +9,24 @@ */ #import +#import "MacVim.h" @class MMWindowController; -@interface MMVimController : NSObject { +@interface MMVimController : NSObject +#if MM_USE_DO + +#endif +{ MMWindowController *windowController; +#if MM_USE_DO + id backendProxy; +#else NSPort *sendPort; NSPort *receivePort; +#endif NSMutableArray *mainMenuItems; BOOL shouldUpdateMainMenu; //NSMutableArray *popupMenus; @@ -25,9 +34,15 @@ NSMutableDictionary *toolbarItemDict; } +#if MM_USE_DO +- (id)initWithBackend:(id)backend; +- (id)backendProxy; +#else - (id)initWithPort:(NSPort *)port; -- (void)windowWillClose:(NSNotification *)notification; - (NSPort *)sendPort; +#endif +- (void)windowWillClose:(NSNotification *)notification; +- (void)sendMessage:(int)msgid data:(NSData *)data wait:(BOOL)wait; @end diff --git a/MMVimController.m b/MMVimController.m index cd7e44451c..54045efb19 100644 --- a/MMVimController.m +++ b/MMVimController.m @@ -10,7 +10,6 @@ #import "MMVimController.h" #import "MMWindowController.h" -#import "MacVim.h" #import "MMAppController.h" #import "MMTextView.h" #import "MMTextStorage.h" @@ -32,6 +31,7 @@ static NSString *DefaultToolbarImageName = @"Attention"; - (IBAction)toolbarAction:(id)sender; - (void)addToolbarItemToDictionaryWithTag:(int)tag label:(NSString *)title toolTip:(NSString *)tip icon:(NSString *)icon; +- (void)connectionDidDie:(NSNotification *)notification; @end @@ -67,10 +67,40 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) @implementation MMVimController +#if MM_USE_DO +- (id)initWithBackend:(id)backend +#else - (id)initWithPort:(NSPort *)port +#endif { if ((self = [super init])) { - windowController = [[MMWindowController alloc] initWithPort:port]; + windowController = + [[MMWindowController alloc] initWithVimController:self]; +#if MM_USE_DO + backendProxy = [backend retain]; + + NSConnection *connection = [backendProxy connectionForProxy]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(connectionDidDie:) + name:NSConnectionDidDieNotification object:connection]; +#else + sendPort = [port retain]; + + // Init receive port and send connected message to VimTask + receivePort = [NSMachPort new]; + [receivePort setDelegate:self]; + + // Add to the default run loop mode as well as the event tracking mode; + // the latter ensures that updates from the VimTask reaches + // MMVimController whilst the user resizes a window with the mouse. + [[NSRunLoop currentRunLoop] addPort:receivePort + forMode:NSDefaultRunLoopMode]; + [[NSRunLoop currentRunLoop] addPort:receivePort + forMode:NSEventTrackingRunLoopMode]; + + [NSPortMessage sendMessage:ConnectedMsgID withSendPort:sendPort + receivePort:receivePort wait:YES]; +#endif mainMenuItems = [[NSMutableArray alloc] init]; @@ -90,22 +120,6 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) name:NSWindowDidBecomeMainNotification object:[windowController window]]; - sendPort = [port retain]; - - // Init receive port and send connected message to VimTask - receivePort = [NSMachPort new]; - [receivePort setDelegate:self]; - - // Add to the default run loop mode as well as the event tracking mode; - // the latter ensures that updates from the VimTask reaches - // MMVimController whilst the user resizes a window with the mouse. - [[NSRunLoop currentRunLoop] addPort:receivePort - forMode:NSDefaultRunLoopMode]; - [[NSRunLoop currentRunLoop] addPort:receivePort - forMode:NSEventTrackingRunLoopMode]; - - [NSPortMessage sendMessage:ConnectedMsgID withSendPort:sendPort - receivePort:receivePort wait:YES]; } return self; @@ -113,24 +127,67 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) - (void)dealloc { + //NSLog(@"%@ %s", [self className], _cmd); + + [[NSNotificationCenter defaultCenter] removeObserver:self]; + +#if MM_USE_DO + [backendProxy release]; +#else if (sendPort) { // Kill task immediately [NSPortMessage sendMessage:KillTaskMsgID withSendPort:sendPort receivePort:receivePort wait:NO]; } - [[NSNotificationCenter defaultCenter] removeObserver:self]; + [sendPort release]; + [receivePort release]; +#endif [toolbarItemDict release]; [toolbar release]; [mainMenuItems release]; [windowController release]; - [sendPort release]; - [receivePort release]; [super dealloc]; } +- (id)backendProxy +{ + return backendProxy; +} + +- (void)sendMessage:(int)msgid data:(NSData *)data wait:(BOOL)wait +{ +#if MM_USE_DO + // TODO: Decrease reply/request timeouts if 'wait' is off. + [backendProxy processInput:msgid data:data]; +#else + [NSPortMessage sendMessage:msgid withSendPort:sendPort data:data + wait:wait]; +#endif +} + +#if MM_USE_DO +- (oneway void)processCommandQueue:(in NSArray *)queue +{ + unsigned i, count = [queue count]; + if (count % 2) { + NSLog(@"WARNING: Uneven number of components (%d) in flush queue " + "message; ignoring this message.", count); + return; + } + + for (i = 0; i < count; i += 2) { + NSData *value = [queue objectAtIndex:i]; + NSData *data = [queue objectAtIndex:i+1]; + + [self handleMessage:*((int*)[value bytes]) data:data]; + } +} + +#else // MM_USE_DO + - (NSPort *)sendPort { return sendPort; @@ -138,6 +195,8 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) - (void)handlePortMessage:(NSPortMessage *)portMessage { + //NSLog(@"%@ %s %@", [self className], _cmd, portMessage); + NSArray *components = [portMessage components]; unsigned msgid = [portMessage msgid]; @@ -168,6 +227,7 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) if (shouldUpdateMainMenu) [self updateMainMenu]; } +#endif // MM_USE_DO - (void)windowWillClose:(NSNotification *)notification { @@ -216,6 +276,8 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) - (void)handleMessage:(int)msgid data:(NSData *)data { + //NSLog(@"%@ %s", [self className], _cmd); + if (OpenVimWindowMsgID == msgid) { const void *bytes = [data bytes]; int rows = *((int*)bytes); bytes += sizeof(int); @@ -225,7 +287,9 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) // cols, rows); [windowController openWindowWithRows:rows columns:cols]; - } else if (TaskExitedMsgID == msgid) { + } +#if !MM_USE_DO + else if (TaskExitedMsgID == msgid) { //NSLog(@"Received task exited message from VimTask; closing window."); // Release sendPort immediately to avoid dealloc trying to send a 'kill @@ -237,7 +301,9 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) // HACK! Make sure no menu updating is done, we're about to close. shouldUpdateMainMenu = NO; - } else if (BatchDrawMsgID == msgid) { + } +#endif // !MM_USE_DO + else if (BatchDrawMsgID == msgid) { //NSLog(@"Received batch draw message from VimTask."); [self performBatchDrawWithData:data]; @@ -673,6 +739,7 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) - (void)panelDidEnd:(NSSavePanel *)panel code:(int)code context:(void *)context { +#if !MM_USE_DO NSMutableData *data = [NSMutableData data]; int ok = (code == NSOKButton); NSString *filename = [panel filename]; @@ -690,6 +757,7 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) } [windowController setStatusText:@""]; +#endif // !MM_USE_DO } - (NSMenuItem *)menuItemForTag:(int)tag @@ -801,6 +869,15 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) [item release]; } +#if MM_USE_DO +- (void)connectionDidDie:(NSNotification *)notification +{ + //NSLog(@"A MMVimController lost its connection to the backend; " + // "closing the controller."); + [windowController close]; +} +#endif // MM_USE_DO + @end // MMVimController (Private) diff --git a/MMWindowController.h b/MMWindowController.h index 8afa6df892..fbe82d2803 100644 --- a/MMWindowController.h +++ b/MMWindowController.h @@ -13,6 +13,7 @@ @class PSMTabBarControl; @class MMTextView; @class MMTextStorage; +@class MMVimController; @interface MMWindowController : NSWindowController @@ -20,7 +21,8 @@ IBOutlet PSMTabBarControl *tabBarControl; IBOutlet NSTabView *tabView; IBOutlet NSTextField *statusTextField; - NSPort *sendPort; + + MMVimController *vimController; BOOL vimTaskSelectedTab; NSTimer *statusTimer; MMTextView *textView; @@ -29,7 +31,8 @@ BOOL setupDone; } -- (id)initWithPort:(NSPort *)port; +- (id)initWithVimController:(MMVimController *)controller; +- (MMVimController *)vimController; - (MMTextView *)textView; - (MMTextStorage *)textStorage; - (void)openWindowWithRows:(int)rows columns:(int)cols; diff --git a/MMWindowController.m b/MMWindowController.m index fa85832de9..fdfdc23fd4 100644 --- a/MMWindowController.m +++ b/MMWindowController.m @@ -12,6 +12,7 @@ #import #import "MMTextView.h" #import "MMTextStorage.h" +#import "MMVimController.h" #import "MacVim.h" @@ -93,10 +94,10 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) @implementation MMWindowController -- (id)initWithPort:(NSPort *)port +- (id)initWithVimController:(MMVimController *)controller { if ((self = [super initWithWindowNibName:@"VimWindow"])) { - sendPort = [port retain]; + vimController = controller; scrollbars = [[NSMutableArray alloc] init]; textStorage = [[MMTextStorage alloc] init]; } @@ -106,8 +107,12 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) - (void)dealloc { + //NSLog(@"%@ %s", [self className], _cmd); + // TODO: release tabBarControl and tabView? + vimController = nil; + [tabBarControl setDelegate:nil]; [[self window] setDelegate:nil]; @@ -116,11 +121,15 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) [scrollbars release]; [textView release]; [textStorage release]; - [sendPort release]; [super dealloc]; } +- (MMVimController *)vimController +{ + return vimController; +} + - (void)windowDidLoad { // Called after window nib file is loaded. @@ -223,39 +232,6 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) - (void)openWindowWithRows:(int)rows columns:(int)cols { -#if 0 - // Make sure window nib file is loaded. - [self window]; - - // Set up text system - textStorage = [[MMTextStorage alloc] init]; - NSLayoutManager *lm = [[NSLayoutManager alloc] init]; - NSTextContainer *tc = [[NSTextContainer alloc] initWithContainerSize: - NSMakeSize(1.0e7,1.0e7)]; - - [tc setWidthTracksTextView:NO]; - [tc setHeightTracksTextView:NO]; - [tc setLineFragmentPadding:0]; - - [textStorage setMaxRows:rows columns:cols]; - [textStorage addLayoutManager:lm]; - [lm addTextContainer:tc]; - //[[lm typesetter] setUsesFontLeading:NO]; - - textView = [[MMTextView alloc] initWithPort:sendPort frame:[tabView frame] - textContainer:tc]; - [[self window] makeFirstResponder:textView]; - - // Keep track of when the layout has changed. - [[textView layoutManager] setDelegate:self]; - - // The text storage retains the layout manager which in turn retains the - // text container. - [tc release]; - [lm release]; - - [self addNewTabViewItem]; -#else // Setup a complete text system. NSLayoutManager *lm = [[NSLayoutManager alloc] init]; NSTextContainer *tc = [[NSTextContainer alloc] initWithContainerSize: @@ -269,8 +245,8 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) [textStorage addLayoutManager:lm]; [lm addTextContainer:tc]; - textView = [[MMTextView alloc] initWithPort:sendPort frame:[tabView frame] - textContainer:tc]; + textView = [[MMTextView alloc] initWithFrame:[tabView frame] + textContainer:tc]; [[self window] makeFirstResponder:textView]; @@ -283,7 +259,6 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) [lm release]; [self addNewTabViewItem]; -#endif // NOTE! This flag is set once the entire text system is set up. setupDone = YES; @@ -409,7 +384,7 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) - (IBAction)addNewTab:(id)sender { - [NSPortMessage sendMessage:AddNewTabMsgID withSendPort:sendPort wait:NO]; + [vimController sendMessage:AddNewTabMsgID data:nil wait:NO]; } - (IBAction)showTabBar:(id)sender @@ -446,8 +421,7 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) // Propagate the selection message to the VimTask. int idx = [self representedIndexOfTabViewItem:tabViewItem]; NSData *data = [NSData dataWithBytes:&idx length:sizeof(int)]; - [NSPortMessage sendMessage:SelectTabMsgID withSendPort:sendPort - data:data wait:YES]; + [vimController sendMessage:SelectTabMsgID data:data wait:YES]; } } @@ -460,8 +434,7 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) int idx = [self representedIndexOfTabViewItem:tabViewItem]; //NSLog(@"Closing tab with index %d", idx); NSData *data = [NSData dataWithBytes:&idx length:sizeof(int)]; - [NSPortMessage sendMessage:CloseTabMsgID withSendPort:sendPort - data:data wait:YES]; + [vimController sendMessage:CloseTabMsgID data:data wait:YES]; return NO; } @@ -472,8 +445,7 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) NSMutableData *data = [NSMutableData data]; [data appendBytes:&idx length:sizeof(int)]; - [NSPortMessage sendMessage:DraggedTabMsgID withSendPort:sendPort - data:data wait:YES]; + [vimController sendMessage:DraggedTabMsgID data:data wait:YES]; } @@ -524,11 +496,24 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) // -- NSWindow delegate ------------------------------------------------------ -#if 0 -- (void)windowWillClose:(NSNotification *)notification +- (BOOL)windowShouldClose:(id)sender { + [vimController sendMessage:VimShouldCloseMsgID data:nil wait:YES]; + return NO; } +- (void)windowWillClose:(NSNotification *)notification +{ + //NSLog(@"%@ %s", [self className], _cmd); + + // NOTE! There is a bug in PSMTabBarControl in that it retains the delegate + // (which is the MMWindowController) so reset the delegate here, otherwise + // the MMWindowController never gets released resulting in a pretty serious + // memory leak. + [tabBarControl setDelegate:nil]; +} + +#if 0 - (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)proposedFrameSize { //NSLog(@"%s (%.2f,%.2f)", _cmd, proposedFrameSize.width, @@ -725,8 +710,7 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) NSMutableData *data = [NSMutableData data]; [data appendBytes:&tag length:sizeof(int)]; - [NSPortMessage sendMessage:ExecuteMenuMsgID withSendPort:sendPort - data:data wait:NO]; + [vimController sendMessage:ExecuteMenuMsgID data:data wait:NO]; } - (MMScroller *)scrollbarForIdentifier:(long)ident index:(unsigned *)idx @@ -871,8 +855,7 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) [data appendBytes:&hitPart length:sizeof(int)]; [data appendBytes:&value length:sizeof(float)]; - [NSPortMessage sendMessage:ScrollbarEventMsgID withSendPort:sendPort - data:data wait:YES]; + [vimController sendMessage:ScrollbarEventMsgID data:data wait:YES]; } - (void)fitWindowToScrollbars:(id)sender @@ -902,10 +885,8 @@ NSMutableArray *buildMenuAddress(NSMenu *menu) //NSLog(@"Notify Vim that text storage dimensions changed to %dx%d", // dim[0], dim[1]); NSData *data = [NSData dataWithBytes:dim length:2*sizeof(int)]; - [NSPortMessage sendMessage:SetTextDimensionsMsgID - withSendPort:sendPort - data:data - wait:![textView inLiveResize]]; + [vimController sendMessage:SetTextDimensionsMsgID data:data + wait:![textView inLiveResize]]; } [tabView setFrame:textViewRect]; diff --git a/MacVim.h b/MacVim.h index cd28046690..2945850216 100644 --- a/MacVim.h +++ b/MacVim.h @@ -11,6 +11,30 @@ #import +#define MM_USE_DO 1 + + + +#if MM_USE_DO + +@protocol MMBackendProtocol +- (oneway void)processInput:(int)msgid data:(in NSData *)data; +- (BOOL)checkForModifiedBuffers; +@end + +@protocol MMFrontendProtocol +- (oneway void)processCommandQueue:(in NSArray *)queue; +@end + +@protocol MMAppProtocol +- (byref id )connectBackend: + (byref in id )backend; +@end + +#endif + + + enum { CheckinMsgID = 1, ConnectedMsgID, @@ -44,9 +68,11 @@ enum { EnableMenuItemMsgID, ExecuteMenuMsgID, ShowToolbarMsgID, +#if !MM_USE_DO TaskShouldTerminateMsgID, TerminateReplyYesMsgID, TerminateReplyNoMsgID, +#endif CreateScrollbarMsgID, DestroyScrollbarMsgID, ShowScrollbarMsgID, @@ -54,6 +80,7 @@ enum { SetScrollbarThumbMsgID, ScrollbarEventMsgID, SetFontMsgID, + VimShouldCloseMsgID, };