forked from mirrors/gecko-dev
		
	 5552be67a8
			
		
	
	
		5552be67a8
		
	
	
	
	
		
			
			MozReview-Commit-ID: IDFaUR2gK4R --HG-- extra : amend_source : 3913ac1516e7aa3f5b2e4005c2f1a68dfc5d22a0
		
			
				
	
	
		
			742 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			742 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim:expandtab:shiftwidth=2:tabstop=8:
 | |
|  */
 | |
| /* vim:set ts=8 sw=2 et cindent: */
 | |
| /* 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 "mozilla/ArrayUtils.h"
 | |
| #include "mozilla/IntegerPrintfMacros.h"
 | |
| #include "mozilla/Sprintf.h"
 | |
| #include "mozilla/Unused.h"
 | |
| #include "XRemoteClient.h"
 | |
| #include "RemoteUtils.h"
 | |
| #include "plstr.h"
 | |
| #include "prsystem.h"
 | |
| #include "mozilla/Logging.h"
 | |
| #include "prenv.h"
 | |
| #include "prdtoa.h"
 | |
| #include <stdlib.h>
 | |
| #include <unistd.h>
 | |
| #include <string.h>
 | |
| #include <strings.h>
 | |
| #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_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) \
 | |
|     ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
 | |
|     (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
 | |
| #else
 | |
| #define TO_LITTLE_ENDIAN32(x) (x)
 | |
| #endif
 | |
| 
 | |
| #ifndef MAX_PATH
 | |
| #ifdef PATH_MAX
 | |
| #define MAX_PATH PATH_MAX
 | |
| #else
 | |
| #define MAX_PATH 1024
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| using mozilla::LogLevel;
 | |
| using mozilla::Unused;
 | |
| 
 | |
| static mozilla::LazyLogModule sRemoteLm("XRemoteClient");
 | |
| 
 | |
| static int (*sOldHandler)(Display *, XErrorEvent *);
 | |
| static bool sGotBadWindow;
 | |
| 
 | |
| XRemoteClient::XRemoteClient()
 | |
| {
 | |
|   mDisplay = 0;
 | |
|   mInitialized = false;
 | |
|   mMozVersionAtom = 0;
 | |
|   mMozLockAtom = 0;
 | |
|   mMozCommandLineAtom = 0;
 | |
|   mMozResponseAtom = 0;
 | |
|   mMozWMStateAtom = 0;
 | |
|   mMozUserAtom = 0;
 | |
|   mMozProfileAtom = 0;
 | |
|   mMozProgramAtom = 0;
 | |
|   mLockData = 0;
 | |
|   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::XRemoteClient"));
 | |
| }
 | |
| 
 | |
| XRemoteClient::~XRemoteClient()
 | |
| {
 | |
|   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::~XRemoteClient"));
 | |
|   if (mInitialized)
 | |
|     Shutdown();
 | |
| }
 | |
| 
 | |
| // Minimize the roundtrips to the X-server
 | |
| static const char *XAtomNames[] = {
 | |
|   MOZILLA_VERSION_PROP,
 | |
|   MOZILLA_LOCK_PROP,
 | |
|   MOZILLA_RESPONSE_PROP,
 | |
|   "WM_STATE",
 | |
|   MOZILLA_USER_PROP,
 | |
|   MOZILLA_PROFILE_PROP,
 | |
|   MOZILLA_PROGRAM_PROP,
 | |
|   MOZILLA_COMMANDLINE_PROP
 | |
| };
 | |
| static Atom XAtoms[MOZ_ARRAY_LENGTH(XAtomNames)];
 | |
| 
 | |
| nsresult
 | |
| XRemoteClient::Init()
 | |
| {
 | |
|   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::Init"));
 | |
| 
 | |
|   if (mInitialized)
 | |
|     return NS_OK;
 | |
| 
 | |
|   // try to open the display
 | |
|   mDisplay = XOpenDisplay(0);
 | |
|   if (!mDisplay)
 | |
|     return NS_ERROR_FAILURE;
 | |
| 
 | |
|   // get our atoms
 | |
|   XInternAtoms(mDisplay, const_cast<char**>(XAtomNames),
 | |
|                MOZ_ARRAY_LENGTH(XAtomNames), False, XAtoms);
 | |
| 
 | |
|   int i = 0;
 | |
|   mMozVersionAtom  = XAtoms[i++];
 | |
|   mMozLockAtom     = XAtoms[i++];
 | |
|   mMozResponseAtom = XAtoms[i++];
 | |
|   mMozWMStateAtom  = XAtoms[i++];
 | |
|   mMozUserAtom     = XAtoms[i++];
 | |
|   mMozProfileAtom  = XAtoms[i++];
 | |
|   mMozProgramAtom  = XAtoms[i++];
 | |
|   mMozCommandLineAtom = XAtoms[i];
 | |
| 
 | |
|   mInitialized = true;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void
 | |
| XRemoteClient::Shutdown (void)
 | |
| {
 | |
|   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::Shutdown"));
 | |
| 
 | |
|   if (!mInitialized)
 | |
|     return;
 | |
| 
 | |
|   // shut everything down
 | |
|   XCloseDisplay(mDisplay);
 | |
|   mDisplay = 0;
 | |
|   mInitialized = false;
 | |
|   if (mLockData) {
 | |
|     free(mLockData);
 | |
|     mLockData = 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static int
 | |
| HandleBadWindow(Display *display, XErrorEvent *event)
 | |
| {
 | |
|   if (event->error_code == BadWindow) {
 | |
|     sGotBadWindow = true;
 | |
|     return 0; // ignored
 | |
|   }
 | |
| 
 | |
|     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)
 | |
| {
 | |
|   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::SendCommandLine"));
 | |
| 
 | |
|   *aWindowFound = false;
 | |
| 
 | |
|   // 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);
 | |
| 
 | |
|   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
 | |
|     // FindBestWindow() was a synchronous XGetWindowProperty(), so no need to
 | |
|     // Sync.  Leave the error handler installed to detect if w gets destroyed.
 | |
|     sGotBadWindow = false;
 | |
| 
 | |
|     // make sure we get the right events on that window
 | |
|     XSelectInput(mDisplay, w,
 | |
|                  (PropertyChangeMask|StructureNotifyMask));
 | |
| 
 | |
|     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 the window was destroyed, don't bother trying to free the
 | |
|       // lock.
 | |
|       if (!destroyed)
 | |
|           FreeLock(w); // doesn't really matter what this returns
 | |
| 
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   XSetErrorHandler(sOldHandler);
 | |
| 
 | |
|   MOZ_LOG(sRemoteLm, LogLevel::Debug, ("SendCommandInternal returning 0x%" PRIx32 "\n",
 | |
|                                        static_cast<uint32_t>(rv)));
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| Window
 | |
| XRemoteClient::CheckWindow(Window aWindow)
 | |
| {
 | |
|   Atom type = None;
 | |
|   int  format;
 | |
|   unsigned long nitems, bytesafter;
 | |
|   unsigned char *data;
 | |
|   Window innerWindow;
 | |
| 
 | |
|   XGetWindowProperty(mDisplay, aWindow, mMozWMStateAtom,
 | |
| 		     0, 0, False, AnyPropertyType,
 | |
| 		     &type, &format, &nitems, &bytesafter, &data);
 | |
| 
 | |
|   if (type) {
 | |
|     XFree(data);
 | |
|     return aWindow;
 | |
|   }
 | |
| 
 | |
|   // didn't find it here so check the children of this window
 | |
|   innerWindow = CheckChildren(aWindow);
 | |
| 
 | |
|   if (innerWindow)
 | |
|     return innerWindow;
 | |
| 
 | |
|   return aWindow;
 | |
| }
 | |
| 
 | |
| Window
 | |
| XRemoteClient::CheckChildren(Window aWindow)
 | |
| {
 | |
|   Window root, parent;
 | |
|   Window *children;
 | |
|   unsigned int nchildren;
 | |
|   unsigned int i;
 | |
|   Atom type = None;
 | |
|   int format;
 | |
|   unsigned long nitems, after;
 | |
|   unsigned char *data;
 | |
|   Window retval = None;
 | |
| 
 | |
|   if (!XQueryTree(mDisplay, aWindow, &root, &parent, &children,
 | |
| 		  &nchildren))
 | |
|     return None;
 | |
| 
 | |
|   // scan the list first before recursing into the list of windows
 | |
|   // which can get quite deep.
 | |
|   for (i=0; !retval && (i < nchildren); i++) {
 | |
|     XGetWindowProperty(mDisplay, children[i], mMozWMStateAtom,
 | |
| 		       0, 0, False, AnyPropertyType, &type, &format,
 | |
| 		       &nitems, &after, &data);
 | |
|     if (type) {
 | |
|       XFree(data);
 | |
|       retval = children[i];
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // otherwise recurse into the list
 | |
|   for (i=0; !retval && (i < nchildren); i++) {
 | |
|     retval = CheckChildren(children[i]);
 | |
|   }
 | |
| 
 | |
|   if (children)
 | |
|     XFree((char *)children);
 | |
| 
 | |
|   return retval;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| XRemoteClient::GetLock(Window aWindow, bool *aDestroyed)
 | |
| {
 | |
|   bool locked = false;
 | |
|   bool waited = false;
 | |
|   *aDestroyed = false;
 | |
| 
 | |
|   nsresult rv = NS_OK;
 | |
| 
 | |
|   if (!mLockData) {
 | |
| 
 | |
|     char pidstr[32];
 | |
|     char sysinfobuf[SYS_INFO_BUFFER_LENGTH];
 | |
|     SprintfLiteral(pidstr, "pid%d@", getpid());
 | |
|     PRStatus status;
 | |
|     status = PR_GetSystemInfo(PR_SI_HOSTNAME, sysinfobuf,
 | |
| 			      SYS_INFO_BUFFER_LENGTH);
 | |
|     if (status != PR_SUCCESS) {
 | |
|       return NS_ERROR_FAILURE;
 | |
|     }
 | |
| 
 | |
|     // allocate enough space for the string plus the terminating
 | |
|     // char
 | |
|     mLockData = (char *)malloc(strlen(pidstr) + strlen(sysinfobuf) + 1);
 | |
|     if (!mLockData)
 | |
|       return NS_ERROR_OUT_OF_MEMORY;
 | |
| 
 | |
|     strcpy(mLockData, pidstr);
 | |
|     if (!strcat(mLockData, sysinfobuf))
 | |
|       return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     int result;
 | |
|     Atom actual_type;
 | |
|     int actual_format;
 | |
|     unsigned long nitems, bytes_after;
 | |
|     unsigned char *data = 0;
 | |
| 
 | |
|     XGrabServer(mDisplay);
 | |
| 
 | |
|     result = XGetWindowProperty (mDisplay, aWindow, mMozLockAtom,
 | |
| 				 0, (65536 / sizeof (long)),
 | |
| 				 False, /* don't delete */
 | |
