LCOV - code coverage report
Current view: top level - xpfe/appshell - nsWindowMediator.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 95 427 22.2 %
Date: 2017-07-14 16:53:18 Functions: 16 35 45.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13