- Request/reply timeout set on root connection object - Check for unresponsive Vim processes in applicationShouldTerminate: and present alert if any are detectd - Send SIGINT to all Vim processes in applicationWillTerminate: - Started adding support for 'enc' (set MM_ENABLE_CONV in MacVim.h) - Cmd-. sends SIGINT to Vim - Use @try/@catch for starRegisterToPasteboard: calls - Removed starRegisterFromPasteboard: message

git-svn-id: http://macvim.googlecode.com/svn/trunk@163 96c4425d-ca35-0410-94e5-3396d5c13a8f
This commit is contained in:
Bjorn Winckler
2007-08-19 14:47:17 +00:00
parent 12a4710db4
commit 3c50385282
6 changed files with 183 additions and 50 deletions
+65 -7
View File
@@ -14,6 +14,14 @@
// Default timeout intervals on all connections.
static NSTimeInterval MMRequestTimeout = 5;
static NSTimeInterval MMReplyTimeout = 5;
// Timeout used when the app should terminate.
static NSTimeInterval MMTerminateTimeout = 3;
@interface MMAppController (MMServices)
- (void)openSelection:(NSPasteboard *)pboard userData:(NSString *)userData
@@ -73,6 +81,8 @@
[[NSBundle mainBundle] bundleIdentifier]];
//NSLog(@"Registering connection with name '%@'", name);
if ([connection registerName:name]) {
[connection setRequestTimeout:MMRequestTimeout];
[connection setReplyTimeout:MMReplyTimeout];
[connection setRootObject:self];
// NOTE: When the user is resizing the window the AppKit puts the
@@ -188,24 +198,53 @@
{
int reply = NSTerminateNow;
BOOL modifiedBuffers = NO;
BOOL notResponding = NO;
// Go through vim controllers, checking for modified buffers. If a process
// is not responding then note this as well.
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;
NSConnection *connection = [proxy connectionForProxy];
if (connection) {
NSTimeInterval req = [connection requestTimeout];
NSTimeInterval rep = [connection replyTimeout];
[connection setRequestTimeout:MMTerminateTimeout];
[connection setReplyTimeout:MMTerminateTimeout];
@try {
if ([proxy checkForModifiedBuffers])
modifiedBuffers = YES;
}
@catch (NSException *e) {
NSLog(@"WARNING: Got exception while waiting for "
"checkForModifiedBuffers: \"%@\"", e);
notResponding = YES;
}
@finally {
[connection setRequestTimeout:req];
[connection setReplyTimeout:rep];
if (modifiedBuffers || notResponding)
break;
}
}
}
if (modifiedBuffers) {
if (modifiedBuffers || notResponding) {
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?"];
if (modifiedBuffers) {
[alert setMessageText:@"Quit without saving?"];
[alert setInformativeText:@"There are modified buffers, "
"if you quit now all changes will be lost. Quit anyway?"];
} else {
[alert setMessageText:@"Force Quit?"];
[alert setInformativeText:@"At least one Vim process is not "
"responding, if you quit now any changes you have made "
"will be lost. Quit anyway?"];
}
[alert setAlertStyle:NSWarningAlertStyle];
if ([alert runModal] != NSAlertFirstButtonReturn) {
@@ -220,6 +259,23 @@
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
// Send a SIGINT to all running Vim processes, so that they are sure to
// receive the connectionDidDie: notification (a process has to checking
// the run-loop for this to happen).
unsigned i, count = [vimControllers count];
for (i = 0; i < count; ++i) {
MMVimController *controller = [vimControllers objectAtIndex:i];
int pid = [controller pid];
if (pid > 0)
kill(pid, SIGINT);
id proxy = [controller backendProxy];
NSConnection *connection = [proxy connectionForProxy];
if (connection) {
[connection invalidate];
}
}
// NOTE! Is this a correct way of releasing the MMAppController?
[NSApp setDelegate:nil];
[self autorelease];
@@ -227,6 +283,8 @@
- (void)removeVimController:(id)controller
{
//NSLog(@"%s%@", _cmd, controller);
[[controller windowController] close];
[vimControllers removeObject:controller];
+16 -12
View File
@@ -810,15 +810,6 @@ static int specialKeyToNSKey(int key);
return NO;
}
- (BOOL)starRegisterFromPasteboard:(byref NSPasteboard *)pboard
{
if (curbuf && !curbuf->b_p_ro) {
return YES;
}
return NO;
}
@end // MMBackend
@@ -837,12 +828,21 @@ static int specialKeyToNSKey(int key);
if (!data) return;
NSString *key = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
char_u *chars = (char_u*)[key UTF8String];
char_u *str = (char_u*)[key UTF8String];
int i, len = [key lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
#if MM_ENABLE_CONV
char_u *conv_str = NULL;
if (input_conv.vc_type != CONV_NONE) {
conv_str = string_convert(&input_conv, str, &len);
if (conv_str)
str = conv_str;
}
#endif
for (i = 0; i < len; ++i) {
add_to_input_buf(chars+i, 1);
if (CSI == chars[i]) {
add_to_input_buf(str+i, 1);
if (CSI == str[i]) {
// NOTE: If the converted string contains the byte CSI, then it
// must be followed by the bytes KS_EXTRA, KE_CSI or things
// won't work.
@@ -851,6 +851,10 @@ static int specialKeyToNSKey(int key);
}
}
#if MM_ENABLE_CONV
if (conv_str)
vim_free(conv_str);
#endif
[key release];
} else if (KeyDownMsgID == msgid || CmdKeyMsgID == msgid) {
if (!data) return;
+13 -5
View File
@@ -118,16 +118,24 @@
//NSLog(@"%s%@", _cmd, event);
NSMutableData *data = [NSMutableData data];
NSString *string = [event charactersIgnoringModifiers];
int flags = [event modifierFlags];
int len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
[data appendBytes:&flags length:sizeof(int)];
[data appendBytes:&len length:sizeof(int)];
[data appendBytes:[string UTF8String] length:len];
if (len > 0 && [string characterAtIndex:0] == '.') {
// HACK! Intercept Cmd-. and send SIGINT to Vim.
int pid = [[self vimController] pid];
if (pid > 0)
kill(pid, SIGINT);
} else {
NSMutableData *data = [NSMutableData data];
[[self vimController] sendMessage:CmdKeyMsgID data:data wait:NO];
[data appendBytes:&flags length:sizeof(int)];
[data appendBytes:&len length:sizeof(int)];
[data appendBytes:[string UTF8String] length:len];
[[self vimController] sendMessage:CmdKeyMsgID data:data wait:NO];
}
return YES;
}
+17 -8
View File
@@ -662,13 +662,13 @@ NSMutableArray *buildMenuAddress(NSMenu *menu)
{
id backendProxy = [vimController backendProxy];
if ((!sendType || [sendType isEqual:NSStringPboardType])
&& (!returnType || [returnType isEqual:NSStringPboardType]))
{
if ((!sendType || [backendProxy starRegisterToPasteboard:nil]) &&
(!returnType || [backendProxy starRegisterFromPasteboard:nil]))
{
return self;
if (backendProxy && [sendType isEqual:NSStringPboardType]) {
@try {
if ([backendProxy starRegisterToPasteboard:nil])
return self;
}
@catch (NSException *e) {
NSLog(@"WARNING: Caught exception in %s: \"%@\"", _cmd, e);
}
}
@@ -682,7 +682,16 @@ NSMutableArray *buildMenuAddress(NSMenu *menu)
return NO;
id backendProxy = [vimController backendProxy];
return [backendProxy starRegisterToPasteboard:pboard];
if (backendProxy) {
@try {
return [backendProxy starRegisterToPasteboard:pboard];
}
@catch (NSException *e) {
NSLog(@"WARNING: Caught exception in %s: \"%@\"", _cmd, e);
}
}
return NO;
}
@end // MMWindowController
+11 -2
View File
@@ -11,20 +11,29 @@
#import <Cocoa/Cocoa.h>
// Enable to use experimental 'enc' support.
#define MM_ENABLE_CONV 0
//
// This is the protocol MMBackend implements.
//
// Only processInput:data: is allowed to cause state changes in Vim; all other
// messages should only read the Vim state.
// messages should only read the Vim state. (Note that setDialogReturn: is an
// exception to this rule; there really is no other way to deal with dialogs
// since they work with callbacks, so we cannot wait for them to return.)
//
// Be careful with messages with return type other than 'oneway void' -- there
// is a reply timeout set in MMAppController, if a message fails to get a
// response within the given timeout an exception will be thrown. Use
// @try/@catch/@finally to deal with timeouts.
//
@protocol MMBackendProtocol
- (oneway void)processInput:(int)msgid data:(in NSData *)data;
- (BOOL)checkForModifiedBuffers;
- (oneway void)setDialogReturn:(in bycopy id)obj;
- (BOOL)starRegisterToPasteboard:(byref NSPasteboard *)pboard;
- (BOOL)starRegisterFromPasteboard:(byref NSPasteboard *)pboard;
@end
+61 -16
View File
@@ -305,6 +305,15 @@ gui_macvim_draw_string(int row, int col, char_u *s, int len, int flags)
BOOL outPad = NO;
MMBackend *backend = [MMBackend sharedInstance];
static char ZeroWidthSpace[] = { 0xe2, 0x80, 0x8b };
#if MM_ENABLE_CONV
char_u *conv_str = NULL;
if (output_conv.vc_type != CONV_NONE) {
char_u *conv_str = string_convert(&output_conv, s, &len);
if (conv_str)
s = conv_str;
}
#endif
for (i = 0; i < len; i += cl) {
c = utf_ptr2char(s + i);
@@ -375,6 +384,11 @@ gui_macvim_draw_string(int row, int col, char_u *s, int len, int flags)
row:row column:endcol-1 flags:flags];
}
#if MM_ENABLE_CONV
if (conv_str)
vim_free(conv_str);
#endif
return endcol - col;
#else
// This will fail abysmally when wide or composing characters are used.
@@ -475,9 +489,9 @@ clip_mch_own_selection(VimClipboard *cbd)
clip_mch_request_selection(VimClipboard *cbd)
{
NSPasteboard *pb = [NSPasteboard generalPasteboard];
NSString *type = [pb availableTypeFromArray:
NSString *pbType = [pb availableTypeFromArray:
[NSArray arrayWithObject:NSStringPboardType]];
if (type) {
if (pbType) {
NSMutableString *string =
[[pb stringForType:NSStringPboardType] mutableCopy];
@@ -496,9 +510,24 @@ clip_mch_request_selection(VimClipboard *cbd)
int type = MCHAR;
if (0 < n || NSNotFound != [string rangeOfString:@"\n"].location)
type = MLINE;
const char *utf8chars = [string UTF8String];
clip_yank_selection(type, (char_u*)utf8chars, strlen(utf8chars), cbd);
char_u *str = (char_u*)[string UTF8String];
int len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
#if MM_ENABLE_CONV
if (input_conv.vc_type != CONV_NONE) {
NSLog(@"Converting from: '%@'", string);
char_u *conv_str = string_convert(&input_conv, str, &len);
if (conv_str) {
NSLog(@" to: '%s'", conv_str);
clip_yank_selection(type, conv_str, len, cbd);
vim_free(conv_str);
return;
}
}
#endif
clip_yank_selection(type, str, len, cbd);
}
}
@@ -515,19 +544,35 @@ clip_mch_set_selection(VimClipboard *cbd)
cbd->owned = FALSE;
// Get the text to put on the pasteboard.
long_u len = 0; char_u *str = 0;
int type = clip_convert_selection(&str, &len, cbd);
long_u llen = 0; char_u *str = 0;
int type = clip_convert_selection(&str, &llen, cbd);
if (type < 0)
return;
NSString *string = [[NSString alloc] initWithBytes:str length:len
encoding:NSUTF8StringEncoding];
NSPasteboard *pb = [NSPasteboard generalPasteboard];
[pb declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
[pb setString:string forType:NSStringPboardType];
[string release];
// TODO: Avoid overflow.
int len = (int)llen;
#if MM_ENABLE_CONV
if (output_conv.vc_type != CONV_NONE) {
char_u *conv_str = string_convert(&output_conv, str, &len);
if (conv_str) {
vim_free(str);
str = conv_str;
}
}
#endif
if (len > 0) {
NSString *string = [[NSString alloc]
initWithBytes:str length:len encoding:NSUTF8StringEncoding];
NSPasteboard *pb = [NSPasteboard generalPasteboard];
[pb declareTypes:[NSArray arrayWithObject:NSStringPboardType]
owner:nil];
[pb setString:string forType:NSStringPboardType];
[string release];
}
vim_free(str);
}