mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-04 21:18:35 +00:00
Bug 1565597 - Mozilla Remoting implementation for macOS, r=mossop
Differential Revision: https://phabricator.services.mozilla.com/D56997 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
35f21af04d
commit
9da62d84ad
@ -3,11 +3,20 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#ifndef RemoteUtils_h__
|
#ifndef TOOLKIT_COMPONENTS_REMOTE_REMOTEUTILS_H_
|
||||||
#define RemoteUtils_h__
|
#define TOOLKIT_COMPONENTS_REMOTE_REMOTEUTILS_H_
|
||||||
|
|
||||||
|
#include "nsString.h"
|
||||||
|
|
||||||
|
#if defined XP_WIN || defined XP_MACOSX
|
||||||
|
static void BuildClassName(const char* aProgram, const char* aProfile,
|
||||||
|
nsString& aClassName) {
|
||||||
|
aClassName.AppendPrintf("Mozilla_%s_%s_RemoteWindow", aProgram, aProfile);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
char* ConstructCommandLine(int32_t argc, char** argv,
|
char* ConstructCommandLine(int32_t argc, char** argv,
|
||||||
const char* aDesktopStartupID,
|
const char* aDesktopStartupID,
|
||||||
int* aCommandLineLength);
|
int* aCommandLineLength);
|
||||||
|
|
||||||
#endif // RemoteUtils_h__
|
#endif // TOOLKIT_COMPONENTS_REMOTE_REMOTEUTILS_H_
|
@ -32,8 +32,14 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||||||
'nsWinRemoteClient.cpp',
|
'nsWinRemoteClient.cpp',
|
||||||
'nsWinRemoteServer.cpp',
|
'nsWinRemoteServer.cpp',
|
||||||
]
|
]
|
||||||
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||||
|
SOURCES += [
|
||||||
|
'nsMacRemoteClient.mm',
|
||||||
|
'nsMacRemoteServer.mm',
|
||||||
|
]
|
||||||
|
|
||||||
LOCAL_INCLUDES += [
|
LOCAL_INCLUDES += [
|
||||||
'../../profile',
|
'../../profile',
|
||||||
|
'../../xre',
|
||||||
]
|
]
|
||||||
FINAL_LIBRARY = 'xul'
|
FINAL_LIBRARY = 'xul'
|
||||||
|
28
toolkit/components/remote/nsMacRemoteClient.h
Normal file
28
toolkit/components/remote/nsMacRemoteClient.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
||||||
|
*/
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
#ifndef TOOLKIT_COMPONENTS_REMOTE_NSMACREMOTECLIENT_H_
|
||||||
|
#define TOOLKIT_COMPONENTS_REMOTE_NSMACREMOTECLIENT_H_
|
||||||
|
|
||||||
|
#import <CoreFoundation/CoreFoundation.h>
|
||||||
|
|
||||||
|
#include "nscore.h"
|
||||||
|
#include "nsRemoteClient.h"
|
||||||
|
|
||||||
|
class nsMacRemoteClient : public nsRemoteClient {
|
||||||
|
public:
|
||||||
|
virtual ~nsMacRemoteClient() = default;
|
||||||
|
|
||||||
|
nsresult Init() override;
|
||||||
|
|
||||||
|
nsresult SendCommandLine(const char* aProgram, const char* aProfile,
|
||||||
|
int32_t argc, char** argv,
|
||||||
|
const char* aDesktopStartupID, char** aResponse,
|
||||||
|
bool* aSucceeded) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TOOLKIT_COMPONENTS_REMOTE_NSMACREMOTECLIENT_H_
|
62
toolkit/components/remote/nsMacRemoteClient.mm
Normal file
62
toolkit/components/remote/nsMacRemoteClient.mm
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
||||||
|
*/
|
||||||
|
/* 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 <CoreFoundation/CoreFoundation.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#include "MacAutoreleasePool.h"
|
||||||
|
#include "nsMacRemoteClient.h"
|
||||||
|
#include "RemoteUtils.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
|
||||||
|
nsresult nsMacRemoteClient::Init() { return NS_OK; }
|
||||||
|
|
||||||
|
nsresult nsMacRemoteClient::SendCommandLine(const char* aProgram, const char* aProfile,
|
||||||
|
int32_t argc, char** argv,
|
||||||
|
const char* aDesktopStartupID, char** aResponse,
|
||||||
|
bool* aSucceeded) {
|
||||||
|
mozilla::MacAutoreleasePool pool;
|
||||||
|
|
||||||
|
*aSucceeded = false;
|
||||||
|
|
||||||
|
nsString className;
|
||||||
|
BuildClassName(aProgram, aProfile, className);
|
||||||
|
NSString* serverNameString =
|
||||||
|
[NSString stringWithCharacters:reinterpret_cast<const unichar*>(className.get())
|
||||||
|
length:className.Length()];
|
||||||
|
|
||||||
|
CFMessagePortRef messageServer = CFMessagePortCreateRemote(0, (CFStringRef)serverNameString);
|
||||||
|
|
||||||
|
if (messageServer) {
|
||||||
|
// Getting current process directory
|
||||||
|
char cwdPtr[MAXPATHLEN + 1];
|
||||||
|
getcwd(cwdPtr, MAXPATHLEN + 1);
|
||||||
|
|
||||||
|
NSMutableArray* argumentsArray = [NSMutableArray array];
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
NSString* argument = [NSString stringWithUTF8String:argv[i]];
|
||||||
|
[argumentsArray addObject:argument];
|
||||||
|
}
|
||||||
|
NSDictionary* dict = @{@"args" : argumentsArray};
|
||||||
|
|
||||||
|
NSData* data = [NSKeyedArchiver archivedDataWithRootObject:dict];
|
||||||
|
|
||||||
|
CFMessagePortSendRequest(messageServer, 0, (CFDataRef)data, 10.0, 0.0, NULL, NULL);
|
||||||
|
|
||||||
|
CFMessagePortInvalidate(messageServer);
|
||||||
|
CFRelease(messageServer);
|
||||||
|
*aSucceeded = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Remote Server not found. Doing nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
30
toolkit/components/remote/nsMacRemoteServer.h
Normal file
30
toolkit/components/remote/nsMacRemoteServer.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/* -*- 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/. */
|
||||||
|
|
||||||
|
#ifndef TOOLKIT_COMPONENTS_REMOTE_NSMACREMOTESERVER_H_
|
||||||
|
#define TOOLKIT_COMPONENTS_REMOTE_NSMACREMOTESERVER_H_
|
||||||
|
|
||||||
|
#import <CoreFoundation/CoreFoundation.h>
|
||||||
|
|
||||||
|
#include "nsRemoteServer.h"
|
||||||
|
|
||||||
|
class nsMacRemoteServer final : public nsRemoteServer {
|
||||||
|
public:
|
||||||
|
nsMacRemoteServer() = default;
|
||||||
|
~nsMacRemoteServer() override { Shutdown(); }
|
||||||
|
|
||||||
|
nsresult Startup(const char* aAppName, const char* aProfileName) override;
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
void HandleCommandLine(CFDataRef aData);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CFRunLoopSourceRef mRunLoopSource;
|
||||||
|
CFMessagePortRef mMessageServer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TOOLKIT_COMPONENTS_REMOTE_NSMACREMOTESERVER_H_
|
134
toolkit/components/remote/nsMacRemoteServer.mm
Normal file
134
toolkit/components/remote/nsMacRemoteServer.mm
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/* -*- 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;
|
||||||
|
}
|
||||||
|
}
|
@ -5,8 +5,8 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#ifndef nsRemoteClient_h__
|
#ifndef TOOLKIT_COMPONENTS_REMOTE_NSREMOTECLIENT_H_
|
||||||
#define nsRemoteClient_h__
|
#define TOOLKIT_COMPONENTS_REMOTE_NSREMOTECLIENT_H_
|
||||||
|
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
|
|
||||||
@ -59,4 +59,4 @@ class nsRemoteClient {
|
|||||||
char** aResponse, bool* aSucceeded) = 0;
|
char** aResponse, bool* aSucceeded) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsRemoteClient_h__
|
#endif // TOOLKIT_COMPONENTS_REMOTE_NSREMOTECLIENT_H_
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
#elif defined(XP_WIN)
|
#elif defined(XP_WIN)
|
||||||
# include "nsWinRemoteServer.h"
|
# include "nsWinRemoteServer.h"
|
||||||
# include "nsWinRemoteClient.h"
|
# include "nsWinRemoteClient.h"
|
||||||
|
#elif defined(XP_DARWIN)
|
||||||
|
# include "nsMacRemoteServer.h"
|
||||||
|
# include "nsMacRemoteClient.h"
|
||||||
#endif
|
#endif
|
||||||
#include "nsRemoteService.h"
|
#include "nsRemoteService.h"
|
||||||
|
|
||||||
@ -107,6 +110,8 @@ RemoteResult nsRemoteService::StartClient(const char* aDesktopStartupID) {
|
|||||||
}
|
}
|
||||||
#elif defined(XP_WIN)
|
#elif defined(XP_WIN)
|
||||||
client = new nsWinRemoteClient();
|
client = new nsWinRemoteClient();
|
||||||
|
#elif defined(XP_DARWIN)
|
||||||
|
client = new nsMacRemoteClient();
|
||||||
#else
|
#else
|
||||||
return REMOTE_NOT_FOUND;
|
return REMOTE_NOT_FOUND;
|
||||||
#endif
|
#endif
|
||||||
@ -154,6 +159,8 @@ void nsRemoteService::StartupServer() {
|
|||||||
}
|
}
|
||||||
#elif defined(XP_WIN)
|
#elif defined(XP_WIN)
|
||||||
mRemoteServer = MakeUnique<nsWinRemoteServer>();
|
mRemoteServer = MakeUnique<nsWinRemoteServer>();
|
||||||
|
#elif defined(XP_DARWIN)
|
||||||
|
mRemoteServer = MakeUnique<nsMacRemoteServer>();
|
||||||
#else
|
#else
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#ifndef __nsRemoteService_h__
|
#ifndef TOOLKIT_COMPONENTS_REMOTE_NSREMOTESERVER_H_
|
||||||
#define __nsRemoteService_h__
|
#define TOOLKIT_COMPONENTS_REMOTE_NSREMOTESERVER_H_
|
||||||
|
|
||||||
#include "nsRemoteServer.h"
|
#include "nsRemoteServer.h"
|
||||||
#include "nsIObserver.h"
|
#include "nsIObserver.h"
|
||||||
@ -46,4 +46,4 @@ class nsRemoteService final : public nsIObserver {
|
|||||||
nsCString mProfile;
|
nsCString mProfile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __nsRemoteService_h__
|
#endif // TOOLKIT_COMPONENTS_REMOTE_NSREMOTESERVER_H_
|
||||||
|
@ -6,9 +6,8 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nsWinRemoteClient.h"
|
#include "nsWinRemoteClient.h"
|
||||||
#include "nsWinRemoteUtils.h"
|
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include "RemoteUtils.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
|
@ -11,10 +11,6 @@
|
|||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
#include "nsRemoteClient.h"
|
#include "nsRemoteClient.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* Pure-virtual common base class for remoting implementations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class nsWinRemoteClient : public nsRemoteClient {
|
class nsWinRemoteClient : public nsRemoteClient {
|
||||||
public:
|
public:
|
||||||
virtual ~nsWinRemoteClient() = default;
|
virtual ~nsWinRemoteClient() = default;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nsWinRemoteServer.h"
|
#include "nsWinRemoteServer.h"
|
||||||
#include "nsWinRemoteUtils.h"
|
#include "RemoteUtils.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsXPCOM.h"
|
#include "nsXPCOM.h"
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
||||||
*/
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#ifndef nsWinRemoteUtils_h__
|
|
||||||
#define nsWinRemoteUtils_h__
|
|
||||||
|
|
||||||
#include "nsString.h"
|
|
||||||
|
|
||||||
static void BuildClassName(const char* aProgram, const char* aProfile,
|
|
||||||
nsString& aClassName) {
|
|
||||||
aClassName.AppendPrintf("Mozilla_%s_%s_RemoteWindow", aProgram, aProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // nsWinRemoteUtils_h__
|
|
@ -1763,7 +1763,7 @@ with only_when(compile_environment & target_is_windows):
|
|||||||
|
|
||||||
@depends(toolkit)
|
@depends(toolkit)
|
||||||
def has_remote(toolkit):
|
def has_remote(toolkit):
|
||||||
if toolkit in ('gtk', 'windows'):
|
if toolkit in ('gtk', 'windows', 'cocoa'):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
set_config('MOZ_HAS_REMOTE', has_remote)
|
set_config('MOZ_HAS_REMOTE', has_remote)
|
||||||
|
@ -50,61 +50,6 @@ nsresult GetNativeWindowPointerFromDOMWindow(mozIDOMWindowProxy* a_window,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Essentially this notification handler implements the
|
|
||||||
// "Mozilla remote" functionality on Mac, handing command line arguments (passed
|
|
||||||
// to a newly launched process) to another copy of the current process that was
|
|
||||||
// already running (which had registered the handler for this notification). All
|
|
||||||
// other new copies just broadcast this notification and quit (unless -no-remote
|
|
||||||
// was specified in either of these processes), making the original process handle
|
|
||||||
// the arguments passed to this handler.
|
|
||||||
void remoteClientNotificationCallback(CFNotificationCenterRef aCenter, void* aObserver,
|
|
||||||
CFStringRef aName, const void* aObject,
|
|
||||||
CFDictionaryRef aUserInfo) {
|
|
||||||
// Autorelease pool to prevent memory leaks, in case there is no outer pool.
|
|
||||||
mozilla::MacAutoreleasePool pool;
|
|
||||||
NSDictionary* userInfoDict = (__bridge NSDictionary*)aUserInfo;
|
|
||||||
if (userInfoDict && [userInfoDict objectForKey:@"commandLineArgs"] &&
|
|
||||||
[userInfoDict objectForKey:@"senderPath"]) {
|
|
||||||
NSString* senderPath = [userInfoDict objectForKey:@"senderPath"];
|
|
||||||
if (![senderPath isEqual:[[NSBundle mainBundle] bundlePath]]) {
|
|
||||||
// The caller is not the process at the same path as we are at. Skipping.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSArray* args = [userInfoDict objectForKey:@"commandLineArgs"];
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're not currently passing the working dir as third argument because it
|
|
||||||
// does not appear to be required.
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class nsNativeAppSupportCocoa : public nsNativeAppSupportBase {
|
class nsNativeAppSupportCocoa : public nsNativeAppSupportBase {
|
||||||
public:
|
public:
|
||||||
nsNativeAppSupportCocoa() : mCanShowUI(false) {}
|
nsNativeAppSupportCocoa() : mCanShowUI(false) {}
|
||||||
@ -141,121 +86,6 @@ NS_IMETHODIMP nsNativeAppSupportCocoa::Start(bool* _retval) {
|
|||||||
|
|
||||||
*_retval = true;
|
*_retval = true;
|
||||||
|
|
||||||
// Here are the "special" CLI arguments that we can expect to be passed that
|
|
||||||
// should alter the default "hand args list to remote process and quit" algorithm:
|
|
||||||
// -headless : was already handled on macOS (allowing running multiple instances
|
|
||||||
// of the app), meaning this patch shouldn't break it.
|
|
||||||
// -no-remote : should always proceed, creating a second instance (which will
|
|
||||||
// fail on macOS, showing a MessageBox "Only one instance can be run at a time",
|
|
||||||
// unless a different profile dir path is specified).
|
|
||||||
// The rest of the arguments should be either passed on to
|
|
||||||
// the original running process (exiting the current process), or be processed by
|
|
||||||
// the current process (if -no-remote is specified).
|
|
||||||
|
|
||||||
mozilla::MacAutoreleasePool pool;
|
|
||||||
|
|
||||||
NSArray* arguments = [[NSProcessInfo processInfo] arguments];
|
|
||||||
BOOL shallProceedLikeNoRemote = NO;
|
|
||||||
for (NSString* arg in arguments) {
|
|
||||||
if ([arg isEqualToString:@"-no-remote"] || [arg isEqualToString:@"--no-remote"] ||
|
|
||||||
[arg isEqualToString:@"-headless"] || [arg isEqualToString:@"--headless"] ||
|
|
||||||
[arg isEqualToString:@"-createProfile"] || [arg isEqualToString:@"--createProfile"]) {
|
|
||||||
shallProceedLikeNoRemote = YES;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL mozillaRestarting = NO;
|
|
||||||
if ([[[[NSProcessInfo processInfo] environment] objectForKey:@"MOZ_APP_RESTART"]
|
|
||||||
isEqualToString:@"1"]) {
|
|
||||||
// Update process completed or restarting the app for another reason.
|
|
||||||
// Triggered by an old instance that just quit.
|
|
||||||
mozillaRestarting = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apart from -no-remote, the user can specify an env variable
|
|
||||||
// MOZ_NO_REMOTE=1, which makes it behave the same way.
|
|
||||||
// Also, to make sure the tests do not break,
|
|
||||||
// if env var MOZ_TEST_PROCESS_UPDATES is present, it means the test is running.
|
|
||||||
// We should proceed as if -no-remote had been specified.
|
|
||||||
if (shallProceedLikeNoRemote == NO) {
|
|
||||||
NSDictionary* environmentVariables = [[NSProcessInfo processInfo] environment];
|
|
||||||
for (NSString* key in [environmentVariables allKeys]) {
|
|
||||||
if ([key isEqualToString:@"MOZ_NO_REMOTE"] &&
|
|
||||||
[environmentVariables[key] isEqualToString:@"1"]) {
|
|
||||||
shallProceedLikeNoRemote = YES;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we have handled no-remote-like arguments, at this point:
|
|
||||||
// 1) Either only the first instance of the process has been launched in any way
|
|
||||||
// (.app double click, "open", "open -n", invoking executable in Terminal, etc.
|
|
||||||
// 2) Or the process has been launched with a "macos single instance" mechanism
|
|
||||||
// override (using "open -n" OR directly by invoking the executable in Terminal
|
|
||||||
// instead of clicking the .app bundle's icon, etc.).
|
|
||||||
|
|
||||||
// So, let's check if this is the first instance ever of the process for the
|
|
||||||
// current user.
|
|
||||||
NSString* notificationName = [[[NSBundle mainBundle] bundleIdentifier]
|
|
||||||
stringByAppendingString:@".distributedNotification.commandLineArgs"];
|
|
||||||
|
|
||||||
BOOL runningInstanceFound = NO;
|
|
||||||
if (!shallProceedLikeNoRemote) {
|
|
||||||
// We check for other running instances only if -no-remote was not specified.
|
|
||||||
// The check is needed so the marAppApplyUpdateSuccess.js test doesn't fail on next call.
|
|
||||||
NSArray* appsWithMatchingId = [NSRunningApplication
|
|
||||||
runningApplicationsWithBundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]];
|
|
||||||
NSString* currentAppBundlePath = [[NSBundle mainBundle] bundlePath];
|
|
||||||
NSRunningApplication* currentApp = [NSRunningApplication currentApplication];
|
|
||||||
for (NSRunningApplication* app in appsWithMatchingId) {
|
|
||||||
if ([currentAppBundlePath isEqual:[[app bundleURL] path]] && ![currentApp isEqual:app]) {
|
|
||||||
runningInstanceFound = YES;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!shallProceedLikeNoRemote && !mozillaRestarting && runningInstanceFound) {
|
|
||||||
// There is another instance of this app already running!
|
|
||||||
NSArray* arguments = [[NSProcessInfo processInfo] arguments];
|
|
||||||
NSString* senderPath = [[NSBundle mainBundle] bundlePath];
|
|
||||||
CFDictionaryRef userInfoDict =
|
|
||||||
(__bridge CFDictionaryRef) @{@"commandLineArgs" : arguments, @"senderPath" : senderPath};
|
|
||||||
|
|
||||||
// This code is shared between Firefox, Thunderbird and other Mozilla products.
|
|
||||||
// So we need a notification name that is unique to the product, so we
|
|
||||||
// do not send a notification to Firefox from Thunderbird and so on. I am using
|
|
||||||
// bundle Id (assuming all Mozilla products come wrapped in .app bundles) -
|
|
||||||
// it should be unique
|
|
||||||
// (e.g., org.mozilla.firefox.distributedNotification.commandLineArgs for Firefox).
|
|
||||||
// We also need to make sure the notifications are "local" to the current user,
|
|
||||||
// so we do not pass it on to perhaps another running Thunderbird by another
|
|
||||||
// logged in user. Distributed notifications is the best candidate
|
|
||||||
// (while darwin notifications ignore the user context).
|
|
||||||
CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),
|
|
||||||
(__bridge CFStringRef)notificationName, NULL, userInfoDict,
|
|
||||||
true);
|
|
||||||
|
|
||||||
// Do not continue start up sequence for this process - just self-terminate,
|
|
||||||
// we already passed the arguments on to the original instance of the process.
|
|
||||||
*_retval = false;
|
|
||||||
} else {
|
|
||||||
// This is the first instance ever (or launched as -no-remote)!
|
|
||||||
// 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.
|
|
||||||
CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), NULL,
|
|
||||||
remoteClientNotificationCallback,
|
|
||||||
(__bridge CFStringRef)notificationName, NULL,
|
|
||||||
CFNotificationSuspensionBehaviorDeliverImmediately);
|
|
||||||
|
|
||||||
// Continue the start up sequence of this process.
|
|
||||||
*_retval = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user