Close the blank browser window from a download earlier, before showing the helper app dialog (bug 343921). Patch by marria@gmail.com, r=biesi, sr=darin.

This commit is contained in:
bryner%brianryner.com 2006-08-08 18:02:46 +00:00
Родитель 5b1ca12641
Коммит 07e3f00ad0
2 изменённых файлов: 66 добавлений и 25 удалений

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

@ -1336,6 +1336,7 @@ NS_INTERFACE_MAP_BEGIN(nsExternalAppHandler)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY(nsIHelperAppLauncher)
NS_INTERFACE_MAP_ENTRY(nsICancelable)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
NS_INTERFACE_MAP_END_THREADSAFE
nsExternalAppHandler::nsExternalAppHandler(nsIMIMEInfo * aMIMEInfo,
@ -1345,9 +1346,9 @@ nsExternalAppHandler::nsExternalAppHandler(nsIMIMEInfo * aMIMEInfo,
PRUint32 aReason)
: mMimeInfo(aMIMEInfo)
, mWindowContext(aWindowContext)
, mWindowToClose(nsnull)
, mSuggestedFileName(aSuggestedFilename)
, mCanceled(PR_FALSE)
, mHasRefreshHeader(PR_FALSE)
, mShouldCloseWindow(PR_FALSE)
, mReceivedDispositionInfo(PR_FALSE)
, mStopRequestIssued(PR_FALSE)
@ -1651,6 +1652,24 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest *request, nsISuppo
// retarget all load notifications to our docloader instead of the original window's docloader...
RetargetLoadNotifications(request);
// Check to see if there is a refresh header on the original channel.
if (mOriginalChannel) {
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mOriginalChannel));
if (httpChannel) {
nsCAutoString refreshHeader;
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
refreshHeader);
if (!refreshHeader.IsEmpty()) {
mShouldCloseWindow = PR_FALSE;
}
}
}
// Close the underlying DOMWindow if there is no refresh header
// and it was opened specifically for the download
MaybeCloseWindow();
nsCOMPtr<nsIEncodedChannel> encChannel = do_QueryInterface( aChannel );
if (encChannel)
{
@ -2084,10 +2103,6 @@ nsresult nsExternalAppHandler::ExecuteDesiredAction()
}
mWebProgressListener->OnStateChange(nsnull, nsnull, nsIWebProgressListener::STATE_STOP, NS_OK);
}
// Close the underlying DOMWindow if there is no refresh header
// and it was opened specifically for the download
MaybeCloseWindow();
}
return rv;
@ -2474,10 +2489,6 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel(nsresult aReason)
NS_ENSURE_ARG(NS_FAILED(aReason));
// XXX should not ignore the reason
// Close the underlying DOMWindow if there is no refresh header
// and it was opened specifically for the download
MaybeCloseWindow();
mCanceled = PR_TRUE;
// Break our reference cycle with the helper app dialog (set up in
// OnStartRequest)
@ -2524,10 +2535,7 @@ void nsExternalAppHandler::ProcessAnyRefreshTags()
{
nsCOMPtr<nsIRefreshURI> refreshHandler (do_GetInterface(mWindowContext));
if (refreshHandler) {
nsresult rv = refreshHandler->SetupRefreshURI(mOriginalChannel);
if (rv == NS_REFRESHURI_HEADER_FOUND) {
mHasRefreshHeader = PR_TRUE;
}
refreshHandler->SetupRefreshURI(mOriginalChannel);
}
mOriginalChannel = nsnull;
}
@ -2566,15 +2574,42 @@ nsresult nsExternalAppHandler::MaybeCloseWindow()
nsCOMPtr<nsIDOMWindowInternal> internalWindow = do_QueryInterface(window);
NS_ENSURE_STATE(internalWindow);
// Only close the page if there is no refresh header and if the window
// was opened specifically for the download
if (!mHasRefreshHeader && mShouldCloseWindow) {
internalWindow->Close();
if (mShouldCloseWindow) {
// Reset the window context to the opener window so that the dependent
// dialogs have a parent
nsCOMPtr<nsIDOMWindowInternal> opener;
internalWindow->GetOpener(getter_AddRefs(opener));
if (opener) {
mWindowContext = do_GetInterface(opener);
// Now close the old window. Do it on a timer so that we don't run
// into issues trying to close the window before it has fully opened.
NS_ASSERTION(!mTimer, "mTimer was already initialized once!");
mTimer = do_CreateInstance("@mozilla.org/timer;1");
if (!mTimer) {
return NS_ERROR_FAILURE;
}
mTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT);
mWindowToClose = internalWindow;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsExternalAppHandler::Notify(nsITimer* timer)
{
NS_ASSERTION(mWindowToClose, "No window to close after timer fired");
mWindowToClose->Close();
mWindowToClose = nsnull;
mTimer = nsnull;
return NS_OK;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The following section contains our nsIMIMEService implementation and related methods.
//

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

@ -65,6 +65,7 @@
#include "nsIInterfaceRequestorUtils.h"
#include "nsILocalFile.h"
#include "nsIChannel.h"
#include "nsITimer.h"
#include "nsIRDFDataSource.h"
#include "nsIRDFResource.h"
@ -78,6 +79,7 @@ class nsExternalAppHandler;
class nsIMIMEInfo;
class nsIRDFService;
class nsITransfer;
class nsIDOMWindowInternal;
/**
* The helper app service. Responsible for handling content that Mozilla
@ -318,7 +320,8 @@ protected:
* data using a helper app.
*/
class nsExternalAppHandler : public nsIStreamListener,
public nsIHelperAppLauncher
public nsIHelperAppLauncher,
public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS
@ -326,6 +329,7 @@ public:
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSIHELPERAPPLAUNCHER
NS_DECL_NSICANCELABLE
NS_DECL_NSITIMERCALLBACK
/**
* @param aMIMEInfo MIMEInfo object, representing the type of the
@ -353,7 +357,15 @@ protected:
*/
nsCOMPtr<nsIMIMEInfo> mMimeInfo;
nsCOMPtr<nsIOutputStream> mOutStream; /**< output stream to the temp file */
nsCOMPtr<nsIInterfaceRequestor> mWindowContext;
nsCOMPtr<nsIInterfaceRequestor> mWindowContext;
/**
* Used to close the window on a timer, to avoid any exceptions that are
* thrown if we try to close the window before it's fully loaded.
*/
nsCOMPtr<nsIDOMWindowInternal> mWindowToClose;
nsCOMPtr<nsITimer> mTimer;
/**
* The following field is set if we were processing an http channel that had
* a content disposition header which specified the SUGGESTED file name we
@ -367,12 +379,6 @@ protected:
*/
PRPackedBool mCanceled;
/**
* This flag is set if a refresh header was found. In this case, we
* don't want to close the dom window after handling the content.
*/
PRPackedBool mHasRefreshHeader;
/**
* This is set based on whether the channel indicates that a new window
* was opened specifically for this download. If so, then we