Back to index

lightning-sunbird  0.9+nobinonly
nsAppShellWindowEnumerator.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsIContentViewer.h"
00039 #include "nsIDocShell.h"
00040 #include "nsIDocumentViewer.h"
00041 #include "nsIDocument.h"
00042 #include "nsIDOMDocument.h"
00043 #include "nsIDOMElement.h"
00044 #include "nsIDOMWindow.h"
00045 #include "nsIDOMWindowInternal.h"
00046 #include "nsIFactory.h"
00047 #include "nsIInterfaceRequestor.h"
00048 #include "nsIInterfaceRequestorUtils.h"
00049 #include "nsIXULWindow.h"
00050 
00051 #include "nsAppShellWindowEnumerator.h"
00052 #include "nsWindowMediator.h"
00053 
00054 /********************************************************************/
00055 /************************ static helper functions *******************/
00056 /********************************************************************/
00057 
00058 static nsresult GetDOMWindow(nsIXULWindow* inWindow,
00059                   nsCOMPtr<nsIDOMWindowInternal> &outDOMWindow);
00060 static nsCOMPtr<nsIDOMNode> GetDOMNodeFromDocShell(nsIDocShell *aShell);
00061 static void GetAttribute(nsIXULWindow *inWindow, const nsAString &inAttribute,
00062                          nsAString &outValue);
00063 static void GetWindowType(nsIXULWindow* inWindow, nsString &outType);
00064 
00065 // fetch the nsIDOMWindow(Internal) from a XUL Window
00066 nsresult GetDOMWindow(nsIXULWindow *aWindow, nsCOMPtr<nsIDOMWindowInternal> &aDOMWindow)
00067 {
00068   nsCOMPtr<nsIDocShell> docShell;
00069 
00070   aWindow->GetDocShell(getter_AddRefs(docShell));
00071   aDOMWindow = do_GetInterface(docShell);
00072   return aDOMWindow ? NS_OK : NS_ERROR_FAILURE;
00073 }
00074 
00075 
00076 // QueryInterface fu
00077 nsCOMPtr<nsIDOMNode> GetDOMNodeFromDocShell(nsIDocShell *aShell)
00078 {
00079   nsCOMPtr<nsIDOMNode> node;
00080 
00081   nsCOMPtr<nsIContentViewer> cv;
00082   aShell->GetContentViewer(getter_AddRefs(cv));
00083   if (cv) {
00084     nsCOMPtr<nsIDocumentViewer> docv(do_QueryInterface(cv));
00085     if (docv) {
00086       nsCOMPtr<nsIDocument> doc;
00087       docv->GetDocument(getter_AddRefs(doc));
00088       if (doc) {
00089         nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(doc));
00090         if (domdoc) {
00091           nsCOMPtr<nsIDOMElement> element;
00092           domdoc->GetDocumentElement(getter_AddRefs(element));
00093           if (element)
00094             node = do_QueryInterface(element);
00095         }
00096       }
00097     }
00098   }
00099 
00100   return node;
00101 }
00102 
00103 // generic "retrieve the value of a XUL attribute" function
00104 void GetAttribute(nsIXULWindow *inWindow, const nsAString &inAttribute,
00105                   nsAString &outValue)
00106 {
00107   nsCOMPtr<nsIDocShell> shell;
00108   if (inWindow && NS_SUCCEEDED(inWindow->GetDocShell(getter_AddRefs(shell)))) {
00109 
00110     nsCOMPtr<nsIDOMNode> node(GetDOMNodeFromDocShell(shell));
00111     if (node) {
00112       nsCOMPtr<nsIDOMElement> webshellElement(do_QueryInterface(node));
00113       if (webshellElement)
00114         webshellElement->GetAttribute(inAttribute, outValue);
00115     }
00116   }
00117 }
00118 
00119 // retrieve the window type, stored as the value of a particular
00120 // attribute in its XUL window tag
00121 void GetWindowType(nsIXULWindow* aWindow, nsString &outType)
00122 {
00123   GetAttribute(aWindow, NS_LITERAL_STRING("windowtype"), outType);
00124 }
00125 
00126 /********************************************************************/
00127 /**************************** nsWindowInfo **************************/
00128 /********************************************************************/
00129 
00130 nsWindowInfo::nsWindowInfo(nsIXULWindow* inWindow, PRInt32 inTimeStamp) :
00131   mWindow(inWindow),mTimeStamp(inTimeStamp),mZLevel(nsIXULWindow::normalZ)
00132 {
00133   ReferenceSelf(PR_TRUE, PR_TRUE);
00134 }
00135 
00136 nsWindowInfo::~nsWindowInfo()
00137 {
00138 }
00139   
00140 // return true if the window described by this WindowInfo has a type
00141 // equal to the given type
00142 PRBool nsWindowInfo::TypeEquals(const nsAString &aType)
00143 { 
00144   nsAutoString rtnString;
00145   GetWindowType(mWindow, rtnString);
00146   return rtnString == aType;
00147 }
00148 
00149 // insert the struct into their two linked lists, in position after the
00150 // given (independent) method arguments
00151 void nsWindowInfo::InsertAfter(nsWindowInfo *inOlder , nsWindowInfo *inHigher) {
00152   if (inOlder) {
00153     mOlder = inOlder;
00154     mYounger = inOlder->mYounger;
00155     mOlder->mYounger = this;
00156     if (mOlder->mOlder == mOlder)
00157       mOlder->mOlder = this;
00158     mYounger->mOlder = this;
00159     if (mYounger->mYounger == mYounger)
00160       mYounger->mYounger = this;
00161   }
00162   if (inHigher) {
00163     mHigher = inHigher;
00164     mLower = inHigher->mLower;
00165     mHigher->mLower = this;
00166     if (mHigher->mHigher == mHigher)
00167       mHigher->mHigher = this;
00168     mLower->mHigher = this;
00169     if (mLower->mLower == mLower)
00170       mLower->mLower = this;
00171   }
00172 }
00173 
00174 // remove the struct from its linked lists
00175 void nsWindowInfo::Unlink(PRBool inAge, PRBool inZ) {
00176 
00177   if (inAge) {
00178     mOlder->mYounger = mYounger;
00179     mYounger->mOlder = mOlder;
00180   }
00181   if (inZ) {
00182     mLower->mHigher = mHigher;
00183     mHigher->mLower = mLower;
00184   }
00185   ReferenceSelf( inAge, inZ );
00186 }
00187 
00188 // initialize the struct to be a valid linked list of one element
00189 void nsWindowInfo::ReferenceSelf(PRBool inAge, PRBool inZ) {
00190 
00191   if (inAge) {
00192     mYounger = this;
00193     mOlder = this;
00194   }
00195   if (inZ) {
00196     mLower = this;
00197     mHigher = this;
00198   }
00199 }
00200 
00201 /********************************************************************/
00202 /*********************** nsAppShellWindowEnumerator *****************/
00203 /********************************************************************/
00204 
00205 NS_IMPL_ISUPPORTS1(nsAppShellWindowEnumerator, nsISimpleEnumerator)
00206 
00207 nsAppShellWindowEnumerator::nsAppShellWindowEnumerator (
00208     const PRUnichar* aTypeString,
00209     nsWindowMediator& aMediator) :
00210 
00211     mWindowMediator(&aMediator), mType(aTypeString),
00212     mCurrentPosition(0)
00213 {
00214   mWindowMediator->AddEnumerator(this);
00215   NS_ADDREF(mWindowMediator);
00216 }
00217 
00218 nsAppShellWindowEnumerator::~nsAppShellWindowEnumerator() {
00219 
00220   mWindowMediator->RemoveEnumerator(this);
00221   NS_RELEASE(mWindowMediator);
00222 }
00223 
00224 // after mCurrentPosition has been initialized to point to the beginning
00225 // of the appropriate list, adjust it if necessary
00226 void nsAppShellWindowEnumerator::AdjustInitialPosition() {
00227 
00228   if (!mType.IsEmpty() && mCurrentPosition && !mCurrentPosition->TypeEquals(mType))
00229     mCurrentPosition = FindNext();
00230 }
00231 
00232 NS_IMETHODIMP nsAppShellWindowEnumerator::HasMoreElements(PRBool *retval)
00233 {
00234   if (!retval)
00235     return NS_ERROR_INVALID_ARG;
00236 
00237   *retval = mCurrentPosition ? PR_TRUE : PR_FALSE;
00238   return NS_OK;
00239 }
00240        
00241 // if a window is being removed adjust the iterator's current position
00242 void nsAppShellWindowEnumerator::WindowRemoved(nsWindowInfo *inInfo) {
00243 
00244   if (mCurrentPosition == inInfo)
00245     mCurrentPosition = FindNext();
00246 }
00247 
00248 /********************************************************************/
00249 /*********************** nsASDOMWindowEnumerator ********************/
00250 /********************************************************************/
00251 
00252 nsASDOMWindowEnumerator::nsASDOMWindowEnumerator(
00253     const PRUnichar* aTypeString,
00254     nsWindowMediator& aMediator) :
00255 
00256   nsAppShellWindowEnumerator(aTypeString, aMediator) {
00257 
00258 }
00259 
00260 nsASDOMWindowEnumerator::~nsASDOMWindowEnumerator() {
00261 }
00262 
00263 NS_IMETHODIMP nsASDOMWindowEnumerator::GetNext(nsISupports **retval) {
00264 
00265   if (!retval)
00266     return NS_ERROR_INVALID_ARG;
00267 
00268   *retval = NULL;
00269   if (mCurrentPosition) {
00270     nsCOMPtr<nsIDOMWindowInternal> domWindow;
00271     GetDOMWindow(mCurrentPosition->mWindow, domWindow);
00272     CallQueryInterface(domWindow, retval);
00273     mCurrentPosition = FindNext();
00274   }
00275   return NS_OK;
00276 }
00277 
00278 /********************************************************************/
00279 /*********************** nsASXULWindowEnumerator ********************/
00280 /********************************************************************/
00281 
00282 nsASXULWindowEnumerator::nsASXULWindowEnumerator(
00283     const PRUnichar* aTypeString,
00284     nsWindowMediator& aMediator) :
00285 
00286   nsAppShellWindowEnumerator(aTypeString, aMediator) {
00287 
00288 }
00289 
00290 nsASXULWindowEnumerator::~nsASXULWindowEnumerator() {
00291 }
00292 
00293 NS_IMETHODIMP nsASXULWindowEnumerator::GetNext(nsISupports **retval) {
00294 
00295   if (!retval)
00296     return NS_ERROR_INVALID_ARG;
00297 
00298   *retval = NULL;
00299   if (mCurrentPosition) {
00300     CallQueryInterface(mCurrentPosition->mWindow, retval);
00301     mCurrentPosition = FindNext();
00302   }
00303   return NS_OK;
00304 }
00305 
00306 /********************************************************************/
00307 /****************** nsASDOMWindowEarlyToLateEnumerator **************/
00308 /********************************************************************/
00309 
00310 nsASDOMWindowEarlyToLateEnumerator::nsASDOMWindowEarlyToLateEnumerator(
00311     const PRUnichar *aTypeString,
00312     nsWindowMediator &aMediator) :
00313 
00314   nsASDOMWindowEnumerator(aTypeString, aMediator) {
00315 
00316   mCurrentPosition = aMediator.mOldestWindow;
00317   AdjustInitialPosition();
00318 }
00319 
00320 nsASDOMWindowEarlyToLateEnumerator::~nsASDOMWindowEarlyToLateEnumerator() {
00321 }
00322 
00323 nsWindowInfo *nsASDOMWindowEarlyToLateEnumerator::FindNext() {
00324 
00325   nsWindowInfo *info,
00326                *listEnd;
00327   PRBool        allWindows = mType.IsEmpty();
00328 
00329   // see nsXULWindowEarlyToLateEnumerator::FindNext
00330   if (!mCurrentPosition)
00331     return 0;
00332 
00333   info = mCurrentPosition->mYounger;
00334   listEnd = mWindowMediator->mOldestWindow;
00335 
00336   while (info != listEnd) {
00337     if (allWindows || info->TypeEquals(mType))
00338       return info;
00339     info = info->mYounger;
00340   }
00341 
00342   return 0;
00343 }
00344 
00345 /********************************************************************/
00346 /****************** nsASXULWindowEarlyToLateEnumerator **************/
00347 /********************************************************************/
00348 
00349 nsASXULWindowEarlyToLateEnumerator::nsASXULWindowEarlyToLateEnumerator(
00350     const PRUnichar *aTypeString,
00351     nsWindowMediator &aMediator) :
00352 
00353   nsASXULWindowEnumerator(aTypeString, aMediator) {
00354 
00355   mCurrentPosition = aMediator.mOldestWindow;
00356   AdjustInitialPosition();
00357 }
00358 
00359 nsASXULWindowEarlyToLateEnumerator::~nsASXULWindowEarlyToLateEnumerator() {
00360 }
00361 
00362 nsWindowInfo *nsASXULWindowEarlyToLateEnumerator::FindNext() {
00363 
00364   nsWindowInfo *info,
00365                *listEnd;
00366   PRBool        allWindows = mType.IsEmpty();
00367 
00368   /* mCurrentPosition null is assumed to mean that the enumerator has run
00369      its course and is now basically useless. It could also be interpreted
00370      to mean that it was created at a time when there were no windows. In
00371      that case it would probably be more appropriate to check to see whether
00372      windows have subsequently been added. But it's not guaranteed that we'll
00373      pick up newly added windows anyway (if they occurred previous to our
00374      current position) so we just don't worry about that. */
00375   if (!mCurrentPosition)
00376     return 0;
00377 
00378   info = mCurrentPosition->mYounger;
00379   listEnd = mWindowMediator->mOldestWindow;
00380 
00381   while (info != listEnd) {
00382     if (allWindows || info->TypeEquals(mType))
00383       return info;
00384     info = info->mYounger;
00385   }
00386 
00387   return 0;
00388 }
00389 
00390 /********************************************************************/
00391 /****************** nsASDOMWindowFrontToBackEnumerator **************/
00392 /********************************************************************/
00393 
00394 nsASDOMWindowFrontToBackEnumerator::nsASDOMWindowFrontToBackEnumerator(
00395     const PRUnichar *aTypeString,
00396     nsWindowMediator &aMediator) :
00397 
00398   nsASDOMWindowEnumerator(aTypeString, aMediator) {
00399 
00400   mCurrentPosition = aMediator.mTopmostWindow;
00401   AdjustInitialPosition();
00402 }
00403 
00404 nsASDOMWindowFrontToBackEnumerator::~nsASDOMWindowFrontToBackEnumerator() {
00405 }
00406 
00407 nsWindowInfo *nsASDOMWindowFrontToBackEnumerator::FindNext() {
00408 
00409   nsWindowInfo *info,
00410                *listEnd;
00411   PRBool        allWindows = mType.IsEmpty();
00412 
00413   // see nsXULWindowEarlyToLateEnumerator::FindNext
00414   if (!mCurrentPosition)
00415     return 0;
00416 
00417   info = mCurrentPosition->mLower;
00418   listEnd = mWindowMediator->mTopmostWindow;
00419 
00420   while (info != listEnd) {
00421     if (allWindows || info->TypeEquals(mType))
00422       return info;
00423     info = info->mLower;
00424   }
00425 
00426   return 0;
00427 }
00428 
00429 /********************************************************************/
00430 /****************** nsASXULWindowFrontToBackEnumerator **************/
00431 /********************************************************************/
00432 
00433 nsASXULWindowFrontToBackEnumerator::nsASXULWindowFrontToBackEnumerator(
00434     const PRUnichar *aTypeString,
00435     nsWindowMediator &aMediator) :
00436 
00437   nsASXULWindowEnumerator(aTypeString, aMediator) {
00438 
00439   mCurrentPosition = aMediator.mTopmostWindow;
00440   AdjustInitialPosition();
00441 }
00442 
00443 nsASXULWindowFrontToBackEnumerator::~nsASXULWindowFrontToBackEnumerator()
00444 {
00445 }
00446 
00447 nsWindowInfo *nsASXULWindowFrontToBackEnumerator::FindNext() {
00448 
00449   nsWindowInfo *info,
00450                *listEnd;
00451   PRBool        allWindows = mType.IsEmpty();
00452 
00453   // see nsXULWindowEarlyToLateEnumerator::FindNext
00454   if (!mCurrentPosition)
00455     return 0;
00456 
00457   info = mCurrentPosition->mLower;
00458   listEnd = mWindowMediator->mTopmostWindow;
00459 
00460   while (info != listEnd) {
00461     if (allWindows || info->TypeEquals(mType))
00462       return info;
00463     info = info->mLower;
00464   }
00465 
00466   return 0;
00467 }
00468 
00469 /********************************************************************/
00470 /****************** nsASDOMWindowBackToFrontEnumerator **************/
00471 /********************************************************************/
00472 
00473 nsASDOMWindowBackToFrontEnumerator::nsASDOMWindowBackToFrontEnumerator(
00474     const PRUnichar *aTypeString,
00475     nsWindowMediator &aMediator) :
00476 
00477   nsASDOMWindowEnumerator(aTypeString, aMediator) {
00478 
00479   mCurrentPosition = aMediator.mTopmostWindow ?
00480                      aMediator.mTopmostWindow->mHigher : 0;
00481   AdjustInitialPosition();
00482 }
00483 
00484 nsASDOMWindowBackToFrontEnumerator::~nsASDOMWindowBackToFrontEnumerator() {
00485 }
00486 
00487 nsWindowInfo *nsASDOMWindowBackToFrontEnumerator::FindNext() {
00488 
00489   nsWindowInfo *info,
00490                *listEnd;
00491   PRBool        allWindows = mType.IsEmpty();
00492 
00493   // see nsXULWindowEarlyToLateEnumerator::FindNext
00494   if (!mCurrentPosition)
00495     return 0;
00496 
00497   info = mCurrentPosition->mHigher;
00498   listEnd = mWindowMediator->mTopmostWindow;
00499   if (listEnd)
00500     listEnd = listEnd->mHigher;
00501 
00502   while (info != listEnd) {
00503     if (allWindows || info->TypeEquals(mType))
00504       return info;
00505     info = info->mHigher;
00506   }
00507 
00508   return 0;
00509 }
00510 
00511 /********************************************************************/
00512 /****************** nsASXULWindowBackToFrontEnumerator **************/
00513 /********************************************************************/
00514 
00515 nsASXULWindowBackToFrontEnumerator::nsASXULWindowBackToFrontEnumerator(
00516     const PRUnichar *aTypeString,
00517     nsWindowMediator &aMediator) :
00518 
00519   nsASXULWindowEnumerator(aTypeString, aMediator) {
00520 
00521   mCurrentPosition = aMediator.mTopmostWindow ?
00522                      aMediator.mTopmostWindow->mHigher : 0;
00523   AdjustInitialPosition();
00524 }
00525 
00526 nsASXULWindowBackToFrontEnumerator::~nsASXULWindowBackToFrontEnumerator()
00527 {
00528 }
00529 
00530 nsWindowInfo *nsASXULWindowBackToFrontEnumerator::FindNext() {
00531 
00532   nsWindowInfo *info,
00533                *listEnd;
00534   PRBool        allWindows = mType.IsEmpty();
00535 
00536   // see nsXULWindowEarlyToLateEnumerator::FindNext
00537   if (!mCurrentPosition)
00538     return 0;
00539 
00540   info = mCurrentPosition->mHigher;
00541   listEnd = mWindowMediator->mTopmostWindow;
00542   if (listEnd)
00543     listEnd = listEnd->mHigher;
00544 
00545   while (info != listEnd) {
00546     if (allWindows || info->TypeEquals(mType))
00547       return info;
00548     info = info->mHigher;
00549   }
00550 
00551   return 0;
00552 }
00553