2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* 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/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Runs the main native Cocoa run loop, interrupting it as needed to process
|
|
|
|
* Gecko events.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#import <Cocoa/Cocoa.h>
|
2014-11-14 08:31:04 -08:00
|
|
|
#import <CoreVideo/CoreVideo.h>
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-03-03 08:20:02 -08:00
|
|
|
#include "CustomCocoaEvents.h"
|
|
|
|
#include "mozilla/WidgetTraceEvent.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsAppShell.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsIFile.h"
|
|
|
|
#include "nsDirectoryServiceDefs.h"
|
|
|
|
#include "nsString.h"
|
2007-07-17 13:29:39 -07:00
|
|
|
#include "nsIRollupListener.h"
|
|
|
|
#include "nsIWidget.h"
|
2007-09-19 12:17:06 -07:00
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
#include "nsIWindowMediator.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "nsIInterfaceRequestor.h"
|
|
|
|
#include "nsIWebBrowserChrome.h"
|
2008-02-13 15:11:11 -08:00
|
|
|
#include "nsObjCExceptions.h"
|
2012-05-17 00:53:20 -07:00
|
|
|
#include "nsCocoaFeatures.h"
|
2008-03-26 20:42:57 -07:00
|
|
|
#include "nsCocoaUtils.h"
|
2008-06-30 09:30:22 -07:00
|
|
|
#include "nsChildView.h"
|
2008-10-17 14:58:47 -07:00
|
|
|
#include "nsToolkit.h"
|
2011-02-23 20:48:12 -08:00
|
|
|
#include "TextInputHandler.h"
|
2011-11-11 13:13:36 -08:00
|
|
|
#include "mozilla/HangMonitor.h"
|
2013-03-18 07:25:50 -07:00
|
|
|
#include "GeckoProfiler.h"
|
2013-07-11 13:21:45 -07:00
|
|
|
#include "pratom.h"
|
2007-07-17 13:29:39 -07:00
|
|
|
|
2014-06-13 10:58:00 -07:00
|
|
|
#include <IOKit/pwr_mgt/IOPMLib.h>
|
|
|
|
#include "nsIDOMWakeLockListener.h"
|
|
|
|
#include "nsIPowerManagerService.h"
|
2014-11-14 08:31:04 -08:00
|
|
|
#include "mozilla/TimeStamp.h"
|
|
|
|
#include "mozilla/VsyncDispatcher.h"
|
|
|
|
#include "gfxPrefs.h"
|
2009-09-30 21:15:05 -07:00
|
|
|
|
2011-02-23 20:48:12 -08:00
|
|
|
using namespace mozilla::widget;
|
|
|
|
|
2014-06-13 10:58:00 -07:00
|
|
|
// A wake lock listener that disables screen saver when requested by
|
|
|
|
// Gecko. For example when we're playing video in a foreground tab we
|
|
|
|
// don't want the screen saver to turn on.
|
|
|
|
|
2014-06-19 23:03:54 -07:00
|
|
|
class MacWakeLockListener MOZ_FINAL : public nsIDOMMozWakeLockListener {
|
2014-06-13 10:58:00 -07:00
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS;
|
|
|
|
|
|
|
|
private:
|
2014-07-06 08:25:31 -07:00
|
|
|
~MacWakeLockListener() {}
|
|
|
|
|
2014-06-13 10:58:00 -07:00
|
|
|
IOPMAssertionID mAssertionID = kIOPMNullAssertionID;
|
|
|
|
|
|
|
|
NS_IMETHOD Callback(const nsAString& aTopic, const nsAString& aState) {
|
2014-10-07 18:20:00 -07:00
|
|
|
if (!aTopic.EqualsASCII("screen")) {
|
2014-06-13 10:58:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2014-10-07 18:20:00 -07:00
|
|
|
// Note the wake lock code ensures that we're not sent duplicate
|
|
|
|
// "locked-foreground" notifications when multiple wake locks are held.
|
|
|
|
if (aState.EqualsASCII("locked-foreground")) {
|
|
|
|
// Prevent screen saver.
|
|
|
|
CFStringRef cf_topic =
|
|
|
|
::CFStringCreateWithCharacters(kCFAllocatorDefault,
|
|
|
|
reinterpret_cast<const UniChar*>
|
|
|
|
(aTopic.Data()),
|
|
|
|
aTopic.Length());
|
|
|
|
IOReturn success =
|
|
|
|
::IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
|
|
|
|
kIOPMAssertionLevelOn,
|
|
|
|
cf_topic,
|
|
|
|
&mAssertionID);
|
|
|
|
CFRelease(cf_topic);
|
|
|
|
if (success != kIOReturnSuccess) {
|
|
|
|
NS_WARNING("failed to disable screensaver");
|
2014-06-13 10:58:00 -07:00
|
|
|
}
|
|
|
|
} else {
|
2014-10-07 18:20:00 -07:00
|
|
|
// Re-enable screen saver.
|
|
|
|
NS_WARNING("Releasing screensaver");
|
|
|
|
if (mAssertionID != kIOPMNullAssertionID) {
|
|
|
|
IOReturn result = ::IOPMAssertionRelease(mAssertionID);
|
|
|
|
if (result != kIOReturnSuccess) {
|
|
|
|
NS_WARNING("failed to release screensaver");
|
2014-06-13 10:58:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2014-11-14 08:31:04 -08:00
|
|
|
}; // MacWakeLockListener
|
|
|
|
|
|
|
|
// This is the renderer output callback function, called on the vsync thread
|
|
|
|
static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink,
|
|
|
|
const CVTimeStamp* aNow,
|
|
|
|
const CVTimeStamp* aOutputTime,
|
|
|
|
CVOptionFlags aFlagsIn,
|
|
|
|
CVOptionFlags* aFlagsOut,
|
|
|
|
void* aDisplayLinkContext)
|
|
|
|
{
|
|
|
|
VsyncSource* vsyncSource = (VsyncSource*) aDisplayLinkContext;
|
|
|
|
if (vsyncSource->IsVsyncEnabled()) {
|
|
|
|
// Now refers to "Now" as in when this callback is called or when the current frame
|
|
|
|
// is displayed. aOutputTime is when the next frame should be displayed.
|
|
|
|
// Now is VERY VERY noisy, aOutputTime is in the future though.
|
|
|
|
int64_t timestamp = aOutputTime->hostTime;
|
|
|
|
mozilla::TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(timestamp);
|
|
|
|
mozilla::VsyncDispatcher::GetInstance()->NotifyVsync(vsyncTime);
|
|
|
|
return kCVReturnSuccess;
|
|
|
|
} else {
|
|
|
|
return kCVReturnDisplayLinkNotRunning;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class OSXVsyncSource MOZ_FINAL : public VsyncSource
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
OSXVsyncSource()
|
|
|
|
{
|
|
|
|
EnableVsync();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void EnableVsync() MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
// Create a display link capable of being used with all active displays
|
|
|
|
// TODO: See if we need to create an active DisplayLink for each monitor in multi-monitor
|
|
|
|
// situations. According to the docs, it is compatible with all displays running on the computer
|
|
|
|
// But if we have different monitors at different display rates, we may hit issues.
|
|
|
|
if (CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink) != kCVReturnSuccess) {
|
|
|
|
NS_WARNING("Could not create a display link, returning");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the renderer output callback function
|
|
|
|
if (CVDisplayLinkSetOutputCallback(mDisplayLink, &VsyncCallback, this) != kCVReturnSuccess) {
|
|
|
|
NS_WARNING("Could not set displaylink output callback");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Activate the display link
|
|
|
|
if (CVDisplayLinkStart(mDisplayLink) != kCVReturnSuccess) {
|
|
|
|
NS_WARNING("Could not activate the display link");
|
|
|
|
mDisplayLink = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void DisableVsync() MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
// Release the display link
|
|
|
|
if (mDisplayLink) {
|
|
|
|
CVDisplayLinkRelease(mDisplayLink);
|
|
|
|
mDisplayLink = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool IsVsyncEnabled() MOZ_OVERRIDE
|
|
|
|
{
|
|
|
|
return mDisplayLink != nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
virtual ~OSXVsyncSource()
|
|
|
|
{
|
|
|
|
DisableVsync();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Manages the display link render thread
|
|
|
|
CVDisplayLinkRef mDisplayLink;
|
|
|
|
}; // OSXVsyncSource
|
2014-06-13 10:58:00 -07:00
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
// defined in nsCocoaWindow.mm
|
2012-08-22 08:56:38 -07:00
|
|
|
extern int32_t gXULModalLevel;
|
2007-09-19 12:17:06 -07:00
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool gAppShellMethodsSwizzled = false;
|
2009-03-18 15:51:40 -07:00
|
|
|
|
2011-03-03 08:20:02 -08:00
|
|
|
@implementation GeckoNSApplication
|
2011-12-01 09:50:04 -08:00
|
|
|
|
2011-03-03 08:20:02 -08:00
|
|
|
- (void)sendEvent:(NSEvent *)anEvent
|
|
|
|
{
|
2011-11-11 13:13:36 -08:00
|
|
|
mozilla::HangMonitor::NotifyActivity();
|
2011-03-03 08:20:02 -08:00
|
|
|
if ([anEvent type] == NSApplicationDefined &&
|
|
|
|
[anEvent subtype] == kEventSubtypeTrace) {
|
|
|
|
mozilla::SignalTracerThread();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
[super sendEvent:anEvent];
|
|
|
|
}
|
2011-12-01 09:50:04 -08:00
|
|
|
|
|
|
|
- (NSEvent*)nextEventMatchingMask:(NSUInteger)mask
|
|
|
|
untilDate:(NSDate*)expiration
|
|
|
|
inMode:(NSString*)mode
|
|
|
|
dequeue:(BOOL)flag
|
|
|
|
{
|
|
|
|
if (expiration) {
|
|
|
|
mozilla::HangMonitor::Suspend();
|
|
|
|
}
|
|
|
|
return [super nextEventMatchingMask:mask
|
|
|
|
untilDate:expiration inMode:mode dequeue:flag];
|
|
|
|
}
|
|
|
|
|
2011-03-03 08:20:02 -08:00
|
|
|
@end
|
|
|
|
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// AppShellDelegate
|
|
|
|
//
|
2007-09-19 12:17:06 -07:00
|
|
|
// Cocoa bridge class. An object of this class is registered to receive
|
|
|
|
// notifications.
|
2007-03-22 10:30:00 -07:00
|
|
|
//
|
|
|
|
@interface AppShellDelegate : NSObject
|
|
|
|
{
|
|
|
|
@private
|
|
|
|
nsAppShell* mAppShell;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)initWithAppShell:(nsAppShell*)aAppShell;
|
|
|
|
- (void)applicationWillTerminate:(NSNotification*)aNotification;
|
2007-07-17 13:29:39 -07:00
|
|
|
- (void)beginMenuTracking:(NSNotification*)aNotification;
|
2007-03-22 10:30:00 -07:00
|
|
|
@end
|
|
|
|
|
|
|
|
// nsAppShell implementation
|
|
|
|
|
2007-03-22 16:04:51 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsAppShell::ResumeNative(void)
|
|
|
|
{
|
|
|
|
nsresult retval = nsBaseAppShell::ResumeNative();
|
2007-04-05 17:16:07 -07:00
|
|
|
if (NS_SUCCEEDED(retval) && (mSuspendNativeCount == 0) &&
|
|
|
|
mSkippedNativeCallback)
|
|
|
|
{
|
2011-09-30 17:20:33 -07:00
|
|
|
mSkippedNativeCallback = false;
|
2007-03-22 16:04:51 -07:00
|
|
|
ScheduleNativeEventCallback();
|
2007-04-05 17:16:07 -07:00
|
|
|
}
|
2007-03-22 16:04:51 -07:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsAppShell::nsAppShell()
|
2012-07-30 07:20:58 -07:00
|
|
|
: mAutoreleasePools(nullptr)
|
|
|
|
, mDelegate(nullptr)
|
2007-09-19 12:17:06 -07:00
|
|
|
, mCFRunLoop(NULL)
|
|
|
|
, mCFRunLoopSource(NULL)
|
2011-09-30 17:20:33 -07:00
|
|
|
, mRunningEventLoop(false)
|
|
|
|
, mStarted(false)
|
|
|
|
, mTerminated(false)
|
|
|
|
, mSkippedNativeCallback(false)
|
2007-09-27 09:23:31 -07:00
|
|
|
, mNativeEventCallbackDepth(0)
|
2009-06-17 08:30:46 -07:00
|
|
|
, mNativeEventScheduledDepth(0)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-02-02 13:23:42 -08:00
|
|
|
// A Cocoa event loop is running here if (and only if) we've been embedded
|
2014-10-10 08:00:29 -07:00
|
|
|
// by a Cocoa app.
|
2011-09-30 17:20:33 -07:00
|
|
|
mRunningCocoaEmbedded = [NSApp isRunning] ? true : false;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsAppShell::~nsAppShell()
|
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
if (mCFRunLoop) {
|
|
|
|
if (mCFRunLoopSource) {
|
|
|
|
::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource,
|
|
|
|
kCFRunLoopCommonModes);
|
|
|
|
::CFRelease(mCFRunLoopSource);
|
|
|
|
}
|
|
|
|
::CFRelease(mCFRunLoop);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mAutoreleasePools) {
|
|
|
|
NS_ASSERTION(::CFArrayGetCount(mAutoreleasePools) == 0,
|
|
|
|
"nsAppShell destroyed without popping all autorelease pools");
|
|
|
|
::CFRelease(mAutoreleasePools);
|
|
|
|
}
|
|
|
|
|
|
|
|
[mDelegate release];
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2014-06-13 10:58:00 -07:00
|
|
|
NS_IMPL_ISUPPORTS(MacWakeLockListener, nsIDOMMozWakeLockListener)
|
|
|
|
mozilla::StaticRefPtr<MacWakeLockListener> sWakeLockListener;
|
|
|
|
|
|
|
|
static void
|
|
|
|
AddScreenWakeLockListener()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPowerManagerService> sPowerManagerService = do_GetService(
|
|
|
|
POWERMANAGERSERVICE_CONTRACTID);
|
|
|
|
if (sPowerManagerService) {
|
|
|
|
sWakeLockListener = new MacWakeLockListener();
|
|
|
|
sPowerManagerService->AddWakeLockListener(sWakeLockListener);
|
|
|
|
} else {
|
|
|
|
NS_WARNING("Failed to retrieve PowerManagerService, wakelocks will be broken!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
RemoveScreenWakeLockListener()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIPowerManagerService> sPowerManagerService = do_GetService(
|
|
|
|
POWERMANAGERSERVICE_CONTRACTID);
|
|
|
|
if (sPowerManagerService) {
|
|
|
|
sPowerManagerService->RemoveWakeLockListener(sWakeLockListener);
|
|
|
|
sPowerManagerService = nullptr;
|
|
|
|
sWakeLockListener = nullptr;
|
|
|
|
}
|
|
|
|
}
|
2014-11-11 13:28:18 -08:00
|
|
|
|
|
|
|
// An undocumented CoreGraphics framework method, present in the same form
|
|
|
|
// since at least OS X 10.5.
|
|
|
|
extern "C" CGError CGSSetDebugOptions(int options);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Init
|
|
|
|
//
|
2007-09-19 12:17:06 -07:00
|
|
|
// Loads the nib (see bug 316076c21) and sets up the CFRunLoopSource used to
|
|
|
|
// interrupt the main native run loop.
|
2007-03-22 10:30:00 -07:00
|
|
|
//
|
|
|
|
// public
|
|
|
|
nsresult
|
|
|
|
nsAppShell::Init()
|
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2014-10-10 08:00:29 -07:00
|
|
|
// No event loop is running yet (unless an embedding app that uses
|
|
|
|
// NSApplicationMain() is running).
|
2007-03-22 10:30:00 -07:00
|
|
|
NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
|
|
|
|
|
|
|
|
// mAutoreleasePools is used as a stack of NSAutoreleasePool objects created
|
|
|
|
// by |this|. CFArray is used instead of NSArray because NSArray wants to
|
|
|
|
// retain each object you add to it, and you can't retain an
|
|
|
|
// NSAutoreleasePool.
|
2012-07-30 07:20:58 -07:00
|
|
|
mAutoreleasePools = ::CFArrayCreateMutable(nullptr, 0, nullptr);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_STATE(mAutoreleasePools);
|
|
|
|
|
|
|
|
// Get the path of the nib file, which lives in the GRE location
|
|
|
|
nsCOMPtr<nsIFile> nibFile;
|
|
|
|
nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(nibFile));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nibFile->AppendNative(NS_LITERAL_CSTRING("res"));
|
|
|
|
nibFile->AppendNative(NS_LITERAL_CSTRING("MainMenu.nib"));
|
|
|
|
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString nibPath;
|
2007-03-22 10:30:00 -07:00
|
|
|
rv = nibFile->GetNativePath(nibPath);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
// This call initializes NSApplication unless:
|
|
|
|
// 1) we're using xre -- NSApp's already been initialized by
|
|
|
|
// MacApplicationDelegate.mm's EnsureUseCocoaDockAPI().
|
2014-10-10 08:00:29 -07:00
|
|
|
// 2) an embedding app that uses NSApplicationMain() is running -- NSApp's
|
|
|
|
// already been initialized and its main run loop is already running.
|
2007-03-22 10:30:00 -07:00
|
|
|
[NSBundle loadNibFile:
|
|
|
|
[NSString stringWithUTF8String:(const char*)nibPath.get()]
|
|
|
|
externalNameTable:
|
2011-03-03 08:20:02 -08:00
|
|
|
[NSDictionary dictionaryWithObject:[GeckoNSApplication sharedApplication]
|
2007-03-22 10:30:00 -07:00
|
|
|
forKey:@"NSOwner"]
|
|
|
|
withZone:NSDefaultMallocZone()];
|
|
|
|
|
|
|
|
mDelegate = [[AppShellDelegate alloc] initWithAppShell:this];
|
|
|
|
NS_ENSURE_STATE(mDelegate);
|
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
// 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;
|
2014-11-14 08:31:04 -08:00
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
mCFRunLoopSource = ::CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
|
|
|
|
NS_ENSURE_STATE(mCFRunLoopSource);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
::CFRunLoopAddSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
rv = nsBaseAppShell::Init();
|
|
|
|
|
2014-11-14 08:31:04 -08:00
|
|
|
// gfxPrefs are init on the main thread and we need it super early
|
|
|
|
// to see if we should enable vsync aligned compositor
|
|
|
|
gfxPrefs::GetSingleton();
|
|
|
|
if (gfxPrefs::HardwareVsyncEnabled() && gfxPrefs::VsyncAlignedCompositor())
|
|
|
|
{
|
|
|
|
nsRefPtr<VsyncSource> osxVsyncSource = new OSXVsyncSource();
|
|
|
|
mozilla::VsyncDispatcher::GetInstance()->SetVsyncSource(osxVsyncSource);
|
|
|
|
}
|
|
|
|
|
2012-10-15 05:38:34 -07:00
|
|
|
#ifndef __LP64__
|
2011-02-23 20:48:12 -08:00
|
|
|
TextInputHandler::InstallPluginKeyEventsHandler();
|
2009-09-30 21:15:05 -07:00
|
|
|
#endif
|
2008-06-30 09:30:22 -07:00
|
|
|
|
2008-10-17 14:58:47 -07:00
|
|
|
if (!gAppShellMethodsSwizzled) {
|
2010-10-16 15:22:21 -07:00
|
|
|
// We should only replace the original terminate: method if we're not
|
2014-10-10 08:00:29 -07:00
|
|
|
// running in a Cocoa embedder. See bug 604901.
|
2010-10-16 15:22:21 -07:00
|
|
|
if (!mRunningCocoaEmbedded) {
|
|
|
|
nsToolkit::SwizzleMethods([NSApplication class], @selector(terminate:),
|
|
|
|
@selector(nsAppShell_NSApplication_terminate:));
|
|
|
|
}
|
2011-09-30 17:20:33 -07:00
|
|
|
gAppShellMethodsSwizzled = true;
|
2008-10-17 14:58:47 -07:00
|
|
|
}
|
|
|
|
|
2014-11-11 13:28:18 -08:00
|
|
|
if (nsCocoaFeatures::OnYosemiteOrLater()) {
|
|
|
|
// Explicitly turn off CGEvent logging. This works around bug 1092855.
|
|
|
|
// If there are already CGEvents in the log, turning off logging also
|
|
|
|
// causes those events to be written to disk. But at this point no
|
|
|
|
// CGEvents have yet been processed. CGEvents are events (usually
|
|
|
|
// input events) pulled from the WindowServer. An option of 0x80000008
|
|
|
|
// turns on CGEvent logging.
|
|
|
|
CGSSetDebugOptions(0x80000007);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
[localPool release];
|
|
|
|
|
|
|
|
return rv;
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// ProcessGeckoEvents
|
|
|
|
//
|
2007-09-19 12:17:06 -07:00
|
|
|
// The "perform" target of mCFRunLoop, called when mCFRunLoopSource is
|
|
|
|
// signalled from ScheduleNativeEventCallback.
|
2007-03-22 10:30:00 -07:00
|
|
|
//
|
2007-09-19 12:17:06 -07:00
|
|
|
// Arrange for Gecko events to be processed on demand (in response to a call
|
|
|
|
// to ScheduleNativeEventCallback(), if processing of Gecko events via "native
|
2008-10-17 14:58:47 -07:00
|
|
|
// methods" hasn't been suspended). This happens in NativeEventCallback().
|
2007-03-22 10:30:00 -07:00
|
|
|
//
|
2007-09-19 12:17:06 -07:00
|
|
|
// protected static
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
2007-09-19 12:17:06 -07:00
|
|
|
nsAppShell::ProcessGeckoEvents(void* aInfo)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
2014-05-23 14:12:29 -07:00
|
|
|
PROFILER_LABEL("Events", "ProcessGeckoEvents",
|
|
|
|
js::ProfileEntry::Category::EVENTS);
|
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
nsAppShell* self = static_cast<nsAppShell*> (aInfo);
|
|
|
|
|
|
|
|
if (self->mRunningEventLoop) {
|
2011-09-30 17:20:33 -07:00
|
|
|
self->mRunningEventLoop = false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-09-24 15:31:49 -07:00
|
|
|
// The run loop may be sleeping -- [NSRunLoop runMode:...]
|
2007-09-19 12:17:06 -07:00
|
|
|
// won't return until it's given a reason to wake up. Awaken it by
|
|
|
|
// posting a bogus event. There's no need to make the event
|
|
|
|
// presentable.
|
2007-09-24 07:33:45 -07:00
|
|
|
//
|
|
|
|
// But _don't_ set windowNumber to '-1' -- that can lead to nasty
|
|
|
|
// wierdness like bmo bug 397039 (a crash in [NSApp sendEvent:] on one of
|
|
|
|
// these fake events, because the -1 has gotten changed into the number
|
|
|
|
// of an actual NSWindow object, and that NSWindow object has just been
|
|
|
|
// destroyed). Setting windowNumber to '0' seems to work fine -- this
|
|
|
|
// seems to prevent the OS from ever trying to associate our bogus event
|
|
|
|
// with a particular NSWindow object.
|
2007-03-22 10:30:00 -07:00
|
|
|
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
|
|
|
|
location:NSMakePoint(0,0)
|
|
|
|
modifierFlags:0
|
|
|
|
timestamp:0
|
2007-09-24 07:33:45 -07:00
|
|
|
windowNumber:0
|
2007-03-22 10:30:00 -07:00
|
|
|
context:NULL
|
2011-03-03 08:20:02 -08:00
|
|
|
subtype:kEventSubtypeNone
|
2007-03-22 10:30:00 -07:00
|
|
|
data1:0
|
|
|
|
data2:0]
|
|
|
|
atStart:NO];
|
|
|
|
}
|
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
if (self->mSuspendNativeCount <= 0) {
|
2007-09-27 09:23:31 -07:00
|
|
|
++self->mNativeEventCallbackDepth;
|
2011-01-27 15:27:39 -08:00
|
|
|
self->NativeEventCallback();
|
2007-09-27 09:23:31 -07:00
|
|
|
--self->mNativeEventCallbackDepth;
|
2007-04-05 17:16:07 -07:00
|
|
|
} else {
|
2011-09-30 17:20:33 -07:00
|
|
|
self->mSkippedNativeCallback = true;
|
2007-04-05 17:16:07 -07:00
|
|
|
}
|
2007-03-22 16:04:51 -07:00
|
|
|
|
2014-05-10 09:58:07 -07:00
|
|
|
// Still needed to avoid crashes on quit in most Mochitests.
|
2007-03-22 10:30:00 -07:00
|
|
|
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
|
|
|
|
location:NSMakePoint(0,0)
|
|
|
|
modifierFlags:0
|
|
|
|
timestamp:0
|
2007-09-24 07:33:45 -07:00
|
|
|
windowNumber:0
|
2007-03-22 10:30:00 -07:00
|
|
|
context:NULL
|
2011-03-03 08:20:02 -08:00
|
|
|
subtype:kEventSubtypeNone
|
2007-03-22 10:30:00 -07:00
|
|
|
data1:0
|
|
|
|
data2:0]
|
|
|
|
atStart:NO];
|
2007-09-19 12:17:06 -07:00
|
|
|
|
2009-06-17 08:30:46 -07:00
|
|
|
// Normally every call to ScheduleNativeEventCallback() results in
|
|
|
|
// exactly one call to ProcessGeckoEvents(). So each Release() here
|
|
|
|
// normally balances exactly one AddRef() in ScheduleNativeEventCallback().
|
|
|
|
// But if Exit() is called just after ScheduleNativeEventCallback(), the
|
|
|
|
// corresponding call to ProcessGeckoEvents() will never happen. We check
|
|
|
|
// for this possibility in two different places -- here and in Exit()
|
|
|
|
// itself. If we find here that Exit() has been called (that mTerminated
|
2011-09-30 17:20:33 -07:00
|
|
|
// is true), it's because we've been called recursively, that Exit() was
|
2009-06-17 08:30:46 -07:00
|
|
|
// called from self->NativeEventCallback() above, and that we're unwinding
|
|
|
|
// the recursion. In this case we'll never be called again, and we balance
|
|
|
|
// here any extra calls to ScheduleNativeEventCallback().
|
|
|
|
//
|
|
|
|
// When ProcessGeckoEvents() is called recursively, it's because of a
|
|
|
|
// call to ScheduleNativeEventCallback() from NativeEventCallback(). We
|
|
|
|
// balance the "extra" AddRefs here (rather than always in Exit()) in order
|
|
|
|
// to ensure that 'self' stays alive until the end of this method. We also
|
|
|
|
// make sure not to finish the balancing until all the recursion has been
|
|
|
|
// unwound.
|
|
|
|
if (self->mTerminated) {
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t releaseCount = 0;
|
2009-06-17 08:30:46 -07:00
|
|
|
if (self->mNativeEventScheduledDepth > self->mNativeEventCallbackDepth) {
|
2011-03-28 12:58:49 -07:00
|
|
|
releaseCount = PR_ATOMIC_SET(&self->mNativeEventScheduledDepth,
|
|
|
|
self->mNativeEventCallbackDepth);
|
2009-06-17 08:30:46 -07:00
|
|
|
}
|
|
|
|
while (releaseCount-- > self->mNativeEventCallbackDepth)
|
|
|
|
self->Release();
|
|
|
|
} else {
|
|
|
|
// As best we can tell, every call to ProcessGeckoEvents() is triggered
|
|
|
|
// by a call to ScheduleNativeEventCallback(). But we've seen a few
|
|
|
|
// (non-reproducible) cases of double-frees that *might* have been caused
|
|
|
|
// by spontaneous calls (from the OS) to ProcessGeckoEvents(). So we
|
|
|
|
// deal with that possibility here.
|
2011-03-28 12:58:49 -07:00
|
|
|
if (PR_ATOMIC_DECREMENT(&self->mNativeEventScheduledDepth) < 0) {
|
|
|
|
PR_ATOMIC_SET(&self->mNativeEventScheduledDepth, 0);
|
2009-06-17 08:30:46 -07:00
|
|
|
NS_WARNING("Spontaneous call to ProcessGeckoEvents()!");
|
|
|
|
} else {
|
|
|
|
self->Release();
|
|
|
|
}
|
|
|
|
}
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// WillTerminate
|
|
|
|
//
|
|
|
|
// Called by the AppShellDelegate when an NSApplicationWillTerminate
|
|
|
|
// notification is posted. After this method is called, native events should
|
2007-09-19 12:17:06 -07:00
|
|
|
// no longer be processed. The NSApplicationWillTerminate notification is
|
|
|
|
// only posted when [NSApp terminate:] is called, which doesn't happen on a
|
|
|
|
// "normal" application quit.
|
2007-03-22 10:30:00 -07:00
|
|
|
//
|
|
|
|
// public
|
|
|
|
void
|
|
|
|
nsAppShell::WillTerminate()
|
|
|
|
{
|
2007-09-19 12:17:06 -07:00
|
|
|
if (mTerminated)
|
|
|
|
return;
|
|
|
|
|
2010-10-15 09:30:07 -07:00
|
|
|
// Make sure that the nsAppExitEvent posted by nsAppStartup::Quit() (called
|
|
|
|
// from [MacApplicationDelegate applicationShouldTerminate:]) gets run.
|
2007-09-19 12:17:06 -07:00
|
|
|
NS_ProcessPendingEvents(NS_GetCurrentThread());
|
|
|
|
|
2011-09-30 17:20:33 -07:00
|
|
|
mTerminated = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// ScheduleNativeEventCallback
|
|
|
|
//
|
|
|
|
// Called (possibly on a non-main thread) when Gecko has an event that
|
|
|
|
// needs to be processed. The Gecko event needs to be processed on the
|
|
|
|
// main thread, so the native run loop must be interrupted.
|
|
|
|
//
|
2007-09-19 12:17:06 -07:00
|
|
|
// In nsBaseAppShell.cpp, the mNativeEventPending variable is used to
|
|
|
|
// ensure that ScheduleNativeEventCallback() is called no more than once
|
|
|
|
// per call to NativeEventCallback(). ProcessGeckoEvents() can skip its
|
|
|
|
// call to NativeEventCallback() if processing of Gecko events by native
|
|
|
|
// means is suspended (using nsIAppShell::SuspendNative()), which will
|
|
|
|
// suspend calls from nsBaseAppShell::OnDispatchedEvent() to
|
|
|
|
// ScheduleNativeEventCallback(). But when Gecko event processing by
|
|
|
|
// native means is resumed (in ResumeNative()), an extra call is made to
|
|
|
|
// ScheduleNativeEventCallback() (from ResumeNative()). This triggers
|
|
|
|
// another call to ProcessGeckoEvents(), which calls NativeEventCallback(),
|
|
|
|
// and nsBaseAppShell::OnDispatchedEvent() resumes calling
|
|
|
|
// ScheduleNativeEventCallback().
|
|
|
|
//
|
2007-03-22 10:30:00 -07:00
|
|
|
// protected virtual
|
|
|
|
void
|
|
|
|
nsAppShell::ScheduleNativeEventCallback()
|
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
if (mTerminated)
|
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-06-17 08:30:46 -07:00
|
|
|
// Each AddRef() here is normally balanced by exactly one Release() in
|
|
|
|
// ProcessGeckoEvents(). But there are exceptions, for which see
|
|
|
|
// ProcessGeckoEvents() and Exit().
|
2007-09-19 12:17:06 -07:00
|
|
|
NS_ADDREF_THIS();
|
2011-03-28 12:58:49 -07:00
|
|
|
PR_ATOMIC_INCREMENT(&mNativeEventScheduledDepth);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
// This will invoke ProcessGeckoEvents on the main thread.
|
|
|
|
::CFRunLoopSourceSignal(mCFRunLoopSource);
|
|
|
|
::CFRunLoopWakeUp(mCFRunLoop);
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2014-05-10 09:58:07 -07:00
|
|
|
// Undocumented Cocoa Event Manager function, present in the same form since
|
|
|
|
// at least OS X 10.6.
|
|
|
|
extern "C" EventAttributes GetEventAttributes(EventRef inEvent);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// ProcessNextNativeEvent
|
|
|
|
//
|
|
|
|
// If aMayWait is false, process a single native event. If it is true, run
|
|
|
|
// the native run loop until stopped by ProcessGeckoEvents.
|
|
|
|
//
|
|
|
|
// Returns true if more events are waiting in the native event queue.
|
|
|
|
//
|
|
|
|
// protected virtual
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
|
|
|
nsAppShell::ProcessNextNativeEvent(bool aMayWait)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-09-28 23:19:26 -07:00
|
|
|
bool moreEvents = false;
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool eventProcessed = false;
|
2007-09-19 12:17:06 -07:00
|
|
|
NSString* currentMode = nil;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (mTerminated)
|
2011-09-30 17:20:33 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool wasRunningEventLoop = mRunningEventLoop;
|
2007-03-22 10:30:00 -07:00
|
|
|
mRunningEventLoop = aMayWait;
|
|
|
|
NSDate* waitUntil = nil;
|
|
|
|
if (aMayWait)
|
|
|
|
waitUntil = [NSDate distantFuture];
|
|
|
|
|
2007-09-24 15:31:49 -07:00
|
|
|
NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
|
|
|
|
|
2014-05-10 09:58:07 -07:00
|
|
|
EventQueueRef currentEventQueue = GetCurrentEventQueue();
|
|
|
|
EventTargetRef eventDispatcherTarget = GetEventDispatcherTarget();
|
|
|
|
|
|
|
|
if (aMayWait) {
|
|
|
|
mozilla::HangMonitor::Suspend();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only call -[NSApp sendEvent:] (and indirectly send user-input events to
|
|
|
|
// Gecko) if aMayWait is true. Tbis ensures most calls to -[NSApp
|
|
|
|
// sendEvent:] happen under nsAppShell::Run(), at the lowest level of
|
|
|
|
// recursion -- thereby making it less likely Gecko will process user-input
|
|
|
|
// events in the wrong order or skip some of them. It also avoids eating
|
|
|
|
// too much CPU in nsBaseAppShell::OnProcessNextEvent() (which calls
|
|
|
|
// us) -- thereby avoiding the starvation of nsIRunnable events in
|
|
|
|
// nsThread::ProcessNextEvent(). For more information see bug 996848.
|
2007-03-22 10:30:00 -07:00
|
|
|
do {
|
|
|
|
// No autorelease pool is provided here, because OnProcessNextEvent
|
|
|
|
// and AfterProcessNextEvent are responsible for maintaining it.
|
|
|
|
NS_ASSERTION(mAutoreleasePools && ::CFArrayGetCount(mAutoreleasePools),
|
|
|
|
"No autorelease pool for native event");
|
|
|
|
|
2011-11-11 13:13:36 -08:00
|
|
|
if (aMayWait) {
|
2014-05-10 09:58:07 -07:00
|
|
|
currentMode = [currentRunLoop currentMode];
|
|
|
|
if (!currentMode)
|
|
|
|
currentMode = NSDefaultRunLoopMode;
|
|
|
|
NSEvent *nextEvent = [NSApp nextEventMatchingMask:NSAnyEventMask
|
|
|
|
untilDate:waitUntil
|
|
|
|
inMode:currentMode
|
|
|
|
dequeue:YES];
|
|
|
|
if (nextEvent) {
|
2011-11-11 13:13:36 -08:00
|
|
|
mozilla::HangMonitor::NotifyActivity();
|
2014-05-10 09:58:07 -07:00
|
|
|
[NSApp sendEvent:nextEvent];
|
2011-09-30 17:20:33 -07:00
|
|
|
eventProcessed = true;
|
2007-09-19 12:17:06 -07:00
|
|
|
}
|
|
|
|
} else {
|
2014-05-10 09:58:07 -07:00
|
|
|
// AcquireFirstMatchingEventInQueue() doesn't spin the (native) event
|
|
|
|
// loop, though it does queue up any newly available events from the
|
|
|
|
// window server.
|
|
|
|
EventRef currentEvent = AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
|
|
|
|
kEventQueueOptionsNone);
|
|
|
|
if (!currentEvent) {
|
|
|
|
continue;
|
2014-05-07 09:13:27 -07:00
|
|
|
}
|
2014-05-10 09:58:07 -07:00
|
|
|
EventAttributes attrs = GetEventAttributes(currentEvent);
|
2014-06-02 14:43:31 -07:00
|
|
|
UInt32 eventKind = GetEventKind(currentEvent);
|
2014-06-30 10:28:45 -07:00
|
|
|
UInt32 eventClass = GetEventClass(currentEvent);
|
2014-06-02 14:43:31 -07:00
|
|
|
bool osCocoaEvent =
|
2014-10-31 15:14:44 -07:00
|
|
|
((eventClass == 'appl') || (eventClass == kEventClassAppleEvent) ||
|
2014-06-30 10:28:45 -07:00
|
|
|
((eventClass == 'cgs ') && (eventKind != NSApplicationDefined)));
|
2014-05-10 09:58:07 -07:00
|
|
|
// If attrs is kEventAttributeUserEvent or kEventAttributeMonitored
|
|
|
|
// (i.e. a user input event), we shouldn't process it here while
|
2014-06-02 14:43:31 -07:00
|
|
|
// aMayWait is false. Likewise if currentEvent will eventually be
|
2014-10-31 15:14:44 -07:00
|
|
|
// turned into an OS-defined Cocoa event, or otherwise needs AppKit
|
|
|
|
// processing. Doing otherwise risks doing too much work here, and
|
|
|
|
// preventing the event from being properly processed by the AppKit
|
|
|
|
// framework.
|
2014-06-02 14:43:31 -07:00
|
|
|
if ((attrs != kEventAttributeNone) || osCocoaEvent) {
|
2014-05-10 09:58:07 -07:00
|
|
|
// Since we can't process the next event here (while aMayWait is false),
|
|
|
|
// we want moreEvents to be false on return.
|
|
|
|
eventProcessed = false;
|
|
|
|
// This call to ReleaseEvent() matches a call to RetainEvent() in
|
|
|
|
// AcquireFirstMatchingEventInQueue() above.
|
|
|
|
ReleaseEvent(currentEvent);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// This call to RetainEvent() matches a call to ReleaseEvent() in
|
|
|
|
// RemoveEventFromQueue() below.
|
|
|
|
RetainEvent(currentEvent);
|
|
|
|
RemoveEventFromQueue(currentEventQueue, currentEvent);
|
|
|
|
SendEventToEventTarget(currentEvent, eventDispatcherTarget);
|
|
|
|
// This call to ReleaseEvent() matches a call to RetainEvent() in
|
|
|
|
// AcquireFirstMatchingEventInQueue() above.
|
|
|
|
ReleaseEvent(currentEvent);
|
|
|
|
eventProcessed = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
} while (mRunningEventLoop);
|
|
|
|
|
2014-05-10 09:58:07 -07:00
|
|
|
if (eventProcessed) {
|
|
|
|
moreEvents =
|
|
|
|
(AcquireFirstMatchingEventInQueue(currentEventQueue, 0, NULL,
|
|
|
|
kEventQueueOptionsNone) != NULL);
|
2007-09-19 12:17:06 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
mRunningEventLoop = wasRunningEventLoop;
|
|
|
|
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
|
2009-04-21 16:53:52 -07:00
|
|
|
if (!moreEvents) {
|
|
|
|
nsChildView::UpdateCurrentInputEventCount();
|
|
|
|
}
|
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
return moreEvents;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Run
|
|
|
|
//
|
2007-09-19 12:17:06 -07:00
|
|
|
// Overrides the base class's Run() method to call [NSApp run] (which spins
|
|
|
|
// the native run loop until the application quits). Since (unlike the base
|
|
|
|
// class's Run() method) we don't process any Gecko events here, they need
|
|
|
|
// to be processed elsewhere (in NativeEventCallback(), called from
|
|
|
|
// ProcessGeckoEvents()).
|
2007-03-22 10:30:00 -07:00
|
|
|
//
|
2014-10-10 08:00:29 -07:00
|
|
|
// Camino called [NSApp run] on its own (via NSApplicationMain()), and so
|
|
|
|
// didn't call nsAppShell::Run().
|
2007-03-22 10:30:00 -07:00
|
|
|
//
|
|
|
|
// public
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsAppShell::Run(void)
|
|
|
|
{
|
2007-09-19 12:17:06 -07:00
|
|
|
NS_ASSERTION(!mStarted, "nsAppShell::Run() called multiple times");
|
2014-01-15 13:09:41 -08:00
|
|
|
if (mStarted || mTerminated)
|
2007-09-19 12:17:06 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
2011-09-30 17:20:33 -07:00
|
|
|
mStarted = true;
|
2014-06-13 10:58:00 -07:00
|
|
|
|
|
|
|
AddScreenWakeLockListener();
|
|
|
|
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_TRY_ABORT([NSApp run]);
|
2007-09-19 12:17:06 -07:00
|
|
|
|
2014-06-13 10:58:00 -07:00
|
|
|
RemoveScreenWakeLockListener();
|
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsAppShell::Exit(void)
|
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
// This method is currently called more than once -- from (according to
|
|
|
|
// mento) an nsAppExitEvent dispatched by nsAppStartup::Quit() and from an
|
|
|
|
// XPCOM shutdown notification that nsBaseAppShell has registered to
|
|
|
|
// receive. So we need to ensure that multiple calls won't break anything.
|
|
|
|
// But we should also complain about it (since it isn't quite kosher).
|
2007-09-22 06:52:14 -07:00
|
|
|
if (mTerminated) {
|
|
|
|
NS_WARNING("nsAppShell::Exit() called redundantly");
|
2007-09-19 12:17:06 -07:00
|
|
|
return NS_OK;
|
2007-09-22 06:52:14 -07:00
|
|
|
}
|
2007-09-19 12:17:06 -07:00
|
|
|
|
2011-09-30 17:20:33 -07:00
|
|
|
mTerminated = true;
|
2007-09-19 12:17:06 -07:00
|
|
|
|
2012-10-15 05:38:34 -07:00
|
|
|
#ifndef __LP64__
|
2011-02-23 20:48:12 -08:00
|
|
|
TextInputHandler::RemovePluginKeyEventsHandler();
|
2009-09-30 21:15:05 -07:00
|
|
|
#endif
|
2008-06-30 09:30:22 -07:00
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
// Quoting from Apple's doc on the [NSApplication stop:] method (from their
|
|
|
|
// doc on the NSApplication class): "If this method is invoked during a
|
|
|
|
// modal event loop, it will break that loop but not the main event loop."
|
|
|
|
// nsAppShell::Exit() shouldn't be called from a modal event loop. So if
|
|
|
|
// it is we complain about it (to users of debug builds) and call [NSApp
|
|
|
|
// stop:] one extra time. (I'm not sure if modal event loops can be nested
|
|
|
|
// -- Apple's docs don't say one way or the other. But the return value
|
|
|
|
// of [NSApp _isRunningModal] doesn't change immediately after a call to
|
|
|
|
// [NSApp stop:], so we have to assume that one extra call to [NSApp stop:]
|
|
|
|
// will do the job.)
|
|
|
|
BOOL cocoaModal = [NSApp _isRunningModal];
|
|
|
|
NS_ASSERTION(!cocoaModal,
|
|
|
|
"Don't call nsAppShell::Exit() from a modal event loop!");
|
|
|
|
if (cocoaModal)
|
2012-07-30 07:20:58 -07:00
|
|
|
[NSApp stop:nullptr];
|
|
|
|
[NSApp stop:nullptr];
|
2007-09-19 12:17:06 -07:00
|
|
|
|
2009-06-17 08:30:46 -07:00
|
|
|
// A call to Exit() just after a call to ScheduleNativeEventCallback()
|
|
|
|
// prevents the (normally) matching call to ProcessGeckoEvents() from
|
|
|
|
// happening. If we've been called from ProcessGeckoEvents() (as usually
|
|
|
|
// happens), we take care of it there. But if we have an unbalanced call
|
|
|
|
// to ScheduleNativeEventCallback() and ProcessGeckoEvents() isn't on the
|
|
|
|
// stack, we need to take care of the problem here.
|
|
|
|
if (!mNativeEventCallbackDepth && mNativeEventScheduledDepth) {
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t releaseCount = PR_ATOMIC_SET(&mNativeEventScheduledDepth, 0);
|
2009-06-17 08:30:46 -07:00
|
|
|
while (releaseCount-- > 0)
|
|
|
|
NS_RELEASE_THIS();
|
|
|
|
}
|
|
|
|
|
2007-09-19 12:17:06 -07:00
|
|
|
return nsBaseAppShell::Exit();
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// OnProcessNextEvent
|
|
|
|
//
|
|
|
|
// This nsIThreadObserver method is called prior to processing an event.
|
|
|
|
// Set up an autorelease pool that will service any autoreleased Cocoa
|
|
|
|
// objects during this event. This includes native events processed by
|
|
|
|
// ProcessNextNativeEvent. The autorelease pool will be popped by
|
|
|
|
// AfterProcessNextEvent, it is important for these two methods to be
|
|
|
|
// tightly coupled.
|
|
|
|
//
|
|
|
|
// public
|
|
|
|
NS_IMETHODIMP
|
2011-09-28 23:19:26 -07:00
|
|
|
nsAppShell::OnProcessNextEvent(nsIThreadInternal *aThread, bool aMayWait,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aRecursionDepth)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(mAutoreleasePools,
|
|
|
|
"No stack on which to store autorelease pool");
|
|
|
|
|
|
|
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
::CFArrayAppendValue(mAutoreleasePools, pool);
|
|
|
|
|
|
|
|
return nsBaseAppShell::OnProcessNextEvent(aThread, aMayWait, aRecursionDepth);
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// AfterProcessNextEvent
|
|
|
|
//
|
|
|
|
// This nsIThreadObserver method is called after event processing is complete.
|
|
|
|
// The Cocoa implementation cleans up the autorelease pool create by the
|
|
|
|
// previous OnProcessNextEvent call.
|
|
|
|
//
|
|
|
|
// public
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsAppShell::AfterProcessNextEvent(nsIThreadInternal *aThread,
|
2013-10-23 05:01:20 -07:00
|
|
|
uint32_t aRecursionDepth,
|
|
|
|
bool aEventWasProcessed)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
CFIndex count = ::CFArrayGetCount(mAutoreleasePools);
|
|
|
|
|
|
|
|
NS_ASSERTION(mAutoreleasePools && count,
|
|
|
|
"Processed an event, but there's no autorelease pool?");
|
|
|
|
|
2007-09-27 15:46:23 -07:00
|
|
|
const NSAutoreleasePool* pool = static_cast<const NSAutoreleasePool*>
|
|
|
|
(::CFArrayGetValueAtIndex(mAutoreleasePools, count - 1));
|
2007-03-22 10:30:00 -07:00
|
|
|
::CFArrayRemoveValueAtIndex(mAutoreleasePools, count - 1);
|
|
|
|
[pool release];
|
|
|
|
|
2013-10-23 05:01:20 -07:00
|
|
|
return nsBaseAppShell::AfterProcessNextEvent(aThread, aRecursionDepth,
|
|
|
|
aEventWasProcessed);
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-03-26 20:42:57 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// AppShellDelegate implementation
|
|
|
|
|
2008-03-26 20:42:57 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
@implementation AppShellDelegate
|
|
|
|
// initWithAppShell:
|
|
|
|
//
|
|
|
|
// Constructs the AppShellDelegate object
|
|
|
|
- (id)initWithAppShell:(nsAppShell*)aAppShell
|
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if ((self = [self init])) {
|
|
|
|
mAppShell = aAppShell;
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
|
selector:@selector(applicationWillTerminate:)
|
|
|
|
name:NSApplicationWillTerminateNotification
|
|
|
|
object:NSApp];
|
2008-12-16 08:50:19 -08:00
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
|
selector:@selector(applicationDidBecomeActive:)
|
|
|
|
name:NSApplicationDidBecomeActiveNotification
|
|
|
|
object:NSApp];
|
2007-07-17 13:29:39 -07:00
|
|
|
[[NSDistributedNotificationCenter defaultCenter] addObserver:self
|
|
|
|
selector:@selector(beginMenuTracking:)
|
|
|
|
name:@"com.apple.HIToolbox.beginMenuTrackingNotification"
|
|
|
|
object:nil];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)dealloc
|
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
2007-07-17 13:29:39 -07:00
|
|
|
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
|
2007-03-22 10:30:00 -07:00
|
|
|
[super dealloc];
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// applicationWillTerminate:
|
|
|
|
//
|
|
|
|
// Notify the nsAppShell that native event processing should be discontinued.
|
|
|
|
- (void)applicationWillTerminate:(NSNotification*)aNotification
|
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
mAppShell->WillTerminate();
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-07-17 13:29:39 -07:00
|
|
|
|
2008-12-16 08:50:19 -08:00
|
|
|
// applicationDidBecomeActive
|
|
|
|
//
|
2011-07-20 17:33:16 -07:00
|
|
|
// Make sure TextInputHandler::sLastModifierState is updated when we become
|
|
|
|
// active (since we won't have received [ChildView flagsChanged:] messages
|
|
|
|
// while inactive).
|
2008-12-16 08:50:19 -08:00
|
|
|
- (void)applicationDidBecomeActive:(NSNotification*)aNotification
|
|
|
|
{
|
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
|
|
|
// [NSEvent modifierFlags] is valid on every kind of event, so we don't need
|
|
|
|
// to worry about getting an NSInternalInconsistencyException here.
|
|
|
|
NSEvent* currentEvent = [NSApp currentEvent];
|
|
|
|
if (currentEvent) {
|
2011-07-20 17:33:16 -07:00
|
|
|
TextInputHandler::sLastModifierState =
|
|
|
|
[currentEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
|
2008-12-16 08:50:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
|
|
|
}
|
|
|
|
|
2007-07-17 13:29:39 -07:00
|
|
|
// beginMenuTracking
|
|
|
|
//
|
|
|
|
// Roll up our context menu (if any) when some other app (or the OS) opens
|
|
|
|
// any sort of menu. But make sure we don't do this for notifications we
|
|
|
|
// send ourselves (whose 'sender' will be @"org.mozilla.gecko.PopupWindow").
|
|
|
|
- (void)beginMenuTracking:(NSNotification*)aNotification
|
|
|
|
{
|
2008-02-13 15:11:11 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-07-17 13:29:39 -07:00
|
|
|
NSString *sender = [aNotification object];
|
|
|
|
if (!sender || ![sender isEqualToString:@"org.mozilla.gecko.PopupWindow"]) {
|
2012-10-26 06:15:22 -07:00
|
|
|
nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
|
|
|
|
nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
|
|
|
|
if (rollupWidget)
|
2013-11-04 08:22:24 -08:00
|
|
|
rollupListener->Rollup(0, nullptr, nullptr);
|
2007-07-17 13:29:39 -07:00
|
|
|
}
|
2008-02-13 15:11:11 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-07-17 13:29:39 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
@end
|
2008-10-17 14:58:47 -07:00
|
|
|
|
2010-10-15 09:30:07 -07:00
|
|
|
// We hook terminate: in order to make OS-initiated termination work nicely
|
|
|
|
// with Gecko's shutdown sequence. (Two ways to trigger OS-initiated
|
|
|
|
// termination: 1) Quit from the Dock menu; 2) Log out from (or shut down)
|
|
|
|
// your computer while the browser is active.)
|
2008-10-17 14:58:47 -07:00
|
|
|
@interface NSApplication (MethodSwizzling)
|
2010-10-16 15:22:21 -07:00
|
|
|
- (void)nsAppShell_NSApplication_terminate:(id)sender;
|
2008-10-17 14:58:47 -07:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSApplication (MethodSwizzling)
|
|
|
|
|
2010-10-15 09:30:07 -07:00
|
|
|
// Called by the OS after [MacApplicationDelegate applicationShouldTerminate:]
|
|
|
|
// has returned NSTerminateNow. This method "subclasses" and replaces the
|
|
|
|
// OS's original implementation. The only thing the orginal method does which
|
|
|
|
// we need is that it posts NSApplicationWillTerminateNotification. Everything
|
|
|
|
// else is unneeded (because it's handled elsewhere), or actively interferes
|
|
|
|
// with Gecko's shutdown sequence. For example the original terminate: method
|
|
|
|
// causes the app to exit() inside [NSApp run] (called from nsAppShell::Run()
|
|
|
|
// above), which means that nothing runs after the call to nsAppStartup::Run()
|
|
|
|
// in XRE_Main(), which in particular means that ScopedXPCOMStartup's destructor
|
|
|
|
// and NS_ShutdownXPCOM() never get called.
|
2010-10-16 15:22:21 -07:00
|
|
|
- (void)nsAppShell_NSApplication_terminate:(id)sender
|
2010-10-15 09:30:07 -07:00
|
|
|
{
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationWillTerminateNotification
|
|
|
|
object:NSApp];
|
|
|
|
}
|
|
|
|
|
2008-10-17 14:58:47 -07:00
|
|
|
@end
|