summaryrefslogtreecommitdiffstats
path: root/widget/uikit/nsAppShell.mm
diff options
context:
space:
mode:
Diffstat (limited to 'widget/uikit/nsAppShell.mm')
-rw-r--r--widget/uikit/nsAppShell.mm271
1 files changed, 271 insertions, 0 deletions
diff --git a/widget/uikit/nsAppShell.mm b/widget/uikit/nsAppShell.mm
new file mode 100644
index 000000000..ac007132f
--- /dev/null
+++ b/widget/uikit/nsAppShell.mm
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#import <UIKit/UIApplication.h>
+#import <UIKit/UIScreen.h>
+#import <UIKit/UIWindow.h>
+#import <UIKit/UIViewController.h>
+
+#include "nsAppShell.h"
+#include "nsCOMPtr.h"
+#include "nsIFile.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsString.h"
+#include "nsIRollupListener.h"
+#include "nsIWidget.h"
+#include "nsThreadUtils.h"
+#include "nsIWindowMediator.h"
+#include "nsMemoryPressure.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIWebBrowserChrome.h"
+
+nsAppShell *nsAppShell::gAppShell = NULL;
+UIWindow *nsAppShell::gWindow = nil;
+NSMutableArray *nsAppShell::gTopLevelViews = [[NSMutableArray alloc] init];
+
+#define ALOG(args...) fprintf(stderr, args); fprintf(stderr, "\n")
+
+// ViewController
+@interface ViewController : UIViewController
+@end
+
+
+@implementation ViewController
+
+- (void)loadView {
+ ALOG("[ViewController loadView]");
+ CGRect r = {{0, 0}, {100, 100}};
+ self.view = [[UIView alloc] initWithFrame:r];
+ [self.view setBackgroundColor:[UIColor lightGrayColor]];
+ // add all of the top level views as children
+ for (UIView* v in nsAppShell::gTopLevelViews) {
+ ALOG("[ViewController.view addSubView:%p]", v);
+ [self.view addSubview:v];
+ }
+ [nsAppShell::gTopLevelViews release];
+ nsAppShell::gTopLevelViews = nil;
+}
+@end
+
+// AppShellDelegate
+//
+// Acts as a delegate for the UIApplication
+
+@interface AppShellDelegate : NSObject <UIApplicationDelegate> {
+}
+@property (strong, nonatomic) UIWindow *window;
+@end
+
+@implementation AppShellDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ ALOG("[AppShellDelegate application:didFinishLaunchingWithOptions:]");
+ // We only create one window, since we can only display one window at
+ // a time anyway. Also, iOS 4 fails to display UIWindows if you
+ // create them before calling UIApplicationMain, so this makes more sense.
+ nsAppShell::gWindow = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] retain];
+ self.window = nsAppShell::gWindow;
+
+ self.window.rootViewController = [[ViewController alloc] init];
+
+ // just to make things more visible for now
+ nsAppShell::gWindow.backgroundColor = [UIColor blueColor];
+ [nsAppShell::gWindow makeKeyAndVisible];
+
+ return YES;
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application
+{
+ ALOG("[AppShellDelegate applicationWillTerminate:]");
+ nsAppShell::gAppShell->WillTerminate();
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application
+{
+ ALOG("[AppShellDelegate applicationDidBecomeActive:]");
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application
+{
+ ALOG("[AppShellDelegate applicationWillResignActive:]");
+}
+
+- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
+{
+ ALOG("[AppShellDelegate applicationDidReceiveMemoryWarning:]");
+ NS_DispatchMemoryPressure(MemPressure_New);
+}
+@end
+
+// nsAppShell implementation
+
+NS_IMETHODIMP
+nsAppShell::ResumeNative(void)
+{
+ return nsBaseAppShell::ResumeNative();
+}
+
+nsAppShell::nsAppShell()
+ : mAutoreleasePool(NULL),
+ mDelegate(NULL),
+ mCFRunLoop(NULL),
+ mCFRunLoopSource(NULL),
+ mTerminated(false),
+ mNotifiedWillTerminate(false)
+{
+ gAppShell = this;
+}
+
+nsAppShell::~nsAppShell()
+{
+ if (mAutoreleasePool) {
+ [mAutoreleasePool release];
+ mAutoreleasePool = NULL;
+ }
+
+ if (mCFRunLoop) {
+ if (mCFRunLoopSource) {
+ ::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource,
+ kCFRunLoopCommonModes);
+ ::CFRelease(mCFRunLoopSource);
+ }
+ ::CFRelease(mCFRunLoop);
+ }
+
+ gAppShell = NULL;
+}
+
+// Init
+//
+// public
+nsresult
+nsAppShell::Init()
+{
+ mAutoreleasePool = [[NSAutoreleasePool alloc] init];
+
+ // Add a CFRunLoopSource to the main native run loop. The source is
+ // responsible for interrupting the run loop when Gecko events are ready.
+
+ mCFRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
+ NS_ENSURE_STATE(mCFRunLoop);
+ ::CFRetain(mCFRunLoop);
+
+ CFRunLoopSourceContext context;
+ bzero(&context, sizeof(context));
+ // context.version = 0;
+ context.info = this;
+ context.perform = ProcessGeckoEvents;
+
+ mCFRunLoopSource = ::CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
+ NS_ENSURE_STATE(mCFRunLoopSource);
+
+ ::CFRunLoopAddSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
+
+ return nsBaseAppShell::Init();
+}
+
+// ProcessGeckoEvents
+//
+// The "perform" target of mCFRunLoop, called when mCFRunLoopSource is
+// signalled from ScheduleNativeEventCallback.
+//
+// protected static
+void
+nsAppShell::ProcessGeckoEvents(void* aInfo)
+{
+ nsAppShell* self = static_cast<nsAppShell*> (aInfo);
+ self->NativeEventCallback();
+ self->Release();
+}
+
+// WillTerminate
+//
+// public
+void
+nsAppShell::WillTerminate()
+{
+ mNotifiedWillTerminate = true;
+ if (mTerminated)
+ return;
+ mTerminated = true;
+ // We won't get another chance to process events
+ NS_ProcessPendingEvents(NS_GetCurrentThread());
+
+ // Unless we call nsBaseAppShell::Exit() here, it might not get called
+ // at all.
+ nsBaseAppShell::Exit();
+}
+
+// ScheduleNativeEventCallback
+//
+// protected virtual
+void
+nsAppShell::ScheduleNativeEventCallback()
+{
+ if (mTerminated)
+ return;
+
+ NS_ADDREF_THIS();
+
+ // This will invoke ProcessGeckoEvents on the main thread.
+ ::CFRunLoopSourceSignal(mCFRunLoopSource);
+ ::CFRunLoopWakeUp(mCFRunLoop);
+}
+
+// ProcessNextNativeEvent
+//
+// protected virtual
+bool
+nsAppShell::ProcessNextNativeEvent(bool aMayWait)
+{
+ if (mTerminated)
+ return false;
+
+ NSString* currentMode = nil;
+ NSDate* waitUntil = nil;
+ if (aMayWait)
+ waitUntil = [NSDate distantFuture];
+ NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
+
+ BOOL eventProcessed = NO;
+ do {
+ currentMode = [currentRunLoop currentMode];
+ if (!currentMode)
+ currentMode = NSDefaultRunLoopMode;
+
+ if (aMayWait)
+ eventProcessed = [currentRunLoop runMode:currentMode beforeDate:waitUntil];
+ else
+ [currentRunLoop acceptInputForMode:currentMode beforeDate:waitUntil];
+ } while(eventProcessed && aMayWait);
+
+ return false;
+}
+
+// Run
+//
+// public
+NS_IMETHODIMP
+nsAppShell::Run(void)
+{
+ ALOG("nsAppShell::Run");
+ char argv[1][4] = {"app"};
+ UIApplicationMain(1, (char**)argv, nil, @"AppShellDelegate");
+ // UIApplicationMain doesn't exit. :-(
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAppShell::Exit(void)
+{
+ if (mTerminated)
+ return NS_OK;
+
+ mTerminated = true;
+ return nsBaseAppShell::Exit();
+}