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/. */
8 #include "nsReadableUtils.h"
9 #include "nsUnicharUtils.h"
11 #include "nsIBaseWindow.h"
12 #include "nsIWidget.h"
13 #include "nsIObserverService.h"
14 #include "nsISimpleEnumerator.h"
15 #include "nsAppShellWindowEnumerator.h"
16 #include "nsWindowMediator.h"
17 #include "nsIWindowMediatorListener.h"
18 #include "nsGlobalWindow.h"
20 #include "nsIDocShell.h"
21 #include "nsIInterfaceRequestor.h"
22 #include "nsIInterfaceRequestorUtils.h"
23 #include "nsIAppWindow.h"
25 using namespace mozilla
;
27 nsresult
nsWindowMediator::GetDOMWindow(
28 nsIAppWindow
* inWindow
, nsCOMPtr
<nsPIDOMWindowOuter
>& outDOMWindow
) {
29 nsCOMPtr
<nsIDocShell
> docShell
;
31 outDOMWindow
= nullptr;
32 inWindow
->GetDocShell(getter_AddRefs(docShell
));
33 NS_ENSURE_TRUE(docShell
, NS_ERROR_FAILURE
);
35 outDOMWindow
= docShell
->GetWindow();
36 return outDOMWindow
? NS_OK
: NS_ERROR_FAILURE
;
39 nsWindowMediator::nsWindowMediator()
41 mOldestWindow(nullptr),
42 mTopmostWindow(nullptr),
44 mSortingZOrder(false),
47 nsWindowMediator::~nsWindowMediator() {
48 while (mOldestWindow
) UnregisterWindow(mOldestWindow
);
51 nsresult
nsWindowMediator::Init() {
53 nsCOMPtr
<nsIObserverService
> obsSvc
=
54 do_GetService("@mozilla.org/observer-service;1", &rv
);
55 NS_ENSURE_SUCCESS(rv
, rv
);
56 rv
= obsSvc
->AddObserver(this, "xpcom-shutdown", true);
57 NS_ENSURE_SUCCESS(rv
, rv
);
63 NS_IMETHODIMP
nsWindowMediator::RegisterWindow(nsIAppWindow
* inWindow
) {
64 MOZ_RELEASE_ASSERT(NS_IsMainThread());
65 NS_ENSURE_STATE(mReady
);
67 if (GetInfoFor(inWindow
)) {
68 NS_ERROR("multiple window registration");
69 return NS_ERROR_FAILURE
;
74 // Create window info struct and add to list of windows
75 nsWindowInfo
* windowInfo
= new nsWindowInfo(inWindow
, mTimeStamp
);
77 for (const auto& listener
: mListeners
.ForwardRange()) {
78 listener
->OnOpenWindow(inWindow
);
82 windowInfo
->InsertAfter(mOldestWindow
->mOlder
, nullptr);
84 mOldestWindow
= windowInfo
;
90 nsWindowMediator::UnregisterWindow(nsIAppWindow
* inWindow
) {
91 MOZ_RELEASE_ASSERT(NS_IsMainThread());
92 NS_ENSURE_STATE(mReady
);
93 nsWindowInfo
* info
= GetInfoFor(inWindow
);
94 if (info
) return UnregisterWindow(info
);
95 return NS_ERROR_INVALID_ARG
;
98 nsresult
nsWindowMediator::UnregisterWindow(nsWindowInfo
* inInfo
) {
99 // Inform the iterators
101 while (index
< mEnumeratorList
.Length()) {
102 mEnumeratorList
[index
]->WindowRemoved(inInfo
);
106 nsIAppWindow
* window
= inInfo
->mWindow
.get();
107 for (const auto& listener
: mListeners
.ForwardRange()) {
108 listener
->OnCloseWindow(window
);
111 // Remove from the lists and free up
112 if (inInfo
== mOldestWindow
) mOldestWindow
= inInfo
->mYounger
;
113 if (inInfo
== mTopmostWindow
) mTopmostWindow
= inInfo
->mLower
;
114 inInfo
->Unlink(true, true);
115 if (inInfo
== mOldestWindow
) mOldestWindow
= nullptr;
116 if (inInfo
== mTopmostWindow
) mTopmostWindow
= nullptr;
122 nsWindowInfo
* nsWindowMediator::GetInfoFor(nsIAppWindow
* aWindow
) {
123 nsWindowInfo
*info
, *listEnd
;
125 if (!aWindow
) return nullptr;
127 info
= mOldestWindow
;
129 while (info
!= listEnd
) {
130 if (info
->mWindow
.get() == aWindow
) return info
;
131 info
= info
->mYounger
;
132 listEnd
= mOldestWindow
;
137 nsWindowInfo
* nsWindowMediator::GetInfoFor(nsIWidget
* aWindow
) {
138 nsWindowInfo
*info
, *listEnd
;
140 if (!aWindow
) return nullptr;
142 info
= mOldestWindow
;
145 nsCOMPtr
<nsIWidget
> scanWidget
;
146 while (info
!= listEnd
) {
147 nsCOMPtr
<nsIBaseWindow
> base(do_QueryInterface(info
->mWindow
));
148 if (base
) base
->GetMainWidget(getter_AddRefs(scanWidget
));
149 if (aWindow
== scanWidget
.get()) return info
;
150 info
= info
->mYounger
;
151 listEnd
= mOldestWindow
;
157 nsWindowMediator::GetEnumerator(const char16_t
* inType
,
158 nsISimpleEnumerator
** outEnumerator
) {
159 MOZ_RELEASE_ASSERT(NS_IsMainThread());
160 NS_ENSURE_ARG_POINTER(outEnumerator
);
161 NS_ENSURE_STATE(mReady
);
163 RefPtr
<nsAppShellWindowEnumerator
> enumerator
=
164 new nsASDOMWindowEarlyToLateEnumerator(inType
, *this);
165 enumerator
.forget(outEnumerator
);
170 nsWindowMediator::GetAppWindowEnumerator(const char16_t
* inType
,
171 nsISimpleEnumerator
** outEnumerator
) {
172 MOZ_RELEASE_ASSERT(NS_IsMainThread());
173 NS_ENSURE_ARG_POINTER(outEnumerator
);
174 NS_ENSURE_STATE(mReady
);
176 RefPtr
<nsAppShellWindowEnumerator
> enumerator
=
177 new nsASAppWindowEarlyToLateEnumerator(inType
, *this);
178 enumerator
.forget(outEnumerator
);
183 nsWindowMediator::GetZOrderAppWindowEnumerator(const char16_t
* aWindowType
,
185 nsISimpleEnumerator
** _retval
) {
186 MOZ_RELEASE_ASSERT(NS_IsMainThread());
187 NS_ENSURE_ARG_POINTER(_retval
);
188 NS_ENSURE_STATE(mReady
);
190 RefPtr
<nsAppShellWindowEnumerator
> enumerator
;
192 enumerator
= new nsASAppWindowFrontToBackEnumerator(aWindowType
, *this);
194 enumerator
= new nsASAppWindowBackToFrontEnumerator(aWindowType
, *this);
196 enumerator
.forget(_retval
);
200 void nsWindowMediator::AddEnumerator(nsAppShellWindowEnumerator
* inEnumerator
) {
201 mEnumeratorList
.AppendElement(inEnumerator
);
204 int32_t nsWindowMediator::RemoveEnumerator(
205 nsAppShellWindowEnumerator
* inEnumerator
) {
206 return mEnumeratorList
.RemoveElement(inEnumerator
);
209 // Returns the window of type inType ( if null return any window type ) which
210 // has the most recent time stamp
212 nsWindowMediator::GetMostRecentWindow(const char16_t
* inType
,
213 mozIDOMWindowProxy
** outWindow
) {
214 MOZ_RELEASE_ASSERT(NS_IsMainThread());
215 NS_ENSURE_ARG_POINTER(outWindow
);
216 *outWindow
= nullptr;
217 if (!mReady
) return NS_OK
;
219 // Find the most window with the highest time stamp that matches
220 // the requested type
221 nsWindowInfo
* info
= MostRecentWindowInfo(inType
, false);
222 if (info
&& info
->mWindow
) {
223 nsCOMPtr
<nsPIDOMWindowOuter
> DOMWindow
;
224 if (NS_SUCCEEDED(GetDOMWindow(info
->mWindow
, DOMWindow
))) {
225 DOMWindow
.forget(outWindow
);
228 return NS_ERROR_FAILURE
;
235 nsWindowMediator::GetMostRecentBrowserWindow(mozIDOMWindowProxy
** outWindow
) {
236 nsresult rv
= GetMostRecentWindow(u
"navigator:browser", outWindow
);
237 NS_ENSURE_SUCCESS(rv
, rv
);
239 #ifdef MOZ_WIDGET_ANDROID
241 rv
= GetMostRecentWindow(u
"navigator:geckoview", outWindow
);
242 NS_ENSURE_SUCCESS(rv
, rv
);
246 #ifdef MOZ_THUNDERBIRD
248 rv
= GetMostRecentWindow(u
"mail:3pane", outWindow
);
249 NS_ENSURE_SUCCESS(rv
, rv
);
257 nsWindowMediator::GetMostRecentNonPBWindow(const char16_t
* aType
,
258 mozIDOMWindowProxy
** aWindow
) {
259 MOZ_RELEASE_ASSERT(NS_IsMainThread());
260 NS_ENSURE_ARG_POINTER(aWindow
);
263 nsWindowInfo
* info
= MostRecentWindowInfo(aType
, true);
264 nsCOMPtr
<nsPIDOMWindowOuter
> domWindow
;
265 if (info
&& info
->mWindow
) {
266 GetDOMWindow(info
->mWindow
, domWindow
);
270 return NS_ERROR_FAILURE
;
273 domWindow
.forget(aWindow
);
277 nsWindowInfo
* nsWindowMediator::MostRecentWindowInfo(
278 const char16_t
* inType
, bool aSkipPrivateBrowsingOrClosed
) {
279 int32_t lastTimeStamp
= -1;
280 nsAutoString
typeString(inType
);
281 bool allWindows
= !inType
|| typeString
.IsEmpty();
283 // Find the most recent window with the highest time stamp that matches
284 // the requested type and has the correct browsing mode.
285 nsWindowInfo
* searchInfo
= mOldestWindow
;
286 nsWindowInfo
* listEnd
= nullptr;
287 nsWindowInfo
* foundInfo
= nullptr;
288 for (; searchInfo
!= listEnd
; searchInfo
= searchInfo
->mYounger
) {
289 listEnd
= mOldestWindow
;
291 if (!allWindows
&& !searchInfo
->TypeEquals(typeString
)) {
294 if (searchInfo
->mTimeStamp
< lastTimeStamp
) {
297 if (!searchInfo
->mWindow
) {
300 if (aSkipPrivateBrowsingOrClosed
) {
301 nsCOMPtr
<nsIDocShell
> docShell
;
302 searchInfo
->mWindow
->GetDocShell(getter_AddRefs(docShell
));
303 nsCOMPtr
<nsILoadContext
> loadContext
= do_QueryInterface(docShell
);
304 if (!loadContext
|| loadContext
->UsePrivateBrowsing()) {
308 nsCOMPtr
<nsPIDOMWindowOuter
> piwindow
= docShell
->GetWindow();
309 if (!piwindow
|| piwindow
->Closed()) {
314 foundInfo
= searchInfo
;
315 lastTimeStamp
= searchInfo
->mTimeStamp
;
322 nsWindowMediator::GetOuterWindowWithId(uint64_t aWindowID
,
323 mozIDOMWindowProxy
** aWindow
) {
324 RefPtr
<nsGlobalWindowOuter
> window
=
325 nsGlobalWindowOuter::GetOuterWindowWithId(aWindowID
);
326 window
.forget(aWindow
);
331 nsWindowMediator::GetCurrentInnerWindowWithId(uint64_t aWindowID
,
332 mozIDOMWindow
** aWindow
) {
333 RefPtr
<nsGlobalWindowInner
> window
=
334 nsGlobalWindowInner::GetInnerWindowWithId(aWindowID
);
337 if (!window
) return NS_OK
;
339 nsCOMPtr
<nsPIDOMWindowOuter
> outer
= window
->GetOuterWindow();
340 NS_ENSURE_TRUE(outer
, NS_ERROR_UNEXPECTED
);
342 // outer is already using another inner, so it's same as not found
343 if (outer
->GetCurrentInnerWindow() != window
) return NS_OK
;
345 window
.forget(aWindow
);
350 nsWindowMediator::UpdateWindowTimeStamp(nsIAppWindow
* inWindow
) {
351 MOZ_RELEASE_ASSERT(NS_IsMainThread());
352 NS_ENSURE_STATE(mReady
);
353 nsWindowInfo
* info
= GetInfoFor(inWindow
);
355 // increment the window's time stamp
356 info
->mTimeStamp
= ++mTimeStamp
;
359 return NS_ERROR_FAILURE
;
362 /* This method's plan is to intervene only when absolutely necessary.
363 We will get requests to place our windows behind unknown windows.
364 For the most part, we need to leave those alone (turning them into
365 explicit requests to be on top breaks Windows.) So generally we
366 calculate a change as seldom as possible.
369 nsWindowMediator::CalculateZPosition(nsIAppWindow
* inWindow
,
370 uint32_t inPosition
, nsIWidget
* inBelow
,
371 uint32_t* outPosition
,
372 nsIWidget
** outBelow
, bool* outAltered
) {
373 MOZ_RELEASE_ASSERT(NS_IsMainThread());
374 NS_ENSURE_ARG_POINTER(outBelow
);
375 NS_ENSURE_STATE(mReady
);
379 if (!inWindow
|| !outPosition
|| !outAltered
) return NS_ERROR_NULL_POINTER
;
381 if (inPosition
!= nsIWindowMediator::zLevelTop
&&
382 inPosition
!= nsIWindowMediator::zLevelBottom
&&
383 inPosition
!= nsIWindowMediator::zLevelBelow
)
384 return NS_ERROR_INVALID_ARG
;
386 nsWindowInfo
* info
= mTopmostWindow
;
387 nsIAppWindow
* belowWindow
= nullptr;
389 nsresult result
= NS_OK
;
391 *outPosition
= inPosition
;
394 if (mSortingZOrder
) { // don't fight SortZOrder()
396 NS_IF_ADDREF(*outBelow
);
401 GetZLevel(inWindow
, &inZ
);
403 if (inPosition
== nsIWindowMediator::zLevelBelow
) {
404 // locate inBelow. use topmost if it can't be found or isn't in the
406 info
= GetInfoFor(inBelow
);
407 if (!info
|| (info
->mYounger
!= info
&& info
->mLower
== info
))
408 info
= mTopmostWindow
;
413 /* Treat unknown windows as a request to be on top.
414 Not as it should be, but that's what Windows gives us.
415 Note we change inPosition, but not *outPosition. This forces
416 us to go through the "on top" calculation just below, without
417 necessarily changing the output parameters. */
418 inPosition
= nsIWindowMediator::zLevelTop
;
422 if (inPosition
== nsIWindowMediator::zLevelTop
) {
423 if (mTopmostWindow
&& mTopmostWindow
->mZLevel
> inZ
) {
424 // asked for topmost, can't have it. locate highest allowed position.
426 if (info
->mZLevel
<= inZ
) break;
428 } while (info
!= mTopmostWindow
);
430 *outPosition
= nsIWindowMediator::zLevelBelow
;
431 belowWindow
= info
->mHigher
->mWindow
;
434 } else if (inPosition
== nsIWindowMediator::zLevelBottom
) {
435 if (mTopmostWindow
&& mTopmostWindow
->mHigher
->mZLevel
< inZ
) {
436 // asked for bottommost, can't have it. locate lowest allowed position.
438 info
= info
->mHigher
;
439 if (info
->mZLevel
>= inZ
) break;
440 } while (info
!= mTopmostWindow
);
442 *outPosition
= nsIWindowMediator::zLevelBelow
;
443 belowWindow
= info
->mWindow
;
447 unsigned long relativeZ
;
449 // check that we're in the right z-plane
451 belowWindow
= info
->mWindow
;
452 relativeZ
= info
->mZLevel
;
453 if (relativeZ
> inZ
) {
454 // might be OK. is lower window, if any, lower?
455 if (info
->mLower
!= info
&& info
->mLower
->mZLevel
> inZ
) {
457 if (info
->mZLevel
<= inZ
) break;
459 } while (info
!= mTopmostWindow
);
461 belowWindow
= info
->mHigher
->mWindow
;
464 } else if (relativeZ
< inZ
) {
465 // nope. look for a higher window to be behind.
467 info
= info
->mHigher
;
468 if (info
->mZLevel
>= inZ
) break;
469 } while (info
!= mTopmostWindow
);
471 if (info
->mZLevel
>= inZ
)
472 belowWindow
= info
->mWindow
;
474 *outPosition
= nsIWindowMediator::zLevelTop
;
476 } // else they're equal, so it's OK
480 if (NS_SUCCEEDED(result
) && belowWindow
) {
481 nsCOMPtr
<nsIBaseWindow
> base(do_QueryInterface(belowWindow
));
483 base
->GetMainWidget(outBelow
);
485 result
= NS_ERROR_NO_INTERFACE
;
492 nsWindowMediator::SetZPosition(nsIAppWindow
* inWindow
, uint32_t inPosition
,
493 nsIAppWindow
* inBelow
) {
494 MOZ_RELEASE_ASSERT(NS_IsMainThread());
495 nsWindowInfo
*inInfo
, *belowInfo
;
497 if ((inPosition
!= nsIWindowMediator::zLevelTop
&&
498 inPosition
!= nsIWindowMediator::zLevelBottom
&&
499 inPosition
!= nsIWindowMediator::zLevelBelow
) ||
501 return NS_ERROR_INVALID_ARG
;
504 if (mSortingZOrder
) // don't fight SortZOrder()
507 NS_ENSURE_STATE(mReady
);
509 /* Locate inWindow and unlink it from the z-order list.
510 It's important we look for it in the age list, not the z-order list.
511 This is because the former is guaranteed complete, while
512 now may be this window's first exposure to the latter. */
513 inInfo
= GetInfoFor(inWindow
);
514 if (!inInfo
) return NS_ERROR_INVALID_ARG
;
516 // locate inBelow, place inWindow behind it
517 if (inPosition
== nsIWindowMediator::zLevelBelow
) {
518 belowInfo
= GetInfoFor(inBelow
);
519 // it had better also be in the z-order list
520 if (belowInfo
&& belowInfo
->mYounger
!= belowInfo
&&
521 belowInfo
->mLower
== belowInfo
) {
526 return NS_ERROR_INVALID_ARG
;
528 inPosition
= nsIWindowMediator::zLevelTop
;
531 if (inPosition
== nsIWindowMediator::zLevelTop
||
532 inPosition
== nsIWindowMediator::zLevelBottom
)
533 belowInfo
= mTopmostWindow
? mTopmostWindow
->mHigher
: nullptr;
535 if (inInfo
!= belowInfo
) {
536 inInfo
->Unlink(false, true);
537 inInfo
->InsertAfter(nullptr, belowInfo
);
539 if (inPosition
== nsIWindowMediator::zLevelTop
) mTopmostWindow
= inInfo
;
545 nsWindowMediator::GetZLevel(nsIAppWindow
* aWindow
, uint32_t* _retval
) {
546 NS_ENSURE_ARG_POINTER(_retval
);
547 *_retval
= nsIAppWindow::normalZ
;
548 // This can fail during window destruction.
549 nsWindowInfo
* info
= GetInfoFor(aWindow
);
551 *_retval
= info
->mZLevel
;
557 nsWindowMediator::SetZLevel(nsIAppWindow
* aWindow
, uint32_t aZLevel
) {
558 MOZ_RELEASE_ASSERT(NS_IsMainThread());
559 NS_ENSURE_STATE(mReady
);
561 nsWindowInfo
* info
= GetInfoFor(aWindow
);
562 NS_ASSERTION(info
, "setting z level of unregistered window");
563 if (!info
) return NS_ERROR_FAILURE
;
565 if (info
->mZLevel
!= aZLevel
) {
566 bool lowered
= info
->mZLevel
> aZLevel
;
567 info
->mZLevel
= aZLevel
;
569 SortZOrderFrontToBack();
571 SortZOrderBackToFront();
576 /* Fix potentially out-of-order windows by performing an insertion sort
577 on the z-order list. The method will work no matter how broken the
578 list, but its assumed usage is immediately after one window's z level
579 has been changed, so one window is potentially out of place. Such a sort
580 is most efficiently done in a particular direction. Use this one
581 if a window's z level has just been reduced, so the sort is most efficiently
583 Note it's hardly worth going to all the trouble to write two versions
584 of this method except that if we choose the inefficient sorting direction,
585 on slow systems windows could visibly bubble around the window that
588 void nsWindowMediator::SortZOrderFrontToBack() {
589 nsWindowInfo
*scan
, // scans list looking for problems
590 *search
, // searches for correct placement for scan window
591 *prev
, // previous search element
592 *lowest
; // bottom-most window in list
595 if (!mTopmostWindow
) // early during program execution there's no z list yet
596 return; // there's also only one window, so this is not dangerous
598 mSortingZOrder
= true;
600 /* Step through the list from top to bottom. If we find a window which
601 should be moved down in the list, move it to its highest legal position. */
604 lowest
= mTopmostWindow
->mHigher
;
605 scan
= mTopmostWindow
;
606 while (scan
!= lowest
) {
607 uint32_t scanZ
= scan
->mZLevel
;
608 if (scanZ
< scan
->mLower
->mZLevel
) { // out of order
609 search
= scan
->mLower
;
612 search
= search
->mLower
;
613 } while (prev
!= lowest
&& scanZ
< search
->mZLevel
);
615 // reposition |scan| within the list
616 if (scan
== mTopmostWindow
) mTopmostWindow
= scan
->mLower
;
617 scan
->Unlink(false, true);
618 scan
->InsertAfter(nullptr, prev
);
620 // fix actual window order
621 nsCOMPtr
<nsIBaseWindow
> base
;
622 nsCOMPtr
<nsIWidget
> scanWidget
;
623 nsCOMPtr
<nsIWidget
> prevWidget
;
624 base
= do_QueryInterface(scan
->mWindow
);
625 if (base
) base
->GetMainWidget(getter_AddRefs(scanWidget
));
626 base
= do_QueryInterface(prev
->mWindow
);
627 if (base
) base
->GetMainWidget(getter_AddRefs(prevWidget
));
629 scanWidget
->PlaceBehind(eZPlacementBelow
, prevWidget
, false);
638 mSortingZOrder
= false;
641 // see comment for SortZOrderFrontToBack
642 void nsWindowMediator::SortZOrderBackToFront() {
643 nsWindowInfo
*scan
, // scans list looking for problems
644 *search
, // searches for correct placement for scan window
645 *lowest
; // bottom-most window in list
648 if (!mTopmostWindow
) // early during program execution there's no z list yet
649 return; // there's also only one window, so this is not dangerous
651 mSortingZOrder
= true;
653 /* Step through the list from bottom to top. If we find a window which
654 should be moved up in the list, move it to its lowest legal position. */
657 lowest
= mTopmostWindow
->mHigher
;
659 while (scan
!= mTopmostWindow
) {
660 uint32_t scanZ
= scan
->mZLevel
;
661 if (scanZ
> scan
->mHigher
->mZLevel
) { // out of order
664 search
= search
->mHigher
;
665 } while (search
!= lowest
&& scanZ
> search
->mZLevel
);
667 // reposition |scan| within the list
668 if (scan
!= search
&& scan
!= search
->mLower
) {
669 scan
->Unlink(false, true);
670 scan
->InsertAfter(nullptr, search
);
672 if (search
== lowest
) mTopmostWindow
= scan
;
674 // fix actual window order
675 nsCOMPtr
<nsIBaseWindow
> base
;
676 nsCOMPtr
<nsIWidget
> scanWidget
;
677 nsCOMPtr
<nsIWidget
> searchWidget
;
678 base
= do_QueryInterface(scan
->mWindow
);
679 if (base
) base
->GetMainWidget(getter_AddRefs(scanWidget
));
680 if (mTopmostWindow
!= scan
) {
681 base
= do_QueryInterface(search
->mWindow
);
682 if (base
) base
->GetMainWidget(getter_AddRefs(searchWidget
));
685 scanWidget
->PlaceBehind(eZPlacementBelow
, searchWidget
, false);
689 scan
= scan
->mHigher
;
693 mSortingZOrder
= false;
696 NS_IMPL_ISUPPORTS(nsWindowMediator
, nsIWindowMediator
, nsIObserver
,
697 nsISupportsWeakReference
)
700 nsWindowMediator::AddListener(nsIWindowMediatorListener
* aListener
) {
701 NS_ENSURE_ARG_POINTER(aListener
);
703 mListeners
.AppendElement(aListener
);
709 nsWindowMediator::RemoveListener(nsIWindowMediatorListener
* aListener
) {
710 NS_ENSURE_ARG_POINTER(aListener
);
712 mListeners
.RemoveElement(aListener
);
718 nsWindowMediator::Observe(nsISupports
* aSubject
, const char* aTopic
,
719 const char16_t
* aData
) {
720 if (!strcmp(aTopic
, "xpcom-shutdown") && mReady
) {
721 MOZ_RELEASE_ASSERT(NS_IsMainThread());
722 while (mOldestWindow
) UnregisterWindow(mOldestWindow
);