Bug 1943650 - Command-line --help output misformatted after --dbus-service. r=emilio
[gecko.git] / toolkit / components / remote / nsMacRemoteServer.mm
blobd43e03a5f56519cfeac94d2da7114113afb26d79
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
3  */
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"
12 #include "nsCOMPtr.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"
22 #include "nsXPCOM.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);
30   return NULL;
33 // aData contains serialized Dictionary, which in turn contains command line
34 // arguments
35 void nsMacRemoteServer::HandleCommandLine(CFDataRef aData) {
36   mozilla::MacAutoreleasePool pool;
38   if (aData) {
39     NSDictionary* dict =
40         [NSKeyedUnarchiver unarchiveObjectWithData:(NSData*)aData];
41     if (dict && [dict isKindOfClass:[NSDictionary class]]) {
42       NSArray* args = dict[@"args"];
43       if (!args) {
44         NS_ERROR("Wrong parameters passed to the Remote Server");
45         return;
46       }
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];
56         argv[i] = arg;
57       }
59       nsresult rv =
60           cmdLine->Init(argc, argv, nullptr, nsICommandLine::STATE_REMOTE_AUTO);
62       // Cleaning up C array.
63       delete[] argv;
65       if (NS_FAILED(rv)) {
66         NS_ERROR("Error initializing command line.");
67         return;
68       }
70       // Processing the command line, passed from a remote instance
71       // in the current instance.
72       cmdLine->Run();
74       NSNumber* raise = dict[@"raise"];
75       if (!raise || [raise boolValue]) {
76         // Activating the application brings the most recent window to the
77         // foreground.
78         ProcessSerialNumber psn;
79         if (::GetCurrentProcess(&psn) == noErr) {
80           ::SetFrontProcess(&psn);
81         }
82       }
83     }
84   }
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;
97   nsString className;
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;
106   context.info = this;
107   context.release = NULL;
108   context.retain = NULL;
109   context.version = NULL;
110   mMessageServer =
111       CFMessagePortCreateLocal(NULL, (CFStringRef)serverNameString,
112                                messageServerCallback, &context, NULL);
113   if (!mMessageServer) {
114     return NS_ERROR_FAILURE;
115   }
116   mRunLoopSource = CFMessagePortCreateRunLoopSource(NULL, mMessageServer, 0);
117   if (!mRunLoopSource) {
118     CFRelease(mMessageServer);
119     mMessageServer = NULL;
120     return NS_ERROR_FAILURE;
121   }
122   CFRunLoopRef runLoop = CFRunLoopGetMain();
123   CFRunLoopAddSource(runLoop, mRunLoopSource, kCFRunLoopDefaultMode);
125   return NS_OK;
128 void nsMacRemoteServer::Shutdown() {
129   // 1) Invalidate server connection
130   if (mMessageServer) {
131     CFMessagePortInvalidate(mMessageServer);
132   }
134   // 2) Release run loop source
135   if (mRunLoopSource) {
136     CFRelease(mRunLoopSource);
137     mRunLoopSource = NULL;
138   }
140   // 3) Release server connection
141   if (mMessageServer) {
142     CFRelease(mMessageServer);
143     mMessageServer = NULL;
144   }