871 lines
29 KiB
Diff
871 lines
29 KiB
Diff
|
diff --git a/browser/components/nsBrowserContentHandler.js b/browser/components/nsBrowserContentHandler.js
|
||
|
index 5b9f9b1..6909621 100644
|
||
|
--- a/browser/components/nsBrowserContentHandler.js
|
||
|
+++ b/browser/components/nsBrowserContentHandler.js
|
||
|
@@ -337,16 +337,96 @@ nsBrowserContentHandler.prototype = {
|
||
|
if (cmdLine.handleFlag("browser", false)) {
|
||
|
// Passing defaultArgs, so use NO_EXTERNAL_URIS
|
||
|
openWindow(null, this.chromeURL, "_blank",
|
||
|
"chrome,dialog=no,all" + this.getFeatures(cmdLine),
|
||
|
this.defaultArgs, NO_EXTERNAL_URIS);
|
||
|
cmdLine.preventDefault = true;
|
||
|
}
|
||
|
|
||
|
+ try {
|
||
|
+ var remoteCommand = cmdLine.handleFlagWithParam("remote", true);
|
||
|
+ }
|
||
|
+ catch (e) {
|
||
|
+ throw NS_ERROR_ABORT;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (remoteCommand != null) {
|
||
|
+ try {
|
||
|
+ var a = /^\s*(\w+)\(([^\)]*)\)\s*$/.exec(remoteCommand);
|
||
|
+ var remoteVerb;
|
||
|
+ if (a) {
|
||
|
+ remoteVerb = a[1].toLowerCase();
|
||
|
+ var remoteParams = [];
|
||
|
+ var sepIndex = a[2].lastIndexOf(",");
|
||
|
+ if (sepIndex == -1)
|
||
|
+ remoteParams[0] = a[2];
|
||
|
+ else {
|
||
|
+ remoteParams[0] = a[2].substring(0, sepIndex);
|
||
|
+ remoteParams[1] = a[2].substring(sepIndex + 1);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ switch (remoteVerb) {
|
||
|
+ case "openurl":
|
||
|
+ case "openfile":
|
||
|
+ // openURL(<url>)
|
||
|
+ // openURL(<url>,new-window)
|
||
|
+ // openURL(<url>,new-tab)
|
||
|
+
|
||
|
+ // First param is the URL, second param (if present) is the "target"
|
||
|
+ // (tab, window)
|
||
|
+ var url = remoteParams[0];
|
||
|
+ var target = nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW;
|
||
|
+ if (remoteParams[1]) {
|
||
|
+ var targetParam = remoteParams[1].toLowerCase()
|
||
|
+ .replace(/^\s*|\s*$/g, "");
|
||
|
+ if (targetParam == "new-tab")
|
||
|
+ target = nsIBrowserDOMWindow.OPEN_NEWTAB;
|
||
|
+ else if (targetParam == "new-window")
|
||
|
+ target = nsIBrowserDOMWindow.OPEN_NEWWINDOW;
|
||
|
+ else {
|
||
|
+ // The "target" param isn't one of our supported values, so
|
||
|
+ // assume it's part of a URL that contains commas.
|
||
|
+ url += "," + remoteParams[1];
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ var uri = resolveURIInternal(cmdLine, url);
|
||
|
+ handURIToExistingBrowser(uri, target, cmdLine);
|
||
|
+ break;
|
||
|
+
|
||
|
+ case "xfedocommand":
|
||
|
+ // xfeDoCommand(openBrowser)
|
||
|
+ if (remoteParams[0].toLowerCase() != "openbrowser")
|
||
|
+ throw NS_ERROR_ABORT;
|
||
|
+
|
||
|
+ // Passing defaultArgs, so use NO_EXTERNAL_URIS
|
||
|
+ openWindow(null, this.chromeURL, "_blank",
|
||
|
+ "chrome,dialog=no,all" + this.getFeatures(cmdLine),
|
||
|
+ this.defaultArgs, NO_EXTERNAL_URIS);
|
||
|
+ break;
|
||
|
+
|
||
|
+ default:
|
||
|
+ // Somebody sent us a remote command we don't know how to process:
|
||
|
+ // just abort.
|
||
|
+ throw "Unknown remote command.";
|
||
|
+ }
|
||
|
+
|
||
|
+ cmdLine.preventDefault = true;
|
||
|
+ }
|
||
|
+ catch (e) {
|
||
|
+ Components.utils.reportError(e);
|
||
|
+ // If we had a -remote flag but failed to process it, throw
|
||
|
+ // NS_ERROR_ABORT so that the xremote code knows to return a failure
|
||
|
+ // back to the handling code.
|
||
|
+ throw NS_ERROR_ABORT;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
var uriparam;
|
||
|
try {
|
||
|
while ((uriparam = cmdLine.handleFlagWithParam("new-window", false))) {
|
||
|
var uri = resolveURIInternal(cmdLine, uriparam);
|
||
|
if (!shouldLoadURI(uri))
|
||
|
continue;
|
||
|
openWindow(null, this.chromeURL, "_blank",
|
||
|
"chrome,dialog=no,all" + this.getFeatures(cmdLine),
|
||
|
diff --git a/toolkit/components/remote/nsXRemoteService.cpp b/toolkit/components/remote/nsXRemoteService.cpp
|
||
|
index 41a40e4..532cc48 100644
|
||
|
--- a/toolkit/components/remote/nsXRemoteService.cpp
|
||
|
+++ b/toolkit/components/remote/nsXRemoteService.cpp
|
||
|
@@ -35,16 +35,17 @@
|
||
|
|
||
|
#include <X11/Xlib.h>
|
||
|
#include <X11/Xatom.h>
|
||
|
|
||
|
using namespace mozilla;
|
||
|
|
||
|
#define MOZILLA_VERSION_PROP "_MOZILLA_VERSION"
|
||
|
#define MOZILLA_LOCK_PROP "_MOZILLA_LOCK"
|
||
|
+#define MOZILLA_COMMAND_PROP "_MOZILLA_COMMAND"
|
||
|
#define MOZILLA_RESPONSE_PROP "_MOZILLA_RESPONSE"
|
||
|
#define MOZILLA_USER_PROP "_MOZILLA_USER"
|
||
|
#define MOZILLA_PROFILE_PROP "_MOZILLA_PROFILE"
|
||
|
#define MOZILLA_PROGRAM_PROP "_MOZILLA_PROGRAM"
|
||
|
#define MOZILLA_COMMANDLINE_PROP "_MOZILLA_COMMANDLINE"
|
||
|
|
||
|
const unsigned char kRemoteVersion[] = "5.1";
|
||
|
|
||
|
@@ -55,26 +56,28 @@ const unsigned char kRemoteVersion[] = "5.1";
|
||
|
#else
|
||
|
#define TO_LITTLE_ENDIAN32(x) (x)
|
||
|
#endif
|
||
|
|
||
|
// Minimize the roundtrips to the X server by getting all the atoms at once
|
||
|
static const char *XAtomNames[] = {
|
||
|
MOZILLA_VERSION_PROP,
|
||
|
MOZILLA_LOCK_PROP,
|
||
|
+ MOZILLA_COMMAND_PROP,
|
||
|
MOZILLA_RESPONSE_PROP,
|
||
|
MOZILLA_USER_PROP,
|
||
|
MOZILLA_PROFILE_PROP,
|
||
|
MOZILLA_PROGRAM_PROP,
|
||
|
MOZILLA_COMMANDLINE_PROP
|
||
|
};
|
||
|
static Atom XAtoms[MOZ_ARRAY_LENGTH(XAtomNames)];
|
||
|
|
||
|
Atom nsXRemoteService::sMozVersionAtom;
|
||
|
Atom nsXRemoteService::sMozLockAtom;
|
||
|
+Atom nsXRemoteService::sMozCommandAtom;
|
||
|
Atom nsXRemoteService::sMozResponseAtom;
|
||
|
Atom nsXRemoteService::sMozUserAtom;
|
||
|
Atom nsXRemoteService::sMozProfileAtom;
|
||
|
Atom nsXRemoteService::sMozProgramAtom;
|
||
|
Atom nsXRemoteService::sMozCommandLineAtom;
|
||
|
|
||
|
nsXRemoteService * nsXRemoteService::sRemoteImplementation = 0;
|
||
|
|
||
|
@@ -174,17 +177,17 @@ bool
|
||
|
nsXRemoteService::HandleNewProperty(XID aWindowId, Display* aDisplay,
|
||
|
Time aEventTime,
|
||
|
Atom aChangedAtom,
|
||
|
nsIWeakReference* aDomWindow)
|
||
|
{
|
||
|
|
||
|
nsCOMPtr<nsIDOMWindow> window (do_QueryReferent(aDomWindow));
|
||
|
|
||
|
- if (aChangedAtom == sMozCommandLineAtom) {
|
||
|
+ if (aChangedAtom == sMozCommandAtom || aChangedAtom == sMozCommandLineAtom) {
|
||
|
// We got a new command atom.
|
||
|
int result;
|
||
|
Atom actual_type;
|
||
|
int actual_format;
|
||
|
unsigned long nitems, bytes_after;
|
||
|
char *data = 0;
|
||
|
|
||
|
result = XGetWindowProperty (aDisplay,
|
||
|
@@ -206,17 +209,21 @@ nsXRemoteService::HandleNewProperty(XID aWindowId, Display* aDisplay,
|
||
|
if (result != Success)
|
||
|
return false;
|
||
|
|
||
|
// Failed to get the data off the window or it was the wrong type?
|
||
|
if (!data || !TO_LITTLE_ENDIAN32(*reinterpret_cast<int32_t*>(data)))
|
||
|
return false;
|
||
|
|
||
|
// cool, we got the property data.
|
||
|
- const char *response = HandleCommandLine(data, window, aEventTime);
|
||
|
+ const char *response = nullptr;
|
||
|
+ if (aChangedAtom == sMozCommandAtom)
|
||
|
+ response = HandleCommand(data, window, aEventTime);
|
||
|
+ else if (aChangedAtom == sMozCommandLineAtom)
|
||
|
+ response = HandleCommandLine(data, window, aEventTime);
|
||
|
|
||
|
// put the property onto the window as the response
|
||
|
XChangeProperty (aDisplay, aWindowId,
|
||
|
sMozResponseAtom, XA_STRING,
|
||
|
8, PropModeReplace,
|
||
|
(const unsigned char *)response,
|
||
|
strlen (response));
|
||
|
XFree(data);
|
||
|
@@ -232,16 +239,71 @@ nsXRemoteService::HandleNewProperty(XID aWindowId, Display* aDisplay,
|
||
|
// someone locked the window
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const char*
|
||
|
+nsXRemoteService::HandleCommand(char* aCommand, 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";
|
||
|
+
|
||
|
+ // 1) Make sure that it looks remotely valid with parens
|
||
|
+ // 2) Treat ping() immediately and specially
|
||
|
+
|
||
|
+ nsAutoCString command(aCommand);
|
||
|
+ int32_t p1, p2;
|
||
|
+ p1 = command.FindChar('(');
|
||
|
+ p2 = command.FindChar(')');
|
||
|
+
|
||
|
+ if (p1 == kNotFound || p2 == kNotFound || p1 == 0 || p2 < p1) {
|
||
|
+ return "500 command not parseable";
|
||
|
+ }
|
||
|
+
|
||
|
+ command.Truncate(p1);
|
||
|
+ command.Trim(" ", true, true);
|
||
|
+ ToLowerCase(command);
|
||
|
+
|
||
|
+ if (!command.EqualsLiteral("ping")) {
|
||
|
+ nsAutoCString desktopStartupID;
|
||
|
+ nsDependentCString cmd(aCommand);
|
||
|
+ FindExtensionParameterInCommand("DESKTOP_STARTUP_ID",
|
||
|
+ cmd, '\n',
|
||
|
+ &desktopStartupID);
|
||
|
+
|
||
|
+ const char* argv[3] = {"dummyappname", "-remote", aCommand};
|
||
|
+ rv = cmdline->Init(3, argv, nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
|
||
|
+ if (NS_FAILED(rv))
|
||
|
+ return "509 internal error";
|
||
|
+
|
||
|
+ if (aWindow)
|
||
|
+ cmdline->SetWindowContext(aWindow);
|
||
|
+
|
||
|
+ if (sRemoteImplementation)
|
||
|
+ sRemoteImplementation->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";
|
||
|
+}
|
||
|
+
|
||
|
+const char*
|
||
|
nsXRemoteService::HandleCommandLine(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))
|
||
|
@@ -311,14 +373,15 @@ nsXRemoteService::EnsureAtoms(void)
|
||
|
return;
|
||
|
|
||
|
XInternAtoms(mozilla::DefaultXDisplay(), const_cast<char**>(XAtomNames),
|
||
|
ArrayLength(XAtomNames), False, XAtoms);
|
||
|
|
||
|
int i = 0;
|
||
|
sMozVersionAtom = XAtoms[i++];
|
||
|
sMozLockAtom = XAtoms[i++];
|
||
|
+ sMozCommandAtom = XAtoms[i++];
|
||
|
sMozResponseAtom = XAtoms[i++];
|
||
|
sMozUserAtom = XAtoms[i++];
|
||
|
sMozProfileAtom = XAtoms[i++];
|
||
|
sMozProgramAtom = XAtoms[i++];
|
||
|
sMozCommandLineAtom = XAtoms[i++];
|
||
|
}
|
||
|
diff --git a/toolkit/components/remote/nsXRemoteService.h b/toolkit/components/remote/nsXRemoteService.h
|
||
|
index 7186336..144a4ec 100644
|
||
|
--- a/toolkit/components/remote/nsXRemoteService.h
|
||
|
+++ b/toolkit/components/remote/nsXRemoteService.h
|
||
|
@@ -36,27 +36,31 @@ protected:
|
||
|
nsIWeakReference* aDomWindow);
|
||
|
|
||
|
void XRemoteBaseStartup(const char *aAppName, const char *aProfileName);
|
||
|
|
||
|
void HandleCommandsFor(Window aWindowId);
|
||
|
static nsXRemoteService *sRemoteImplementation;
|
||
|
private:
|
||
|
void EnsureAtoms();
|
||
|
+ static const char* HandleCommand(char* aCommand, nsIDOMWindow* aWindow,
|
||
|
+ uint32_t aTimestamp);
|
||
|
+
|
||
|
static const char* HandleCommandLine(char* aBuffer, nsIDOMWindow* aWindow,
|
||
|
uint32_t aTimestamp);
|
||
|
|
||
|
virtual void SetDesktopStartupIDOrTimestamp(const nsACString& aDesktopStartupID,
|
||
|
uint32_t aTimestamp) = 0;
|
||
|
|
||
|
nsCString mAppName;
|
||
|
nsCString mProfileName;
|
||
|
|
||
|
static Atom sMozVersionAtom;
|
||
|
static Atom sMozLockAtom;
|
||
|
+ static Atom sMozCommandAtom;
|
||
|
static Atom sMozResponseAtom;
|
||
|
static Atom sMozUserAtom;
|
||
|
static Atom sMozProfileAtom;
|
||
|
static Atom sMozProgramAtom;
|
||
|
static Atom sMozCommandLineAtom;
|
||
|
};
|
||
|
|
||
|
#endif // NSXREMOTESERVICE_H
|
||
|
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
|
||
|
index db8667c..8d840ed 100644
|
||
|
--- a/toolkit/xre/nsAppRunner.cpp
|
||
|
+++ b/toolkit/xre/nsAppRunner.cpp
|
||
|
@@ -1609,16 +1609,76 @@ DumpVersion()
|
||
|
printf("%s ", gAppData->vendor);
|
||
|
printf("%s %s", gAppData->name, gAppData->version);
|
||
|
if (gAppData->copyright)
|
||
|
printf(", %s", gAppData->copyright);
|
||
|
printf("\n");
|
||
|
}
|
||
|
|
||
|
#ifdef MOZ_ENABLE_XREMOTE
|
||
|
+// use int here instead of a PR type since it will be returned
|
||
|
+// from main - just to keep types consistent
|
||
|
+static int
|
||
|
+HandleRemoteArgument(const char* remote, const char* aDesktopStartupID)
|
||
|
+{
|
||
|
+ nsresult rv;
|
||
|
+ ArgResult ar;
|
||
|
+
|
||
|
+ const char *profile = 0;
|
||
|
+ nsAutoCString program(gAppData->name);
|
||
|
+ ToLowerCase(program);
|
||
|
+ const char *username = getenv("LOGNAME");
|
||
|
+
|
||
|
+ ar = CheckArg("p", false, &profile);
|
||
|
+ if (ar == ARG_BAD) {
|
||
|
+ PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n");
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ const char *temp = nullptr;
|
||
|
+ ar = CheckArg("a", false, &temp);
|
||
|
+ if (ar == ARG_BAD) {
|
||
|
+ PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
|
||
|
+ return 1;
|
||
|
+ } else if (ar == ARG_FOUND) {
|
||
|
+ program.Assign(temp);
|
||
|
+ }
|
||
|
+
|
||
|
+ ar = CheckArg("u", false, &username);
|
||
|
+ if (ar == ARG_BAD) {
|
||
|
+ PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ XRemoteClient client;
|
||
|
+ rv = client.Init();
|
||
|
+ if (NS_FAILED(rv)) {
|
||
|
+ PR_fprintf(PR_STDERR, "Error: Failed to connect to X server.\n");
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ nsXPIDLCString response;
|
||
|
+ bool success = false;
|
||
|
+ rv = client.SendCommand(program.get(), username, profile, remote,
|
||
|
+ aDesktopStartupID, getter_Copies(response), &success);
|
||
|
+ // did the command fail?
|
||
|
+ if (NS_FAILED(rv)) {
|
||
|
+ PR_fprintf(PR_STDERR, "Error: Failed to send command: %s\n",
|
||
|
+ response ? response.get() : "No response included");
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!success) {
|
||
|
+ PR_fprintf(PR_STDERR, "Error: No running window found\n");
|
||
|
+ return 2;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static RemoteResult
|
||
|
RemoteCommandLine(const char* aDesktopStartupID)
|
||
|
{
|
||
|
nsresult rv;
|
||
|
ArgResult ar;
|
||
|
|
||
|
nsAutoCString program(gAppData->remotingName);
|
||
|
ToLowerCase(program);
|
||
|
@@ -3600,21 +3660,31 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
|
||
|
if (mDisableRemote) {
|
||
|
newInstance = true;
|
||
|
} else {
|
||
|
e = PR_GetEnv("MOZ_NEW_INSTANCE");
|
||
|
newInstance = (e && *e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ const char* xremotearg;
|
||
|
+ ArgResult ar = CheckArg("remote", true, &xremotearg);
|
||
|
+ if (ar == ARG_BAD) {
|
||
|
+ PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ const char* desktopStartupIDPtr =
|
||
|
+ mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
|
||
|
+ if (ar) {
|
||
|
+ *aExitFlag = true;
|
||
|
+ return HandleRemoteArgument(xremotearg, desktopStartupIDPtr);
|
||
|
+ }
|
||
|
+
|
||
|
if (!newInstance) {
|
||
|
// Try to remote the entire command line. If this fails, start up normally.
|
||
|
- const char* desktopStartupIDPtr =
|
||
|
- mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
|
||
|
-
|
||
|
RemoteResult rr = RemoteCommandLine(desktopStartupIDPtr);
|
||
|
if (rr == REMOTE_FOUND) {
|
||
|
*aExitFlag = true;
|
||
|
return 0;
|
||
|
}
|
||
|
else if (rr == REMOTE_ARG_BAD)
|
||
|
return 1;
|
||
|
}
|
||
|
diff --git a/widget/xremoteclient/XRemoteClient.cpp b/widget/xremoteclient/XRemoteClient.cpp
|
||
|
index dc63704..3ece6dc 100644
|
||
|
--- a/widget/xremoteclient/XRemoteClient.cpp
|
||
|
+++ b/widget/xremoteclient/XRemoteClient.cpp
|
||
|
@@ -21,16 +21,17 @@
|
||
|
#include <sys/time.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <unistd.h>
|
||
|
#include <limits.h>
|
||
|
#include <X11/Xatom.h>
|
||
|
|
||
|
#define MOZILLA_VERSION_PROP "_MOZILLA_VERSION"
|
||
|
#define MOZILLA_LOCK_PROP "_MOZILLA_LOCK"
|
||
|
+#define MOZILLA_COMMAND_PROP "_MOZILLA_COMMAND"
|
||
|
#define MOZILLA_COMMANDLINE_PROP "_MOZILLA_COMMANDLINE"
|
||
|
#define MOZILLA_RESPONSE_PROP "_MOZILLA_RESPONSE"
|
||
|
#define MOZILLA_USER_PROP "_MOZILLA_USER"
|
||
|
#define MOZILLA_PROFILE_PROP "_MOZILLA_PROFILE"
|
||
|
#define MOZILLA_PROGRAM_PROP "_MOZILLA_PROGRAM"
|
||
|
|
||
|
#ifdef IS_BIG_ENDIAN
|
||
|
#define TO_LITTLE_ENDIAN32(x) \
|
||
|
@@ -56,16 +57,17 @@ static int (*sOldHandler)(Display *, XErrorEvent *);
|
||
|
static bool sGotBadWindow;
|
||
|
|
||
|
XRemoteClient::XRemoteClient()
|
||
|
{
|
||
|
mDisplay = 0;
|
||
|
mInitialized = false;
|
||
|
mMozVersionAtom = 0;
|
||
|
mMozLockAtom = 0;
|
||
|
+ mMozCommandAtom = 0;
|
||
|
mMozResponseAtom = 0;
|
||
|
mMozWMStateAtom = 0;
|
||
|
mMozUserAtom = 0;
|
||
|
mLockData = 0;
|
||
|
if (!sRemoteLm)
|
||
|
sRemoteLm = PR_NewLogModule("XRemoteClient");
|
||
|
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::XRemoteClient"));
|
||
|
}
|
||
|
@@ -76,16 +78,17 @@ XRemoteClient::~XRemoteClient()
|
||
|
if (mInitialized)
|
||
|
Shutdown();
|
||
|
}
|
||
|
|
||
|
// Minimize the roundtrips to the X-server
|
||
|
static const char *XAtomNames[] = {
|
||
|
MOZILLA_VERSION_PROP,
|
||
|
MOZILLA_LOCK_PROP,
|
||
|
+ MOZILLA_COMMAND_PROP,
|
||
|
MOZILLA_RESPONSE_PROP,
|
||
|
"WM_STATE",
|
||
|
MOZILLA_USER_PROP,
|
||
|
MOZILLA_PROFILE_PROP,
|
||
|
MOZILLA_PROGRAM_PROP,
|
||
|
MOZILLA_COMMANDLINE_PROP
|
||
|
};
|
||
|
static Atom XAtoms[ARRAY_LENGTH(XAtomNames)];
|
||
|
@@ -105,16 +108,17 @@ XRemoteClient::Init()
|
||
|
|
||
|
// get our atoms
|
||
|
XInternAtoms(mDisplay, const_cast<char**>(XAtomNames),
|
||
|
ARRAY_LENGTH(XAtomNames), False, XAtoms);
|
||
|
|
||
|
int i = 0;
|
||
|
mMozVersionAtom = XAtoms[i++];
|
||
|
mMozLockAtom = XAtoms[i++];
|
||
|
+ mMozCommandAtom = XAtoms[i++];
|
||
|
mMozResponseAtom = XAtoms[i++];
|
||
|
mMozWMStateAtom = XAtoms[i++];
|
||
|
mMozUserAtom = XAtoms[i++];
|
||
|
mMozProfileAtom = XAtoms[i++];
|
||
|
mMozProgramAtom = XAtoms[i++];
|
||
|
mMozCommandLineAtom = XAtoms[i++];
|
||
|
|
||
|
mInitialized = true;
|
||
|
@@ -135,44 +139,72 @@ XRemoteClient::Shutdown (void)
|
||
|
mDisplay = 0;
|
||
|
mInitialized = false;
|
||
|
if (mLockData) {
|
||
|
free(mLockData);
|
||
|
mLockData = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+nsresult
|
||
|
+XRemoteClient::SendCommand (const char *aProgram, const char *aUsername,
|
||
|
+ const char *aProfile, const char *aCommand,
|
||
|
+ const char* aDesktopStartupID,
|
||
|
+ char **aResponse, bool *aWindowFound)
|
||
|
+{
|
||
|
+ PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommand"));
|
||
|
+
|
||
|
+ return SendCommandInternal(aProgram, aUsername, aProfile,
|
||
|
+ aCommand, 0, nullptr,
|
||
|
+ aDesktopStartupID,
|
||
|
+ aResponse, aWindowFound);
|
||
|
+}
|
||
|
+
|
||
|
+nsresult
|
||
|
+XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
|
||
|
+ const char *aProfile,
|
||
|
+ int32_t argc, char **argv,
|
||
|
+ const char* aDesktopStartupID,
|
||
|
+ char **aResponse, bool *aWindowFound)
|
||
|
+{
|
||
|
+ PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommandLine"));
|
||
|
+
|
||
|
+ return SendCommandInternal(aProgram, aUsername, aProfile,
|
||
|
+ nullptr, argc, argv,
|
||
|
+ aDesktopStartupID,
|
||
|
+ aResponse, aWindowFound);
|
||
|
+}
|
||
|
+
|
||
|
static int
|
||
|
HandleBadWindow(Display *display, XErrorEvent *event)
|
||
|
{
|
||
|
if (event->error_code == BadWindow) {
|
||
|
sGotBadWindow = true;
|
||
|
return 0; // ignored
|
||
|
}
|
||
|
else {
|
||
|
return (*sOldHandler)(display, event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
nsresult
|
||
|
-XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
|
||
|
- const char *aProfile,
|
||
|
- int32_t argc, char **argv,
|
||
|
- const char* aDesktopStartupID,
|
||
|
- char **aResponse, bool *aWindowFound)
|
||
|
+XRemoteClient::SendCommandInternal(const char *aProgram, const char *aUsername,
|
||
|
+ const char *aProfile, const char *aCommand,
|
||
|
+ int32_t argc, char **argv,
|
||
|
+ const char* aDesktopStartupID,
|
||
|
+ char **aResponse, bool *aWindowFound)
|
||
|
{
|
||
|
- PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommandLine"));
|
||
|
-
|
||
|
*aWindowFound = false;
|
||
|
+ bool isCommandLine = !aCommand;
|
||
|
|
||
|
// FindBestWindow() iterates down the window hierarchy, so catch X errors
|
||
|
// when windows get destroyed before being accessed.
|
||
|
sOldHandler = XSetErrorHandler(HandleBadWindow);
|
||
|
|
||
|
- Window w = FindBestWindow(aProgram, aUsername, aProfile);
|
||
|
+ Window w = FindBestWindow(aProgram, aUsername, aProfile, isCommandLine);
|
||
|
|
||
|
nsresult rv = NS_OK;
|
||
|
|
||
|
if (w) {
|
||
|
// ok, let the caller know that we at least found a window.
|
||
|
*aWindowFound = true;
|
||
|
|
||
|
// Ignore BadWindow errors up to this point. The last request from
|
||
|
@@ -186,18 +218,24 @@ XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
|
||
|
|
||
|
bool destroyed = false;
|
||
|
|
||
|
// get the lock on the window
|
||
|
rv = GetLock(w, &destroyed);
|
||
|
|
||
|
if (NS_SUCCEEDED(rv)) {
|
||
|
// send our command
|
||
|
- rv = DoSendCommandLine(w, argc, argv, aDesktopStartupID, aResponse,
|
||
|
- &destroyed);
|
||
|
+ if (isCommandLine) {
|
||
|
+ rv = DoSendCommandLine(w, argc, argv, aDesktopStartupID, aResponse,
|
||
|
+ &destroyed);
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ rv = DoSendCommand(w, aCommand, aDesktopStartupID, aResponse,
|
||
|
+ &destroyed);
|
||
|
+ }
|
||
|
|
||
|
// if the window was destroyed, don't bother trying to free the
|
||
|
// lock.
|
||
|
if (!destroyed)
|
||
|
FreeLock(w); // doesn't really matter what this returns
|
||
|
|
||
|
}
|
||
|
}
|
||
|
@@ -405,17 +443,18 @@ XRemoteClient::GetLock(Window aWindow, bool *aDestroyed)
|
||
|
(unsigned int) aWindow));
|
||
|
}
|
||
|
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
Window
|
||
|
XRemoteClient::FindBestWindow(const char *aProgram, const char *aUsername,
|
||
|
- const char *aProfile)
|
||
|
+ const char *aProfile,
|
||
|
+ bool aSupportsCommandLine)
|
||
|
{
|
||
|
Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mDisplay));
|
||
|
Window bestWindow = 0;
|
||
|
Window root2, parent, *kids;
|
||
|
unsigned int nkids;
|
||
|
|
||
|
// Get a list of the children of the root window, walk the list
|
||
|
// looking for the best window that fits the criteria.
|
||
|
@@ -450,17 +489,17 @@ XRemoteClient::FindBestWindow(const char *aProgram, const char *aUsername,
|
||
|
&data_return);
|
||
|
|
||
|
if (!data_return)
|
||
|
continue;
|
||
|
|
||
|
double version = PR_strtod((char*) data_return, nullptr);
|
||
|
XFree(data_return);
|
||
|
|
||
|
- if (!(version >= 5.1 && version < 6))
|
||
|
+ if (aSupportsCommandLine && !(version >= 5.1 && version < 6))
|
||
|
continue;
|
||
|
|
||
|
data_return = 0;
|
||
|
|
||
|
if (status != Success || type == None)
|
||
|
continue;
|
||
|
|
||
|
// If someone passed in a program name, check it against this one
|
||
|
@@ -594,16 +633,56 @@ XRemoteClient::FreeLock(Window aWindow)
|
||
|
return NS_ERROR_FAILURE;
|
||
|
}
|
||
|
|
||
|
if (data)
|
||
|
XFree(data);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
+nsresult
|
||
|
+XRemoteClient::DoSendCommand(Window aWindow, const char *aCommand,
|
||
|
+ const char* aDesktopStartupID,
|
||
|
+ char **aResponse, bool *aDestroyed)
|
||
|
+{
|
||
|
+ *aDestroyed = false;
|
||
|
+
|
||
|
+ PR_LOG(sRemoteLm, PR_LOG_DEBUG,
|
||
|
+ ("(writing " MOZILLA_COMMAND_PROP " \"%s\" to 0x%x)\n",
|
||
|
+ aCommand, (unsigned int) aWindow));
|
||
|
+
|
||
|
+ // We add the DESKTOP_STARTUP_ID setting as an extra line of
|
||
|
+ // the command string. Firefox ignores all lines but the first.
|
||
|
+ static char desktopStartupPrefix[] = "\nDESKTOP_STARTUP_ID=";
|
||
|
+
|
||
|
+ int32_t len = strlen(aCommand);
|
||
|
+ if (aDesktopStartupID) {
|
||
|
+ len += sizeof(desktopStartupPrefix) - 1 + strlen(aDesktopStartupID);
|
||
|
+ }
|
||
|
+ char* buffer = (char*)malloc(len + 1);
|
||
|
+ if (!buffer)
|
||
|
+ return NS_ERROR_OUT_OF_MEMORY;
|
||
|
+
|
||
|
+ strcpy(buffer, aCommand);
|
||
|
+ if (aDesktopStartupID) {
|
||
|
+ strcat(buffer, desktopStartupPrefix);
|
||
|
+ strcat(buffer, aDesktopStartupID);
|
||
|
+ }
|
||
|
+
|
||
|
+ XChangeProperty (mDisplay, aWindow, mMozCommandAtom, XA_STRING, 8,
|
||
|
+ PropModeReplace, (unsigned char *)buffer, len);
|
||
|
+
|
||
|
+ free(buffer);
|
||
|
+
|
||
|
+ if (!WaitForResponse(aWindow, aResponse, aDestroyed, mMozCommandAtom))
|
||
|
+ return NS_ERROR_FAILURE;
|
||
|
+
|
||
|
+ return NS_OK;
|
||
|
+}
|
||
|
+
|
||
|
/* like strcpy, but return the char after the final null */
|
||
|
static char*
|
||
|
estrcpy(const char* s, char* d)
|
||
|
{
|
||
|
while (*s)
|
||
|
*d++ = *s++;
|
||
|
|
||
|
*d++ = '\0';
|
||
|
@@ -786,16 +865,16 @@ XRemoteClient::WaitForResponse(Window aWindow, char **aResponse,
|
||
|
}
|
||
|
|
||
|
else if (event.xany.type == PropertyNotify &&
|
||
|
event.xproperty.window == aWindow &&
|
||
|
event.xproperty.state == PropertyDelete &&
|
||
|
event.xproperty.atom == aCommandAtom) {
|
||
|
PR_LOG(sRemoteLm, PR_LOG_DEBUG,
|
||
|
("(server 0x%x has accepted "
|
||
|
- MOZILLA_COMMANDLINE_PROP ".)\n",
|
||
|
+ MOZILLA_COMMAND_PROP ".)\n",
|
||
|
(unsigned int) aWindow));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return accepted;
|
||
|
}
|
||
|
diff --git a/widget/xremoteclient/XRemoteClient.h b/widget/xremoteclient/XRemoteClient.h
|
||
|
index 840716a..db1f804f 100644
|
||
|
--- a/widget/xremoteclient/XRemoteClient.h
|
||
|
+++ b/widget/xremoteclient/XRemoteClient.h
|
||
|
@@ -10,44 +10,60 @@
|
||
|
|
||
|
class XRemoteClient : public nsRemoteClient
|
||
|
{
|
||
|
public:
|
||
|
XRemoteClient();
|
||
|
~XRemoteClient();
|
||
|
|
||
|
virtual nsresult Init();
|
||
|
+ virtual nsresult SendCommand(const char *aProgram, const char *aUsername,
|
||
|
+ const char *aProfile, const char *aCommand,
|
||
|
+ const char* aDesktopStartupID,
|
||
|
+ char **aResponse, bool *aSucceeded);
|
||
|
virtual nsresult SendCommandLine(const char *aProgram, const char *aUsername,
|
||
|
const char *aProfile,
|
||
|
int32_t argc, char **argv,
|
||
|
const char* aDesktopStartupID,
|
||
|
char **aResponse, bool *aSucceeded);
|
||
|
void Shutdown();
|
||
|
|
||
|
private:
|
||
|
|
||
|
Window CheckWindow (Window aWindow);
|
||
|
Window CheckChildren (Window aWindow);
|
||
|
nsresult GetLock (Window aWindow, bool *aDestroyed);
|
||
|
nsresult FreeLock (Window aWindow);
|
||
|
Window FindBestWindow (const char *aProgram,
|
||
|
const char *aUsername,
|
||
|
- const char *aProfile);
|
||
|
+ const char *aProfile,
|
||
|
+ bool aSupportsCommandLine);
|
||
|
+ nsresult SendCommandInternal(const char *aProgram, const char *aUsername,
|
||
|
+ const char *aProfile, const char *aCommand,
|
||
|
+ int32_t argc, char **argv,
|
||
|
+ const char* aDesktopStartupID,
|
||
|
+ char **aResponse, bool *aWindowFound);
|
||
|
+ nsresult DoSendCommand (Window aWindow,
|
||
|
+ const char *aCommand,
|
||
|
+ const char* aDesktopStartupID,
|
||
|
+ char **aResponse,
|
||
|
+ bool *aDestroyed);
|
||
|
nsresult DoSendCommandLine(Window aWindow,
|
||
|
int32_t argc, char **argv,
|
||
|
const char* aDesktopStartupID,
|
||
|
char **aResponse,
|
||
|
bool *aDestroyed);
|
||
|
bool WaitForResponse (Window aWindow, char **aResponse,
|
||
|
bool *aDestroyed, Atom aCommandAtom);
|
||
|
|
||
|
Display *mDisplay;
|
||
|
|
||
|
Atom mMozVersionAtom;
|
||
|
Atom mMozLockAtom;
|
||
|
+ Atom mMozCommandAtom;
|
||
|
Atom mMozCommandLineAtom;
|
||
|
Atom mMozResponseAtom;
|
||
|
Atom mMozWMStateAtom;
|
||
|
Atom mMozUserAtom;
|
||
|
Atom mMozProfileAtom;
|
||
|
Atom mMozProgramAtom;
|
||
|
|
||
|
char *mLockData;
|
||
|
diff --git a/widget/xremoteclient/nsRemoteClient.h b/widget/xremoteclient/nsRemoteClient.h
|
||
|
index 6d90d69..050aba4 100644
|
||
|
--- a/widget/xremoteclient/nsRemoteClient.h
|
||
|
+++ b/widget/xremoteclient/nsRemoteClient.h
|
||
|
@@ -18,43 +18,62 @@ class nsRemoteClient
|
||
|
{
|
||
|
public:
|
||
|
/**
|
||
|
* Initializes the client
|
||
|
*/
|
||
|
virtual nsresult Init() = 0;
|
||
|
|
||
|
/**
|
||
|
- * Send a complete command line to a running instance.
|
||
|
+ * Sends a command to a running instance.
|
||
|
*
|
||
|
* @param aProgram This is the preferred program that we want to use
|
||
|
* for this particular command.
|
||
|
*
|
||
|
+ * @param aNoProgramFallback This boolean attribute tells the client
|
||
|
+ * code that if the preferred program isn't found that it should
|
||
|
+ * fail not send the command to another server.
|
||
|
+ *
|
||
|
* @param aUsername This allows someone to only talk to an instance
|
||
|
* of the server that's running under a particular username. If
|
||
|
* this isn't specified here it's pulled from the LOGNAME
|
||
|
* environmental variable if it's set.
|
||
|
*
|
||
|
* @param aProfile This allows you to specify a particular server
|
||
|
* running under a named profile. If it is not specified the
|
||
|
* profile is not checked.
|
||
|
*
|
||
|
- * @param argc The number of command-line arguments.
|
||
|
- *
|
||
|
- * @param argv The command-line arguments.
|
||
|
- *
|
||
|
+ * @param aCommand This is the command that is passed to the server.
|
||
|
+ * Please see the additional information located at:
|
||
|
+ * http://www.mozilla.org/unix/remote.html
|
||
|
+ *
|
||
|
* @param aDesktopStartupID the contents of the DESKTOP_STARTUP_ID environment
|
||
|
* variable defined by the Startup Notification specification
|
||
|
* http://standards.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt
|
||
|
*
|
||
|
* @param aResponse If there is a response, it will be here. This
|
||
|
* includes error messages. The string is allocated using stdlib
|
||
|
* string functions, so free it with free().
|
||
|
*
|
||
|
* @return true if succeeded, false if no running instance was found.
|
||
|
+ */
|
||
|
+ virtual nsresult SendCommand(const char *aProgram, const char *aUsername,
|
||
|
+ const char *aProfile, const char *aCommand,
|
||
|
+ const char* aDesktopStartupID,
|
||
|
+ char **aResponse, bool *aSucceeded) = 0;
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Send a complete command line to a running instance.
|
||
|
+ *
|
||
|
+ * @param aDesktopStartupID the contents of the DESKTOP_STARTUP_ID environment
|
||
|
+ * variable defined by the Startup Notification specification
|
||
|
+ * http://standards.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt
|
||
|
+ *
|
||
|
+ * @see sendCommand
|
||
|
+ * @param argc The number of command-line arguments.
|
||
|
*
|
||
|
*/
|
||
|
virtual nsresult SendCommandLine(const char *aProgram, const char *aUsername,
|
||
|
const char *aProfile,
|
||
|
int32_t argc, char **argv,
|
||
|
const char* aDesktopStartupID,
|
||
|
char **aResponse, bool *aSucceeded) = 0;
|
||
|
};
|