Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / widget / uikit / nsAppShell.mm
blob6324a04b4d0c21a406dc781e59b3bc152a470113
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #import <UIKit/UIApplication.h>
7 #import <UIKit/UIScreen.h>
8 #import <UIKit/UIWindow.h>
9 #import <UIKit/UIViewController.h>
11 #include "nsAppShell.h"
12 #include "nsCOMPtr.h"
13 #include "nsDirectoryServiceDefs.h"
14 #include "nsString.h"
15 #include "nsIRollupListener.h"
16 #include "nsIWidget.h"
17 #include "nsThreadUtils.h"
18 #include "nsMemoryPressure.h"
19 #include "nsServiceManagerUtils.h"
21 nsAppShell* nsAppShell::gAppShell = NULL;
22 UIWindow* nsAppShell::gWindow = nil;
23 NSMutableArray* nsAppShell::gTopLevelViews = [[NSMutableArray alloc] init];
25 #define ALOG(args...)    \
26   fprintf(stderr, args); \
27   fprintf(stderr, "\n")
29 // ViewController
30 @interface ViewController : UIViewController
31 @end
33 @implementation ViewController
35 - (void)loadView {
36   ALOG("[ViewController loadView]");
37   CGRect r = {{0, 0}, {100, 100}};
38   self.view = [[UIView alloc] initWithFrame:r];
39   [self.view setBackgroundColor:[UIColor lightGrayColor]];
40   // add all of the top level views as children
41   for (UIView* v in nsAppShell::gTopLevelViews) {
42     ALOG("[ViewController.view addSubView:%p]", v);
43     [self.view addSubview:v];
44   }
45   [nsAppShell::gTopLevelViews release];
46   nsAppShell::gTopLevelViews = nil;
48 @end
50 // AppShellDelegate
52 // Acts as a delegate for the UIApplication
54 @interface AppShellDelegate : NSObject <UIApplicationDelegate> {
56 @property(strong, nonatomic) UIWindow* window;
57 @end
59 @implementation AppShellDelegate
61 - (BOOL)application:(UIApplication*)application
62     didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
63   ALOG("[AppShellDelegate application:didFinishLaunchingWithOptions:]");
64   // We only create one window, since we can only display one window at
65   // a time anyway. Also, iOS 4 fails to display UIWindows if you
66   // create them before calling UIApplicationMain, so this makes more sense.
67   nsAppShell::gWindow = [[[UIWindow alloc]
68       initWithFrame:[[UIScreen mainScreen] applicationFrame]] retain];
69   self.window = nsAppShell::gWindow;
71   self.window.rootViewController = [[ViewController alloc] init];
73   // just to make things more visible for now
74   nsAppShell::gWindow.backgroundColor = [UIColor blueColor];
75   [nsAppShell::gWindow makeKeyAndVisible];
77   return YES;
80 - (void)applicationWillTerminate:(UIApplication*)application {
81   ALOG("[AppShellDelegate applicationWillTerminate:]");
82   nsAppShell::gAppShell->WillTerminate();
85 - (void)applicationDidBecomeActive:(UIApplication*)application {
86   ALOG("[AppShellDelegate applicationDidBecomeActive:]");
89 - (void)applicationWillResignActive:(UIApplication*)application {
90   ALOG("[AppShellDelegate applicationWillResignActive:]");
93 - (void)applicationDidReceiveMemoryWarning:(UIApplication*)application {
94   ALOG("[AppShellDelegate applicationDidReceiveMemoryWarning:]");
95   NS_NotifyOfMemoryPressure(MemoryPressureState::LowMemory);
97 @end
99 // nsAppShell implementation
101 NS_IMETHODIMP
102 nsAppShell::ResumeNative(void) { return nsBaseAppShell::ResumeNative(); }
104 nsAppShell::nsAppShell()
105     : mAutoreleasePool(NULL),
106       mDelegate(NULL),
107       mCFRunLoop(NULL),
108       mCFRunLoopSource(NULL),
109       mTerminated(false),
110       mNotifiedWillTerminate(false) {
111   gAppShell = this;
114 nsAppShell::~nsAppShell() {
115   if (mAutoreleasePool) {
116     [mAutoreleasePool release];
117     mAutoreleasePool = NULL;
118   }
120   if (mCFRunLoop) {
121     if (mCFRunLoopSource) {
122       ::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource,
123                               kCFRunLoopCommonModes);
124       ::CFRelease(mCFRunLoopSource);
125     }
126     ::CFRelease(mCFRunLoop);
127   }
129   gAppShell = NULL;
132 // Init
134 // public
135 nsresult nsAppShell::Init() {
136   mAutoreleasePool = [[NSAutoreleasePool alloc] init];
138   // Add a CFRunLoopSource to the main native run loop.  The source is
139   // responsible for interrupting the run loop when Gecko events are ready.
141   mCFRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
142   NS_ENSURE_STATE(mCFRunLoop);
143   ::CFRetain(mCFRunLoop);
145   CFRunLoopSourceContext context;
146   bzero(&context, sizeof(context));
147   // context.version = 0;
148   context.info = this;
149   context.perform = ProcessGeckoEvents;
151   mCFRunLoopSource = ::CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
152   NS_ENSURE_STATE(mCFRunLoopSource);
154   ::CFRunLoopAddSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
156   return nsBaseAppShell::Init();
159 // ProcessGeckoEvents
161 // The "perform" target of mCFRunLoop, called when mCFRunLoopSource is
162 // signalled from ScheduleNativeEventCallback.
164 // protected static
165 void nsAppShell::ProcessGeckoEvents(void* aInfo) {
166   nsAppShell* self = static_cast<nsAppShell*>(aInfo);
167   self->NativeEventCallback();
168   self->Release();
171 // WillTerminate
173 // public
174 void nsAppShell::WillTerminate() {
175   mNotifiedWillTerminate = true;
176   if (mTerminated) return;
177   mTerminated = true;
178   // We won't get another chance to process events
179   NS_ProcessPendingEvents(NS_GetCurrentThread());
181   // Unless we call nsBaseAppShell::Exit() here, it might not get called
182   // at all.
183   nsBaseAppShell::Exit();
186 // ScheduleNativeEventCallback
188 // protected virtual
189 void nsAppShell::ScheduleNativeEventCallback() {
190   if (mTerminated) return;
192   NS_ADDREF_THIS();
194   // This will invoke ProcessGeckoEvents on the main thread.
195   ::CFRunLoopSourceSignal(mCFRunLoopSource);
196   ::CFRunLoopWakeUp(mCFRunLoop);
199 // ProcessNextNativeEvent
201 // protected virtual
202 bool nsAppShell::ProcessNextNativeEvent(bool aMayWait) {
203   if (mTerminated) return false;
205   NSString* currentMode = nil;
206   NSDate* waitUntil = nil;
207   if (aMayWait) waitUntil = [NSDate distantFuture];
208   NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
210   BOOL eventProcessed = NO;
211   do {
212     currentMode = [currentRunLoop currentMode];
213     if (!currentMode) currentMode = NSDefaultRunLoopMode;
215     if (aMayWait)
216       eventProcessed = [currentRunLoop runMode:currentMode
217                                     beforeDate:waitUntil];
218     else
219       [currentRunLoop acceptInputForMode:currentMode beforeDate:waitUntil];
220   } while (eventProcessed && aMayWait);
222   return false;
225 // Run
227 // public
228 NS_IMETHODIMP
229 nsAppShell::Run(void) {
230   ALOG("nsAppShell::Run");
231   char argv[1][4] = {"app"};
232   UIApplicationMain(1, (char**)argv, nil, @"AppShellDelegate");
233   // UIApplicationMain doesn't exit. :-(
234   return NS_OK;
237 NS_IMETHODIMP
238 nsAppShell::Exit(void) {
239   if (mTerminated) return NS_OK;
241   mTerminated = true;
242   return nsBaseAppShell::Exit();