| 				 XA_STRING,
 | |
| 				 &actual_type, &actual_format,
 | |
| 				 &nitems, &bytes_after,
 | |
| 				 &data);
 | |
| 
 | |
|     // aWindow may have been destroyed before XSelectInput was processed, in
 | |
|     // which case there may not be any DestroyNotify event in the queue to
 | |
|     // tell us.  XGetWindowProperty() was synchronous so error responses have
 | |
|     // now been processed, setting sGotBadWindow.
 | |
|     if (sGotBadWindow) {
 | |
|       *aDestroyed = true;
 | |
|       rv = NS_ERROR_FAILURE;
 | |
|     }
 | |
|     else if (result != Success || actual_type == None) {
 | |
|       /* It's not now locked - lock it. */
 | |
|       XChangeProperty (mDisplay, aWindow, mMozLockAtom, XA_STRING, 8,
 | |
| 		       PropModeReplace,
 | |
| 		       (unsigned char *)mLockData,
 | |
| 		       strlen(mLockData));
 | |
|       locked = True;
 | |
|     }
 | |
| 
 | |
|     XUngrabServer(mDisplay);
 | |
|     XFlush(mDisplay); // ungrab now!
 | |
| 
 | |
|     if (!locked && !NS_FAILED(rv)) {
 | |
|       /* We tried to grab the lock this time, and failed because someone
 | |
| 	 else is holding it already.  So, wait for a PropertyDelete event
 | |
| 	 to come in, and try again. */
 | |
|       MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
| 	     ("window 0x%x is locked by %s; waiting...\n",
 | |
| 	      (unsigned int) aWindow, data));
 | |
