Dialog box handling updated

Keep waiting for dialog reply until it is received.  Any input received
during this wait is discarded unless it is a 'set text dimensions'
message (or keyboard/mouse input).  Also, make setDialogReturn: a
synchronous call so that it is less likely to get dropped.
This commit is contained in:
Bjorn Winckler
2008-06-09 21:34:54 +02:00
parent 04cd1420c1
commit 404077032e
3 changed files with 69 additions and 8 deletions
+54 -7
View File
@@ -80,6 +80,7 @@ static NSString *MMSymlinkWarningString =
@interface MMBackend (Private)
- (void)waitForDialogReturn;
- (void)queueVimStateMessage;
- (void)processInputQueue;
- (void)handleInputEvent:(int)msgid data:(NSData *)data;
@@ -640,9 +641,7 @@ static NSString *MMSymlinkWarningString =
@try {
[frontendProxy showSavePanelForDirectory:ds title:ts saving:saving];
// Wait until a reply is sent from MMVimController.
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
[self waitForDialogReturn];
if (dialogReturn && [dialogReturn isKindOfClass:[NSString class]]) {
char_u *ret = (char_u*)[dialogReturn UTF8String];
@@ -664,13 +663,18 @@ static NSString *MMSymlinkWarningString =
return (char *)s;
}
- (oneway void)setDialogReturn:(in bycopy id)obj
- (void)setDialogReturn:(in bycopy id)obj
{
// NOTE: This is called by
// - [MMVimController panelDidEnd:::], and
// - [MMVimController alertDidEnd:::],
// to indicate that a save/open panel or alert has finished.
// We want to distinguish between "no dialog return yet" and "dialog
// returned nothing". The former can be tested with dialogReturn == nil,
// the latter with dialogReturn == [NSNull null].
if (!obj) obj = [NSNull null];
if (obj != dialogReturn) {
[dialogReturn release];
dialogReturn = [obj retain];
@@ -719,9 +723,7 @@ static NSString *MMSymlinkWarningString =
informativeText:text buttonTitles:buttons
textFieldString:textFieldString];
// Wait until a reply is sent from MMVimController.
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
[self waitForDialogReturn];
if (dialogReturn && [dialogReturn isKindOfClass:[NSArray class]]
&& [dialogReturn count]) {
@@ -1475,6 +1477,49 @@ static NSString *MMSymlinkWarningString =
@implementation MMBackend (Private)
- (void)waitForDialogReturn
{
// Keep processing the run loop until a dialog returns. To avoid getting
// stuck in an endless loop (could happen if the setDialogReturn: message
// was lost) we also do some paranoia checks.
//
// Note that in Cocoa the user can still resize windows and select menu
// items while a sheet is being displayed, so we can't just wait for the
// first message to arrive and assume that is the setDialogReturn: call.
while (nil == dialogReturn && !got_int && [connection isValid]
&& !isTerminating)
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
// Search for any resize messages on the input queue. All other messages
// on the input queue are dropped. The reason why we single out resize
// messages is because the user may have resized the window while a sheet
// was open.
int i, count = [inputQueue count];
if (count > 0) {
id textDimData = nil;
if (count%2 == 0) {
for (i = count-2; i >= 0; i -= 2) {
int msgid = [[inputQueue objectAtIndex:i] intValue];
if (SetTextDimensionsMsgID == msgid) {
textDimData = [[inputQueue objectAtIndex:i+1] retain];
break;
}
}
}
[inputQueue removeAllObjects];
if (textDimData) {
[inputQueue addObject:
[NSNumber numberWithInt:SetTextDimensionsMsgID]];
[inputQueue addObject:textDimData];
[textDimData release];
}
}
}
- (void)queueVimStateMessage
{
// NOTE: This is the place to add Vim state that needs to be accessed from
@@ -1494,6 +1539,8 @@ static NSString *MMSymlinkWarningString =
- (void)processInputQueue
{
if ([inputQueue count] == 0) return;
// NOTE: One of the input events may cause this method to be called
// recursively, so copy the input queue to a local variable and clear it
// before starting to process input events (otherwise we could get stuck in
+14
View File
@@ -47,6 +47,8 @@ static NSTimeInterval MMBackendProxyRequestTimeout = 0;
static NSTimeInterval MMResendInterval = 0.5;
#endif
static NSTimeInterval MMSetDialogReturnTimeout = 1.0;
@interface MMAlert : NSAlert {
NSTextField *textField;
@@ -813,6 +815,15 @@ static NSTimeInterval MMResendInterval = 0.5;
context:(void *)context
{
NSString *path = (code == NSOKButton) ? [panel filename] : nil;
// NOTE! setDialogReturn: is a synchronous call so set a proper timeout to
// avoid waiting forever for it to finish. We make this a synchronous call
// so that we can be fairly certain that Vim doesn't think the dialog box
// is still showing when MacVim has in fact already dismissed it.
NSConnection *conn = [backendProxy connectionForProxy];
NSTimeInterval oldTimeout = [conn requestTimeout];
[conn setRequestTimeout:MMSetDialogReturnTimeout];
@try {
[backendProxy setDialogReturn:path];
@@ -825,6 +836,9 @@ static NSTimeInterval MMResendInterval = 0.5;
@catch (NSException *e) {
NSLog(@"Exception caught in %s %@", _cmd, e);
}
@finally {
[conn setRequestTimeout:oldTimeout];
}
}
- (void)alertDidEnd:(MMAlert *)alert code:(int)code context:(void *)context
+1 -1
View File
@@ -29,7 +29,7 @@
@protocol MMBackendProtocol
- (oneway void)processInput:(int)msgid data:(in bycopy NSData *)data;
- (oneway void)processInputAndData:(in bycopy NSArray *)messages;
- (oneway void)setDialogReturn:(in bycopy id)obj;
- (void)setDialogReturn:(in bycopy id)obj;
- (NSString *)evaluateExpression:(in bycopy NSString *)expr;
- (BOOL)starRegisterToPasteboard:(byref NSPasteboard *)pboard;
@end