Bug 531552: Force handling of at-launch open-url and open-file Apple Events to happen during command line construction so that we can put them on the command line and don't open unnecessary windows. r=benwa

This commit is contained in:
Josh Aas 2010-07-30 09:44:51 -04:00
parent 44b3560686
commit 6616e71c71
4 changed files with 107 additions and 11 deletions

View File

@ -64,6 +64,21 @@
#include "nsIStandaloneNativeMenu.h"
#include "nsILocalFileMac.h"
#include "nsString.h"
#include "nsCommandLineServiceMac.h"
class AutoAutoreleasePool {
public:
AutoAutoreleasePool()
{
mLocalPool = [[NSAutoreleasePool alloc] init];
}
~AutoAutoreleasePool()
{
[mLocalPool release];
}
private:
NSAutoreleasePool *mLocalPool;
};
@interface MacApplicationDelegate : NSObject
{
@ -92,7 +107,7 @@ SetupMacApplicationDelegate()
// this is called during startup, outside an event loop, and therefore
// needs an autorelease pool to avoid cocoa object leakage (bug 559075)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
AutoAutoreleasePool pool;
// This call makes it so that application:openFile: doesn't get bogus calls
// from Cocoa doing its own parsing of the argument string. And yes, we need
@ -104,8 +119,6 @@ SetupMacApplicationDelegate()
MacApplicationDelegate *delegate = [[MacApplicationDelegate alloc] init];
[NSApp setDelegate:delegate];
[pool release];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
@ -128,6 +141,11 @@ SetupMacApplicationDelegate()
forEventClass:'WWW!'
andEventID:'OURL'];
[aeMgr setEventHandler:self
andSelector:@selector(handleAppleEvent:withReplyEvent:)
forEventClass:kCoreEventClass
andEventID:kAEOpenDocuments];
if (![NSApp windowsMenu]) {
// If the application has a windows menu, it will keep it up to date and
// prepend the window list to the Dock menu automatically.
@ -148,6 +166,7 @@ SetupMacApplicationDelegate()
NSAppleEventManager *aeMgr = [NSAppleEventManager sharedAppleEventManager];
[aeMgr removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
[aeMgr removeEventHandlerForEventClass:'WWW!' andEventID:'OURL'];
[aeMgr removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEOpenDocuments];
[super dealloc];
NS_OBJC_END_TRY_ABORT_BLOCK;
@ -175,10 +194,20 @@ SetupMacApplicationDelegate()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
NSString *escapedPath = [filename stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL fileURLWithPath:filename];
if (!url)
return NO;
NSString *urlString = [url absoluteString];
if (!urlString)
return NO;
// Add the URL to any command line we're currently setting up.
if (CommandLineServiceMac::AddURLToCurrentCommandLine([urlString UTF8String]))
return YES;
nsCOMPtr<nsILocalFileMac> inFile;
nsresult rv = NS_NewLocalFileWithCFURL((CFURLRef)[NSURL URLWithString:escapedPath], PR_TRUE, getter_AddRefs(inFile));
nsresult rv = NS_NewLocalFileWithCFURL((CFURLRef)url, PR_TRUE, getter_AddRefs(inFile));
if (NS_FAILED(rv))
return NO;
@ -307,6 +336,8 @@ SetupMacApplicationDelegate()
if (!event)
return;
AutoAutoreleasePool pool;
if (([event eventClass] == kInternetEventClass && [event eventID] == kAEGetURL) ||
([event eventClass] == 'WWW!' && [event eventID] == 'OURL')) {
NSString* urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
@ -320,6 +351,10 @@ SetupMacApplicationDelegate()
return;
}
// Add the URL to any command line we're currently setting up.
if (CommandLineServiceMac::AddURLToCurrentCommandLine([urlString UTF8String]))
return;
nsCOMPtr<nsICommandLineRunner> cmdLine(do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
if (!cmdLine) {
NS_ERROR("Couldn't create command line!");
@ -335,6 +370,26 @@ SetupMacApplicationDelegate()
return;
rv = cmdLine->Run();
}
else if ([event eventClass] == kCoreEventClass && [event eventID] == kAEOpenDocuments) {
NSAppleEventDescriptor* fileListDescriptor = [event paramDescriptorForKeyword:keyDirectObject];
if (!fileListDescriptor)
return;
// Descriptor list indexing is one-based...
NSInteger numberOfFiles = [fileListDescriptor numberOfItems];
for (NSInteger i = 1; i <= numberOfFiles; i++) {
NSString* urlString = [[fileListDescriptor descriptorAtIndex:i] stringValue];
if (!urlString)
continue;
// We need a path, not a URL
NSURL* url = [NSURL URLWithString:urlString];
if (!url)
continue;
[self application:NSApp openFile:[url path]];
}
}
}
@end

View File

@ -3565,6 +3565,10 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
#endif
#ifdef XP_MACOSX
// Set up ability to respond to system (Apple) events. This must be
// done before setting up the command line service.
SetupMacApplicationDelegate();
// we re-initialize the command-line service and do appleevents munging
// after we are sure that we're not restarting
cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
@ -3575,9 +3579,6 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
rv = cmdLine->Init(gArgc, gArgv,
workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
NS_ENSURE_SUCCESS(rv, 1);
// Set up ability to respond to system (Apple) events.
SetupMacApplicationDelegate();
#endif
MOZ_SPLASHSCREEN_UPDATE(70);

View File

@ -51,6 +51,8 @@ static char** sArgs = NULL;
static int sArgsAllocated = 0;
static int sArgsUsed = 0;
static PRBool sBuildingCommandLine = PR_FALSE;
void AddToCommandLine(const char* inArgText)
{
if (sArgsUsed >= sArgsAllocated - 1) {
@ -81,6 +83,8 @@ void SetupMacCommandLine(int& argc, char**& argv, PRBool forRestart)
sArgs[0] = NULL;
sArgsUsed = 0;
sBuildingCommandLine = PR_TRUE;
// Copy args, stripping anything we don't want.
for (int arg = 0; arg < argc; arg++) {
char* flag = argv[arg];
@ -89,10 +93,27 @@ void SetupMacCommandLine(int& argc, char**& argv, PRBool forRestart)
AddToCommandLine(flag);
}
// Force processing of any pending Apple Events while we're building the
// command line. The handlers will append to the command line rather than
// act directly so there is no chance we'll process them during a XUL window
// load and accidentally open unnecessary windows and home pages.
const EventTypeSpec kAppleEventList[] = {
{ kEventClassAppleEvent, kEventAppleEvent },
};
EventRef carbonEvent;
while (::ReceiveNextEvent(GetEventTypeCount(kAppleEventList),
kAppleEventList,
kEventDurationNoWait,
PR_TRUE,
&carbonEvent) == noErr) {
::AEProcessEvent(carbonEvent);
::ReleaseEvent(carbonEvent);
}
// If the process will be relaunched, the child should be in the foreground
// if the parent is in the foreground. This will be communicated in a
// command-line argument to the child.
if (forRestart) {
// If the process will be relaunched, the child should be in the foreground
// if the parent is in the foreground. This will be communicated in a
// command-line argument to the child.
Boolean isForeground = false;
ProcessSerialNumber psnSelf, psnFront;
if (::GetCurrentProcess(&psnSelf) == noErr &&
@ -103,8 +124,22 @@ void SetupMacCommandLine(int& argc, char**& argv, PRBool forRestart)
}
}
sBuildingCommandLine = PR_FALSE;
argc = sArgsUsed;
argv = sArgs;
}
PRBool AddURLToCurrentCommandLine(const char* aURL)
{
if (!sBuildingCommandLine) {
return PR_FALSE;
}
AddToCommandLine("-url");
AddToCommandLine(aURL);
return PR_TRUE;
}
} // namespace CommandLineServiceMac

View File

@ -42,6 +42,11 @@
namespace CommandLineServiceMac {
void SetupMacCommandLine(int& argc, char**& argv, PRBool forRestart);
// Add a URL to the command line currently being set up via
// SetupMacCommandLine. Returns false if no command line is
// being set up or the addition fails for any other reason.
PRBool AddURLToCurrentCommandLine(const char* aURL);
}
#endif // nsCommandLineServiceMac_h_