|       waited = True;
 | |
|       while (true) {
 | |
| 	XEvent event;
 | |
| 	int select_retval;
 | |
| 	fd_set select_set;
 | |
| 	struct timeval delay;
 | |
| 	delay.tv_sec = 10;
 | |
| 	delay.tv_usec = 0;
 | |
| 
 | |
| 	FD_ZERO(&select_set);
 | |
| 	// add the x event queue to the select set
 | |
| 	FD_SET(ConnectionNumber(mDisplay), &select_set);
 | |
| 	select_retval = select(ConnectionNumber(mDisplay) + 1,
 | |
| 			       &select_set, nullptr, nullptr, &delay);
 | |
| 	// did we time out?
 | |
| 	if (select_retval == 0) {
 | |
| 	  MOZ_LOG(sRemoteLm, LogLevel::Debug, ("timed out waiting for window\n"));
 | |
|           rv = NS_ERROR_FAILURE;
 | |
|           break;
 | |
| 	}
 | |
| 	MOZ_LOG(sRemoteLm, LogLevel::Debug, ("xevent...\n"));
 | |
| 	XNextEvent (mDisplay, &event);
 | |
| 	if (event.xany.type == DestroyNotify &&
 | |
| 	    event.xdestroywindow.window == aWindow) {
 | |
| 	  *aDestroyed = true;
 | |
|           rv = NS_ERROR_FAILURE;
 | |
|           break;
 | |
| 	}
 | |
| 	if (event.xany.type == PropertyNotify &&
 | |
| 		 event.xproperty.state == PropertyDelete &&
 | |
| 		 event.xproperty.window == aWindow &&
 | |
| 		 event.xproperty.atom == mMozLockAtom) {
 | |
| 	  /* Ok!  Someone deleted their lock, so now we can try
 | |
| 	     again. */
 | |
| 	  MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
| 		 ("(0x%x unlocked, trying again...)\n",
 | |
| 		  (unsigned int) aWindow));
 | |
| 		  break;
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|     if (data)
 | |
|       XFree(data);
 | |
|   } while (!locked && !NS_FAILED(rv));
 | |
