xpfe/appshell/src/nsWindowMediator.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsCOMPtr.h"
     7 #include "nsString.h"
     8 #include "nsReadableUtils.h"
     9 #include "nsUnicharUtils.h"
    10 #include "nsTArray.h"
    11 #include "nsIBaseWindow.h"
    12 #include "nsIWidget.h"
    13 #include "nsIDOMWindow.h"
    14 #include "nsIObserverService.h"
    15 #include "nsIServiceManager.h"
    16 #include "nsISimpleEnumerator.h"
    17 #include "nsAppShellWindowEnumerator.h"
    18 #include "nsWindowMediator.h"
    19 #include "nsIWindowMediatorListener.h"
    20 #include "nsXPIDLString.h"
    21 #include "nsGlobalWindow.h"
    23 #include "nsIDocShell.h"
    24 #include "nsIInterfaceRequestor.h"
    25 #include "nsIInterfaceRequestorUtils.h"
    26 #include "nsIXULWindow.h"
    28 using namespace mozilla;
    30 static bool notifyOpenWindow(nsIWindowMediatorListener *aElement, void* aData);
    31 static bool notifyCloseWindow(nsIWindowMediatorListener *aElement, void* aData);
    32 static bool notifyWindowTitleChange(nsIWindowMediatorListener *aElement, void* aData);
    34 // for notifyWindowTitleChange
    35 struct WindowTitleData {
    36   nsIXULWindow* mWindow;
    37   const char16_t *mTitle;
    38 };
    40 nsresult
    41 nsWindowMediator::GetDOMWindow(nsIXULWindow* inWindow,
    42                                nsCOMPtr<nsIDOMWindow>& outDOMWindow)
    43 {
    44   nsCOMPtr<nsIDocShell> docShell;
    46   inWindow->GetDocShell(getter_AddRefs(docShell));
    47   outDOMWindow = do_GetInterface(docShell);
    48   return outDOMWindow ? NS_OK : NS_ERROR_FAILURE;
    49 }
    51 nsWindowMediator::nsWindowMediator() :
    52   mEnumeratorList(), mOldestWindow(nullptr), mTopmostWindow(nullptr),
    53   mTimeStamp(0), mSortingZOrder(false), mReady(false),
    54   mListLock("nsWindowMediator.mListLock")
    55 {
    56 }
    58 nsWindowMediator::~nsWindowMediator()
    59 {
    60   while (mOldestWindow)
    61     UnregisterWindow(mOldestWindow);
    62 }
    64 nsresult nsWindowMediator::Init()
    65 {
    66   nsresult rv;
    67   nsCOMPtr<nsIObserverService> obsSvc =
    68     do_GetService("@mozilla.org/observer-service;1", &rv);
    69   NS_ENSURE_SUCCESS(rv, rv);
    70   rv = obsSvc->AddObserver(this, "xpcom-shutdown", true);
    71   NS_ENSURE_SUCCESS(rv, rv);
    73   mReady = true;
    74   return NS_OK;
    75 }
    77 NS_IMETHODIMP nsWindowMediator::RegisterWindow(nsIXULWindow* inWindow)
    78 {
    79   NS_ENSURE_STATE(mReady);
    81   if (GetInfoFor(inWindow)) {
    82     NS_ERROR("multiple window registration");
    83     return NS_ERROR_FAILURE;
    84   }
    86   mTimeStamp++;
    88   // Create window info struct and add to list of windows
    89   nsWindowInfo* windowInfo = new nsWindowInfo(inWindow, mTimeStamp);
    90   if (!windowInfo)
    91     return NS_ERROR_OUT_OF_MEMORY;
    93   WindowTitleData winData = { inWindow, nullptr };
    94   mListeners.EnumerateForwards(notifyOpenWindow, &winData);
    96   MutexAutoLock lock(mListLock);
    97   if (mOldestWindow)
    98     windowInfo->InsertAfter(mOldestWindow->mOlder, nullptr);
    99   else
   100     mOldestWindow = windowInfo;
   102   return NS_OK;
   103 }
   105 NS_IMETHODIMP
   106 nsWindowMediator::UnregisterWindow(nsIXULWindow* inWindow)
   107 {
   108   NS_ENSURE_STATE(mReady);
   109   MutexAutoLock lock(mListLock);
   110   nsWindowInfo *info = GetInfoFor(inWindow);
   111   if (info)
   112     return UnregisterWindow(info);
   113   return NS_ERROR_INVALID_ARG;
   114 }
   116 nsresult
   117 nsWindowMediator::UnregisterWindow(nsWindowInfo *inInfo)
   118 {
   119   // Inform the iterators
   120   uint32_t index = 0;
   121   while (index < mEnumeratorList.Length()) {
   122     mEnumeratorList[index]->WindowRemoved(inInfo);
   123     index++;
   124   }
   126   WindowTitleData winData = { inInfo->mWindow.get(), nullptr };
   127   mListeners.EnumerateForwards(notifyCloseWindow, &winData);
   129   // Remove from the lists and free up 
   130   if (inInfo == mOldestWindow)
   131     mOldestWindow = inInfo->mYounger;
   132   if (inInfo == mTopmostWindow)
   133     mTopmostWindow = inInfo->mLower;
   134   inInfo->Unlink(true, true);
   135   if (inInfo == mOldestWindow)
   136     mOldestWindow = nullptr;
   137   if (inInfo == mTopmostWindow)
   138     mTopmostWindow = nullptr;
   139   delete inInfo;  
   141   return NS_OK;
   142 }
   144 nsWindowInfo*
   145 nsWindowMediator::GetInfoFor(nsIXULWindow *aWindow)
   146 {
   147   nsWindowInfo *info,
   148                *listEnd;
   150   if (!aWindow)
   151     return nullptr;
   153   info = mOldestWindow;
   154   listEnd = nullptr;
   155   while (info != listEnd) {
   156     if (info->mWindow.get() == aWindow)
   157       return info;
   158     info = info->mYounger;
   159     listEnd = mOldestWindow;
   160   }
   161   return nullptr;
   162 }
   164 nsWindowInfo*
   165 nsWindowMediator::GetInfoFor(nsIWidget *aWindow)
   166 {
   167   nsWindowInfo *info,
   168                *listEnd;
   170   if (!aWindow)
   171     return nullptr;
   173   info = mOldestWindow;
   174   listEnd = nullptr;
   176   nsCOMPtr<nsIWidget> scanWidget;
   177   while (info != listEnd) {
   178     nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(info->mWindow));
   179     if (base)
   180       base->GetMainWidget(getter_AddRefs(scanWidget));
   181     if (aWindow == scanWidget.get())
   182       return info;
   183     info = info->mYounger;
   184     listEnd = mOldestWindow;
   185   }
   186   return nullptr;
   187 }
   189 NS_IMETHODIMP
   190 nsWindowMediator::GetEnumerator(const char16_t* inType, nsISimpleEnumerator** outEnumerator)
   191 {
   192   NS_ENSURE_ARG_POINTER(outEnumerator);
   193   NS_ENSURE_STATE(mReady);
   194   MutexAutoLock lock(mListLock);
   195   nsAppShellWindowEnumerator *enumerator = new nsASDOMWindowEarlyToLateEnumerator(inType, *this);
   196   if (enumerator)
   197     return enumerator->QueryInterface(NS_GET_IID(nsISimpleEnumerator) , (void**)outEnumerator);
   199   return NS_ERROR_OUT_OF_MEMORY;
   200 }
   202 NS_IMETHODIMP
   203 nsWindowMediator::GetXULWindowEnumerator(const char16_t* inType, nsISimpleEnumerator** outEnumerator)
   204 {
   205   NS_ENSURE_ARG_POINTER(outEnumerator);
   206   NS_ENSURE_STATE(mReady);
   207   MutexAutoLock lock(mListLock);
   208   nsAppShellWindowEnumerator *enumerator = new nsASXULWindowEarlyToLateEnumerator(inType, *this);
   209   if (enumerator)
   210     return enumerator->QueryInterface(NS_GET_IID(nsISimpleEnumerator) , (void**)outEnumerator);
   212   return NS_ERROR_OUT_OF_MEMORY;
   213 }
   215 NS_IMETHODIMP
   216 nsWindowMediator::GetZOrderDOMWindowEnumerator(
   217             const char16_t *aWindowType, bool aFrontToBack,
   218             nsISimpleEnumerator **_retval)
   219 {
   220   NS_ENSURE_ARG_POINTER(_retval);
   221   NS_ENSURE_STATE(mReady);
   222   MutexAutoLock lock(mListLock);
   223   nsAppShellWindowEnumerator *enumerator;
   224   if (aFrontToBack)
   225     enumerator = new nsASDOMWindowFrontToBackEnumerator(aWindowType, *this);
   226   else
   227     enumerator = new nsASDOMWindowBackToFrontEnumerator(aWindowType, *this);
   228   if (enumerator)
   229     return CallQueryInterface(enumerator, _retval);
   231   return NS_ERROR_OUT_OF_MEMORY;
   232 }
   234 NS_IMETHODIMP
   235 nsWindowMediator::GetZOrderXULWindowEnumerator(
   236             const char16_t *aWindowType, bool aFrontToBack,
   237             nsISimpleEnumerator **_retval)
   238 {
   239   NS_ENSURE_ARG_POINTER(_retval);
   240   NS_ENSURE_STATE(mReady);
   241   MutexAutoLock lock(mListLock);
   242   nsAppShellWindowEnumerator *enumerator;
   243   if (aFrontToBack)
   244     enumerator = new nsASXULWindowFrontToBackEnumerator(aWindowType, *this);
   245   else
   246     enumerator = new nsASXULWindowBackToFrontEnumerator(aWindowType, *this);
   247   if (enumerator)
   248     return CallQueryInterface(enumerator, _retval);
   250   return NS_ERROR_OUT_OF_MEMORY;
   251 }
   253 int32_t
   254 nsWindowMediator::AddEnumerator(nsAppShellWindowEnumerator * inEnumerator)
   255 {
   256   return mEnumeratorList.AppendElement(inEnumerator) != nullptr;
   257 }
   259 int32_t
   260 nsWindowMediator::RemoveEnumerator(nsAppShellWindowEnumerator * inEnumerator)
   261 {
   262   return mEnumeratorList.RemoveElement(inEnumerator);
   263 }
   265 // Returns the window of type inType ( if null return any window type ) which has the most recent
   266 // time stamp
   267 NS_IMETHODIMP
   268 nsWindowMediator::GetMostRecentWindow(const char16_t* inType, nsIDOMWindow** outWindow)
   269 {
   270   NS_ENSURE_ARG_POINTER(outWindow);
   271   *outWindow = nullptr;
   272   if (!mReady)
   273     return NS_OK;
   275   // Find the most window with the highest time stamp that matches
   276   // the requested type
   278   MutexAutoLock lock(mListLock);
   279   nsWindowInfo *info = MostRecentWindowInfo(inType);
   281   if (info && info->mWindow) {
   282     nsCOMPtr<nsIDOMWindow> DOMWindow;
   283     if (NS_SUCCEEDED(GetDOMWindow(info->mWindow, DOMWindow))) {  
   284       *outWindow = DOMWindow;
   285       NS_ADDREF(*outWindow);
   286       return NS_OK;
   287     }
   288     return NS_ERROR_FAILURE;
   289   }
   291   return NS_OK;
   292 }
   294 nsWindowInfo*
   295 nsWindowMediator::MostRecentWindowInfo(const char16_t* inType)
   296 {
   297   int32_t       lastTimeStamp = -1;
   298   nsAutoString  typeString(inType);
   299   bool          allWindows = !inType || typeString.IsEmpty();
   301   // Find the most window with the highest time stamp that matches
   302   // the requested type
   303   nsWindowInfo *searchInfo,
   304                *listEnd,
   305                *foundInfo = nullptr;
   307   searchInfo = mOldestWindow;
   308   listEnd = nullptr;
   309   while (searchInfo != listEnd) {
   310     if ((allWindows || searchInfo->TypeEquals(typeString)) &&
   311         searchInfo->mTimeStamp >= lastTimeStamp) {
   313       foundInfo = searchInfo;
   314       lastTimeStamp = searchInfo->mTimeStamp;
   315     }
   316     searchInfo = searchInfo->mYounger;
   317     listEnd = mOldestWindow;
   318   }
   319   return foundInfo;
   320 }
   322 NS_IMETHODIMP
   323 nsWindowMediator::GetOuterWindowWithId(uint64_t aWindowID,
   324                                        nsIDOMWindow** aWindow)
   325 {
   326   *aWindow = nsGlobalWindow::GetOuterWindowWithId(aWindowID);
   327   NS_IF_ADDREF(*aWindow);
   328   return NS_OK;
   329 }
   331 NS_IMETHODIMP
   332 nsWindowMediator::GetCurrentInnerWindowWithId(uint64_t aWindowID,
   333                                               nsIDOMWindow** aWindow)
   334 {
   335   nsCOMPtr<nsPIDOMWindow> inner = nsGlobalWindow::GetInnerWindowWithId(aWindowID);
   337   // not found
   338   if (!inner)
   339     return NS_OK;
   341   nsCOMPtr<nsPIDOMWindow> outer = inner->GetOuterWindow();
   342   NS_ENSURE_TRUE(outer, NS_ERROR_UNEXPECTED);
   344   // outer is already using another inner, so it's same as not found
   345   if (outer->GetCurrentInnerWindow() != inner)
   346     return NS_OK;
   348   nsCOMPtr<nsIDOMWindow> ret = do_QueryInterface(outer);
   349   ret.forget(aWindow);
   350   return NS_OK;
   351 }
   353 NS_IMETHODIMP
   354 nsWindowMediator::UpdateWindowTimeStamp(nsIXULWindow* inWindow)
   355 {
   356   NS_ENSURE_STATE(mReady);
   357   MutexAutoLock lock(mListLock);
   358   nsWindowInfo *info = GetInfoFor(inWindow);
   359   if (info) {
   360     // increment the window's time stamp
   361     info->mTimeStamp = ++mTimeStamp;
   362     return NS_OK;
   363   }
   364   return NS_ERROR_FAILURE; 
   365 }
   367 NS_IMETHODIMP
   368 nsWindowMediator::UpdateWindowTitle(nsIXULWindow* inWindow,
   369                                     const char16_t* inTitle)
   370 {
   371   NS_ENSURE_STATE(mReady);
   372   MutexAutoLock lock(mListLock);
   373   if (GetInfoFor(inWindow)) {
   374     WindowTitleData winData = { inWindow, inTitle };
   375     mListeners.EnumerateForwards(notifyWindowTitleChange, &winData);
   376   }
   378   return NS_OK;
   379 }
   381 /* This method's plan is to intervene only when absolutely necessary.
   382    We will get requests to place our windows behind unknown windows.
   383    For the most part, we need to leave those alone (turning them into
   384    explicit requests to be on top breaks Windows.) So generally we
   385    calculate a change as seldom as possible.
   386 */
   387 NS_IMETHODIMP
   388 nsWindowMediator::CalculateZPosition(
   389                 nsIXULWindow   *inWindow,
   390                 uint32_t        inPosition,
   391                 nsIWidget      *inBelow,
   392                 uint32_t       *outPosition,
   393                 nsIWidget     **outBelow,
   394                 bool           *outAltered)
   395 {
   396   NS_ENSURE_ARG_POINTER(outBelow);
   397   NS_ENSURE_STATE(mReady);
   399   *outBelow = nullptr;
   401   if (!inWindow || !outPosition || !outAltered)
   402     return NS_ERROR_NULL_POINTER;
   404   if (inPosition != nsIWindowMediator::zLevelTop &&
   405       inPosition != nsIWindowMediator::zLevelBottom &&
   406       inPosition != nsIWindowMediator::zLevelBelow)
   407     return NS_ERROR_INVALID_ARG;
   409   nsWindowInfo *info = mTopmostWindow;
   410   nsIXULWindow *belowWindow = nullptr;
   411   bool          found = false;
   412   nsresult      result = NS_OK;
   414   *outPosition = inPosition;
   415   *outAltered = false;
   417   if (mSortingZOrder) { // don't fight SortZOrder()
   418     *outBelow = inBelow;
   419     NS_IF_ADDREF(*outBelow);
   420     return NS_OK;
   421   }
   423   uint32_t inZ;
   424   GetZLevel(inWindow, &inZ);
   426   MutexAutoLock lock(mListLock);
   428   if (inPosition == nsIWindowMediator::zLevelBelow) {
   429     // locate inBelow. use topmost if it can't be found or isn't in the
   430     // z-order list
   431     info = GetInfoFor(inBelow);
   432     if (!info || (info->mYounger != info && info->mLower == info))
   433       info = mTopmostWindow;
   434     else
   435       found = true;
   437     if (!found) {
   438       /* Treat unknown windows as a request to be on top.
   439          Not as it should be, but that's what Windows gives us.
   440          Note we change inPosition, but not *outPosition. This forces
   441          us to go through the "on top" calculation just below, without
   442          necessarily changing the output parameters. */
   443       inPosition = nsIWindowMediator::zLevelTop;
   444     }
   445   }
   447   if (inPosition == nsIWindowMediator::zLevelTop) {
   448     if (mTopmostWindow && mTopmostWindow->mZLevel > inZ) {
   449       // asked for topmost, can't have it. locate highest allowed position.
   450       do {
   451         if (info->mZLevel <= inZ)
   452           break;
   453         info = info->mLower;
   454       } while (info != mTopmostWindow);
   456       *outPosition = nsIWindowMediator::zLevelBelow;
   457       belowWindow = info->mHigher->mWindow;
   458       *outAltered = true;
   459     }
   460   } else if (inPosition == nsIWindowMediator::zLevelBottom) {
   461     if (mTopmostWindow && mTopmostWindow->mHigher->mZLevel < inZ) {
   462       // asked for bottommost, can't have it. locate lowest allowed position.
   463       do {
   464         info = info->mHigher;
   465         if (info->mZLevel >= inZ)
   466           break;
   467       } while (info != mTopmostWindow);
   469       *outPosition = nsIWindowMediator::zLevelBelow;
   470       belowWindow = info->mWindow;
   471       *outAltered = true;
   472     }
   473   } else {
   474     unsigned long relativeZ;
   476     // check that we're in the right z-plane
   477     if (found) {
   478       belowWindow = info->mWindow;
   479       relativeZ = info->mZLevel;
   480       if (relativeZ > inZ) {
   481         // might be OK. is lower window, if any, lower?
   482         if (info->mLower != info && info->mLower->mZLevel > inZ) {
   483           do {
   484             if (info->mZLevel <= inZ)
   485               break;
   486             info = info->mLower;
   487           } while (info != mTopmostWindow);
   489           belowWindow = info->mHigher->mWindow;
   490           *outAltered = true;
   491         }
   492       } else if (relativeZ < inZ) {
   493         // nope. look for a higher window to be behind.
   494         do {
   495           info = info->mHigher;
   496           if (info->mZLevel >= inZ)
   497             break;
   498         } while (info != mTopmostWindow);
   500         if (info->mZLevel >= inZ)
   501           belowWindow = info->mWindow;
   502         else
   503           *outPosition = nsIWindowMediator::zLevelTop;
   504         *outAltered = true;
   505       } // else they're equal, so it's OK
   506     }
   507   }
   509   if (NS_SUCCEEDED(result) && belowWindow) {
   510     nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(belowWindow));
   511     if (base)
   512       base->GetMainWidget(outBelow);
   513     else
   514       result = NS_ERROR_NO_INTERFACE;
   515   }
   517   return result;
   518 }
   520 NS_IMETHODIMP
   521 nsWindowMediator::SetZPosition(
   522                 nsIXULWindow *inWindow,
   523                 uint32_t      inPosition,
   524                 nsIXULWindow *inBelow)
   525 {
   526   nsWindowInfo *inInfo,
   527                *belowInfo;
   529   if ((inPosition != nsIWindowMediator::zLevelTop &&
   530        inPosition != nsIWindowMediator::zLevelBottom &&
   531        inPosition != nsIWindowMediator::zLevelBelow) ||
   532       !inWindow) {
   533     return NS_ERROR_INVALID_ARG;
   534   }
   536   if (mSortingZOrder) // don't fight SortZOrder()
   537     return NS_OK;
   539   NS_ENSURE_STATE(mReady);
   540   MutexAutoLock lock(mListLock);
   542   /* Locate inWindow and unlink it from the z-order list.
   543      It's important we look for it in the age list, not the z-order list.
   544      This is because the former is guaranteed complete, while
   545      now may be this window's first exposure to the latter. */
   546   inInfo = GetInfoFor(inWindow);
   547   if (!inInfo)
   548     return NS_ERROR_INVALID_ARG;
   550   // locate inBelow, place inWindow behind it
   551   if (inPosition == nsIWindowMediator::zLevelBelow) {
   552     belowInfo = GetInfoFor(inBelow);
   553     // it had better also be in the z-order list
   554     if (belowInfo &&
   555         belowInfo->mYounger != belowInfo && belowInfo->mLower == belowInfo) {
   556       belowInfo = nullptr;
   557     }
   558     if (!belowInfo) {
   559       if (inBelow)
   560         return NS_ERROR_INVALID_ARG;
   561       else
   562         inPosition = nsIWindowMediator::zLevelTop;
   563     }
   564   }
   565   if (inPosition == nsIWindowMediator::zLevelTop ||
   566       inPosition == nsIWindowMediator::zLevelBottom)
   567     belowInfo = mTopmostWindow ? mTopmostWindow->mHigher : nullptr;
   569   if (inInfo != belowInfo) {
   570     inInfo->Unlink(false, true);
   571     inInfo->InsertAfter(nullptr, belowInfo);
   572   }
   573   if (inPosition == nsIWindowMediator::zLevelTop)
   574     mTopmostWindow = inInfo;
   576   return NS_OK;
   577 }
   579 NS_IMETHODIMP
   580 nsWindowMediator::GetZLevel(nsIXULWindow *aWindow, uint32_t *_retval)
   581 {
   582   NS_ENSURE_ARG_POINTER(_retval);
   583   *_retval = nsIXULWindow::normalZ;
   584   nsWindowInfo *info = GetInfoFor(aWindow);
   585   if (info) {
   586     *_retval = info->mZLevel;
   587   } else {
   588     NS_WARNING("getting z level of unregistered window");
   589     // this goes off during window destruction
   590   }
   591   return NS_OK;
   592 }
   594 NS_IMETHODIMP
   595 nsWindowMediator::SetZLevel(nsIXULWindow *aWindow, uint32_t aZLevel)
   596 {
   597   NS_ENSURE_STATE(mReady);
   598   MutexAutoLock lock(mListLock);
   600   nsWindowInfo *info = GetInfoFor(aWindow);
   601   NS_ASSERTION(info, "setting z level of unregistered window");
   602   if (!info)
   603     return NS_ERROR_FAILURE;
   605   if (info->mZLevel != aZLevel) {
   606     bool lowered = info->mZLevel > aZLevel;
   607     info->mZLevel = aZLevel;
   608     if (lowered)
   609       SortZOrderFrontToBack();
   610     else
   611       SortZOrderBackToFront();
   612   }
   613   return NS_OK;
   614 }
   616 /*   Fix potentially out-of-order windows by performing an insertion sort
   617    on the z-order list. The method will work no matter how broken the
   618    list, but its assumed usage is immediately after one window's z level
   619    has been changed, so one window is potentially out of place. Such a sort
   620    is most efficiently done in a particular direction. Use this one
   621    if a window's z level has just been reduced, so the sort is most efficiently
   622    done front to back. Assumes caller has locked mListLock.
   623      Note it's hardly worth going to all the trouble to write two versions
   624    of this method except that if we choose the inefficient sorting direction,
   625    on slow systems windows could visibly bubble around the window that
   626    was moved.
   627 */
   628 void
   629 nsWindowMediator::SortZOrderFrontToBack()
   630 {
   631   nsWindowInfo *scan,   // scans list looking for problems
   632                *search, // searches for correct placement for scan window
   633                *prev,   // previous search element
   634                *lowest; // bottom-most window in list
   635   bool         finished;
   637   if (!mTopmostWindow) // early during program execution there's no z list yet
   638     return;            // there's also only one window, so this is not dangerous
   640   mSortingZOrder = true;
   642   /* Step through the list from top to bottom. If we find a window which
   643      should be moved down in the list, move it to its highest legal position. */
   644   do {
   645     finished = true;
   646     lowest = mTopmostWindow->mHigher;
   647     scan = mTopmostWindow;
   648     while (scan != lowest) {
   649       uint32_t scanZ = scan->mZLevel;
   650       if (scanZ < scan->mLower->mZLevel) { // out of order
   651         search = scan->mLower;
   652         do {
   653           prev = search;
   654           search = search->mLower;
   655         } while (prev != lowest && scanZ < search->mZLevel);
   657         // reposition |scan| within the list
   658         if (scan == mTopmostWindow)
   659           mTopmostWindow = scan->mLower;
   660         scan->Unlink(false, true);
   661         scan->InsertAfter(nullptr, prev);
   663         // fix actual window order
   664         nsCOMPtr<nsIBaseWindow> base;
   665         nsCOMPtr<nsIWidget> scanWidget;
   666         nsCOMPtr<nsIWidget> prevWidget;
   667         base = do_QueryInterface(scan->mWindow);
   668         if (base)
   669           base->GetMainWidget(getter_AddRefs(scanWidget));
   670         base = do_QueryInterface(prev->mWindow);
   671         if (base)
   672           base->GetMainWidget(getter_AddRefs(prevWidget));
   673         if (scanWidget)
   674           scanWidget->PlaceBehind(eZPlacementBelow, prevWidget, false);
   676         finished = false;
   677         break;
   678       }
   679       scan = scan->mLower;
   680     }
   681   } while (!finished);
   683   mSortingZOrder = false;
   684 }
   686 // see comment for SortZOrderFrontToBack
   687 void
   688 nsWindowMediator::SortZOrderBackToFront()
   689 {
   690   nsWindowInfo *scan,   // scans list looking for problems
   691                *search, // searches for correct placement for scan window
   692                *lowest; // bottom-most window in list
   693   bool         finished;
   695   if (!mTopmostWindow) // early during program execution there's no z list yet
   696     return;            // there's also only one window, so this is not dangerous
   698   mSortingZOrder = true;
   700   /* Step through the list from bottom to top. If we find a window which
   701      should be moved up in the list, move it to its lowest legal position. */
   702   do {
   703     finished = true;
   704     lowest = mTopmostWindow->mHigher;
   705     scan = lowest;
   706     while (scan != mTopmostWindow) {
   707       uint32_t scanZ = scan->mZLevel;
   708       if (scanZ > scan->mHigher->mZLevel) { // out of order
   709         search = scan;
   710         do {
   711           search = search->mHigher;
   712         } while (search != lowest && scanZ > search->mZLevel);
   714         // reposition |scan| within the list
   715         if (scan != search && scan != search->mLower) {
   716           scan->Unlink(false, true);
   717           scan->InsertAfter(nullptr, search);
   718         }
   719         if (search == lowest)
   720           mTopmostWindow = scan;
   722         // fix actual window order
   723         nsCOMPtr<nsIBaseWindow> base;
   724         nsCOMPtr<nsIWidget> scanWidget;
   725         nsCOMPtr<nsIWidget> searchWidget;
   726         base = do_QueryInterface(scan->mWindow);
   727         if (base)
   728           base->GetMainWidget(getter_AddRefs(scanWidget));
   729         if (mTopmostWindow != scan) {
   730           base = do_QueryInterface(search->mWindow);
   731           if (base)
   732             base->GetMainWidget(getter_AddRefs(searchWidget));
   733         }
   734         if (scanWidget)
   735           scanWidget->PlaceBehind(eZPlacementBelow, searchWidget, false);
   736         finished = false;
   737         break;
   738       }
   739       scan = scan->mHigher;
   740     }
   741   } while (!finished);
   743   mSortingZOrder = false;
   744 }
   746 NS_IMPL_ISUPPORTS(nsWindowMediator,
   747   nsIWindowMediator,
   748   nsIObserver,
   749   nsISupportsWeakReference)
   751 NS_IMETHODIMP
   752 nsWindowMediator::AddListener(nsIWindowMediatorListener* aListener)
   753 {
   754   NS_ENSURE_ARG_POINTER(aListener);
   756   mListeners.AppendObject(aListener);
   758   return NS_OK;
   759 }
   761 NS_IMETHODIMP
   762 nsWindowMediator::RemoveListener(nsIWindowMediatorListener* aListener)
   763 {
   764   NS_ENSURE_ARG_POINTER(aListener);
   766   mListeners.RemoveObject(aListener);
   768   return NS_OK;
   769 }
   771 NS_IMETHODIMP
   772 nsWindowMediator::Observe(nsISupports* aSubject,
   773                           const char* aTopic,
   774                           const char16_t* aData)
   775 {
   776   if (!strcmp(aTopic, "xpcom-shutdown") && mReady) {
   777     // Unregistering a window may cause its destructor to run, causing it to
   778     // call into the window mediator, try to acquire mListLock, and deadlock.
   779     // Our solution is to hold strong refs to all windows until we release
   780     // mListLock.
   781     nsTArray<nsCOMPtr<nsIXULWindow> > windows;
   783     {
   784       MutexAutoLock lock(mListLock);
   785       while (mOldestWindow) {
   786         windows.AppendElement(mOldestWindow->mWindow);
   787         UnregisterWindow(mOldestWindow);
   788       }
   789     }
   790     mReady = false;
   791   }
   792   return NS_OK;
   793 }
   795 bool
   796 notifyOpenWindow(nsIWindowMediatorListener *aListener, void* aData)
   797 {
   798   WindowTitleData* winData = static_cast<WindowTitleData*>(aData);
   799   aListener->OnOpenWindow(winData->mWindow);
   801   return true;
   802 }
   804 bool
   805 notifyCloseWindow(nsIWindowMediatorListener *aListener, void* aData)
   806 {
   807   WindowTitleData* winData = static_cast<WindowTitleData*>(aData);
   808   aListener->OnCloseWindow(winData->mWindow);
   810   return true;
   811 }
   813 bool 
   814 notifyWindowTitleChange(nsIWindowMediatorListener *aListener, void* aData)
   815 {
   816   WindowTitleData* titleData = reinterpret_cast<WindowTitleData*>(aData);
   817   aListener->OnWindowTitleChange(titleData->mWindow, titleData->mTitle);
   819   return true;
   820 }

mercurial