1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #import <Cocoa/Cocoa.h>
9 #import <CoreServices/CoreServices.h>
11 #include "MacAutoreleasePool.h"
13 #include "nsIComponentManager.h"
14 #include "nsIServiceManager.h"
15 #include "nsIWindowMediator.h"
16 #include "nsIWidget.h"
17 #include "nsICommandLineRunner.h"
18 #include "nsICommandLine.h"
19 #include "nsCommandLine.h"
20 #include "nsIDocShell.h"
21 #include "nsMacRemoteServer.h"
23 #include "RemoteUtils.h"
25 CFDataRef messageServerCallback(CFMessagePortRef aLocal, int32_t aMsgid,
26 CFDataRef aData, void* aInfo) {
27 // One of the clients submitted a structure.
28 static_cast<nsMacRemoteServer*>(aInfo)->HandleCommandLine(aData);
33 // aData contains serialized Dictionary, which in turn contains command line
35 void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
36 mozilla::MacAutoreleasePool pool;
40 [NSKeyedUnarchiver unarchiveObjectWithData:(NSData*)aData];
41 if (dict && [dict isKindOfClass:[NSDictionary class]]) {
42 NSArray* args = dict[@"args"];
44 NS_ERROR("Wrong parameters passed to the Remote Server");
48 nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
50 // Converting Objective-C array into a C array,
51 // which nsICommandLineRunner understands.
52 int argc = [args count];
53 const char** argv = new const char*[argc];
54 for (int i = 0; i < argc; i++) {
55 const char* arg = [[args objectAtIndex:i] UTF8String];
60 cmdLine->Init(argc, argv, nullptr, nsICommandLine::STATE_REMOTE_AUTO);
62 // Cleaning up C array.
66 NS_ERROR("Error initializing command line.");
70 // Processing the command line, passed from a remote instance
71 // in the current instance.
74 NSNumber* raise = dict[@"raise"];
75 if (!raise || [raise boolValue]) {
76 // Activating the application brings the most recent window to the
78 ProcessSerialNumber psn;
79 if (::GetCurrentProcess(&psn) == noErr) {
80 ::SetFrontProcess(&psn);
87 nsresult nsMacRemoteServer::Startup(const char* aAppName,
88 const char* aProfileName) {
89 // This is the first instance ever.
90 // Let's register a notification listener here,
91 // In case future instances would want to notify us about command line
92 // arguments passed to them. Note, that if mozilla process is restarting, we
93 // still need to register for notifications.
95 mozilla::MacAutoreleasePool pool;
98 BuildClassName(aAppName, aProfileName, className);
100 NSString* serverNameString = [NSString
101 stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
102 length:className.Length()];
104 CFMessagePortContext context;
105 context.copyDescription = NULL;
107 context.release = NULL;
108 context.retain = NULL;
109 context.version = NULL;
111 CFMessagePortCreateLocal(NULL, (CFStringRef)serverNameString,
112 messageServerCallback, &context, NULL);
113 if (!mMessageServer) {
114 return NS_ERROR_FAILURE;
116 mRunLoopSource = CFMessagePortCreateRunLoopSource(NULL, mMessageServer, 0);
117 if (!mRunLoopSource) {
118 CFRelease(mMessageServer);
119 mMessageServer = NULL;
120 return NS_ERROR_FAILURE;
122 CFRunLoopRef runLoop = CFRunLoopGetMain();
123 CFRunLoopAddSource(runLoop, mRunLoopSource, kCFRunLoopDefaultMode);
128 void nsMacRemoteServer::Shutdown() {
129 // 1) Invalidate server connection
130 if (mMessageServer) {
131 CFMessagePortInvalidate(mMessageServer);
134 // 2) Release run loop source
135 if (mRunLoopSource) {
136 CFRelease(mRunLoopSource);
137 mRunLoopSource = NULL;
140 // 3) Release server connection
141 if (mMessageServer) {
142 CFRelease(mMessageServer);
143 mMessageServer = NULL;