| 
 | |
|   if (waited && locked) {
 | |
|     MOZ_LOG(sRemoteLm, LogLevel::Debug, ("obtained lock.\n"));
 | |
|   } else if (*aDestroyed) {
 | |
|     MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|            ("window 0x%x unexpectedly destroyed.\n",
 | |
|             (unsigned int) aWindow));
 | |
|   }
 | |
| 
 | |
|   return rv;
 | |
| }
 | |
| 
 | |
| Window
 | |
| XRemoteClient::FindBestWindow(const char *aProgram, const char *aUsername,
 | |
|                               const char *aProfile)
 | |
| {
 | |
|   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.
 | |
|   if (!XQueryTree(mDisplay, root, &root2, &parent, &kids, &nkids)) {
 | |
|     MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|            ("XQueryTree failed in XRemoteClient::FindBestWindow"));
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   if (!(kids && nkids)) {
 | |
|     MOZ_LOG(sRemoteLm, LogLevel::Debug, ("root window has no children"));
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   // We'll walk the list of windows looking for a window that best
 | |
|   // fits the criteria here.
 | |
| 
 | |
|   for (unsigned int i = 0; i < nkids; i++) {
 | |
|     Atom type;
 | |
|     int format;
 | |
|     unsigned long nitems, bytesafter;
 | |
|     unsigned char *data_return = 0;
 | |
|     Window w;
 | |
|     w = kids[i];
 | |
|     // find the inner window with WM_STATE on it
 | |
|     w = CheckWindow(w);
 | |
| 
 | |
|     int status = XGetWindowProperty(mDisplay, w, mMozVersionAtom,
 | |
|                                     0, (65536 / sizeof (long)),
 | |
|                                     False, XA_STRING,
 | |
|                                     &type, &format, &nitems, &bytesafter,
 | |
|                                     &data_return);
 | |
| 
 | |
|     if (!data_return)
 | |
|       continue;
 | |
| 
 | |
|     double version = PR_strtod((char*) data_return, nullptr);
 | |
|     XFree(data_return);
 | |
| 
 | |
|     if (!(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
 | |
|     // unless it's "any" in which case, we don't care.  If someone did
 | |
|     // pass in a program name and this window doesn't support that
 | |
|     // protocol, we don't include it in our list.
 | |
|     if (aProgram && strcmp(aProgram, "any")) {
 | |
|         Unused << XGetWindowProperty(mDisplay, w, mMozProgramAtom,
 | |
|                                      0, (65536 / sizeof(long)),
 | |
|                                      False, XA_STRING,
 | |
|                                      &type, &format, &nitems, &bytesafter,
 | |
|                                      &data_return);
 | |
| 
 | |
|         // If the return name is not the same as what someone passed in,
 | |
|         // we don't want this window.
 | |
|         if (data_return) {
 | |
|             if (strcmp(aProgram, (const char *)data_return)) {
 | |
|                 XFree(data_return);
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             // This is actually the success condition.
 | |
|             XFree(data_return);
 | |
|         }
 | |
|         else {
 | |
|             // Doesn't support the protocol, even though the user
 | |
|             // requested it.  So we're not going to use this window.
 | |
|             continue;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Check to see if it has the user atom on that window.  If there
 | |
|     // is then we need to make sure that it matches what we have.
 | |
|     const char *username;
 | |
|     if (aUsername) {
 | |
|       username = aUsername;
 | |
|     }
 | |
|     else {
 | |
|       username = PR_GetEnv("LOGNAME");
 | |
|     }
 | |
| 
 | |
|     if (username) {
 | |
|         Unused << XGetWindowProperty(mDisplay, w, mMozUserAtom,
 | |
|                                      0, (65536 / sizeof(long)),
 | |
|                                      False, XA_STRING,
 | |
|                                      &type, &format, &nitems, &bytesafter,
 | |
|                                      &data_return);
 | |
| 
 | |
|         // if there's a username compare it with what we have
 | |
|         if (data_return) {
 | |
|             // If the IDs aren't equal, we don't want this window.
 | |
|             if (strcmp(username, (const char *)data_return)) {
 | |
|                 XFree(data_return);
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             XFree(data_return);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Check to see if there's a profile name on this window.  If
 | |
|     // there is, then we need to make sure it matches what someone
 | |
|     // passed in.
 | |
|     if (aProfile) {
 | |
|         Unused << XGetWindowProperty(mDisplay, w, mMozProfileAtom,
 | |
|                                      0, (65536 / sizeof(long)),
 | |
|                                      False, XA_STRING,
 | |
|                                      &type, &format, &nitems, &bytesafter,
 | |
|                                      &data_return);
 | |
| 
 | |
|         // If there's a profile compare it with what we have
 | |
|         if (data_return) {
 | |
|             // If the profiles aren't equal, we don't want this window.
 | |
|             if (strcmp(aProfile, (const char *)data_return)) {
 | |
|                 XFree(data_return);
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             XFree(data_return);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Check to see if the window supports the new command-line passing
 | |
|     // protocol, if that is requested.
 | |
| 
 | |
|     // If we got this far, this is the best window.  It passed
 | |
|     // all the tests.
 | |
|     bestWindow = w;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   if (kids)
 | |
|     XFree((char *) kids);
 | |
| 
 | |
|   return bestWindow;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| XRemoteClient::FreeLock(Window aWindow)
 | |
| {
 | |
|   int result;
 | |
|   Atom actual_type;
 | |
|   int actual_format;
 | |
|   unsigned long nitems, bytes_after;
 | |
|   unsigned char *data = 0;
 | |
| 
 | |
|   result = XGetWindowProperty(mDisplay, aWindow, mMozLockAtom,
 | |
|                               0, (65536 / sizeof(long)),
 | |
|                               True, /* atomic delete after */
 | |
|                               XA_STRING,
 | |
|                               &actual_type, &actual_format,
 | |
|                               &nitems, &bytes_after,
 | |
|                               &data);
 | |
|   if (result != Success) {
 | |
|       MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|              ("unable to read and delete " MOZILLA_LOCK_PROP
 | |
|               " property\n"));
 | |
|       return NS_ERROR_FAILURE;
 | |
|   }
 | |
|   if (!data || !*data){
 | |
|       MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|              ("invalid data on " MOZILLA_LOCK_PROP
 | |
|               " of window 0x%x.\n",
 | |
|               (unsigned int) aWindow));
 | |
|       return NS_ERROR_FAILURE;
 | |
|   }
 | |
|   else if (strcmp((char *)data, mLockData)) {
 | |
|       MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|              (MOZILLA_LOCK_PROP " was stolen!  Expected \"%s\", saw \"%s\"!\n",
 | |
|               mLockData, data));
 | |
|       return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   if (data)
 | |
|       XFree(data);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| XRemoteClient::DoSendCommandLine(Window aWindow, int32_t argc, char **argv,
 | |
|                                  const char* aDesktopStartupID,
 | |
|                                  char **aResponse, bool *aDestroyed)
 | |
| {
 | |
|   *aDestroyed = false;
 | |
| 
 | |
|   int commandLineLength;
 | |
|   char* commandLine = ConstructCommandLine(argc, argv, aDesktopStartupID,
 | |
|                                            &commandLineLength);
 | |
|   XChangeProperty (mDisplay, aWindow, mMozCommandLineAtom, XA_STRING, 8,
 | |
|                    PropModeReplace, (unsigned char *) commandLine,
 | |
|                    commandLineLength);
 | |
|   free(commandLine);
 | |
| 
 | |
|   if (!WaitForResponse(aWindow, aResponse, aDestroyed, mMozCommandLineAtom))
 | |
|     return NS_ERROR_FAILURE;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| bool
 | |
| XRemoteClient::WaitForResponse(Window aWindow, char **aResponse,
 | |
|                                bool *aDestroyed, Atom aCommandAtom)
 | |
| {
 | |
|   bool done = false;
 | |
|   bool accepted = false;
 | |
| 
 | |
|   while (!done) {
 | |
|     XEvent event;
 | |
|     XNextEvent (mDisplay, &event);
 | |
|     if (event.xany.type == DestroyNotify &&
 | |
|         event.xdestroywindow.window == aWindow) {
 | |
|       /* Print to warn user...*/
 | |
|       MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|              ("window 0x%x was destroyed.\n",
 | |
|               (unsigned int) aWindow));
 | |
|       *aResponse = strdup("Window was destroyed while reading response.");
 | |
|       *aDestroyed = true;
 | |
|       return false;
 | |
|     }
 | |
|     if (event.xany.type == PropertyNotify &&
 | |
|              event.xproperty.state == PropertyNewValue &&
 | |
|              event.xproperty.window == aWindow &&
 | |
|              event.xproperty.atom == mMozResponseAtom) {
 | |
|       Atom actual_type;
 | |
|       int actual_format;
 | |
|       unsigned long nitems, bytes_after;
 | |
|       unsigned char *data = 0;
 | |
|       Bool result;
 | |
|       result = XGetWindowProperty (mDisplay, aWindow, mMozResponseAtom,
 | |
|                                    0, (65536 / sizeof (long)),
 | |
|                                    True, /* atomic delete after */
 | |
|                                    XA_STRING,
 | |
|                                    &actual_type, &actual_format,
 | |
|                                    &nitems, &bytes_after,
 | |
|                                    &data);
 | |
|       if (result != Success) {
 | |
|         MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|                ("failed reading " MOZILLA_RESPONSE_PROP
 | |
|                 " from window 0x%0x.\n",
 | |
|                 (unsigned int) aWindow));
 | |
|         *aResponse = strdup("Internal error reading response from window.");
 | |
|         done = true;
 | |
|       }
 | |
|       else if (!data || strlen((char *) data) < 5) {
 | |
|         MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|                ("invalid data on " MOZILLA_RESPONSE_PROP
 | |
|                 " property of window 0x%0x.\n",
 | |
|                 (unsigned int) aWindow));
 | |
|         *aResponse = strdup("Server returned invalid data in response.");
 | |
|         done = true;
 | |
|       }
 | |
|       else if (*data == '1') {  /* positive preliminary reply */
 | |
|         MOZ_LOG(sRemoteLm, LogLevel::Debug,  ("%s\n", data + 4));
 | |
|         /* keep going */
 | |
|         done = false;
 | |
|       }
 | |
| 
 | |
|       else if (!strncmp ((char *)data, "200", 3)) { /* positive completion */
 | |
|         *aResponse = strdup((char *)data);
 | |
|         accepted = true;
 | |
|         done = true;
 | |
|       }
 | |
| 
 | |
|       else if (*data == '2') {  /* positive completion */
 | |
|         MOZ_LOG(sRemoteLm, LogLevel::Debug, ("%s\n", data + 4));
 | |
|         *aResponse = strdup((char *)data);
 | |
|         accepted = true;
 | |
|         done = true;
 | |
|       }
 | |
| 
 | |
|       else if (*data == '3') {  /* positive intermediate reply */
 | |
|         MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|                ("internal error: "
 | |
|                 "server wants more information?  (%s)\n",
 | |
|                 data));
 | |
|         *aResponse = strdup((char *)data);
 | |
|         done = true;
 | |
|       }
 | |
| 
 | |
|       else if (*data == '4' ||  /* transient negative completion */
 | |
|                *data == '5') {  /* permanent negative completion */
 | |
|         MOZ_LOG(sRemoteLm, LogLevel::Debug, ("%s\n", data + 4));
 | |
|         *aResponse = strdup((char *)data);
 | |
|         done = true;
 | |
|       }
 | |
| 
 | |
|       else {
 | |
|         MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|                ("unrecognised " MOZILLA_RESPONSE_PROP
 | |
|                 " from window 0x%x: %s\n",
 | |
|                 (unsigned int) aWindow, data));
 | |
|         *aResponse = strdup((char *)data);
 | |
|         done = true;
 | |
|       }
 | |
| 
 | |
|       if (data)
 | |
|         XFree(data);
 | |
|     }
 | |
| 
 | |
|     else if (event.xany.type == PropertyNotify &&
 | |
|              event.xproperty.window == aWindow &&
 | |
|              event.xproperty.state == PropertyDelete &&
 | |
|              event.xproperty.atom == aCommandAtom) {
 | |
|       MOZ_LOG(sRemoteLm, LogLevel::Debug,
 | |
|              ("(server 0x%x has accepted "
 | |
|               MOZILLA_COMMANDLINE_PROP ".)\n",
 | |
|               (unsigned int) aWindow));
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   return accepted;
 | |
| }
 |