- Added support for Distributed Objects, as an alternative to NSPortMessage 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
This commit is contained in:
Bjorn Winckler
2007-07-28 20:19:20 +00:00
parent 0f60f1a416
commit 2bb270f60c
12 changed files with 478 additions and 228 deletions
+6 -1
View File
@@ -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;
+70 -1
View File
@@ -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 <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
+12 -2
View File
@@ -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;
+181 -59
View File
@@ -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)
+2
View File
@@ -54,6 +54,8 @@
- (void)dealloc
{
//NSLog(@"%@ %s", [self className], _cmd);
[emptyRowString release];
//[paragraphStyle release];
[font release];
-6
View File
@@ -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
+21 -76
View File
@@ -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)
+17 -2
View File
@@ -9,15 +9,24 @@
*/
#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;
@@ -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
+100 -23
View File
@@ -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)
+5 -2
View File
@@ -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;
+37 -56
View File
@@ -12,6 +12,7 @@
#import <PSMTabBarControl.h>
#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];
+27
View File
@@ -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,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,
};