b=499498 BadWindow errors on startup r=roc

--HG--
extra : rebase_source : 8e47f6374273fa5d44c1b3a96be5fa71f6662976
This commit is contained in:
Karl Tomlinson 2009-09-03 08:47:44 +12:00
Родитель 87d4ee061f
Коммит d2fc5e2ab7
2 изменённых файлов: 89 добавлений и 52 удалений

Просмотреть файл

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=4:tabstop=4:
/* -*- 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: */
/* ***** BEGIN LICENSE BLOCK *****
@ -88,6 +88,9 @@
static PRLogModuleInfo *sRemoteLm = NULL;
static int (*sOldHandler)(Display *, XErrorEvent *);
static PRBool sGotBadWindow;
XRemoteClient::XRemoteClient()
{
mDisplay = 0;
@ -183,40 +186,10 @@ XRemoteClient::SendCommand (const char *aProgram, const char *aUsername,
{
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommand"));
*aWindowFound = PR_FALSE;
Window w = FindBestWindow(aProgram, aUsername, aProfile, PR_FALSE);
nsresult rv = NS_OK;
if (w) {
// ok, let the caller know that we at least found a window.
*aWindowFound = PR_TRUE;
// make sure we get the right events on that window
XSelectInput(mDisplay, w,
(PropertyChangeMask|StructureNotifyMask));
PRBool destroyed = PR_FALSE;
// get the lock on the window
rv = GetLock(w, &destroyed);
if (NS_SUCCEEDED(rv)) {
// send our command
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
}
}
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("SendCommand returning 0x%x\n", rv));
return rv;
return SendCommandInternal(aProgram, aUsername, aProfile,
aCommand, 0, nsnull,
aDesktopStartupID,
aResponse, aWindowFound);
}
nsresult
@ -228,9 +201,39 @@ XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
{
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommandLine"));
*aWindowFound = PR_FALSE;
return SendCommandInternal(aProgram, aUsername, aProfile,
nsnull, argc, argv,
aDesktopStartupID,
aResponse, aWindowFound);
}
Window w = FindBestWindow(aProgram, aUsername, aProfile, PR_TRUE);
static int
HandleBadWindow(Display *display, XErrorEvent *event)
{
if (event->error_code == BadWindow) {
sGotBadWindow = PR_TRUE;
return 0; // ignored
}
else {
return (*sOldHandler)(display, event);
}
}
nsresult
XRemoteClient::SendCommandInternal(const char *aProgram, const char *aUsername,
const char *aProfile, const char *aCommand,
PRInt32 argc, char **argv,
const char* aDesktopStartupID,
char **aResponse, PRBool *aWindowFound)
{
*aWindowFound = PR_FALSE;
PRBool 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, isCommandLine);
nsresult rv = NS_OK;
@ -238,10 +241,15 @@ XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
// ok, let the caller know that we at least found a window.
*aWindowFound = PR_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 = PR_FALSE;
// make sure we get the right events on that window
XSelectInput(mDisplay, w,
(PropertyChangeMask|StructureNotifyMask));
PRBool destroyed = PR_FALSE;
// get the lock on the window
@ -249,7 +257,14 @@ XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
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.
@ -259,7 +274,9 @@ XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
}
}
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("SendCommandLine returning 0x%x\n", rv));
XSetErrorHandler(sOldHandler);
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("SendCommandInternal returning 0x%x\n", rv));
return rv;
}
@ -338,6 +355,8 @@ XRemoteClient::GetLock(Window aWindow, PRBool *aDestroyed)
PRBool waited = PR_FALSE;
*aDestroyed = PR_FALSE;
nsresult rv = NS_OK;
if (!mLockData) {
char pidstr[32];
@ -377,7 +396,16 @@ XRemoteClient::GetLock(Window aWindow, PRBool *aDestroyed)
&actual_type, &actual_format,
&nitems, &bytes_after,
&data);
if (result != Success || actual_type == None) {
// 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 = PR_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,
@ -387,9 +415,9 @@ XRemoteClient::GetLock(Window aWindow, PRBool *aDestroyed)
}
XUngrabServer(mDisplay);
XSync(mDisplay, False);
XFlush(mDisplay); // ungrab now!
if (!locked) {
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. */
@ -420,17 +448,16 @@ XRemoteClient::GetLock(Window aWindow, PRBool *aDestroyed)
// did we time out?
if (select_retval == 0) {
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("timed out waiting for window\n"));
return NS_ERROR_FAILURE;
rv = NS_ERROR_FAILURE;
break;
}
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("xevent...\n"));
XNextEvent (mDisplay, &event);
if (event.xany.type == DestroyNotify &&
event.xdestroywindow.window == aWindow) {
PR_LOG(sRemoteLm, PR_LOG_DEBUG,
("window 0x%x unexpectedly destroyed.\n",
(unsigned int) aWindow));
*aDestroyed = PR_TRUE;
return NS_ERROR_FAILURE;
rv = NS_ERROR_FAILURE;
break;
}
else if (event.xany.type == PropertyNotify &&
event.xproperty.state == PropertyDelete &&
@ -447,13 +474,17 @@ XRemoteClient::GetLock(Window aWindow, PRBool *aDestroyed)
}
if (data)
XFree(data);
} while (!locked);
} while (!locked && !NS_FAILED(rv));
if (waited) {
if (waited && locked) {
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("obtained lock.\n"));
} else if (*aDestroyed) {
PR_LOG(sRemoteLm, PR_LOG_DEBUG,
("window 0x%x unexpectedly destroyed.\n",
(unsigned int) aWindow));
}
return NS_OK;
return rv;
}
Window

Просмотреть файл

@ -1,3 +1,4 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -67,6 +68,11 @@ private:
const char *aUsername,
const char *aProfile,
PRBool aSupportsCommandLine);
nsresult SendCommandInternal(const char *aProgram, const char *aUsername,
const char *aProfile, const char *aCommand,
PRInt32 argc, char **argv,
const char* aDesktopStartupID,
char **aResponse, PRBool *aWindowFound);
nsresult DoSendCommand (Window aWindow,
const char *aCommand,
const char* aDesktopStartupID,