mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	For some reason, its value in the Google style we use is 80... except for Objective-C, where it's 100, which led to things like: https://hg.mozilla.org/mozilla-central/rev/31bf68247e6e https://hg.mozilla.org/mozilla-central/rev/64ceb33533a4. There's probably a discussion to have about whether 80 is the right limit, but since it's what's used for everything except ObjC, let's roll with it. # ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D187409
		
			
				
	
	
		
			243 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* 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 "nsDirectoryServiceDefs.h"
 | 
						|
#include "nsString.h"
 | 
						|
#include "nsIRollupListener.h"
 | 
						|
#include "nsIWidget.h"
 | 
						|
#include "nsThreadUtils.h"
 | 
						|
#include "nsMemoryPressure.h"
 | 
						|
#include "nsServiceManagerUtils.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_NotifyOfMemoryPressure(MemoryPressureState::LowMemory);
 | 
						|
}
 | 
						|
@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();
 | 
						|
}
 |