1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=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 <Cocoa/Cocoa.h>
#import <CoreServices/CoreServices.h>
#include "MacAutoreleasePool.h"
#include "nsCOMPtr.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIWindowMediator.h"
#include "nsIWidget.h"
#include "nsICommandLineRunner.h"
#include "nsICommandLine.h"
#include "nsCommandLine.h"
#include "nsIDocShell.h"
#include "nsMacRemoteServer.h"
#include "nsXPCOM.h"
#include "RemoteUtils.h"
CFDataRef messageServerCallback(CFMessagePortRef aLocal, int32_t aMsgid,
CFDataRef aData, void* aInfo) {
// One of the clients submitted a structure.
static_cast<nsMacRemoteServer*>(aInfo)->HandleCommandLine(aData);
return NULL;
}
// aData contains serialized Dictionary, which in turn contains command line
// arguments
void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
mozilla::MacAutoreleasePool pool;
if (aData) {
NSDictionary* dict =
[NSKeyedUnarchiver unarchiveObjectWithData:(NSData*)aData];
if (dict && [dict isKindOfClass:[NSDictionary class]]) {
NSArray* args = dict[@"args"];
if (!args) {
NS_ERROR("Wrong parameters passed to the Remote Server");
return;
}
nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
// Converting Objective-C array into a C array,
// which nsICommandLineRunner understands.
int argc = [args count];
const char** argv = new const char*[argc];
for (int i = 0; i < argc; i++) {
const char* arg = [[args objectAtIndex:i] UTF8String];
argv[i] = arg;
}
nsresult rv =
cmdLine->Init(argc, argv, nullptr, nsICommandLine::STATE_REMOTE_AUTO);
// Cleaning up C array.
delete[] argv;
if (NS_FAILED(rv)) {
NS_ERROR("Error initializing command line.");
return;
}
// Processing the command line, passed from a remote instance
// in the current instance.
cmdLine->Run();
// And bring the app's window to front.
[[NSRunningApplication currentApplication]
activateWithOptions:NSApplicationActivateIgnoringOtherApps];
}
}
}
nsresult nsMacRemoteServer::Startup(const char* aAppName,
const char* aProfileName) {
// This is the first instance ever.
// Let's register a notification listener here,
// In case future instances would want to notify us about command line
// arguments passed to them. Note, that if mozilla process is restarting, we
// still need to register for notifications.
mozilla::MacAutoreleasePool pool;
nsString className;
BuildClassName(aAppName, aProfileName, className);
NSString* serverNameString = [NSString
stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
length:className.Length()];
CFMessagePortContext context;
context.copyDescription = NULL;
context.info = this;
context.release = NULL;
context.retain = NULL;
context.version = NULL;
mMessageServer =
CFMessagePortCreateLocal(NULL, (CFStringRef)serverNameString,
messageServerCallback, &context, NULL);
if (!mMessageServer) {
return NS_ERROR_FAILURE;
}
mRunLoopSource = CFMessagePortCreateRunLoopSource(NULL, mMessageServer, 0);
if (!mRunLoopSource) {
CFRelease(mMessageServer);
mMessageServer = NULL;
return NS_ERROR_FAILURE;
}
CFRunLoopRef runLoop = CFRunLoopGetMain();
CFRunLoopAddSource(runLoop, mRunLoopSource, kCFRunLoopDefaultMode);
return NS_OK;
}
void nsMacRemoteServer::Shutdown() {
// 1) Invalidate server connection
if (mMessageServer) {
CFMessagePortInvalidate(mMessageServer);
}
// 2) Release run loop source
if (mRunLoopSource) {
CFRelease(mRunLoopSource);
mRunLoopSource = NULL;
}
// 3) Release server connection
if (mMessageServer) {
CFRelease(mMessageServer);
mMessageServer = NULL;
}
}
|