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() + // openURL(,new-window) + // openURL(,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 #include 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 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(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 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 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(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 #include #include #include #include #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(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; };