Back to index

lightning-sunbird  0.9+nobinonly
nsXULWindow.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Travis Bogard <travis@netscape.com>
00025  *   Dan Rosen <dr@netscape.com>
00026  *   Ben Goodger <ben@netscape.com>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 // Local includes
00043 #include "nsXULWindow.h"
00044 
00045 // Helper classes
00046 #include "nsString.h"
00047 #include "nsWidgetsCID.h"
00048 #include "prprf.h"
00049 #include "nsCRT.h"
00050 
00051 //Interfaces needed to be included
00052 #include "nsIAppShell.h"
00053 #include "nsIAppShellService.h"
00054 #include "nsIServiceManager.h"
00055 #include "nsIDocumentViewer.h"
00056 #include "nsIDocument.h"
00057 #include "nsIDOMBarProp.h"
00058 #include "nsIDOMDocument.h"
00059 #include "nsIDOMDocumentEvent.h"
00060 #include "nsIDOMXULDocument.h"
00061 #include "nsIDOMElement.h"
00062 #include "nsIPrivateDOMEvent.h"
00063 #include "nsIDOMEventTarget.h"
00064 #include "nsIDOMXULElement.h"
00065 #include "nsIDOMWindowInternal.h"
00066 #include "nsIDOMScreen.h"
00067 #include "nsIEmbeddingSiteWindow.h"
00068 #include "nsIEmbeddingSiteWindow2.h"
00069 #include "nsIInterfaceRequestor.h"
00070 #include "nsIInterfaceRequestorUtils.h"
00071 #include "nsIIOService.h"
00072 #include "nsNetCID.h"
00073 #include "nsIJSContextStack.h"
00074 #include "nsIMarkupDocumentViewer.h"
00075 #include "nsIObserverService.h"
00076 #include "nsIWindowMediator.h"
00077 #include "nsIScreenManager.h"
00078 #include "nsIScreen.h"
00079 #include "nsIScrollable.h"
00080 #include "nsIPref.h"
00081 #include "nsIScriptGlobalObject.h"
00082 #include "nsIScriptSecurityManager.h"
00083 #include "nsIWindowWatcher.h"
00084 #include "nsIURI.h"
00085 #include "nsIDOMDocumentView.h"
00086 #include "nsIDOMViewCSS.h"
00087 #include "nsIDOMCSSStyleDeclaration.h"
00088 #include "nsITimelineService.h"
00089 #include "nsAppShellCID.h"
00090 #include "nsReadableUtils.h"
00091 #include "nsStyleConsts.h"
00092 
00093 #include "nsWebShellWindow.h" // get rid of this one, too...
00094 
00095 #define SIZEMODE_NORMAL    NS_LITERAL_STRING("normal")
00096 #define SIZEMODE_MAXIMIZED NS_LITERAL_STRING("maximized")
00097 #define SIZEMODE_MINIMIZED NS_LITERAL_STRING("minimized")
00098 
00099 #define WINDOWTYPE_ATTRIBUTE NS_LITERAL_STRING("windowtype")
00100 
00101 #define PERSIST_ATTRIBUTE  NS_LITERAL_STRING("persist")
00102 #define SCREENX_ATTRIBUTE  NS_LITERAL_STRING("screenX")
00103 #define SCREENY_ATTRIBUTE  NS_LITERAL_STRING("screenY")
00104 #define WIDTH_ATTRIBUTE    NS_LITERAL_STRING("width")
00105 #define HEIGHT_ATTRIBUTE   NS_LITERAL_STRING("height")
00106 #define MODE_ATTRIBUTE     NS_LITERAL_STRING("sizemode")
00107 #define ZLEVEL_ATTRIBUTE   NS_LITERAL_STRING("zlevel")
00108 // CIDs
00109 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
00110 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00111 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
00112 static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
00113 static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID);
00114 
00115 //*****************************************************************************
00116 //***    nsXULWindow: Object Management
00117 //*****************************************************************************
00118 
00119 nsXULWindow::nsXULWindow() : mChromeTreeOwner(nsnull), 
00120    mContentTreeOwner(nsnull), mPrimaryContentTreeOwner(nsnull),
00121    mModalStatus(NS_OK), mContinueModalLoop(PR_FALSE),
00122    mDebuting(PR_FALSE), mChromeLoaded(PR_FALSE), 
00123    mShowAfterLoad(PR_FALSE), mIntrinsicallySized(PR_FALSE),
00124    mCenterAfterLoad(PR_FALSE), mIsHiddenWindow(PR_FALSE),
00125    mLockedUntilChromeLoad(PR_FALSE),
00126    mContextFlags(0), mBlurSuppressionLevel(0),
00127    mPersistentAttributesDirty(0), mPersistentAttributesMask(0),
00128    mChromeFlags(nsIWebBrowserChrome::CHROME_ALL)
00129 {
00130 }
00131 
00132 nsXULWindow::~nsXULWindow()
00133 {
00134   Destroy();
00135 }
00136 
00137 //*****************************************************************************
00138 // nsXULWindow::nsISupports
00139 //*****************************************************************************
00140 
00141 NS_IMPL_THREADSAFE_ADDREF(nsXULWindow)
00142 NS_IMPL_THREADSAFE_RELEASE(nsXULWindow)
00143 
00144 NS_INTERFACE_MAP_BEGIN(nsXULWindow)
00145    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULWindow)
00146    NS_INTERFACE_MAP_ENTRY(nsIXULWindow)
00147    NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
00148    NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
00149    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00150    if (aIID.Equals(NS_GET_IID(nsXULWindow)))
00151        foundInterface = NS_REINTERPRET_CAST(nsISupports*, this);
00152    else
00153 NS_INTERFACE_MAP_END
00154 
00155 //*****************************************************************************
00156 // nsXULWindow::nsIIntefaceRequestor
00157 //*****************************************************************************   
00158 
00159 NS_IMETHODIMP nsXULWindow::GetInterface(const nsIID& aIID, void** aSink)
00160 {
00161   nsresult rv;
00162 
00163   NS_ENSURE_ARG_POINTER(aSink);
00164 
00165   if (aIID.Equals(NS_GET_IID(nsIPrompt))) {
00166     rv = EnsurePrompter();
00167     if (NS_FAILED(rv)) return rv;
00168     return mPrompter->QueryInterface(aIID, aSink);
00169   }   
00170   if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
00171     rv = EnsureAuthPrompter();
00172     if (NS_FAILED(rv)) return rv;
00173     return mAuthPrompter->QueryInterface(aIID, aSink);
00174   }
00175   if (aIID.Equals(NS_GET_IID(nsIWebBrowserChrome)) && 
00176     NS_SUCCEEDED(EnsureContentTreeOwner()) &&
00177     NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink)))
00178     return NS_OK;
00179 
00180   if (aIID.Equals(NS_GET_IID(nsIEmbeddingSiteWindow)) && 
00181     NS_SUCCEEDED(EnsureContentTreeOwner()) &&
00182     NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink)))
00183     return NS_OK;
00184   if (aIID.Equals(NS_GET_IID(nsIEmbeddingSiteWindow2)) && 
00185     NS_SUCCEEDED(EnsureContentTreeOwner()) &&
00186     NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink)))
00187     return NS_OK;
00188 
00189   return QueryInterface(aIID, aSink);
00190 }
00191 
00192 //*****************************************************************************
00193 // nsXULWindow::nsIXULWindow
00194 //*****************************************************************************   
00195 
00196 NS_IMETHODIMP nsXULWindow::GetDocShell(nsIDocShell** aDocShell)
00197 {
00198   NS_ENSURE_ARG_POINTER(aDocShell);
00199 
00200   *aDocShell = mDocShell;
00201   NS_IF_ADDREF(*aDocShell);
00202   return NS_OK;
00203 }
00204 
00205 NS_IMETHODIMP nsXULWindow::GetZLevel(PRUint32 *outLevel)
00206 {
00207   nsCOMPtr<nsIWindowMediator> mediator(do_GetService(kWindowMediatorCID));
00208   if (mediator)
00209     mediator->GetZLevel(this, outLevel);
00210   else
00211     *outLevel = normalZ;
00212   return NS_OK;
00213 }
00214 
00215 NS_IMETHODIMP nsXULWindow::SetZLevel(PRUint32 aLevel)
00216 {
00217   nsCOMPtr<nsIWindowMediator> mediator(do_GetService(kWindowMediatorCID));
00218   if (!mediator)
00219     return NS_ERROR_FAILURE;
00220 
00221   PRUint32 zLevel;
00222   mediator->GetZLevel(this, &zLevel);
00223   if (zLevel == aLevel)
00224     return NS_OK;
00225 
00226   /* refuse to raise a maximized window above the normal browser level,
00227      for fear it could hide newly opened browser windows */
00228   if (aLevel > nsIXULWindow::normalZ) {
00229     PRInt32 sizeMode;
00230     if (mWindow) {
00231       mWindow->GetSizeMode(&sizeMode);
00232       if (sizeMode == nsSizeMode_Maximized)
00233         return NS_ERROR_FAILURE;
00234     }
00235   }
00236 
00237   // disallow user script
00238   nsCOMPtr<nsIScriptSecurityManager> secMan =
00239            do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
00240   if (!secMan)
00241     return NS_ERROR_FAILURE;
00242   PRBool inChrome;
00243   if (NS_FAILED(secMan->SubjectPrincipalIsSystem(&inChrome)) || !inChrome)
00244     return NS_ERROR_FAILURE;
00245 
00246   // do it
00247   mediator->SetZLevel(this, aLevel);
00248   PersistentAttributesDirty(PAD_MISC);
00249   SavePersistentAttributes();
00250 
00251   // finally, send a notification DOM event
00252   nsCOMPtr<nsIContentViewer> cv;
00253   mDocShell->GetContentViewer(getter_AddRefs(cv));
00254   nsCOMPtr<nsIDocumentViewer> dv(do_QueryInterface(cv));
00255   if (dv) {
00256     nsCOMPtr<nsIDocument> doc;
00257     dv->GetDocument(getter_AddRefs(doc));
00258     nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(doc));
00259     if (docEvent) {
00260       nsCOMPtr<nsIDOMEvent> event;
00261       docEvent->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
00262       if (event) {
00263         event->InitEvent(NS_LITERAL_STRING("windowZLevel"), PR_TRUE, PR_FALSE);
00264 
00265         nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
00266         privateEvent->SetTrusted(PR_TRUE);
00267 
00268         nsCOMPtr<nsIDOMEventTarget> targ(do_QueryInterface(doc));
00269         if (targ) {
00270           PRBool defaultActionEnabled;
00271           targ->DispatchEvent(event, &defaultActionEnabled);
00272         }
00273       }
00274     }
00275   }
00276   
00277   return NS_OK;
00278 }
00279 
00280 NS_IMETHODIMP nsXULWindow::GetContextFlags(PRUint32 *aContextFlags)
00281 {
00282   NS_ENSURE_ARG_POINTER(aContextFlags);
00283   *aContextFlags = mContextFlags;
00284   return NS_OK;
00285 }
00286 
00287 NS_IMETHODIMP nsXULWindow::SetContextFlags(PRUint32 aContextFlags)
00288 {
00289   mContextFlags = aContextFlags;
00290   return NS_OK;
00291 }
00292 
00293 NS_IMETHODIMP nsXULWindow::GetChromeFlags(PRUint32 *aChromeFlags)
00294 {
00295   NS_ENSURE_ARG_POINTER(aChromeFlags);
00296   *aChromeFlags = mChromeFlags;
00297   /* mChromeFlags is kept up to date, except for scrollbar visibility.
00298      That can be changed directly by the content DOM window, which
00299      doesn't know to update the chrome window. So that we must check
00300      separately. */
00301 
00302   // however, it's pointless to ask if the window isn't set up yet
00303   if (!mChromeLoaded)
00304     return NS_OK;
00305 
00306   if (GetContentScrollbarVisibility())
00307     *aChromeFlags |= nsIWebBrowserChrome::CHROME_SCROLLBARS;
00308   else
00309     *aChromeFlags &= ~nsIWebBrowserChrome::CHROME_SCROLLBARS;
00310 
00311   return NS_OK;
00312 }
00313 
00314 NS_IMETHODIMP nsXULWindow::SetChromeFlags(PRUint32 aChromeFlags)
00315 {
00316   mChromeFlags = aChromeFlags;
00317   if (mChromeLoaded)
00318     NS_ENSURE_SUCCESS(ApplyChromeFlags(), NS_ERROR_FAILURE);
00319   return NS_OK;
00320 }
00321 
00322 NS_IMETHODIMP nsXULWindow::SetIntrinsicallySized(PRBool aIntrinsicallySized)
00323 {
00324    mIntrinsicallySized = aIntrinsicallySized;
00325    return NS_OK;
00326 }
00327 
00328 NS_IMETHODIMP nsXULWindow::GetIntrinsicallySized(PRBool* aIntrinsicallySized)
00329 {
00330    NS_ENSURE_ARG_POINTER(aIntrinsicallySized);
00331 
00332    *aIntrinsicallySized = mIntrinsicallySized;
00333    return NS_OK;
00334 }
00335 
00336 NS_IMETHODIMP nsXULWindow::GetPrimaryContentShell(nsIDocShellTreeItem** 
00337    aDocShellTreeItem)
00338 {
00339   NS_ENSURE_ARG_POINTER(aDocShellTreeItem);
00340   NS_IF_ADDREF(*aDocShellTreeItem = mPrimaryContentShell);
00341   return NS_OK;
00342 }
00343 
00344 NS_IMETHODIMP nsXULWindow::GetContentShellById(const PRUnichar* aID, 
00345    nsIDocShellTreeItem** aDocShellTreeItem)
00346 {
00347   NS_ENSURE_ARG_POINTER(aDocShellTreeItem);
00348   *aDocShellTreeItem = nsnull;
00349 
00350   PRInt32 count = mContentShells.Count();
00351   for (PRInt32 i = 0; i < count; i++) {
00352     nsContentShellInfo* shellInfo = (nsContentShellInfo*)mContentShells.ElementAt(i);
00353     if (shellInfo->id.Equals(aID)) {
00354       *aDocShellTreeItem = nsnull;
00355       if (shellInfo->child)
00356         CallQueryReferent(shellInfo->child.get(), aDocShellTreeItem);
00357       return NS_OK;
00358     }
00359   }
00360   return NS_ERROR_FAILURE;
00361 }
00362 
00363 NS_IMETHODIMP nsXULWindow::AddChildWindow(nsIXULWindow *aChild)
00364 {
00365    // we're not really keeping track of this right now
00366    return NS_OK;
00367 }
00368 
00369 NS_IMETHODIMP nsXULWindow::RemoveChildWindow(nsIXULWindow *aChild)
00370 {
00371   // we're not really keeping track of this right now
00372   return NS_OK;
00373 }
00374 
00375 NS_IMETHODIMP nsXULWindow::ShowModal()
00376 {
00377   nsCOMPtr<nsIAppShell> appShell(do_CreateInstance(kAppShellCID));
00378   NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
00379 
00380   appShell->Create(0, nsnull);
00381   appShell->Spinup();
00382   // Store locally so it doesn't die on us
00383   nsCOMPtr<nsIWidget> window = mWindow;
00384   nsCOMPtr<nsIXULWindow> tempRef = this;  
00385 
00386   window->SetModal(PR_TRUE);
00387   mContinueModalLoop = PR_TRUE;
00388   EnableParent(PR_FALSE);
00389 
00390   nsCOMPtr<nsIAppShellService> appShellService(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
00391   if (appShellService)
00392       appShellService->TopLevelWindowIsModal(
00393                          NS_STATIC_CAST(nsIXULWindow*, this), PR_TRUE);
00394 
00395   nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
00396   nsresult rv = NS_OK;
00397   if (stack && NS_SUCCEEDED(stack->Push(nsnull))) {
00398     while(NS_SUCCEEDED(rv) && mContinueModalLoop) {
00399       void* data;
00400       PRBool isRealEvent;
00401       PRBool processEvent;
00402 
00403       rv = appShell->GetNativeEvent(isRealEvent, data);
00404       if(NS_SUCCEEDED(rv)) {
00405         window->ModalEventFilter(isRealEvent, data, &processEvent);
00406         if(processEvent)
00407           appShell->DispatchNativeEvent(isRealEvent, data);
00408       }
00409     }
00410     JSContext* cx;
00411     stack->Pop(&cx);
00412     NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
00413   } else
00414     rv = NS_ERROR_FAILURE;
00415 
00416   mContinueModalLoop = PR_FALSE;
00417   window->SetModal(PR_FALSE);
00418   if (appShellService)
00419       appShellService->TopLevelWindowIsModal(
00420                          NS_STATIC_CAST(nsIXULWindow*, this), PR_FALSE);
00421   /*   Note there's no EnableParent(PR_TRUE) here to match the PR_FALSE one
00422      above. That's done in ExitModalLoop. It's important that the parent
00423      be re-enabled before this window is made invisible; to do otherwise
00424      causes bizarre z-ordering problems. At this point, the window is
00425      already invisible.
00426        No known current implementation of Enable would have a problem with
00427      re-enabling the parent twice, so we could do it again here without
00428      breaking any current implementation. But that's unnecessary if the
00429      modal loop is always exited using ExitModalLoop (the other way would be
00430      to change the protected member variable directly.)
00431   */
00432   appShell->Spindown();
00433 
00434   return mModalStatus;
00435 }
00436 
00437 //*****************************************************************************
00438 // nsXULWindow::nsIBaseWindow
00439 //*****************************************************************************   
00440 
00441 NS_IMETHODIMP nsXULWindow::InitWindow(nativeWindow aParentNativeWindow,
00442    nsIWidget* parentWidget, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)   
00443 {
00444    //XXX First Check In
00445    NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
00446    return NS_OK;
00447 }
00448 
00449 NS_IMETHODIMP nsXULWindow::Create()
00450 {
00451    //XXX First Check In
00452    NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
00453    return NS_OK;
00454 }
00455 
00456 NS_IMETHODIMP nsXULWindow::Destroy()
00457 {
00458    if(!mWindow)
00459       return NS_OK;
00460 
00461    nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
00462    NS_ASSERTION(appShell, "Couldn't get appShell... xpcom shutdown?");
00463    if(appShell)
00464      appShell->UnregisterTopLevelWindow(NS_STATIC_CAST(nsIXULWindow*, this));
00465 
00466    nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow));
00467    if (parentWindow)
00468      parentWindow->RemoveChildWindow(this);
00469 
00470    // let's make sure the window doesn't get deleted out from under us
00471    // while we are trying to close....this can happen if the docshell
00472    // we close ends up being the last owning reference to this xulwindow
00473 
00474    // XXXTAB This shouldn't be an issue anymore because the ownership model
00475    // only goes in one direction.  When webshell container is fully removed
00476    // try removing this...
00477 
00478    nsCOMPtr<nsIXULWindow> placeHolder = this;
00479 
00480    // Remove modality (if any) and hide while destroying. More than
00481    // a convenience, the hide prevents user interaction with the partially
00482    // destroyed window. This is especially necessary when the eldest window
00483    // in a stack of modal windows is destroyed first. It happens.
00484    ExitModalLoop(NS_OK);
00485    if (mWindow)
00486      mWindow->Show(PR_FALSE);
00487 
00488 #if defined(XP_WIN) || defined(XP_OS2)
00489   // We need to explicitly set the focus on Windows
00490   nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow));
00491   if (parent) {
00492     nsCOMPtr<nsIBaseWindow> baseHiddenWindow;
00493     if (appShell) {
00494       nsCOMPtr<nsIXULWindow> hiddenWindow;
00495       appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
00496       if (hiddenWindow)
00497         baseHiddenWindow = do_GetInterface(hiddenWindow);
00498     }
00499     // somebody screwed up somewhere. hiddenwindow shouldn't be anybody's
00500     // parent. still, when it happens, skip activating it.
00501     if (baseHiddenWindow != parent) {
00502       nsCOMPtr<nsIWidget> parentWidget;
00503       parent->GetMainWidget(getter_AddRefs(parentWidget));
00504       if (parentWidget)
00505         parentWidget->PlaceBehind(eZPlacementTop, 0, PR_TRUE);
00506     }
00507   }
00508 #endif
00509    
00510    mDOMWindow = nsnull;
00511    if(mDocShell) {
00512       nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
00513       shellAsWin->Destroy();
00514       mDocShell = nsnull; // this can cause reentrancy of this function
00515    }
00516 
00517    // Remove our ref on the content shells
00518    PRInt32 count;
00519    count = mContentShells.Count();
00520    for(PRInt32 i = 0; i < count; i++) {
00521       nsContentShellInfo* shellInfo = (nsContentShellInfo*)(mContentShells.ElementAt(i));
00522       delete shellInfo;
00523    }
00524    mContentShells.Clear();
00525    mPrimaryContentShell = nsnull;
00526 
00527    if(mContentTreeOwner) {
00528       mContentTreeOwner->XULWindow(nsnull);
00529       NS_RELEASE(mContentTreeOwner);
00530    }
00531    if(mPrimaryContentTreeOwner) {
00532       mPrimaryContentTreeOwner->XULWindow(nsnull);
00533       NS_RELEASE(mPrimaryContentTreeOwner);
00534    }
00535    if(mChromeTreeOwner) {
00536       mChromeTreeOwner->XULWindow(nsnull);
00537       NS_RELEASE(mChromeTreeOwner);
00538    }
00539    if(mWindow) {
00540       mWindow->SetClientData(0); // nsWebShellWindow hackery
00541       mWindow = nsnull;
00542    }
00543 
00544    /* Inform appstartup we've destroyed this window and it could
00545       quit now if it wanted. This must happen at least after mDocShell
00546       is destroyed, because onunload handlers fire then, and those being
00547       script, anything could happen. A new window could open, even.
00548       See bug 130719. */
00549    nsCOMPtr<nsIObserverService> obssvc =
00550      do_GetService("@mozilla.org/observer-service;1");
00551    NS_ASSERTION(obssvc, "Couldn't get observer service?");
00552 
00553    if (obssvc)
00554      obssvc->NotifyObservers(nsnull, "xul-window-destroyed", nsnull);
00555 
00556    return NS_OK;
00557 }
00558 
00559 NS_IMETHODIMP nsXULWindow::SetPosition(PRInt32 aX, PRInt32 aY)
00560 {
00561   /* any attempt to set the window's size or position overrides the window's
00562      zoom state. this is important when these two states are competing while
00563      the window is being opened. but it should probably just always be so. */
00564   mWindow->SetSizeMode(nsSizeMode_Normal);
00565     
00566   NS_ENSURE_SUCCESS(mWindow->Move(aX, aY), NS_ERROR_FAILURE);
00567   PersistentAttributesDirty(PAD_POSITION);
00568   SavePersistentAttributes();
00569   return NS_OK;
00570 }
00571 
00572 NS_IMETHODIMP nsXULWindow::GetPosition(PRInt32* aX, PRInt32* aY)
00573 {
00574    return GetPositionAndSize(aX, aY, nsnull, nsnull);
00575 }
00576 
00577 NS_IMETHODIMP nsXULWindow::SetSize(PRInt32 aCX, PRInt32 aCY, PRBool aRepaint)
00578 {
00579   /* any attempt to set the window's size or position overrides the window's
00580      zoom state. this is important when these two states are competing while
00581      the window is being opened. but it should probably just always be so. */
00582   mWindow->SetSizeMode(nsSizeMode_Normal);
00583 
00584   mIntrinsicallySized = PR_FALSE;
00585 
00586   NS_ENSURE_SUCCESS(mWindow->Resize(aCX, aCY, aRepaint), NS_ERROR_FAILURE);
00587   PersistentAttributesDirty(PAD_SIZE);
00588   SavePersistentAttributes();
00589   return NS_OK;
00590 }
00591 
00592 NS_IMETHODIMP nsXULWindow::GetSize(PRInt32* aCX, PRInt32* aCY)
00593 {
00594   return GetPositionAndSize(nsnull, nsnull, aCX, aCY);
00595 }
00596 
00597 NS_IMETHODIMP nsXULWindow::SetPositionAndSize(PRInt32 aX, PRInt32 aY, 
00598    PRInt32 aCX, PRInt32 aCY, PRBool aRepaint)
00599 {
00600   /* any attempt to set the window's size or position overrides the window's
00601      zoom state. this is important when these two states are competing while
00602      the window is being opened. but it should probably just always be so. */
00603   mWindow->SetSizeMode(nsSizeMode_Normal);
00604 
00605   mIntrinsicallySized = PR_FALSE;
00606 
00607   NS_ENSURE_SUCCESS(mWindow->Resize(aX, aY, aCX, aCY, aRepaint), NS_ERROR_FAILURE);
00608   PersistentAttributesDirty(PAD_POSITION | PAD_SIZE);
00609   SavePersistentAttributes();
00610   return NS_OK;
00611 }
00612 
00613 NS_IMETHODIMP nsXULWindow::GetPositionAndSize(PRInt32* x, PRInt32* y, PRInt32* cx,
00614    PRInt32* cy)
00615 {
00616   nsRect rect;
00617 
00618   if (!mWindow)
00619     return NS_ERROR_FAILURE;
00620 
00621   mWindow->GetScreenBounds(rect);
00622 
00623   if(x)
00624     *x = rect.x;
00625   if(y)
00626     *y = rect.y;
00627   if(cx)
00628     *cx = rect.width;
00629   if(cy)
00630     *cy = rect.height;
00631 
00632   return NS_OK;
00633 }
00634 
00635 NS_IMETHODIMP nsXULWindow::Center(nsIXULWindow *aRelative, PRBool aScreen, PRBool aAlert) {
00636 
00637   PRInt32  left, top, width, height,
00638            ourWidth, ourHeight;
00639   PRBool   screenCoordinates =  PR_FALSE,
00640            windowCoordinates =  PR_FALSE;
00641   nsresult result;
00642 
00643   if (!mChromeLoaded) {
00644     // note we lose the parameters. at time of writing, this isn't a problem.
00645     mCenterAfterLoad = PR_TRUE;
00646     return NS_OK;
00647   }
00648 
00649   if (!aScreen && !aRelative)
00650     return NS_ERROR_INVALID_ARG;
00651 
00652   nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1", &result);
00653   if (NS_FAILED(result))
00654     return result;
00655 
00656   nsCOMPtr<nsIScreen> screen;
00657 
00658   if (aRelative) {
00659     nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(aRelative, &result));
00660     if (base) {
00661       // get window rect
00662       result = base->GetPositionAndSize(&left, &top, &width, &height);
00663       if (NS_SUCCEEDED(result)) {
00664         // if centering on screen, convert that to the corresponding screen
00665         if (aScreen)
00666           screenmgr->ScreenForRect(left, top, width, height, getter_AddRefs(screen));
00667         else
00668           windowCoordinates = PR_TRUE;
00669       } else {
00670         // something's wrong with the reference window.
00671         // fall back to the primary screen
00672         aRelative = 0;
00673         aScreen = PR_TRUE;
00674       }
00675     }
00676   }
00677   if (!aRelative)
00678     screenmgr->GetPrimaryScreen(getter_AddRefs(screen));
00679 
00680   if (aScreen && screen) {
00681     screen->GetAvailRect(&left, &top, &width, &height);
00682     screenCoordinates = PR_TRUE;
00683   }
00684 
00685   if (screenCoordinates || windowCoordinates) {
00686     GetSize(&ourWidth, &ourHeight);
00687     left += (width - ourWidth) / 2;
00688     top += (height - ourHeight) / (aAlert ? 3 : 2);
00689     if (windowCoordinates)
00690       mWindow->ConstrainPosition(PR_FALSE, &left, &top);
00691     SetPosition(left, top);
00692     return NS_OK;
00693   }
00694   return NS_ERROR_FAILURE;
00695 }
00696 
00697 NS_IMETHODIMP nsXULWindow::Repaint(PRBool aForce)
00698 {
00699    //XXX First Check In
00700    NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
00701    return NS_OK;
00702 }
00703 
00704 NS_IMETHODIMP nsXULWindow::GetParentWidget(nsIWidget** aParentWidget)
00705 {
00706    NS_ENSURE_ARG_POINTER(aParentWidget);
00707    NS_ENSURE_STATE(mWindow);
00708 
00709    *aParentWidget = mWindow->GetParent();
00710    return NS_OK;
00711 }
00712 
00713 NS_IMETHODIMP nsXULWindow::SetParentWidget(nsIWidget* aParentWidget)
00714 {
00715    //XXX First Check In
00716    NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
00717    return NS_OK;
00718 }
00719 
00720 NS_IMETHODIMP nsXULWindow::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
00721 {
00722    NS_ENSURE_ARG_POINTER(aParentNativeWindow);
00723 
00724    nsCOMPtr<nsIWidget> parentWidget;
00725    NS_ENSURE_SUCCESS(GetParentWidget(getter_AddRefs(parentWidget)), NS_ERROR_FAILURE);
00726 
00727    *aParentNativeWindow = parentWidget->GetNativeData(NS_NATIVE_WIDGET);
00728    
00729    return NS_OK;
00730 }
00731 
00732 NS_IMETHODIMP nsXULWindow::SetParentNativeWindow(nativeWindow aParentNativeWindow)
00733 {
00734    //XXX First Check In
00735    NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
00736    return NS_OK;
00737 }
00738 
00739 NS_IMETHODIMP nsXULWindow::GetVisibility(PRBool* aVisibility)
00740 {
00741   NS_ENSURE_ARG_POINTER(aVisibility);
00742 
00743   // Always claim to be visible for now. See bug
00744   // https://bugzilla.mozilla.org/show_bug.cgi?id=306245.
00745 
00746   *aVisibility = PR_TRUE;
00747 
00748   return NS_OK;
00749 }
00750 
00751 NS_IMETHODIMP nsXULWindow::SetVisibility(PRBool aVisibility)
00752 {
00753    NS_TIMELINE_ENTER("nsXULWindow::SetVisibility.");
00754    if(!mChromeLoaded)
00755       {
00756       mShowAfterLoad = aVisibility;
00757       NS_TIMELINE_LEAVE("nsXULWindow::SetVisibility");
00758       return NS_OK;
00759       }
00760 
00761    if(mDebuting) {
00762       NS_TIMELINE_LEAVE("nsXULWindow::SetVisibility");
00763       return NS_OK;
00764    }
00765    mDebuting = PR_TRUE;  // (Show / Focus is recursive)
00766 
00767    //XXXTAB Do we really need to show docshell and the window?  Isn't 
00768    // the window good enough?
00769    nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
00770    shellAsWin->SetVisibility(aVisibility);
00771    mWindow->Show(aVisibility);
00772 
00773    nsCOMPtr<nsIWindowMediator> windowMediator(do_GetService(kWindowMediatorCID));
00774    if(windowMediator)
00775       windowMediator->UpdateWindowTimeStamp(NS_STATIC_CAST(nsIXULWindow*, this));
00776 
00777    // notify observers so that we can hide the splash screen if possible
00778    nsCOMPtr<nsIObserverService> obssvc
00779      (do_GetService("@mozilla.org/observer-service;1"));
00780    NS_WARN_IF_FALSE(obssvc, "Couldn't get observer service.");
00781    if (obssvc) {
00782      obssvc->NotifyObservers(nsnull, "xul-window-visible", nsnull); 
00783    }
00784 
00785    mDebuting = PR_FALSE;
00786    NS_TIMELINE_LEAVE("nsXULWindow::SetVisibility");
00787    return NS_OK;
00788 }
00789 
00790 NS_IMETHODIMP nsXULWindow::GetEnabled(PRBool *aEnabled)
00791 {
00792   NS_ENSURE_ARG_POINTER(aEnabled);
00793   if (mWindow)
00794     return mWindow->IsEnabled(aEnabled);
00795 
00796   *aEnabled = PR_TRUE; // better guess than most
00797   return NS_ERROR_FAILURE;
00798 }
00799 
00800 NS_IMETHODIMP nsXULWindow::SetEnabled(PRBool aEnable)
00801 {
00802   if (mWindow) {
00803     mWindow->Enable(aEnable);
00804     return NS_OK;
00805   }
00806   return NS_ERROR_FAILURE;
00807 }
00808 
00809 NS_IMETHODIMP nsXULWindow::GetBlurSuppression(PRBool *aBlurSuppression)
00810 {
00811   NS_ENSURE_ARG_POINTER(aBlurSuppression);
00812   *aBlurSuppression = mBlurSuppressionLevel > 0;
00813   return NS_OK;
00814 }
00815 
00816 NS_IMETHODIMP nsXULWindow::SetBlurSuppression(PRBool aBlurSuppression)
00817 {
00818   if (aBlurSuppression)
00819     ++mBlurSuppressionLevel;
00820   else {
00821     NS_ASSERTION(mBlurSuppressionLevel > 0, "blur over-allowed");
00822     if (mBlurSuppressionLevel > 0)
00823       --mBlurSuppressionLevel;
00824   }
00825   return NS_OK;
00826 
00827   /* XXX propagate this information to the widget? It has its own
00828      independent concept of blur suppression. Each is used on
00829      a different platform, so at time of writing it's not necessary
00830      to keep them in sync. (And there's no interface for doing so.) */
00831 }
00832 
00833 NS_IMETHODIMP nsXULWindow::GetMainWidget(nsIWidget** aMainWidget)
00834 {
00835    NS_ENSURE_ARG_POINTER(aMainWidget);
00836    
00837    *aMainWidget = mWindow;
00838    NS_IF_ADDREF(*aMainWidget);
00839    return NS_OK;
00840 }
00841 
00842 NS_IMETHODIMP nsXULWindow::SetFocus()
00843 {
00844    //XXX First Check In
00845    NS_ASSERTION(PR_FALSE, "Not Yet Implemented");
00846    return NS_OK;
00847 }
00848 
00849 NS_IMETHODIMP nsXULWindow::GetTitle(PRUnichar** aTitle)
00850 {
00851    NS_ENSURE_ARG_POINTER(aTitle);
00852 
00853    *aTitle = ToNewUnicode(mTitle);
00854    if (!*aTitle)
00855       return NS_ERROR_OUT_OF_MEMORY;
00856    return NS_OK;
00857 }
00858 
00859 NS_IMETHODIMP nsXULWindow::SetTitle(const PRUnichar* aTitle)
00860 {
00861    NS_ENSURE_STATE(mWindow);
00862    mTitle.Assign(aTitle);
00863    mTitle.StripChars("\n\r");
00864    NS_ENSURE_SUCCESS(mWindow->SetTitle(mTitle), NS_ERROR_FAILURE);
00865 
00866    // Tell the window mediator that a title has changed
00867    nsCOMPtr<nsIWindowMediator> windowMediator(do_GetService(kWindowMediatorCID));
00868    if(!windowMediator)
00869       return NS_OK;
00870 
00871    windowMediator->UpdateWindowTitle(NS_STATIC_CAST(nsIXULWindow*, this), aTitle);
00872 
00873    return NS_OK;
00874 }
00875 
00876 
00877 //*****************************************************************************
00878 // nsXULWindow: Helpers
00879 //*****************************************************************************   
00880 
00881 NS_IMETHODIMP nsXULWindow::EnsureChromeTreeOwner()
00882 {
00883    if(mChromeTreeOwner)
00884       return NS_OK;
00885 
00886    mChromeTreeOwner = new nsChromeTreeOwner();
00887    NS_ENSURE_TRUE(mChromeTreeOwner, NS_ERROR_OUT_OF_MEMORY);
00888 
00889    NS_ADDREF(mChromeTreeOwner);
00890    mChromeTreeOwner->XULWindow(this);
00891 
00892    return NS_OK;
00893 }
00894 
00895 NS_IMETHODIMP nsXULWindow::EnsureContentTreeOwner()
00896 {
00897    if(mContentTreeOwner)
00898       return NS_OK;
00899 
00900    mContentTreeOwner = new nsContentTreeOwner(PR_FALSE);
00901    NS_ENSURE_TRUE(mContentTreeOwner, NS_ERROR_FAILURE);
00902 
00903    NS_ADDREF(mContentTreeOwner);
00904    mContentTreeOwner->XULWindow(this);
00905    
00906    return NS_OK;
00907 }
00908 
00909 NS_IMETHODIMP nsXULWindow::EnsurePrimaryContentTreeOwner()
00910 {
00911    if(mPrimaryContentTreeOwner)
00912       return NS_OK;
00913 
00914    mPrimaryContentTreeOwner = new nsContentTreeOwner(PR_TRUE);
00915    NS_ENSURE_TRUE(mPrimaryContentTreeOwner, NS_ERROR_FAILURE);
00916 
00917    NS_ADDREF(mPrimaryContentTreeOwner);
00918    mPrimaryContentTreeOwner->XULWindow(this);
00919 
00920    return NS_OK;
00921 }
00922 
00923 NS_IMETHODIMP nsXULWindow::EnsurePrompter()
00924 {
00925    if (mPrompter)
00926       return NS_OK;
00927    
00928    nsCOMPtr<nsIDOMWindowInternal> ourWindow;
00929    nsresult rv = GetWindowDOMWindow(getter_AddRefs(ourWindow));
00930    if (NS_SUCCEEDED(rv)) {
00931       nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00932       if (wwatch)
00933          wwatch->GetNewPrompter(ourWindow, getter_AddRefs(mPrompter));
00934    }
00935    return mPrompter ? NS_OK : NS_ERROR_FAILURE;
00936 }
00937 
00938 NS_IMETHODIMP nsXULWindow::EnsureAuthPrompter()
00939 {
00940    if (mAuthPrompter)
00941       return NS_OK;
00942       
00943    nsCOMPtr<nsIDOMWindowInternal> ourWindow;
00944    nsresult rv = GetWindowDOMWindow(getter_AddRefs(ourWindow));
00945    if (NS_SUCCEEDED(rv)) {
00946       nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00947       if (wwatch)
00948          wwatch->GetNewAuthPrompter(ourWindow, getter_AddRefs(mAuthPrompter));
00949    }
00950    return mAuthPrompter ? NS_OK : NS_ERROR_FAILURE;
00951 }
00952  
00953 void nsXULWindow::OnChromeLoaded()
00954 {
00955   nsresult rv = EnsureContentTreeOwner();
00956 
00957   if (NS_SUCCEEDED(rv)) {
00958     mChromeLoaded = PR_TRUE;
00959     ApplyChromeFlags();
00960 
00961     LoadChromeHidingFromXUL();
00962     LoadWindowClassFromXUL();
00963     LoadIconFromXUL();
00964     LoadSizeFromXUL();
00965     if(mIntrinsicallySized) {
00966       // (if LoadSizeFromXUL set the size, mIntrinsicallySized will be false)
00967       nsCOMPtr<nsIContentViewer> cv;
00968       mDocShell->GetContentViewer(getter_AddRefs(cv));
00969       nsCOMPtr<nsIMarkupDocumentViewer> markupViewer(do_QueryInterface(cv));
00970       if(markupViewer)
00971         markupViewer->SizeToContent();
00972     }
00973 
00974     PRBool positionSet = PR_TRUE;
00975     nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow));
00976 #if defined(XP_UNIX) && !defined(XP_MACOSX)
00977     // don't override WM placement on unix for independent, top-level windows
00978     // (however, we think the benefits of intelligent dependent window placement
00979     // trump that override.)
00980     if (!parentWindow)
00981       positionSet = PR_FALSE;
00982 #endif
00983     if (positionSet)
00984       positionSet = LoadPositionFromXUL();
00985     LoadMiscPersistentAttributesFromXUL();
00986 
00987     //LoadContentAreas();
00988 
00989     if (mCenterAfterLoad && !positionSet)
00990       Center(parentWindow, parentWindow ? PR_FALSE : PR_TRUE, PR_FALSE);
00991 
00992     if(mShowAfterLoad)
00993       SetVisibility(PR_TRUE);
00994   }
00995   mPersistentAttributesMask |= PAD_POSITION | PAD_SIZE | PAD_MISC;
00996 }
00997 
00998 nsresult nsXULWindow::LoadChromeHidingFromXUL()
00999 {
01000   NS_ENSURE_STATE(mWindow);
01001 
01002   // Get <window> element.
01003   nsCOMPtr<nsIDOMElement> windowElement;
01004   GetWindowDOMElement(getter_AddRefs(windowElement));
01005   NS_ENSURE_TRUE(windowElement, NS_ERROR_FAILURE);
01006 
01007   nsAutoString attr;
01008   nsresult rv = windowElement->GetAttribute(NS_LITERAL_STRING("hidechrome"), attr);
01009 
01010   if (NS_SUCCEEDED(rv) && attr.LowerCaseEqualsLiteral("true")) {
01011     mWindow->HideWindowChrome(PR_TRUE);
01012   }
01013 
01014   return NS_OK;
01015 }
01016 
01017 PRBool nsXULWindow::LoadPositionFromXUL()
01018 {
01019   nsresult rv;
01020   PRBool   gotPosition = PR_FALSE;
01021   
01022   // if we're the hidden window, don't try to validate our size/position. We're
01023   // special.
01024   if (mIsHiddenWindow)
01025     return PR_FALSE;
01026 
01027   nsCOMPtr<nsIDOMElement> windowElement;
01028   GetWindowDOMElement(getter_AddRefs(windowElement));
01029   NS_ASSERTION(windowElement, "no xul:window");
01030   if (!windowElement)
01031     return PR_FALSE;
01032 
01033   PRInt32 currX = 0;
01034   PRInt32 currY = 0;
01035   PRInt32 currWidth = 0;
01036   PRInt32 currHeight = 0;
01037   PRInt32 errorCode;
01038   PRInt32 temp;
01039 
01040   GetPositionAndSize(&currX, &currY, &currWidth, &currHeight);
01041 
01042   // Obtain the position information from the <xul:window> element.
01043   PRInt32 specX = currX;
01044   PRInt32 specY = currY;
01045   nsAutoString posString;
01046 
01047   rv = windowElement->GetAttribute(NS_LITERAL_STRING("screenX"), posString);
01048   if (NS_SUCCEEDED(rv)) {
01049     temp = posString.ToInteger(&errorCode);
01050     if (NS_SUCCEEDED(errorCode)) {
01051       specX = temp;
01052       gotPosition = PR_TRUE;
01053     }
01054   }
01055   rv = windowElement->GetAttribute(NS_LITERAL_STRING("screenY"), posString);
01056   if (NS_SUCCEEDED(rv)) {
01057     temp = posString.ToInteger(&errorCode);
01058     if (NS_SUCCEEDED(errorCode)) {
01059       specY = temp;
01060       gotPosition = PR_TRUE;
01061     }
01062   }
01063     
01064   if (gotPosition) {
01065     // our position will be relative to our parent, if any
01066     nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow));
01067     if (parent) {
01068       PRInt32 parentX, parentY;
01069       if (NS_SUCCEEDED(parent->GetPosition(&parentX, &parentY))) {
01070         specX += parentX;
01071         specY += parentY;
01072       }
01073     } else
01074       StaggerPosition(specX, specY, currWidth, currHeight);
01075   }
01076   mWindow->ConstrainPosition(PR_FALSE, &specX, &specY);
01077   if (specX != currX || specY != currY)
01078     SetPosition(specX, specY);
01079 
01080   return gotPosition;
01081 }
01082 
01083 PRBool nsXULWindow::LoadSizeFromXUL()
01084 {
01085   nsresult rv;
01086   PRBool   gotSize = PR_FALSE;
01087   
01088   // if we're the hidden window, don't try to validate our size/position. We're
01089   // special.
01090   if (mIsHiddenWindow)
01091     return PR_FALSE;
01092 
01093   nsCOMPtr<nsIDOMElement> windowElement;
01094   GetWindowDOMElement(getter_AddRefs(windowElement));
01095   NS_ASSERTION(windowElement, "no xul:window");
01096   if (!windowElement)
01097     return PR_FALSE;
01098 
01099   PRInt32 currWidth = 0;
01100   PRInt32 currHeight = 0;
01101   PRInt32 errorCode;
01102   PRInt32 temp;
01103 
01104   GetSize(&currWidth, &currHeight);
01105 
01106   // Obtain the position and sizing information from the <xul:window> element.
01107   PRInt32 specWidth = currWidth;
01108   PRInt32 specHeight = currHeight;
01109   nsAutoString sizeString;
01110 
01111   rv = windowElement->GetAttribute(NS_LITERAL_STRING("width"), sizeString);
01112   if (NS_SUCCEEDED(rv)) {
01113     temp = sizeString.ToInteger(&errorCode);
01114     if (NS_SUCCEEDED(errorCode) && temp > 0) {
01115       specWidth = temp > 100 ? temp : 100;
01116       gotSize = PR_TRUE;
01117     }
01118   }
01119   rv = windowElement->GetAttribute(NS_LITERAL_STRING("height"), sizeString);
01120   if (NS_SUCCEEDED(rv)) {
01121     temp = sizeString.ToInteger(&errorCode);
01122     if (NS_SUCCEEDED(errorCode) && temp > 0) {
01123       specHeight = temp > 100 ? temp : 100;
01124       gotSize = PR_TRUE;
01125     }
01126   }
01127 
01128   if (gotSize) {
01129     // constrain to screen size
01130     nsCOMPtr<nsIDOMWindowInternal> domWindow;
01131     GetWindowDOMWindow(getter_AddRefs(domWindow));
01132     if (domWindow) {
01133       nsCOMPtr<nsIDOMScreen> screen;
01134       domWindow->GetScreen(getter_AddRefs(screen));
01135       if (screen) {
01136         PRInt32 screenWidth;
01137         PRInt32 screenHeight;
01138         screen->GetAvailWidth(&screenWidth);
01139         screen->GetAvailHeight(&screenHeight);
01140         if (specWidth > screenWidth)
01141           specWidth = screenWidth;
01142         if (specHeight > screenHeight)
01143           specHeight = screenHeight;
01144       }
01145     }
01146 
01147     mIntrinsicallySized = PR_FALSE;
01148     if (specWidth != currWidth || specHeight != currHeight)
01149       SetSize(specWidth, specHeight, PR_FALSE);
01150   }
01151 
01152   return gotSize;
01153 }
01154 
01155 /* Miscellaneous persistent attributes are attributes named in the
01156    |persist| attribute, other than size and position. Those are special
01157    because it's important to load those before one of the misc
01158    attributes (sizemode) and they require extra processing. */
01159 PRBool nsXULWindow::LoadMiscPersistentAttributesFromXUL()
01160 {
01161   nsresult rv;
01162   PRBool   gotState = PR_FALSE;
01163   
01164   /* There are no misc attributes of interest to the hidden window.
01165      It's especially important not to try to validate that window's
01166      size or position, because some platforms (Mac OS X) need to
01167      make it visible and offscreen. */
01168   if (mIsHiddenWindow)
01169     return PR_FALSE;
01170 
01171   nsCOMPtr<nsIDOMElement> windowElement;
01172   GetWindowDOMElement(getter_AddRefs(windowElement));
01173   NS_ASSERTION(windowElement, "no xul:window");
01174   if (!windowElement)
01175     return PR_FALSE;
01176 
01177   nsAutoString stateString;
01178 
01179   // sizemode
01180   rv = windowElement->GetAttribute(NS_LITERAL_STRING("sizemode"), stateString);
01181   if (NS_SUCCEEDED(rv)) {
01182     PRInt32 sizeMode = nsSizeMode_Normal;
01183     /* ignore request to minimize, to not confuse novices
01184     if (stateString.Equals(SIZEMODE_MINIMIZED))
01185       sizeMode = nsSizeMode_Minimized;
01186     */
01187     if (stateString.Equals(SIZEMODE_MAXIMIZED)) {
01188       /* Honor request to maximize only if the window is sizable.
01189          An unsizable, unmaximizable, yet maximized window confuses
01190          Windows OS and is something of a travesty, anyway. */
01191       if (mChromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
01192         mIntrinsicallySized = PR_FALSE;
01193         sizeMode = nsSizeMode_Maximized;
01194       }
01195     }
01196     // the widget had better be able to deal with not becoming visible yet
01197     mWindow->SetSizeMode(sizeMode);
01198     gotState = PR_TRUE;
01199   }
01200 
01201   // zlevel
01202   rv = windowElement->GetAttribute(NS_LITERAL_STRING("zlevel"), stateString);
01203   if (NS_SUCCEEDED(rv) && stateString.Length() > 0) {
01204     PRInt32  errorCode;
01205     PRUint32 zLevel = stateString.ToInteger(&errorCode);
01206     if (NS_SUCCEEDED(errorCode) && zLevel >= lowestZ && zLevel <= highestZ)
01207       SetZLevel(zLevel);
01208   }
01209 
01210   return gotState;
01211 }
01212 
01213 /* Stagger windows of the same type so they don't appear on top of each other.
01214    This code does have a scary double loop -- it'll keep passing through
01215    the entire list of open windows until it finds a non-collision. Doesn't
01216    seem to be a problem, but it deserves watching.
01217 */
01218 void nsXULWindow::StaggerPosition(PRInt32 &aRequestedX, PRInt32 &aRequestedY,
01219                                   PRInt32 aSpecWidth, PRInt32 aSpecHeight)
01220 {
01221   const PRInt32 kOffset = 22;
01222   const PRInt32 kSlop = 4;
01223   nsresult rv;
01224   PRBool   keepTrying;
01225   int      bouncedX = 0, // bounced off vertical edge of screen
01226            bouncedY = 0; // bounced off horizontal edge
01227 
01228   // look for any other windows of this type
01229   nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
01230   if (!wm)
01231     return;
01232 
01233   nsCOMPtr<nsIDOMElement> windowElement;
01234   GetWindowDOMElement(getter_AddRefs(windowElement));
01235   nsCOMPtr<nsIXULWindow> ourXULWindow(this);
01236 
01237   nsAutoString windowType;
01238   rv = windowElement->GetAttribute(WINDOWTYPE_ATTRIBUTE, windowType);
01239   if (NS_FAILED(rv))
01240     return;
01241 
01242   PRInt32 screenTop = 0,    // it's pointless to initialize these ...
01243           screenRight = 0,  // ... but to prevent oversalubrious and ...
01244           screenBottom = 0, // ... underbright compilers from ...
01245           screenLeft = 0;   // ... issuing warnings.
01246   PRBool  gotScreen = PR_FALSE;
01247 
01248   { // fetch screen coordinates
01249     nsCOMPtr<nsIScreenManager> screenMgr(do_GetService(
01250                                          "@mozilla.org/gfx/screenmanager;1"));
01251     if (screenMgr) {
01252       nsCOMPtr<nsIScreen> ourScreen;
01253       screenMgr->ScreenForRect(aRequestedX, aRequestedY,
01254                                aSpecWidth, aSpecHeight,
01255                                getter_AddRefs(ourScreen));
01256       if (ourScreen) {
01257         PRInt32 screenWidth, screenHeight;
01258         ourScreen->GetAvailRect(&screenLeft, &screenTop,
01259                                 &screenWidth, &screenHeight);
01260         screenBottom = screenTop + screenHeight;
01261         screenRight = screenLeft + screenWidth;
01262         gotScreen = PR_TRUE;
01263       }
01264     }
01265   }
01266 
01267   // one full pass through all windows of this type. repeat until
01268   // no collisions.
01269   do {
01270     keepTrying = PR_FALSE;
01271     nsCOMPtr<nsISimpleEnumerator> windowList;
01272     wm->GetXULWindowEnumerator(windowType.get(), getter_AddRefs(windowList));
01273 
01274     if (!windowList)
01275       break;
01276 
01277     // one full pass through all windows of this type. offset and stop
01278     // on collision.
01279     do {
01280       PRBool more;
01281       PRInt32 listX, listY;
01282       windowList->HasMoreElements(&more);
01283       if (!more)
01284         break;
01285 
01286       nsCOMPtr<nsISupports> supportsWindow;
01287       windowList->GetNext(getter_AddRefs(supportsWindow));
01288 
01289       nsCOMPtr<nsIXULWindow> listXULWindow(do_QueryInterface(supportsWindow));
01290       nsCOMPtr<nsIBaseWindow> listBaseWindow(do_QueryInterface(supportsWindow));
01291 
01292       if (listXULWindow != ourXULWindow) {
01293         listBaseWindow->GetPosition(&listX, &listY);
01294 
01295         if (PR_ABS(listX-aRequestedX) <= kSlop &&
01296             PR_ABS(listY-aRequestedY) <= kSlop) {
01297           // collision! offset and start over
01298           if (bouncedX & 0x1)
01299             aRequestedX -= kOffset;
01300           else
01301             aRequestedX += kOffset;
01302           aRequestedY += kOffset;
01303 
01304           if (gotScreen) {
01305             // bounce off left and right edges
01306             if (!(bouncedX & 0x1) && aRequestedX + aSpecWidth > screenRight) {
01307               aRequestedX = screenRight - aSpecWidth;
01308               ++bouncedX;
01309             }
01310             if ((bouncedX & 0x1) && aRequestedX < screenLeft) {
01311               aRequestedX = screenLeft;
01312               ++bouncedX;
01313             }
01314             // hit the bottom and start again at the top
01315             if (aRequestedY + aSpecHeight > screenBottom) {
01316               aRequestedY = screenTop;
01317               ++bouncedY;
01318             }
01319           }
01320 
01321           /* loop around again,
01322              but it's time to give up once we've covered the screen.
01323              there's a potential infinite loop with lots of windows. */
01324           keepTrying = bouncedX < 2 || bouncedY == 0;
01325           break;
01326         }
01327       }
01328     } while(1);
01329   } while (keepTrying);
01330 }
01331 
01332 NS_IMETHODIMP nsXULWindow::LoadWindowClassFromXUL()
01333 {
01334   if (mWindow->GetWindowClass(nsnull)==NS_ERROR_NOT_IMPLEMENTED)
01335     return NS_OK;
01336 
01337   nsCOMPtr<nsIDOMElement> docShellElement;
01338   GetWindowDOMElement(getter_AddRefs(docShellElement));
01339   NS_ENSURE_TRUE(docShellElement, NS_ERROR_FAILURE);
01340 
01341   nsAutoString windowClass;
01342 
01343   docShellElement->GetAttribute(NS_LITERAL_STRING("windowtype"),
01344                                 windowClass);
01345 
01346   if (!windowClass.IsEmpty())
01347   {
01348     PRBool persistPosition;
01349     PRBool persistSize;
01350     PRBool persistSizeMode;
01351 
01352     if (NS_SUCCEEDED(
01353          mContentTreeOwner->
01354            GetPersistence(&persistPosition, &persistSize, &persistSizeMode)
01355         ) && !persistPosition && !persistSize && !persistSizeMode)
01356       windowClass.AppendLiteral("-jsSpamPopupCrap");
01357 
01358     char *windowClass_cstr = ToNewCString(windowClass);
01359     mWindow->SetWindowClass(windowClass_cstr);
01360     nsMemory::Free(windowClass_cstr);
01361   }
01362 
01363   return NS_OK;
01364 }
01365 
01366 NS_IMETHODIMP nsXULWindow::LoadIconFromXUL()
01367 {
01368     NS_ENSURE_STATE(mWindow);
01369 
01370     // Get <window> element.
01371     nsCOMPtr<nsIDOMElement> windowElement;
01372     GetWindowDOMElement(getter_AddRefs(windowElement));
01373     NS_ENSURE_TRUE(windowElement, NS_ERROR_FAILURE);
01374 
01375     // XXX The following code is being #if 0'd out since it
01376     // basically does nothing until bug 70974 is fixed.
01377     // After bug 70974 is fixed, we will also need to implement
01378     // computed style for that property before this will
01379     // be of any use.  And even then, it will *still* 
01380     // do nothing on platforms which don't implement 
01381     // nsWindow::SetIcon(). See bug 76211 for that.
01382     // Also see bug 57576 and its dependency tree.
01383 #if 0
01384     // Get document in which this <window> is contained.
01385     nsCOMPtr<nsIDOMDocument> document;
01386     windowElement->GetOwnerDocument(getter_AddRefs(document));
01387     NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
01388 
01389     // Get document view.
01390     nsCOMPtr<nsIDOMDocumentView> docView(do_QueryInterface(document));
01391     NS_ENSURE_TRUE(docView, NS_ERROR_FAILURE);
01392 
01393     // Get default/abstract view.
01394     nsCOMPtr<nsIDOMAbstractView> abstractView;
01395     docView->GetDefaultView(getter_AddRefs(abstractView));
01396     NS_ENSURE_TRUE(abstractView, NS_ERROR_FAILURE);
01397 
01398     // Get "view CSS."
01399     nsCOMPtr<nsIDOMViewCSS> viewCSS(do_QueryInterface(abstractView));
01400     NS_ENSURE_TRUE(viewCSS, NS_ERROR_FAILURE);
01401 
01402     // Next, get CSS style declaration.
01403     nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl;
01404     viewCSS->GetComputedStyle(windowElement, EmptyString(),
01405                               getter_AddRefs(cssDecl));
01406     NS_ENSURE_TRUE(cssDecl, NS_ERROR_FAILURE);
01407 
01408     // Whew.  Now get "list-style-image" property value.
01409     nsAutoString windowIcon;
01410     windowIcon.AssignLiteral("-moz-window-icon");
01411     nsAutoString icon;
01412     cssDecl->GetPropertyValue(windowIcon, icon);
01413 #endif
01414 
01415     nsAutoString id;
01416     windowElement->GetAttribute(NS_LITERAL_STRING("id"), id);
01417 
01418     if (id.IsEmpty()) {
01419         id.AssignLiteral("default");
01420     }
01421 
01422     mWindow->SetIcon(id);
01423     return NS_OK;
01424 }
01425 
01426 NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
01427 {
01428   // can happen when the persistence timer fires at an inopportune time
01429   // during window shutdown
01430   if (!mDocShell)
01431     return NS_ERROR_FAILURE;
01432 
01433   nsCOMPtr<nsIDOMElement> docShellElement;
01434   GetWindowDOMElement(getter_AddRefs(docShellElement));
01435   if(!docShellElement)
01436     return NS_ERROR_FAILURE;
01437 
01438   nsAutoString   persistString;
01439   docShellElement->GetAttribute(PERSIST_ATTRIBUTE, persistString);
01440   if (persistString.IsEmpty()) { // quick check which sometimes helps
01441     mPersistentAttributesDirty = 0;
01442     return NS_OK;
01443   }
01444 
01445   PRInt32 x, y, cx, cy;
01446   PRInt32 sizeMode;
01447 
01448   // get our size, position and mode to persist
01449   NS_ENSURE_SUCCESS(GetPositionAndSize(&x, &y, &cx, &cy), NS_ERROR_FAILURE);
01450   mWindow->GetSizeMode(&sizeMode);
01451 
01452   // make our position relative to our parent, if any
01453   nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow));
01454   if (parent) {
01455     PRInt32 parentX, parentY;
01456     if (NS_SUCCEEDED(parent->GetPosition(&parentX, &parentY))) {
01457       x -= parentX;
01458       y -= parentY;
01459     }
01460   }
01461 
01462   char                        sizeBuf[10];
01463   nsAutoString                sizeString;
01464   nsAutoString                windowElementId;
01465   nsCOMPtr<nsIDOMXULDocument> ownerXULDoc;
01466 
01467   { // fetch docShellElement's ID and XUL owner document
01468     nsCOMPtr<nsIDOMDocument> ownerDoc;
01469     docShellElement->GetOwnerDocument(getter_AddRefs(ownerDoc));
01470     ownerXULDoc = do_QueryInterface(ownerDoc);
01471     nsCOMPtr<nsIDOMXULElement> XULElement(do_QueryInterface(docShellElement));
01472     if (XULElement)
01473       XULElement->GetId(windowElementId);
01474   }
01475 
01476   // (only for size elements which are persisted)
01477   if ((mPersistentAttributesDirty & PAD_POSITION) &&
01478       sizeMode == nsSizeMode_Normal) {
01479     if(persistString.Find("screenX") >= 0) {
01480       PR_snprintf(sizeBuf, sizeof(sizeBuf), "%ld", (long)x);
01481       sizeString.AssignWithConversion(sizeBuf);
01482       docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString);
01483       if (ownerXULDoc) // force persistence in case the value didn't change
01484         ownerXULDoc->Persist(windowElementId, SCREENX_ATTRIBUTE);
01485     }
01486     if(persistString.Find("screenY") >= 0) {
01487       PR_snprintf(sizeBuf, sizeof(sizeBuf), "%ld", (long)y);
01488       sizeString.AssignWithConversion(sizeBuf);
01489       docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString);
01490       if (ownerXULDoc)
01491         ownerXULDoc->Persist(windowElementId, SCREENY_ATTRIBUTE);
01492     }
01493   }
01494 
01495   if ((mPersistentAttributesDirty & PAD_SIZE) &&
01496       sizeMode == nsSizeMode_Normal) {
01497     if(persistString.Find("width") >= 0) {
01498       PR_snprintf(sizeBuf, sizeof(sizeBuf), "%ld", (long)cx);
01499       sizeString.AssignWithConversion(sizeBuf);
01500       docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString);
01501       if (ownerXULDoc)
01502         ownerXULDoc->Persist(windowElementId, WIDTH_ATTRIBUTE);
01503     }
01504     if(persistString.Find("height") >= 0) {
01505       PR_snprintf(sizeBuf, sizeof(sizeBuf), "%ld", (long)cy);
01506       sizeString.AssignWithConversion(sizeBuf);
01507       docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString);
01508       if (ownerXULDoc)
01509         ownerXULDoc->Persist(windowElementId, HEIGHT_ATTRIBUTE);
01510     }
01511   }
01512 
01513   if (mPersistentAttributesDirty & PAD_MISC) {
01514     if (sizeMode != nsSizeMode_Minimized &&
01515         persistString.Find("sizemode") >= 0) {
01516       if (sizeMode == nsSizeMode_Maximized)
01517         sizeString.Assign(SIZEMODE_MAXIMIZED);
01518       else
01519         sizeString.Assign(SIZEMODE_NORMAL);
01520       docShellElement->SetAttribute(MODE_ATTRIBUTE, sizeString);
01521       if (ownerXULDoc)
01522         ownerXULDoc->Persist(windowElementId, MODE_ATTRIBUTE);
01523     }
01524     if (persistString.Find("zlevel") >= 0) {
01525       PRUint32 zLevel;
01526       nsCOMPtr<nsIWindowMediator> mediator(do_GetService(kWindowMediatorCID));
01527       if (mediator) {
01528         mediator->GetZLevel(this, &zLevel);
01529         PR_snprintf(sizeBuf, sizeof(sizeBuf), "%lu", (unsigned long)zLevel);
01530         sizeString.AssignWithConversion(sizeBuf);
01531         docShellElement->SetAttribute(ZLEVEL_ATTRIBUTE, sizeString);
01532         ownerXULDoc->Persist(windowElementId, ZLEVEL_ATTRIBUTE);
01533       }
01534     }
01535   }
01536 
01537   mPersistentAttributesDirty = 0;
01538   return NS_OK;
01539 }
01540 
01541 NS_IMETHODIMP nsXULWindow::GetWindowDOMWindow(nsIDOMWindowInternal** aDOMWindow)
01542 {
01543    NS_ENSURE_STATE(mDocShell);
01544 
01545    if(!mDOMWindow)
01546       mDOMWindow = do_GetInterface(mDocShell);
01547    NS_ENSURE_TRUE(mDOMWindow, NS_ERROR_FAILURE);
01548 
01549    *aDOMWindow = mDOMWindow;
01550    NS_ADDREF(*aDOMWindow);
01551    return NS_OK;
01552 }
01553 
01554 NS_IMETHODIMP nsXULWindow::GetWindowDOMElement(nsIDOMElement** aDOMElement)
01555 {
01556    NS_ENSURE_STATE(mDocShell);
01557    NS_ENSURE_ARG_POINTER(aDOMElement);
01558 
01559    *aDOMElement = nsnull;
01560 
01561    nsCOMPtr<nsIContentViewer> cv;
01562    
01563    mDocShell->GetContentViewer(getter_AddRefs(cv));
01564    NS_ENSURE_TRUE(cv, NS_ERROR_FAILURE);
01565 
01566    nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(cv));
01567    NS_ENSURE_TRUE(docv, NS_ERROR_FAILURE);
01568 
01569    nsCOMPtr<nsIDocument> doc;
01570    docv->GetDocument(getter_AddRefs(doc));
01571    nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(doc));
01572    NS_ENSURE_TRUE(domdoc, NS_ERROR_FAILURE);
01573 
01574    domdoc->GetDocumentElement(aDOMElement);
01575    NS_ENSURE_TRUE(*aDOMElement, NS_ERROR_FAILURE);
01576 
01577    return NS_OK;
01578 }
01579 
01580 NS_IMETHODIMP nsXULWindow::GetDOMElementById(char* aID, nsIDOMElement** aDOMElement)
01581 {
01582    NS_ENSURE_STATE(mDocShell);
01583    NS_ENSURE_ARG_POINTER(aDOMElement);
01584 
01585    *aDOMElement = nsnull;
01586 
01587    nsCOMPtr<nsIContentViewer> cv;
01588    
01589    mDocShell->GetContentViewer(getter_AddRefs(cv));
01590    if(!cv)
01591       return NS_ERROR_FAILURE;
01592 
01593    nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(cv));
01594    if(!docv)   
01595       return NS_ERROR_FAILURE;
01596 
01597    nsCOMPtr<nsIDocument> doc;
01598    docv->GetDocument(getter_AddRefs(doc));
01599    nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(doc));
01600    if(!domdoc) 
01601       return NS_ERROR_FAILURE;
01602    
01603    NS_ENSURE_SUCCESS(domdoc->GetElementById(NS_ConvertASCIItoUCS2(aID), aDOMElement), NS_ERROR_FAILURE);
01604 
01605    return NS_OK;
01606 }
01607 
01608 nsresult nsXULWindow::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
01609    PRBool aPrimary, PRBool aTargetable, const nsAString& aID)
01610 {
01611   nsContentShellInfo* shellInfo = nsnull;
01612 
01613   PRInt32 count = mContentShells.Count();
01614   PRInt32 i;
01615   nsWeakPtr contentShellWeak = do_GetWeakReference(aContentShell);
01616   for (i = 0; i < count; i++) {
01617     nsContentShellInfo* info = (nsContentShellInfo*)mContentShells.ElementAt(i);
01618     if (info->id.Equals(aID)) {
01619       // We already exist. Do a replace.
01620       info->child = contentShellWeak;
01621       shellInfo = info;
01622     }
01623     else if (info->child == contentShellWeak)
01624       info->child = nsnull;
01625   }
01626 
01627   if (!shellInfo) {
01628     shellInfo = new nsContentShellInfo(aID, contentShellWeak);
01629     mContentShells.AppendElement((void*)shellInfo);
01630   }
01631     
01632   // Set the default content tree owner
01633   if (aPrimary) {
01634     NS_ENSURE_SUCCESS(EnsurePrimaryContentTreeOwner(), NS_ERROR_FAILURE);
01635     aContentShell->SetTreeOwner(mPrimaryContentTreeOwner);
01636     mPrimaryContentShell = aContentShell;
01637   }
01638   else {
01639     NS_ENSURE_SUCCESS(EnsureContentTreeOwner(), NS_ERROR_FAILURE);
01640     aContentShell->SetTreeOwner(mContentTreeOwner);
01641     if (mPrimaryContentShell == aContentShell)
01642       mPrimaryContentShell = nsnull;
01643   }
01644 
01645   if (aTargetable) {
01646 #ifdef DEBUG
01647     PRInt32 debugCount = mTargetableShells.Count();
01648     PRInt32 debugCounter;
01649     for (debugCounter = debugCount - 1; debugCounter >= 0; --debugCounter) {
01650       nsCOMPtr<nsIDocShellTreeItem> curItem =
01651         do_QueryReferent(mTargetableShells[debugCounter]);
01652       NS_ASSERTION(!SameCOMIdentity(curItem, aContentShell),
01653                    "Adding already existing item to mTargetableShells");
01654     }
01655 #endif
01656     
01657     NS_ENSURE_TRUE(mTargetableShells.AppendObject(contentShellWeak),
01658                    NS_ERROR_OUT_OF_MEMORY);
01659   }
01660 
01661   return NS_OK;
01662 }
01663 
01664 nsresult nsXULWindow::ContentShellRemoved(nsIDocShellTreeItem* aContentShell)
01665 {
01666   if (mPrimaryContentShell == aContentShell) {
01667     mPrimaryContentShell = nsnull;
01668   }
01669 
01670   PRInt32 count = mContentShells.Count();
01671   PRInt32 i;
01672   for (i = count - 1; i >= 0; --i) {
01673     nsContentShellInfo* info = (nsContentShellInfo*)mContentShells.ElementAt(i);
01674     nsCOMPtr<nsIDocShellTreeItem> curItem = do_QueryReferent(info->child);
01675     if (!curItem || SameCOMIdentity(curItem, aContentShell)) {
01676       mContentShells.RemoveElementAt(i);
01677     }
01678   }
01679 
01680   count = mTargetableShells.Count();
01681   for (i = count - 1; i >= 0; --i) {
01682     nsCOMPtr<nsIDocShellTreeItem> curItem =
01683       do_QueryReferent(mTargetableShells[i]);
01684     if (!curItem || SameCOMIdentity(curItem, aContentShell)) {
01685       mTargetableShells.RemoveObjectAt(i);
01686     }
01687   }
01688   
01689   return NS_OK;
01690 }
01691 
01692 NS_IMETHODIMP nsXULWindow::SizeShellTo(nsIDocShellTreeItem* aShellItem,
01693    PRInt32 aCX, PRInt32 aCY)
01694 {
01695    // XXXTAB This is wrong, we should actually reflow based on the passed in'
01696    // shell.  For now we are hacking and doing delta sizing.  This is bad
01697    // because it assumes all size we add will go to the shell which probably
01698    // won't happen.
01699 
01700    nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem));
01701    NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
01702 
01703    PRInt32 width = 0;
01704    PRInt32 height = 0;
01705    shellAsWin->GetSize(&width, &height);
01706 
01707    PRInt32 widthDelta = aCX - width;
01708    PRInt32 heightDelta = aCY - height;
01709 
01710    if(widthDelta || heightDelta)
01711       {
01712       PRInt32 winCX = 0;
01713       PRInt32 winCY = 0;
01714 
01715       GetSize(&winCX, &winCY);
01716       SetSize(winCX + widthDelta, winCY + heightDelta, PR_TRUE);
01717       }
01718 
01719    return NS_OK;
01720 }
01721 
01722 NS_IMETHODIMP nsXULWindow::ExitModalLoop(nsresult aStatus)
01723 {
01724   if (mContinueModalLoop)
01725     EnableParent(PR_TRUE);
01726   mContinueModalLoop = PR_FALSE;
01727   mModalStatus = aStatus;
01728   return NS_OK;
01729 }
01730 
01731 // top-level function to create a new window
01732 NS_IMETHODIMP nsXULWindow::CreateNewWindow(PRInt32 aChromeFlags,
01733                              nsIAppShell* aAppShell, nsIXULWindow **_retval)
01734 {
01735   NS_ENSURE_ARG_POINTER(_retval);
01736 
01737   if (aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)
01738     return CreateNewChromeWindow(aChromeFlags, aAppShell, _retval);
01739   return CreateNewContentWindow(aChromeFlags, aAppShell, _retval);
01740 }
01741 
01742 NS_IMETHODIMP nsXULWindow::CreateNewChromeWindow(PRInt32 aChromeFlags,
01743    nsIAppShell* aAppShell, nsIXULWindow **_retval)
01744 {
01745    NS_TIMELINE_ENTER("nsXULWindow::CreateNewChromeWindow");
01746    nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
01747    NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
01748    
01749    // Just do a normal create of a window and return.
01750    //XXXTAB remove this when appshell talks in terms of nsIXULWindow
01751    nsCOMPtr<nsIXULWindow> parent;
01752    if(aChromeFlags & nsIWebBrowserChrome::CHROME_DEPENDENT)
01753       parent = this;
01754 
01755    nsCOMPtr<nsIXULWindow> newWindow;
01756    appShell->CreateTopLevelWindow(parent, nsnull, aChromeFlags,
01757                                   nsIAppShellService::SIZE_TO_CONTENT,
01758                                   nsIAppShellService::SIZE_TO_CONTENT,
01759                                   aAppShell, getter_AddRefs(newWindow));
01760 
01761    NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE);
01762 
01763    newWindow->SetChromeFlags(aChromeFlags);
01764 
01765    *_retval = newWindow;
01766    NS_ADDREF(*_retval);
01767    
01768    NS_TIMELINE_LEAVE("nsXULWindow::CreateNewChromeWindow done");
01769    return NS_OK;
01770 }
01771 
01772 NS_IMETHODIMP nsXULWindow::CreateNewContentWindow(PRInt32 aChromeFlags,
01773    nsIAppShell* aAppShell, nsIXULWindow **_retval)
01774 {
01775    NS_TIMELINE_ENTER("nsXULWindow::CreateNewContentWindow");
01776    nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
01777    NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
01778 
01779    nsCOMPtr<nsIXULWindow> parent;
01780    if(aChromeFlags & nsIWebBrowserChrome::CHROME_DEPENDENT)
01781       parent = this;
01782 
01783    // We need to create a new top level window and then enter a nested
01784    // loop. Eventually the new window will be told that it has loaded,
01785    // at which time we know it is safe to spin out of the nested loop
01786    // and allow the opening code to proceed.
01787 
01788    // First push a nested event queue for event processing from netlib
01789    // onto our UI thread queue stack.
01790    nsEventQueueStack queuePusher;
01791    NS_ENSURE_SUCCESS(queuePusher.Success(), NS_ERROR_FAILURE);
01792 
01793    nsCOMPtr<nsIURI> uri;
01794 
01795    nsCOMPtr<nsIPref> prefs(do_GetService(kPrefServiceCID));
01796    if (prefs) {
01797      char *urlStr;
01798      PRBool strAllocated = PR_TRUE;
01799      nsresult prefres;
01800      prefres = prefs->CopyCharPref("browser.chromeURL", &urlStr);
01801      if (NS_SUCCEEDED(prefres) && urlStr[0] == '\0') {
01802        PL_strfree(urlStr);
01803        prefres = NS_ERROR_FAILURE;
01804      }
01805      if (NS_FAILED(prefres)) {
01806        urlStr = "chrome://navigator/content/navigator.xul";
01807        strAllocated = PR_FALSE;
01808      }
01809 
01810      nsCOMPtr<nsIIOService> service(do_GetService(kIOServiceCID));
01811      if (service)
01812        service->NewURI(nsDependentCString(urlStr), nsnull, nsnull, getter_AddRefs(uri));
01813      if (strAllocated)
01814        PL_strfree(urlStr);
01815    }
01816    NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
01817 
01818    nsCOMPtr<nsIXULWindow> newWindow;
01819    appShell->CreateTopLevelWindow(parent, uri,
01820                                   aChromeFlags, 615, 480, aAppShell,
01821                                   getter_AddRefs(newWindow));
01822 
01823    NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE);
01824 
01825    newWindow->SetChromeFlags(aChromeFlags);
01826 
01827    nsCOMPtr<nsIAppShell> subShell(do_CreateInstance(kAppShellCID));
01828    NS_ENSURE_TRUE(subShell, NS_ERROR_FAILURE);
01829 
01830    subShell->Create(0, nsnull);
01831    subShell->Spinup();
01832 
01833    // Specify that we want the window to remain locked until the chrome has loaded.
01834    nsXULWindow *xulWin = NS_STATIC_CAST(nsXULWindow*,
01835                                         NS_STATIC_CAST(nsIXULWindow*,
01836                                                        newWindow));
01837 
01838    xulWin->LockUntilChromeLoad();
01839 
01840    // Push nsnull onto the JSContext stack before we dispatch a native event.
01841    nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
01842    if(stack && NS_SUCCEEDED(stack->Push(nsnull)))
01843       {
01844       nsresult looprv = NS_OK;
01845       while(NS_SUCCEEDED(looprv) && xulWin->IsLocked())
01846          {
01847          void      *data;
01848          PRBool    isRealEvent;
01849     
01850          looprv = subShell->GetNativeEvent(isRealEvent, data);
01851          subShell->DispatchNativeEvent(isRealEvent, data);
01852          }
01853 
01854       JSContext *cx;
01855       stack->Pop(&cx);
01856       NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
01857       }
01858 
01859    subShell->Spindown();
01860 
01861    *_retval = newWindow;
01862    NS_ADDREF(*_retval);
01863 
01864    NS_TIMELINE_LEAVE("nsXULWindow::CreateNewContentWindow");
01865    return NS_OK;
01866 }
01867 
01868 void nsXULWindow::EnableParent(PRBool aEnable)
01869 {
01870   nsCOMPtr<nsIBaseWindow> parentWindow;
01871   nsCOMPtr<nsIWidget>     parentWidget;
01872 
01873   parentWindow = do_QueryReferent(mParentWindow);
01874   if (parentWindow)
01875     parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
01876   if (parentWidget)
01877     parentWidget->Enable(aEnable);
01878 }
01879 
01880 // Constrain the window to its proper z-level
01881 PRBool nsXULWindow::ConstrainToZLevel(
01882                       PRBool      aImmediate,
01883                       nsWindowZ  *aPlacement,
01884                       nsIWidget  *aReqBelow,
01885                       nsIWidget **aActualBelow) {
01886 
01887 #if 0
01888   /* Do we have a parent window? This means our z-order is already constrained,
01889      since we're a dependent window. Our window list isn't hierarchical,
01890      so we can't properly calculate placement for such a window.
01891      Should we just abort? */
01892   nsCOMPtr<nsIBaseWindow> parentWindow = do_QueryReferent(mParentWindow);
01893   if (parentWindow)
01894     return PR_FALSE;
01895 #endif
01896 
01897   nsCOMPtr<nsIWindowMediator> mediator(do_GetService(kWindowMediatorCID));
01898   if(!mediator)
01899     return PR_FALSE;
01900 
01901   PRBool         altered;
01902   PRUint32       position,
01903                  newPosition,
01904                  zLevel;
01905   nsIXULWindow  *us = this;
01906 
01907   altered = PR_FALSE;
01908   mediator->GetZLevel(this, &zLevel);
01909 
01910   // translate from nsGUIEvent to nsIWindowMediator constants
01911   position = nsIWindowMediator::zLevelTop;
01912   if (*aPlacement == nsWindowZBottom || zLevel == nsIXULWindow::lowestZ)
01913     position = nsIWindowMediator::zLevelBottom;
01914   else if (*aPlacement == nsWindowZRelative)
01915     position = nsIWindowMediator::zLevelBelow;
01916 
01917   if (NS_SUCCEEDED(mediator->CalculateZPosition(us, position, aReqBelow,
01918                                &newPosition, aActualBelow, &altered))) {
01919 
01920     /* If we were asked to move to the top but constrained to remain
01921        below one of our other windows, first move all windows in that
01922        window's layer and above to the top. This allows the user to
01923        click a window which can't be topmost and still bring mozilla
01924        to the foreground. */
01925     if (altered &&
01926         (position == nsIWindowMediator::zLevelTop ||
01927          position == nsIWindowMediator::zLevelBelow && aReqBelow == 0))
01928 
01929       PlaceWindowLayersBehind(zLevel+1, nsIXULWindow::highestZ, 0);
01930 
01931     if (*aPlacement != nsWindowZBottom &&
01932         position == nsIWindowMediator::zLevelBottom)
01933       altered = PR_TRUE;
01934     if (altered || aImmediate) {
01935       if (newPosition == nsIWindowMediator::zLevelTop)
01936         *aPlacement = nsWindowZTop;
01937       else if (newPosition == nsIWindowMediator::zLevelBottom)
01938         *aPlacement = nsWindowZBottom;
01939       else
01940         *aPlacement = nsWindowZRelative;
01941 
01942       if (aImmediate) {
01943         nsCOMPtr<nsIBaseWindow> ourBase = do_QueryInterface(NS_STATIC_CAST(nsIXULWindow *,this));
01944         if (ourBase) {
01945           nsCOMPtr<nsIWidget> ourWidget;
01946           ourBase->GetMainWidget(getter_AddRefs(ourWidget));
01947           ourWidget->PlaceBehind(*aPlacement == nsWindowZBottom ?
01948                                    eZPlacementBottom : eZPlacementBelow,
01949                                  *aActualBelow, PR_FALSE);
01950         }
01951       }
01952     }
01953 
01954     /* (CalculateZPosition can tell us to be below nothing, because it tries
01955        not to change something it doesn't recognize. A request to verify
01956        being below an unrecognized window, then, is treated as a request
01957        to come to the top (below null) */
01958     nsCOMPtr<nsIXULWindow> windowAbove;
01959     if (newPosition == nsIWindowMediator::zLevelBelow && *aActualBelow) {
01960       void *data;
01961       (*aActualBelow)->GetClientData(data);
01962       if (data) {
01963         windowAbove = NS_REINTERPRET_CAST(nsWebShellWindow*, data);
01964       }
01965     }
01966 
01967     mediator->SetZPosition(us, newPosition, windowAbove);
01968   }
01969 
01970   return altered;
01971 }
01972 
01973 /* Re-z-position all windows in the layers from aLowLevel to aHighLevel,
01974    inclusive, to be behind aBehind. aBehind of null means on top.
01975    Note this method actually does nothing to our relative window positions.
01976    (And therefore there's no need to inform WindowMediator we're moving
01977    things, because we aren't.) This method is useful for, say, moving
01978    a range of layers of our own windows relative to windows belonging to
01979    external applications.
01980 */
01981 void nsXULWindow::PlaceWindowLayersBehind(PRUint32 aLowLevel,
01982                                           PRUint32 aHighLevel,
01983                                           nsIXULWindow *aBehind) {
01984 
01985   // step through windows in z-order from top to bottommost window
01986 
01987   nsCOMPtr<nsIWindowMediator> mediator(do_GetService(kWindowMediatorCID));
01988   if(!mediator)
01989     return;
01990 
01991   nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
01992   mediator->GetZOrderXULWindowEnumerator(0, PR_TRUE,
01993               getter_AddRefs(windowEnumerator));
01994   if (!windowEnumerator)
01995     return;
01996 
01997   // each window will be moved behind previousHighWidget, itself
01998   // a moving target. initialize it.
01999   nsCOMPtr<nsIWidget> previousHighWidget;
02000   if (aBehind) {
02001     nsCOMPtr<nsIBaseWindow> highBase(do_QueryInterface(aBehind));
02002     if (highBase)
02003       highBase->GetMainWidget(getter_AddRefs(previousHighWidget));
02004   }
02005 
02006   // get next lower window
02007   PRBool more;
02008   while (windowEnumerator->HasMoreElements(&more), more) {
02009     PRUint32 nextZ; // z-level of nextWindow
02010     nsCOMPtr<nsISupports> nextWindow;
02011     windowEnumerator->GetNext(getter_AddRefs(nextWindow));
02012     nsCOMPtr<nsIXULWindow> nextXULWindow(do_QueryInterface(nextWindow));
02013     nextXULWindow->GetZLevel(&nextZ);
02014     if (nextZ < aLowLevel)
02015       break; // we've processed all windows through aLowLevel
02016     
02017     // move it just below its next higher window
02018     nsCOMPtr<nsIBaseWindow> nextBase(do_QueryInterface(nextXULWindow));
02019     if (nextBase) {
02020       nsCOMPtr<nsIWidget> nextWidget;
02021       nextBase->GetMainWidget(getter_AddRefs(nextWidget));
02022       if (nextZ <= aHighLevel)
02023         nextWidget->PlaceBehind(eZPlacementBelow, previousHighWidget, PR_FALSE);
02024       previousHighWidget = nextWidget;
02025     }
02026   }
02027 }
02028 
02029 void nsXULWindow::SetContentScrollbarVisibility(PRBool aVisible) {
02030 
02031   nsCOMPtr<nsIDOMWindow> contentWin(do_GetInterface(mPrimaryContentShell));
02032   if (contentWin) {
02033     nsCOMPtr<nsIDOMBarProp> scrollbars;
02034     contentWin->GetScrollbars(getter_AddRefs(scrollbars));
02035     if (scrollbars)
02036       scrollbars->SetVisible(aVisible);
02037   }
02038 }
02039 
02040 PRBool nsXULWindow::GetContentScrollbarVisibility() {
02041 
02042   PRBool visible = PR_TRUE;
02043 
02044   nsCOMPtr<nsIDOMWindow> contentWin(do_GetInterface(mPrimaryContentShell));
02045   if (contentWin) {
02046     nsCOMPtr<nsIDOMBarProp> scrollbars;
02047     contentWin->GetScrollbars(getter_AddRefs(scrollbars));
02048     if (scrollbars)
02049       scrollbars->GetVisible(&visible);
02050   }
02051   return visible;
02052 }
02053 
02054 // during spinup, attributes that haven't been loaded yet can't be dirty
02055 void nsXULWindow::PersistentAttributesDirty(PRUint32 aDirtyFlags) {
02056 
02057   mPersistentAttributesDirty |= aDirtyFlags & mPersistentAttributesMask;
02058 }
02059 
02060 nsresult nsXULWindow::ApplyChromeFlags()
02061 {
02062   nsCOMPtr<nsIDOMElement> window;
02063   GetWindowDOMElement(getter_AddRefs(window));
02064   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
02065 
02066   // menubar has its own special treatment
02067   mWindow->ShowMenuBar(mChromeFlags & nsIWebBrowserChrome::CHROME_MENUBAR ? 
02068                        PR_TRUE : PR_FALSE);
02069 
02070   // Scrollbars have their own special treatment.
02071   SetContentScrollbarVisibility(mChromeFlags &
02072                                   nsIWebBrowserChrome::CHROME_SCROLLBARS ?
02073                                 PR_TRUE : PR_FALSE);
02074 
02075   /* the other flags are handled together. we have style rules
02076      in navigator.css that trigger visibility based on
02077      the 'chromehidden' attribute of the <window> tag. */
02078   nsAutoString newvalue;
02079 
02080   if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_MENUBAR))
02081     newvalue.AppendLiteral("menubar ");
02082 
02083   if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_TOOLBAR))
02084     newvalue.AppendLiteral("toolbar ");
02085 
02086   if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_LOCATIONBAR))
02087     newvalue.AppendLiteral("location ");
02088 
02089   if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR))
02090     newvalue.AppendLiteral("directories ");
02091 
02092   if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_STATUSBAR))
02093     newvalue.AppendLiteral("status ");
02094 
02095   if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_EXTRA))
02096     newvalue.AppendLiteral("extrachrome ");
02097 
02098 
02099   // Get the old value, to avoid useless style reflows if we're just
02100   // setting stuff to the exact same thing.
02101   nsAutoString oldvalue;
02102   window->GetAttribute(NS_LITERAL_STRING("chromehidden"), oldvalue);
02103 
02104   if (oldvalue != newvalue)
02105     window->SetAttribute(NS_LITERAL_STRING("chromehidden"), newvalue);
02106 
02107   return NS_OK;
02108 }
02109 
02110 NS_IMETHODIMP nsXULWindow::GetXULBrowserWindow(nsIXULBrowserWindow * *aXULBrowserWindow)
02111 {
02112   NS_IF_ADDREF(*aXULBrowserWindow = mXULBrowserWindow);
02113   return NS_OK;
02114 }
02115 
02116 NS_IMETHODIMP nsXULWindow::SetXULBrowserWindow(nsIXULBrowserWindow * aXULBrowserWindow)
02117 {
02118   mXULBrowserWindow = aXULBrowserWindow;
02119   return NS_OK;
02120 }
02121 
02122 //*****************************************************************************
02123 // nsXULWindow: Accessors
02124 //*****************************************************************************
02125 
02126 //*****************************************************************************
02127 //*** nsContentShellInfo: Object Management
02128 //*****************************************************************************   
02129 
02130 nsContentShellInfo::nsContentShellInfo(const nsAString& aID,
02131                                        nsIWeakReference* aContentShell)
02132   : id(aID),
02133     child(aContentShell)
02134 {
02135 }
02136 
02137 nsContentShellInfo::~nsContentShellInfo()
02138 {
02139    //XXX Set Tree Owner to null if the tree owner is nsXULWindow->mContentTreeOwner
02140 } 
02141 
02142 //*****************************************************************************
02143 //*** nsEventQueueStack: Object Implementation
02144 //*****************************************************************************   
02145 
02146 nsEventQueueStack::nsEventQueueStack() : mQueue(nsnull)
02147 {
02148    mService = do_GetService(kEventQueueServiceCID);
02149 
02150    if(mService)
02151       mService->PushThreadEventQueue(getter_AddRefs(mQueue));
02152 }
02153 nsEventQueueStack::~nsEventQueueStack()
02154 {
02155    if(mQueue)
02156       mService->PopThreadEventQueue(mQueue);
02157    mService = nsnull;
02158 }
02159 
02160 nsresult nsEventQueueStack::Success()
02161 {
02162    return mQueue ? NS_OK : NS_ERROR_FAILURE; 
02163 }
02164 
02165 
02166