It creates new nsRemoteService instance which is parent (proxy) class which is registered as global nsIRemoteService. It provides basic functionality (watch observer for shutdown, launch firefox instance by HandleCommandLine()) for child services which are system specific. nsDBusRemoteService listens on DBus interface and it's available on DBus enabled systems only. nsGtkRemoteService is the former one based on X window propery mechanism. MozReview-Commit-ID: GHpXdjstwyY
243 lines
6.8 KiB
C++
243 lines
6.8 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=2:tabstop=8:
|
|
*/
|
|
/* 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/. */
|
|
|
|
#include "nsGTKRemoteService.h"
|
|
#include "nsDBusRemoteService.h"
|
|
#include "nsRemoteService.h"
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <gdk/gdk.h>
|
|
#include <gdk/gdkx.h>
|
|
|
|
#include "nsIServiceManager.h"
|
|
#include "nsIAppShellService.h"
|
|
#include "nsAppShellCID.h"
|
|
#include "nsInterfaceHashtable.h"
|
|
#include "mozilla/ModuleUtils.h"
|
|
#include "nsIWeakReference.h"
|
|
#include "nsGTKToolkit.h"
|
|
#include "nsICommandLineRunner.h"
|
|
#include "nsICommandLine.h"
|
|
#include "nsString.h"
|
|
#include "nsIFile.h"
|
|
|
|
NS_IMPL_ISUPPORTS(nsRemoteService,
|
|
nsIRemoteService,
|
|
nsIObserver)
|
|
|
|
NS_IMETHODIMP
|
|
nsRemoteService::Startup(const char* aAppName, const char* aProfileName)
|
|
{
|
|
#if defined(MOZ_ENABLE_DBUS)
|
|
nsresult rv;
|
|
mDBusRemoteService = new nsDBusRemoteService();
|
|
rv = mDBusRemoteService->Startup(aAppName, aProfileName);
|
|
if (NS_FAILED(rv)) {
|
|
mDBusRemoteService = nullptr;
|
|
}
|
|
#endif
|
|
|
|
if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
|
|
mGtkRemoteService = new nsGTKRemoteService();
|
|
mGtkRemoteService->Startup(aAppName, aProfileName);
|
|
}
|
|
|
|
if (!mDBusRemoteService && !mGtkRemoteService)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1"));
|
|
if (obs) {
|
|
obs->AddObserver(this, "xpcom-shutdown", false);
|
|
obs->AddObserver(this, "quit-application", false);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsRemoteService::RegisterWindow(mozIDOMWindow* aWindow)
|
|
{
|
|
// Note: RegisterWindow() is not implemented/needed by DBus service.
|
|
if (mGtkRemoteService) {
|
|
mGtkRemoteService->RegisterWindow(aWindow);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsRemoteService::Shutdown()
|
|
{
|
|
#if defined(MOZ_ENABLE_DBUS)
|
|
if (mDBusRemoteService) {
|
|
mDBusRemoteService->Shutdown();
|
|
mDBusRemoteService = nullptr;
|
|
}
|
|
#endif
|
|
if (mGtkRemoteService) {
|
|
mGtkRemoteService->Shutdown();
|
|
mGtkRemoteService = nullptr;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsRemoteService::~nsRemoteService()
|
|
{
|
|
Shutdown();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsRemoteService::Observe(nsISupports* aSubject,
|
|
const char *aTopic,
|
|
const char16_t *aData)
|
|
{
|
|
// This can be xpcom-shutdown or quit-application, but it's the same either
|
|
// way.
|
|
Shutdown();
|
|
return NS_OK;
|
|
}
|
|
|
|
// Set desktop startup ID to the passed ID, if there is one, so that any created
|
|
// windows get created with the right window manager metadata, and any windows
|
|
// that get new tabs and are activated also get the right WM metadata.
|
|
// The timestamp will be used if there is no desktop startup ID, or if we're
|
|
// raising an existing window rather than showing a new window for the first time.
|
|
void
|
|
nsRemoteService::SetDesktopStartupIDOrTimestamp(const nsACString& aDesktopStartupID,
|
|
uint32_t aTimestamp) {
|
|
nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
|
|
if (!toolkit)
|
|
return;
|
|
|
|
if (!aDesktopStartupID.IsEmpty()) {
|
|
toolkit->SetDesktopStartupID(aDesktopStartupID);
|
|
}
|
|
|
|
toolkit->SetFocusTimestamp(aTimestamp);
|
|
}
|
|
|
|
static bool
|
|
FindExtensionParameterInCommand(const char* aParameterName,
|
|
const nsACString& aCommand,
|
|
char aSeparator,
|
|
nsACString* aValue)
|
|
{
|
|
nsAutoCString searchFor;
|
|
searchFor.Append(aSeparator);
|
|
searchFor.Append(aParameterName);
|
|
searchFor.Append('=');
|
|
|
|
nsACString::const_iterator start, end;
|
|
aCommand.BeginReading(start);
|
|
aCommand.EndReading(end);
|
|
if (!FindInReadable(searchFor, start, end))
|
|
return false;
|
|
|
|
nsACString::const_iterator charStart, charEnd;
|
|
charStart = end;
|
|
aCommand.EndReading(charEnd);
|
|
nsACString::const_iterator idStart = charStart, idEnd;
|
|
if (FindCharInReadable(aSeparator, charStart, charEnd)) {
|
|
idEnd = charStart;
|
|
} else {
|
|
idEnd = charEnd;
|
|
}
|
|
*aValue = nsDependentCSubstring(idStart, idEnd);
|
|
return true;
|
|
}
|
|
|
|
const char*
|
|
nsRemoteService::HandleCommandLine(const char* aBuffer, nsIDOMWindow* aWindow,
|
|
uint32_t aTimestamp)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsICommandLineRunner> cmdline
|
|
(do_CreateInstance("@mozilla.org/toolkit/command-line;1", &rv));
|
|
if (NS_FAILED(rv))
|
|
return "509 internal error";
|
|
|
|
// the commandline property is constructed as an array of int32_t
|
|
// followed by a series of null-terminated strings:
|
|
//
|
|
// [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0
|
|
// (offset is from the beginning of the buffer)
|
|
|
|
int32_t argc = TO_LITTLE_ENDIAN32(*reinterpret_cast<const int32_t*>(aBuffer));
|
|
const char *wd = aBuffer + ((argc + 1) * sizeof(int32_t));
|
|
|
|
nsCOMPtr<nsIFile> lf;
|
|
rv = NS_NewNativeLocalFile(nsDependentCString(wd), true,
|
|
getter_AddRefs(lf));
|
|
if (NS_FAILED(rv))
|
|
return "509 internal error";
|
|
|
|
nsAutoCString desktopStartupID;
|
|
|
|
const char **argv = (const char**) malloc(sizeof(char*) * argc);
|
|
if (!argv) return "509 internal error";
|
|
|
|
const int32_t *offset = reinterpret_cast<const int32_t*>(aBuffer) + 1;
|
|
|
|
for (int i = 0; i < argc; ++i) {
|
|
argv[i] = aBuffer + TO_LITTLE_ENDIAN32(offset[i]);
|
|
|
|
if (i == 0) {
|
|
nsDependentCString cmd(argv[0]);
|
|
FindExtensionParameterInCommand("DESKTOP_STARTUP_ID",
|
|
cmd, ' ',
|
|
&desktopStartupID);
|
|
}
|
|
}
|
|
|
|
rv = cmdline->Init(argc, argv, lf, nsICommandLine::STATE_REMOTE_AUTO);
|
|
|
|
free (argv);
|
|
if (NS_FAILED(rv)) {
|
|
return "509 internal error";
|
|
}
|
|
|
|
if (aWindow)
|
|
cmdline->SetWindowContext(aWindow);
|
|
|
|
SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
|
|
|
|
rv = cmdline->Run();
|
|
|
|
if (NS_ERROR_ABORT == rv)
|
|
return "500 command not parseable";
|
|
|
|
if (NS_FAILED(rv))
|
|
return "509 internal error";
|
|
|
|
return "200 executed command";
|
|
}
|
|
|
|
// {C0773E90-5799-4eff-AD03-3EBCD85624AC}
|
|
#define NS_REMOTESERVICE_CID \
|
|
{ 0xc0773e90, 0x5799, 0x4eff, { 0xad, 0x3, 0x3e, 0xbc, 0xd8, 0x56, 0x24, 0xac } }
|
|
|
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsRemoteService)
|
|
NS_DEFINE_NAMED_CID(NS_REMOTESERVICE_CID);
|
|
|
|
static const mozilla::Module::CIDEntry kRemoteCIDs[] = {
|
|
{ &kNS_REMOTESERVICE_CID, false, nullptr, nsRemoteServiceConstructor },
|
|
{ nullptr }
|
|
};
|
|
|
|
static const mozilla::Module::ContractIDEntry kRemoteContracts[] = {
|
|
{ "@mozilla.org/toolkit/remote-service;1", &kNS_REMOTESERVICE_CID },
|
|
{ nullptr }
|
|
};
|
|
|
|
static const mozilla::Module kRemoteModule = {
|
|
mozilla::Module::kVersion,
|
|
kRemoteCIDs,
|
|
kRemoteContracts
|
|
};
|
|
|
|
NSMODULE_DEFN(RemoteServiceModule) = &kRemoteModule;
|