1/* 2* Copyright 2017 Google Inc. 3* 4* Use of this source code is governed by a BSD-style license that can be 5* found in the LICENSE file. 6*/ 7 8#include "include/core/SkTypes.h" 9#include "include/private/SkTHash.h" 10#include "tools/sk_app/Application.h" 11#include "tools/sk_app/ios/Window_ios.h" 12#include "tools/timer/Timer.h" 13 14#import <UIKit/UIKit.h> 15 16using sk_app::Application; 17 18//////////////////////////////////////////////////////////////////// 19 20@interface AppDelegate : UIResponder<UIApplicationDelegate> 21 22@property (nonatomic, assign) BOOL done; 23@property (strong, nonatomic) UIWindow *window; 24 25@end 26 27@implementation AppDelegate 28 29@synthesize done = _done; 30@synthesize window = _window; 31 32- (void)applicationWillTerminate:(UIApplication *)sender { 33 _done = TRUE; 34} 35 36- (void)launchApp { 37 // Extract argc and argv from NSProcessInfo 38 NSArray *arguments = [[NSProcessInfo processInfo] arguments]; 39 int argc = arguments.count; 40 char** argv = (char **)malloc((argc+1) * sizeof(char *)); 41 int i = 0; 42 for (NSString* string in arguments) { 43 size_t bufferSize = (string.length+1) * sizeof(char); 44 argv[i] = (char*)malloc(bufferSize); 45 [string getCString:argv[i] 46 maxLength:bufferSize 47 encoding:NSUTF8StringEncoding]; 48 ++i; 49 } 50 argv[i] = NULL; 51 [arguments release]; 52 53 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 54 55 Application* app = Application::Create(argc, argv, nullptr); 56 57 // Free the memory we used for argc and argv 58 for (i = 0; i < argc; i++) { 59 free(argv[i]); 60 } 61 free(argv); 62 63 sk_app::Window_ios* mainWindow = sk_app::Window_ios::MainWindow(); 64 if (!mainWindow) { 65 return; 66 } 67 self.window = mainWindow->uiWindow(); 68 69 // take over the main event loop 70 bool done = false; 71 while (!done) { 72 // TODO: consider using a dispatch queue or CADisplayLink instead of this 73 const CFTimeInterval kSeconds = 0.000002; 74 CFRunLoopRunResult result; 75 do { 76 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, kSeconds, TRUE); 77 } while (result == kCFRunLoopRunHandledSource); 78 79 [pool drain]; 80 pool = [[NSAutoreleasePool alloc] init]; 81 82 // TODO: is this the right approach for iOS? 83 // Rather than depending on an iOS event to drive this, we treat our window 84 // invalidation flag as a separate event stream. Window::onPaint() will clear 85 // the invalidation flag, effectively removing it from the stream. 86 sk_app::Window_ios::PaintWindow(); 87 88 app->onIdle(); 89 } 90 delete app; 91} 92 93- (BOOL)application:(UIApplication *)application 94 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 95 // let the system event loop run once, then launch into our main loop 96 [self performSelector:@selector(launchApp) withObject:nil afterDelay:0.0]; 97 98 return YES; 99} 100 101@end 102 103/////////////////////////////////////////////////////////////////// 104 105int main(int argc, char **argv) { 106 /* Give over control to run loop, AppDelegate will handle most things from here */ 107 @autoreleasepool { 108 UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 109 } 110 111 return EXIT_SUCCESS; 112} 113