Permalink
Browse files

- Added support for Distributed Objects, as an alternative to NSPortM…

…essage for communicating between processes (MM_USE_DO=0 to disable in MacVim.h) - MMWindowController, MMTextView does not communicate directly with backend anymore, instead they have to go through MMVimController sendMessage:data:wait:. - If window is closed by clicking the red button, Vim now displays a message if a buffer has been modified.

git-svn-id: http://macvim.googlecode.com/svn/trunk@20 96c4425d-ca35-0410-94e5-3396d5c13a8f
  • Loading branch information...
1 parent 0f60f1a commit 2bb270f60c4d565203bc916b67b3b613312f31f9 @b4winckler committed Jul 28, 2007
Showing with 477 additions and 227 deletions.
  1. +6 −1 MMAppController.h
  2. +70 −1 MMAppController.m
  3. +12 −2 MMBackend.h
  4. +181 −59 MMBackend.m
  5. +2 −0 MMTextStorage.m
  6. +0 −6 MMTextView.h
  7. +21 −76 MMTextView.m
  8. +17 −2 MMVimController.h
  9. +100 −23 MMVimController.m
  10. +5 −2 MMWindowController.h
  11. +36 −55 MMWindowController.m
  12. +27 −0 MacVim.h
View
7 MMAppController.h
@@ -9,10 +9,15 @@
*/
#import <Cocoa/Cocoa.h>
+#import "MacVim.h"
-@interface MMAppController : NSObject {
+@interface MMAppController : NSObject
+#if MM_USE_DO
+ <MMAppProtocol>
+#endif
+{
NSPort *receivePort;
NSMutableArray *vimControllers;
unsigned terminateNowCount;
View
71 MMAppController.m
@@ -10,7 +10,6 @@
#import "MMAppController.h"
#import "MMVimController.h"
-#import "MacVim.h"
@@ -21,6 +20,20 @@ - (id)init
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 @@ - (id)init
name:portName]) {
NSLog(@"WARNING: Failed to start mach bootstrap server");
}
+#endif
}
return self;
@@ -46,7 +60,9 @@ - (void)dealloc
{
//NSLog(@"MMAppController dealloc");
+#if !MM_USE_DO
[receivePort release];
+#endif
[vimControllers release];
[super dealloc];
@@ -86,6 +102,38 @@ - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
- (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 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:
}
return reply;
+#endif
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
@@ -145,6 +194,7 @@ - (void)applicationWillTerminate:(NSNotification *)aNotification
[self autorelease];
}
+#if !MM_USE_DO
- (void)handlePortMessage:(NSPortMessage *)portMessage
{
unsigned msgid = [portMessage msgid];
@@ -163,6 +213,7 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
NSLog(@"WARNING: Unknown message received (msgid=%d)", msgid);
}
}
+#endif
- (void)removeVimController:(id)controller
{
@@ -179,4 +230,22 @@ - (IBAction)newVimWindow:(id)sender
[NSTask launchedTaskWithLaunchPath:path arguments:args];
}
+#if MM_USE_DO
+- (byref id <MMFrontendProtocol>)connectBackend:
+ (byref in id <MMBackendProtocol>)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
View
14 MMBackend.h
@@ -9,15 +9,25 @@
*/
#import <Foundation/Foundation.h>
+#import "MacVim.h"
-@interface MMBackend : NSObject {
+@interface MMBackend : NSObject
+#if MM_USE_DO
+ <MMBackendProtocol>
+#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;
View
240 MMBackend.m
@@ -9,7 +9,6 @@
*/
#import "MMBackend.h"
-#import "MacVim.h"
#import "vim.h"
@@ -21,9 +20,13 @@
@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 @@ - (id)init
- (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,14 +88,24 @@ - (void)setDefaultColorsBackground:(int)bg foreground:(int)fg
- (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",
[[NSBundle mainBundle] bundleIdentifier]];
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 @@ - (BOOL)checkin
// 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 @@ - (BOOL)checkin
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 @@ - (BOOL)openVimWindowWithRows:(int)rows columns:(int)cols
}
#endif
}
+#endif // !MM_USE_DO
NSMutableData *data = [NSMutableData data];
@@ -276,19 +331,25 @@ - (void)flushQueue
// 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 @@ - (BOOL)waitForInput:(int)milliseconds
- (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 @@ - (void)setVimWindowTitle:(char *)title
- (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 @@ - (char *)browseForFileInDirectory:(char *)dir title:(char *)title
[replyData release]; replyData = nil;
return (char*)s;
+#endif // MM_USE_DO
}
- (void)updateInsertionPoint
@@ -665,33 +738,85 @@ - (int)lookupColorWithKey:(NSString *)key
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];
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]);
[key release];
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 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
[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 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
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 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
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 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
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 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
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 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
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 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
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 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
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 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
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 @@ - (void)queueMessage:(int)msgid data:(NSData *)data
[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)
View
2 MMTextStorage.m
@@ -54,6 +54,8 @@ - (id)init
- (void)dealloc
{
+ //NSLog(@"%@ %s", [self className], _cmd);
+
[emptyRowString release];
//[paragraphStyle release];
[font release];
View
6 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
View
97 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 @@ - (void)insertText:(id)string
[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 @@ - (BOOL)performKeyEquivalent:(NSEvent *)event
[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 @@ - (void)scrollWheel:(NSEvent *)event
[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 @@ - (void)mouseDown:(NSEvent *)event
[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 @@ - (void)mouseUp:(NSEvent *)event
[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 @@ - (void)mouseDragged:(NSEvent *)event
[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 @@ - (void)dispatchKeyEvent:(NSEvent *)event
[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)
View
19 MMVimController.h
@@ -9,25 +9,40 @@
*/
#import <Cocoa/Cocoa.h>
+#import "MacVim.h"
@class MMWindowController;
-@interface MMVimController : NSObject {
+@interface MMVimController : NSObject
+#if MM_USE_DO
+ <MMFrontendProtocol>
+#endif
+{
MMWindowController *windowController;
+#if MM_USE_DO
+ id backendProxy;
+#else
NSPort *sendPort;
NSPort *receivePort;
+#endif
NSMutableArray *mainMenuItems;
BOOL shouldUpdateMainMenu;
//NSMutableArray *popupMenus;
NSToolbar *toolbar;
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
View
123 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 @@ - (NSToolbarItem *)toolbarItemForTag:(int)tag index:(int *)index;
- (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 @@ + (NSColor *)colorWithRgbInt:(int)rgb;
@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,54 +120,83 @@ - (id)initWithPort:(NSPort *)port
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;
}
- (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;
}
- (void)handlePortMessage:(NSPortMessage *)portMessage
{
+ //NSLog(@"%@ %s %@", [self className], _cmd, portMessage);
+
NSArray *components = [portMessage components];
unsigned msgid = [portMessage msgid];
@@ -168,6 +227,7 @@ - (void)handlePortMessage:(NSPortMessage *)portMessage
if (shouldUpdateMainMenu)
[self updateMainMenu];
}
+#endif // MM_USE_DO
- (void)windowWillClose:(NSNotification *)notification
{
@@ -216,6 +276,8 @@ @implementation MMVimController (Private)
- (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 @@ - (void)handleMessage:(int)msgid data:(NSData *)data
// 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 @@ - (void)handleMessage:(int)msgid data:(NSData *)data
// 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 @@ - (void)performBatchDrawWithData:(NSData *)data
- (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 @@ - (void)panelDidEnd:(NSSavePanel *)panel code:(int)code context:(void *)context
}
[windowController setStatusText:@""];
+#endif // !MM_USE_DO
}
- (NSMenuItem *)menuItemForTag:(int)tag
@@ -801,6 +869,15 @@ - (void)addToolbarItemToDictionaryWithTag:(int)tag label:(NSString *)title
[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)
View
7 MMWindowController.h
@@ -13,14 +13,16 @@
@class PSMTabBarControl;
@class MMTextView;
@class MMTextStorage;
+@class MMVimController;
@interface MMWindowController : NSWindowController
{
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;
View
91 MMWindowController.m
@@ -12,6 +12,7 @@
#import <PSMTabBarControl.h>
#import "MMTextView.h"
#import "MMTextStorage.h"
+#import "MMVimController.h"
#import "MacVim.h"
@@ -93,10 +94,10 @@ - (void)placeViews;
@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 @@ - (id)initWithPort:(NSPort *)port
- (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 @@ - (void)dealloc
[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 @@ - (MMTextStorage *)textStorage
- (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 @@ - (void)openWindowWithRows:(int)rows columns:(int)cols
[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 @@ - (void)openWindowWithRows:(int)rows columns:(int)cols
[lm release];
[self addNewTabViewItem];
-#endif
// NOTE! This flag is set once the entire text system is set up.
setupDone = YES;
@@ -409,7 +384,7 @@ - (void)flashStatusText:(NSString *)text
- (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 @@ - (void)tabView:(NSTabView *)theTabView didSelectTabViewItem:
// 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 @@ - (BOOL)tabView:(NSTabView *)theTabView shouldCloseTabViewItem:
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 @@ - (void)tabView:(NSTabView *)theTabView didDragTabViewItem:
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 @@ - (void)layoutManager:(NSLayoutManager *)aLayoutManager
// -- NSWindow delegate ------------------------------------------------------
-#if 0
+- (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 @@ - (IBAction)vimMenuItemAction:(id)sender
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 @@ - (void)scroll:(id)sender
[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 @@ - (void)placeViews
//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];
View
27 MacVim.h
@@ -11,6 +11,30 @@
#import <Cocoa/Cocoa.h>
+#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 <MMFrontendProtocol>)connectBackend:
+ (byref in id <MMBackendProtocol>)backend;
+@end
+
+#endif
+
+
+
enum {
CheckinMsgID = 1,
ConnectedMsgID,
@@ -44,16 +68,19 @@ enum {
EnableMenuItemMsgID,
ExecuteMenuMsgID,
ShowToolbarMsgID,
+#if !MM_USE_DO
TaskShouldTerminateMsgID,
TerminateReplyYesMsgID,
TerminateReplyNoMsgID,
+#endif
CreateScrollbarMsgID,
DestroyScrollbarMsgID,
ShowScrollbarMsgID,
SetScrollbarPositionMsgID,
SetScrollbarThumbMsgID,
ScrollbarEventMsgID,
SetFontMsgID,
+ VimShouldCloseMsgID,
};

0 comments on commit 2bb270f

Please sign in to comment.