Added uiMain() and friends on macOS and refined the tests. So now we'll need to add a timeout mechanism because that sendEvent: stuff really is still neeeded and I'd like to prevent shenanigans later.

This commit is contained in:
Pietro Gagliardi 2019-04-28 11:48:21 -04:00
parent 2c57498e44
commit 9c70782a0f
3 changed files with 74 additions and 45 deletions

View File

@ -7,7 +7,34 @@
@implementation uiprivApplication
@end
static NSApplication *uiprivApp;
@interface uiprivApplicationDelegate : NSObject<NSApplicationDelegate>
@end
static uiprivApplication *uiprivApp;
static uiprivApplicationDelegate *uiprivAppDelegate;
@implementation uiprivApplicationDelegate
#if 0
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app
{
// for debugging
NSLog(@"in applicationShouldTerminate:");
if (uiprivShouldQuit()) {
canQuit = YES;
// this will call terminate:, which is the same as uiQuit()
return NSTerminateNow;
}
return NSTerminateCancel;
}
#endif
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app
{
return NO;
}
@end
#define errNSAppAlreadyInitialized "NSApp is not of type uiprivApplication; was likely already initialized beforehand"
@ -25,6 +52,31 @@ int uiInit(void *options, uiInitError *err)
if (![NSApp isKindOfClass:[uiprivApplication class]])
return uiprivInitReturnError(err, errNSAppAlreadyInitialized);
// don't check for a NO return; something (launch services?) causes running from application bundles to always return NO when asking to change activation policy, even if the change is to the same activation policy!
// see https://github.com/andlabs/ui/issues/6
[uiprivApp setActivationPolicy:NSApplicationActivationPolicyRegular];
uiprivAppDelegate = [uiprivApplicationDelegate new];
[uiprivApp setDelegate:uiprivAppDelegate];
uiprivMarkInitialized();
return 1;
}
void uiMain(void)
{
[uiprivApp run];
}
void uiQuit(void)
{
[uiprivApp stop:uiprivApp];
}
// thanks to mikeash in irc.freenode.net/#macdev for suggesting the use of Grand Central Dispatch for this
void uiQueueMain(void (*f)(void *data), void *data)
{
// dispatch_get_main_queue() is a serial queue so it will not execute multiple uiQueueMain() functions concurrently
// the signature of f matches dispatch_function_t
dispatch_async_f(dispatch_get_main_queue(), data, f);
}

View File

@ -52,8 +52,28 @@ static void queued(void *data)
int *flag = (int *) data;
*flag = 1;
uiQuit();
}
testingTest(QueueMain)
{
int flag = 0;
uiQueueMain(queued, &flag);
uiMain();
if (flag != 1)
testingTErrorf(t, "uiQueueMain didn't set flag properly: got %d, want 1", flag);
}
testingTest(QueueMain_Sequence)
{
// TODO
}
// TODO testingTest(QueueMain_DifferentThread)
// TODO testingTest(QueueMain_DifferentThreadSequence)
#if 0
static void timer(void *data)
{
int *n = (int *) data;
@ -62,12 +82,7 @@ static void timer(void *data)
*n++;
}
testingTest(QueueMain)
{
}
// TODO testingTest(QueueMain_DifferentThread)
testingTest(Timer)
{
}
#endif

View File

@ -87,23 +87,6 @@ static BOOL stepsIsRunning;
[super dealloc];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app
{
// for debugging
NSLog(@"in applicationShouldTerminate:");
if (uiprivShouldQuit()) {
canQuit = YES;
// this will call terminate:, which is the same as uiQuit()
return NSTerminateNow;
}
return NSTerminateCancel;
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app
{
return NO;
}
@end
uiInitOptions uiprivOptions;
@ -112,12 +95,6 @@ const char *uiInit(uiInitOptions *o)
{
@autoreleasepool {
uiprivOptions = *o;
app = [[uiprivApplicationClass sharedApplication] retain];
// don't check for a NO return; something (launch services?) causes running from application bundles to always return NO when asking to change activation policy, even if the change is to the same activation policy!
// see https://github.com/andlabs/ui/issues/6
[uiprivNSApp() setActivationPolicy:NSApplicationActivationPolicyRegular];
delegate = [uiprivAppDelegate new];
[uiprivNSApp() setDelegate:delegate];
uiprivInitAlloc();
uiprivLoadFutures();
@ -228,21 +205,6 @@ int uiprivMainStep(uiprivNextEventArgs *nea, BOOL (^interceptEvent)(NSEvent *e))
}
}
void uiQuit(void)
{
canQuit = YES;
[uiprivNSApp() terminate:uiprivNSApp()];
}
// thanks to mikeash in irc.freenode.net/#macdev for suggesting the use of Grand Central Dispatch for this
// LONGTERM will dispatch_get_main_queue() break after _CFRunLoopSetCurrent()?
void uiQueueMain(void (*f)(void *data), void *data)
{
// dispatch_get_main_queue() is a serial queue so it will not execute multiple uiQueueMain() functions concurrently
// the signature of f matches dispatch_function_t
dispatch_async_f(dispatch_get_main_queue(), data, f);
}
@interface uiprivTimerDelegate : NSObject {
int (*f)(void *data);
void *data;