restoring rev 1.159 (bug 97514 r=hyatt,pchen). the root cause of bug 98732 (and rev 1.160) has been fixed elsewhere (bug 98785).
git-svn-id: svn://10.0.0.236/trunk@102559 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -69,6 +69,7 @@ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID);
|
||||
static NS_DEFINE_CID(kXPConnectCID, NS_XPCONNECT_CID);
|
||||
static char *sWindowWatcherContractID = "@mozilla.org/embedcomp/window-watcher;1";
|
||||
|
||||
// copied from nsEventQueue.cpp
|
||||
static char *gEQActivatedNotification = "nsIEventQueueActivated";
|
||||
@@ -80,7 +81,6 @@ NS_NAMED_LITERAL_STRING(gInstallRestartTopic, "xpinstall-restart");
|
||||
|
||||
nsAppShellService::nsAppShellService() :
|
||||
mAppShell( nsnull ),
|
||||
mWindowList( nsnull ),
|
||||
mCmdLineService( nsnull ),
|
||||
mWindowMediator( nsnull ),
|
||||
mHiddenWindow( nsnull ),
|
||||
@@ -133,18 +133,11 @@ nsAppShellService::Initialize( nsICmdLineService *aCmdLineService,
|
||||
mCmdLineService = aCmdLineService;
|
||||
|
||||
// Remember where the native app support lives.
|
||||
mNativeAppSupport = do_QueryInterface( aNativeAppSupportOrSplashScreen );
|
||||
mNativeAppSupport = do_QueryInterface(aNativeAppSupportOrSplashScreen);
|
||||
|
||||
// Or, remember the splash screen (for backward compatibility).
|
||||
if ( !mNativeAppSupport ) {
|
||||
mSplashScreen = do_QueryInterface( aNativeAppSupportOrSplashScreen );
|
||||
}
|
||||
|
||||
// Create the toplevel window list...
|
||||
rv = NS_NewISupportsArray(getter_AddRefs(mWindowList));
|
||||
if (NS_FAILED(rv)) {
|
||||
goto done;
|
||||
}
|
||||
if (!mNativeAppSupport)
|
||||
mSplashScreen = do_QueryInterface(aNativeAppSupportOrSplashScreen);
|
||||
|
||||
NS_TIMELINE_ENTER("nsComponentManager::CreateInstance.");
|
||||
// Create widget application shell
|
||||
@@ -152,25 +145,21 @@ nsAppShellService::Initialize( nsICmdLineService *aCmdLineService,
|
||||
NS_GET_IID(nsIAppShell),
|
||||
(void**)getter_AddRefs(mAppShell));
|
||||
NS_TIMELINE_LEAVE("nsComponentManager::CreateInstance");
|
||||
if (NS_FAILED(rv)) {
|
||||
if (NS_FAILED(rv))
|
||||
goto done;
|
||||
}
|
||||
|
||||
rv = mAppShell->Create(0, nsnull);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
goto done;
|
||||
}
|
||||
if (NS_FAILED(rv))
|
||||
goto done;
|
||||
|
||||
// listen to EventQueues' comings and goings. do this after the appshell
|
||||
// has been created, but after the event queue has been created. that
|
||||
// latter bit is unfortunate, but we deal with it.
|
||||
RegisterObserver(PR_TRUE);
|
||||
|
||||
// enable window mediation
|
||||
mWindowMediator = do_GetService(kWindowMediatorCID);
|
||||
|
||||
// CreateHiddenWindow(); // rjc: now require this to be explicitly called
|
||||
// enable window mediation (and fail if we can't get the mediator)
|
||||
mWindowMediator = do_GetService(kWindowMediatorCID, &rv);
|
||||
mWindowWatcher = do_GetService(sWindowWatcherContractID);
|
||||
|
||||
done:
|
||||
return rv;
|
||||
@@ -464,86 +453,86 @@ nsAppShellService::Quit()
|
||||
// through any events in the queue. This guarantees a tidy cleanup.
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (! mShuttingDown) {
|
||||
mShuttingDown = PR_TRUE;
|
||||
if (mShuttingDown)
|
||||
return NS_OK;
|
||||
|
||||
// Shutdown native app support; doing this first will prevent new
|
||||
// requests to open additional windows coming in.
|
||||
if ( mNativeAppSupport ) {
|
||||
mNativeAppSupport->Quit();
|
||||
mNativeAppSupport = 0;
|
||||
}
|
||||
mShuttingDown = PR_TRUE;
|
||||
|
||||
// Enumerate through each open window and close it
|
||||
if (mWindowMediator) {
|
||||
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
|
||||
rv = mWindowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
|
||||
// Shutdown native app support; doing this first will prevent new
|
||||
// requests to open additional windows coming in.
|
||||
if (mNativeAppSupport) {
|
||||
mNativeAppSupport->Quit();
|
||||
mNativeAppSupport = 0;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRBool more;
|
||||
// Enumerate through each open window and close it
|
||||
if (mWindowMediator) {
|
||||
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
|
||||
mWindowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
|
||||
|
||||
while (1) {
|
||||
rv = windowEnumerator->HasMoreElements(&more);
|
||||
if (NS_FAILED(rv) || !more)
|
||||
break;
|
||||
if (windowEnumerator) {
|
||||
PRBool more;
|
||||
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
rv = windowEnumerator->GetNext(getter_AddRefs(isupports));
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
while (1) {
|
||||
rv = windowEnumerator->HasMoreElements(&more);
|
||||
if (NS_FAILED(rv) || !more)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsIDOMWindowInternal> window = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(window != nsnull, "not an nsIDOMWindowInternal");
|
||||
if (! window)
|
||||
continue;
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
rv = windowEnumerator->GetNext(getter_AddRefs(isupports));
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
window->Close();
|
||||
}
|
||||
nsCOMPtr<nsIDOMWindowInternal> window = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(window != nsnull, "not an nsIDOMWindowInternal");
|
||||
if (! window)
|
||||
continue;
|
||||
|
||||
window->Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
nsCOMPtr<nsIWebShellWindow> hiddenWin(do_QueryInterface(mHiddenWindow));
|
||||
if (hiddenWin) {
|
||||
ClearXPConnectSafeContext();
|
||||
hiddenWin->Close();
|
||||
}
|
||||
mHiddenWindow = nsnull;
|
||||
{
|
||||
nsCOMPtr<nsIWebShellWindow> hiddenWin(do_QueryInterface(mHiddenWindow));
|
||||
if (hiddenWin) {
|
||||
ClearXPConnectSafeContext();
|
||||
hiddenWin->Close();
|
||||
}
|
||||
|
||||
// Note that we don't allow any premature returns from the above
|
||||
// loop: no matter what, make sure we send the exit event. If
|
||||
// worst comes to worst, we'll do a leaky shutdown but we WILL
|
||||
// shut down. Well, assuming that all *this* stuff works ;-).
|
||||
nsCOMPtr<nsIEventQueueService> svc = do_GetService(kEventQueueServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mHiddenWindow = nsnull;
|
||||
}
|
||||
|
||||
// Note that we don't allow any premature returns from the above
|
||||
// loop: no matter what, make sure we send the exit event. If
|
||||
// worst comes to worst, we'll do a leaky shutdown but we WILL
|
||||
// shut down. Well, assuming that all *this* stuff works ;-).
|
||||
nsCOMPtr<nsIEventQueueService> svc = do_GetService(kEventQueueServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIEventQueue> queue;
|
||||
rv = svc->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsCOMPtr<nsIEventQueue> queue;
|
||||
rv = svc->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
ExitEvent* event = new ExitEvent;
|
||||
if (! event)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
ExitEvent* event = new ExitEvent;
|
||||
if (!event)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
PL_InitEvent(NS_REINTERPRET_CAST(PLEvent*, event),
|
||||
nsnull,
|
||||
HandleExitEvent,
|
||||
DestroyExitEvent);
|
||||
PL_InitEvent(NS_REINTERPRET_CAST(PLEvent*, event),
|
||||
nsnull,
|
||||
HandleExitEvent,
|
||||
DestroyExitEvent);
|
||||
|
||||
event->mService = this;
|
||||
NS_ADDREF(event->mService);
|
||||
event->mService = this;
|
||||
NS_ADDREF(event->mService);
|
||||
|
||||
rv = queue->EnterMonitor();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = queue->PostEvent(NS_REINTERPRET_CAST(PLEvent*, event));
|
||||
}
|
||||
(void) queue->ExitMonitor();
|
||||
rv = queue->EnterMonitor();
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = queue->PostEvent(NS_REINTERPRET_CAST(PLEvent*, event));
|
||||
queue->ExitMonitor();
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(event->mService);
|
||||
delete event;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(event->mService);
|
||||
delete event;
|
||||
}
|
||||
|
||||
return rv;
|
||||
@@ -808,64 +797,105 @@ nsAppShellService::GetHiddenWindowAndJSContext(nsIDOMWindowInternal **aWindow,
|
||||
NS_IMETHODIMP
|
||||
nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow)
|
||||
{
|
||||
mWindowList->AppendElement(aWindow);
|
||||
// tell the window mediator about the new window
|
||||
if (mWindowMediator)
|
||||
mWindowMediator->RegisterWindow(aWindow);
|
||||
|
||||
if(mWindowMediator)
|
||||
mWindowMediator->RegisterWindow(aWindow);
|
||||
// tell the window watcher about the new window
|
||||
if (mWindowWatcher) {
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
aWindow->GetDocShell(getter_AddRefs(docShell));
|
||||
if (docShell) {
|
||||
nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(docShell));
|
||||
if (domWindow)
|
||||
mWindowWatcher->AddWindow(domWindow, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
#define SOMEBODY_SET_UP_US_THE_NULL_POINTER 1
|
||||
// to be turned off once we fix callers who do that to us
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAppShellService::UnregisterTopLevelWindow(nsIXULWindow* aWindow)
|
||||
{
|
||||
if (mDeleteCalled) {
|
||||
// return an error code in order to:
|
||||
// - avoid doing anything with other member variables while we are in the destructor
|
||||
// - notify the caller not to release the AppShellService after unregistering the window
|
||||
// (we don't want to be deleted twice consecutively to mHiddenWindow->Close() in our destructor)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
PRBool windowsRemain = PR_TRUE;
|
||||
|
||||
if (mDeleteCalled) {
|
||||
/* return an error code in order to:
|
||||
- avoid doing anything with other member variables while we are in
|
||||
the destructor
|
||||
- notify the caller not to release the AppShellService after
|
||||
unregistering the window
|
||||
(we don't want to be deleted twice consecutively to
|
||||
mHiddenWindow->Close() in our destructor)
|
||||
*/
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if(mWindowMediator)
|
||||
mWindowMediator->UnregisterWindow(aWindow);
|
||||
#ifdef SOMEBODY_SET_UP_US_THE_NULL_POINTER
|
||||
if (aWindow) {
|
||||
#else
|
||||
NS_ENSURE_ARG_POINTER(aWindow);
|
||||
#endif
|
||||
|
||||
// tell the window mediator
|
||||
if (mWindowMediator) {
|
||||
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
|
||||
mWindowMediator->UnregisterWindow(aWindow);
|
||||
|
||||
mWindowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
|
||||
if (windowEnumerator)
|
||||
windowEnumerator->HasMoreElements(&windowsRemain);
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
// tell the window watcher
|
||||
if (mWindowWatcher) {
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
aWindow->GetDocShell(getter_AddRefs(docShell));
|
||||
if (docShell) {
|
||||
nsCOMPtr<nsIDOMWindow> domWindow(do_GetInterface(docShell));
|
||||
if (domWindow)
|
||||
mWindowWatcher->RemoveWindow(domWindow);
|
||||
}
|
||||
}
|
||||
#ifdef SOMEBODY_SET_UP_US_THE_NULL_POINTER
|
||||
}
|
||||
#endif
|
||||
|
||||
mWindowList->RemoveElement(aWindow);
|
||||
// now quit if the last window has been unregistered (unless we shouldn't)
|
||||
|
||||
PRUint32 cnt;
|
||||
rv = mWindowList->Count(&cnt);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (0 == cnt)
|
||||
{
|
||||
if (!mQuitOnLastWindowClosing)
|
||||
return NS_OK;
|
||||
if (!mQuitOnLastWindowClosing)
|
||||
return NS_OK;
|
||||
|
||||
if (!windowsRemain) {
|
||||
|
||||
#if XP_MAC
|
||||
// if no hidden window is available (perhaps due to initial
|
||||
// Profile Manager window being cancelled), then just quit. We don't have
|
||||
// to worry about focussing the hidden window, because it will get activated
|
||||
// by the OS since it is visible (but waaaay offscreen).
|
||||
nsCOMPtr<nsIBaseWindow> hiddenWin(do_QueryInterface(mHiddenWindow));
|
||||
if (!hiddenWin)
|
||||
Quit();
|
||||
#else
|
||||
#if XP_MAC
|
||||
// if no hidden window is available (perhaps due to initial
|
||||
// Profile Manager window being cancelled), then just quit. We don't have
|
||||
// to worry about focussing the hidden window, because it will get activated
|
||||
// by the OS since it is visible (but waaaay offscreen).
|
||||
nsCOMPtr<nsIBaseWindow> hiddenWin(do_QueryInterface(mHiddenWindow));
|
||||
if (!hiddenWin)
|
||||
Quit();
|
||||
#else
|
||||
// Check to see if we should quit in this case.
|
||||
if (mNativeAppSupport) {
|
||||
PRBool serverMode = PR_FALSE;
|
||||
mNativeAppSupport->GetIsServerMode(&serverMode);
|
||||
if (serverMode) {
|
||||
mNativeAppSupport->OnLastWindowClosing(aWindow);
|
||||
return NS_OK;
|
||||
}
|
||||
PRBool serverMode = PR_FALSE;
|
||||
mNativeAppSupport->GetIsServerMode(&serverMode);
|
||||
if (serverMode) {
|
||||
mNativeAppSupport->OnLastWindowClosing(aWindow);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
Quit();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
||||
Reference in New Issue
Block a user