From 9a1f06bd2328561b0ca0a59840470b3f50ec8a47 Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Wed, 3 Apr 2013 01:00:57 +0000 Subject: - Move the SPBeginWaitingAlertSheet function to a beginWaitingAlertSheetWithTitle:... class method on a new SPAlertSheets class, allowing us to use invocation forwarding to ensure the entire function is executing on the main thread. This allows runloop processing to happen on the main thread, addressing Issue #1676 --- Source/SPAlertSheets.h | 34 ++++----- Source/SPAlertSheets.m | 148 +++++++++++++++++++++++----------------- Source/SPCustomQuery.m | 22 +++--- Source/SPDatabaseDocument.m | 21 +++--- Source/SPEditorPreferencePane.m | 25 ++++--- 5 files changed, 139 insertions(+), 111 deletions(-) diff --git a/Source/SPAlertSheets.h b/Source/SPAlertSheets.h index ab6f1812..51f5bb32 100644 --- a/Source/SPAlertSheets.h +++ b/Source/SPAlertSheets.h @@ -30,6 +30,23 @@ // // More info at +@interface SPAlertSheets : NSObject + ++ (void)beginWaitingAlertSheetWithTitle:(NSString *)title + defaultButton:(NSString *)defaultButton + alternateButton:(NSString *)alternateButton + otherButton:(NSString *)otherButton + alertStyle:(NSAlertStyle)alertStyle + docWindow:(NSWindow *)docWindow + modalDelegate:(id)modalDelegate + didEndSelector:(SEL)didEndSelector + contextInfo:(void *)contextInfo + msg:(NSString *)msg + infoText:(NSString *)infoText + returnCode:(NSInteger *)returnCode; + +@end + void SPBeginAlertSheet( NSString *title, NSString *defaultButton, @@ -40,19 +57,4 @@ void SPBeginAlertSheet( SEL didEndSelector, void *contextInfo, NSString *msg -); - -void SPBeginWaitingAlertSheet( - NSString *title, - NSString *defaultButton, - NSString *alternateButton, - NSString *otherButton, -NSAlertStyle alertStyle, - NSWindow *docWindow, - id modalDelegate, - SEL didEndSelector, - void *contextInfo, - NSString *msg, - NSString *infoText, - NSInteger *returnCode -); +); \ No newline at end of file diff --git a/Source/SPAlertSheets.m b/Source/SPAlertSheets.m index fe45741e..f30e6d33 100644 --- a/Source/SPAlertSheets.m +++ b/Source/SPAlertSheets.m @@ -31,54 +31,9 @@ // More info at #import "SPAlertSheets.h" +#import "SPMainThreadTrampoline.h" -/** - * Provide a simple alias of NSBeginAlertSheet, with a few differences: - * - printf-type format strings are no longer supported within the "msg" - * message text argument, preventing access of random stack areas for - * error text which contains inadvertant printf formatting. - * - The didDismissSelector is no longer supported - * - The sheet no longer needs to be orderOut:ed after use - * - The alert is always shown on the main thread. - */ -void SPBeginAlertSheet( - NSString *title, - NSString *defaultButton, - NSString *alternateButton, - NSString *otherButton, - NSWindow *docWindow, - id modalDelegate, - SEL didEndSelector, - void *contextInfo, - NSString *msg) -{ - NSButton *aButton; - - // Set up an NSAlert with the supplied details - NSAlert *alert = [[[NSAlert alloc] init] autorelease]; - [alert setMessageText:title]; - aButton = [alert addButtonWithTitle:defaultButton]; - [aButton setTag:NSAlertDefaultReturn]; - - // Add 'alternate' and 'other' buttons as appropriate - if (alternateButton) { - aButton = [alert addButtonWithTitle:alternateButton]; - [aButton setTag:NSAlertAlternateReturn]; - } - if (otherButton) { - aButton = [alert addButtonWithTitle:otherButton]; - [aButton setTag:NSAlertOtherReturn]; - } - - // Set the informative message if supplied - if (msg) [alert setInformativeText:msg]; - - // Run the alert on the main thread - [[alert onMainThread] beginSheetModalForWindow:docWindow modalDelegate:modalDelegate didEndSelector:didEndSelector contextInfo:contextInfo]; - - // Ensure the alerting window is frontmost - [[docWindow onMainThread] makeKeyWindow]; -} +@implementation SPAlertSheets /** * Provide a simple alias of a NSApp-wide modal NSBeginAlertSheet which waits @@ -91,21 +46,36 @@ void SPBeginAlertSheet( * - The sheet no longer needs to be orderOut:ed after use * - The alert is always shown on the main thread. */ -void SPBeginWaitingAlertSheet( - NSString *title, - NSString *defaultButton, - NSString *alternateButton, - NSString *otherButton, - NSAlertStyle alertStyle, - NSWindow *docWindow, - id modalDelegate, - SEL didEndSelector, - void *contextInfo, - NSString *msg, - NSString *infoText, - NSInteger *returnCode) ++ (void)beginWaitingAlertSheetWithTitle:(NSString *)title + defaultButton:(NSString *)defaultButton + alternateButton:(NSString *)alternateButton + otherButton:(NSString *)otherButton + alertStyle:(NSAlertStyle)alertStyle + docWindow:(NSWindow *)docWindow + modalDelegate:(id)modalDelegate + didEndSelector:(SEL)didEndSelector + contextInfo:(void *)contextInfo + msg:(NSString *)msg + infoText:(NSString *)infoText + returnCode:(NSInteger *)returnCode { + // Ensure execution on the main thread + if (![[NSThread currentThread] isMainThread]) { + return [[self onMainThread] beginWaitingAlertSheetWithTitle:title + defaultButton:defaultButton + alternateButton:alternateButton + otherButton:otherButton + alertStyle:alertStyle + docWindow:docWindow + modalDelegate:modalDelegate + didEndSelector:didEndSelector + contextInfo:contextInfo + msg:msg + infoText:infoText + returnCode:returnCode]; + } + NSButton *aButton; // Initialize returnCode with a value which can't be returned as @@ -142,10 +112,10 @@ void SPBeginWaitingAlertSheet( if (msg) [alert setMessageText:msg]; // Run the alert on the main thread - [[alert onMainThread] beginSheetModalForWindow:docWindow modalDelegate:modalDelegate didEndSelector:didEndSelector contextInfo:contextInfo]; + [alert beginSheetModalForWindow:docWindow modalDelegate:modalDelegate didEndSelector:didEndSelector contextInfo:contextInfo]; // wait for the sheet - NSModalSession session = [[NSApp onMainThread] beginModalSessionForWindow:[alert window]]; + NSModalSession session = [NSApp beginModalSessionForWindow:[alert window]]; for (;;) { // Since the returnCode can only be -1, 0, or 1 @@ -169,6 +139,56 @@ void SPBeginWaitingAlertSheet( } - [[NSApp onMainThread] endModalSession:session]; - [[NSApp onMainThread] endSheet:[alert window]]; + [NSApp endModalSession:session]; + [NSApp endSheet:[alert window]]; +} + +@end + +/** + * Provide a simple alias of NSBeginAlertSheet, with a few differences: + * - printf-type format strings are no longer supported within the "msg" + * message text argument, preventing access of random stack areas for + * error text which contains inadvertant printf formatting. + * - The didDismissSelector is no longer supported + * - The sheet no longer needs to be orderOut:ed after use + * - The alert is always shown on the main thread. + */ +void SPBeginAlertSheet( + NSString *title, + NSString *defaultButton, + NSString *alternateButton, + NSString *otherButton, + NSWindow *docWindow, + id modalDelegate, + SEL didEndSelector, + void *contextInfo, + NSString *msg) +{ + NSButton *aButton; + + // Set up an NSAlert with the supplied details + NSAlert *alert = [[[NSAlert alloc] init] autorelease]; + [alert setMessageText:title]; + aButton = [alert addButtonWithTitle:defaultButton]; + [aButton setTag:NSAlertDefaultReturn]; + + // Add 'alternate' and 'other' buttons as appropriate + if (alternateButton) { + aButton = [alert addButtonWithTitle:alternateButton]; + [aButton setTag:NSAlertAlternateReturn]; + } + if (otherButton) { + aButton = [alert addButtonWithTitle:otherButton]; + [aButton setTag:NSAlertOtherReturn]; + } + + // Set the informative message if supplied + if (msg) [alert setInformativeText:msg]; + + // Run the alert on the main thread + [[alert onMainThread] beginSheetModalForWindow:docWindow modalDelegate:modalDelegate didEndSelector:didEndSelector contextInfo:contextInfo]; + + // Ensure the alerting window is frontmost + [[docWindow onMainThread] makeKeyWindow]; } diff --git a/Source/SPCustomQuery.m b/Source/SPCustomQuery.m index 43bb425a..f89b095c 100644 --- a/Source/SPCustomQuery.m +++ b/Source/SPCustomQuery.m @@ -733,15 +733,19 @@ if (![mySQLConnection lastQueryWasCancelled]) { [tableDocumentInstance setTaskIndicatorShouldAnimate:NO]; - SPBeginWaitingAlertSheet(@"title", - NSLocalizedString(@"Run All", @"run all button"), NSLocalizedString(@"Continue", @"continue button"), NSLocalizedString(@"Stop", @"stop button"), - NSWarningAlertStyle, [tableDocumentInstance parentWindow], self, - @selector(sheetDidEnd:returnCode:contextInfo:), - @"runAllContinueStopSheet", - NSLocalizedString(@"MySQL Error", @"mysql error message"), - [mySQLConnection lastErrorMessage], - &runAllContinueStopSheetReturnCode - ); + [SPAlertSheets beginWaitingAlertSheetWithTitle:@"title" + defaultButton:NSLocalizedString(@"Run All", @"run all button") + alternateButton:NSLocalizedString(@"Continue", @"continue button") + otherButton:NSLocalizedString(@"Stop", @"stop button") + alertStyle:NSWarningAlertStyle + docWindow:[tableDocumentInstance parentWindow] + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo:@"runAllContinueStopSheet" + msg:NSLocalizedString(@"MySQL Error", @"mysql error message") + infoText:[mySQLConnection lastErrorMessage] + returnCode:&runAllContinueStopSheetReturnCode]; + [tableDocumentInstance setTaskIndicatorShouldAnimate:YES]; switch (runAllContinueStopSheetReturnCode) { diff --git a/Source/SPDatabaseDocument.m b/Source/SPDatabaseDocument.m index ed739caf..6511eb4e 100644 --- a/Source/SPDatabaseDocument.m +++ b/Source/SPDatabaseDocument.m @@ -3294,15 +3294,18 @@ static NSString *SPAlterDatabaseAction = @"SPAlterDatabase"; if(!spf || ![spf count] || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - SPBeginWaitingAlertSheet(@"title", - NSLocalizedString(@"OK", @"OK button"), NSLocalizedString(@"Ignore", @"ignore button"), nil, - NSCriticalAlertStyle, parentWindow, self, - @selector(sheetDidEnd:returnCode:contextInfo:), - @"saveDocPrefSheetStatus", - [NSString stringWithFormat:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file")], - [NSString stringWithFormat:NSLocalizedString(@"Connection data file “%@” couldn't be read. Please try to save the document under a different name.", @"message error while reading connection data file and suggesting to save it under a differnet name"), [fileName lastPathComponent]], - &saveDocPrefSheetStatus - ); + [SPAlertSheets beginWaitingAlertSheetWithTitle:@"title" + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:NSLocalizedString(@"Ignore", @"ignore button") + otherButton:nil + alertStyle:NSCriticalAlertStyle + docWindow:parentWindow + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo:@"saveDocPrefSheetStatus" + msg:[NSString stringWithFormat:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file")] + infoText:[NSString stringWithFormat:NSLocalizedString(@"Connection data file “%@” couldn't be read. Please try to save the document under a different name.", @"message error while reading connection data file and suggesting to save it under a differnet name"), [fileName lastPathComponent]] + returnCode:&saveDocPrefSheetStatus]; if (spf) [spf release]; if(saveDocPrefSheetStatus == NSAlertAlternateReturn) diff --git a/Source/SPEditorPreferencePane.m b/Source/SPEditorPreferencePane.m index b9df9845..186af05a 100644 --- a/Source/SPEditorPreferencePane.m +++ b/Source/SPEditorPreferencePane.m @@ -758,19 +758,18 @@ static NSString *SPCustomColorSchemeNameLC = @"user-defined"; [[NSColorPanel sharedColorPanel] close]; - SPBeginWaitingAlertSheet(@"title", - NSLocalizedString(@"Proceed", @"proceed button"), - NSLocalizedString(@"Cancel", @"cancel button"), - nil, - NSWarningAlertStyle, - [[self view] window], - self, - @selector(checkForUnsavedThemeDidEndSheet:returnCode:contextInfo:), - nil, - NSLocalizedString(@"Unsaved Theme", @"unsaved theme message"), - NSLocalizedString(@"The current color theme is unsaved. Do you want to proceed without saving it?", @"unsaved theme informative message"), - &checkForUnsavedThemeSheetStatus - ); + [SPAlertSheets beginWaitingAlertSheetWithTitle:@"title" + defaultButton:NSLocalizedString(@"Proceed", @"proceed button") + alternateButton:NSLocalizedString(@"Cancel", @"cancel button") + otherButton:nil + alertStyle:NSWarningAlertStyle + docWindow:[[self view] window] + modalDelegate:self + didEndSelector:@selector(checkForUnsavedThemeDidEndSheet:returnCode:contextInfo:) + contextInfo:nil + msg:NSLocalizedString(@"Unsaved Theme", @"unsaved theme message") + infoText:NSLocalizedString(@"The current color theme is unsaved. Do you want to proceed without saving it?", @"unsaved theme informative message") + returnCode:&checkForUnsavedThemeSheetStatus]; return (checkForUnsavedThemeSheetStatus == NSAlertDefaultReturn); } -- cgit v1.2.3