Bug 1728955: part 8) Refactor `DisplayErrCode` in Windows' `nsClipboard`. r=masayuki
[gecko.git] / xpfe / appshell / nsWindowMediator.cpp
blob7661e0e4b4729ef8f2ee99126651a49702313a85
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 "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()
40 : mEnumeratorList(),
41 mOldestWindow(nullptr),
42 mTopmostWindow(nullptr),
43 mTimeStamp(0),
44 mSortingZOrder(false),
45 mReady(false) {}
47 nsWindowMediator::~nsWindowMediator() {
48 while (mOldestWindow) UnregisterWindow(mOldestWindow);
51 nsresult nsWindowMediator::Init() {
52 nsresult rv;
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);
59 mReady = true;
60 return NS_OK;
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;
72 mTimeStamp++;
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);
81 if (mOldestWindow)
82 windowInfo->InsertAfter(mOldestWindow->mOlder, nullptr);
83 else
84 mOldestWindow = windowInfo;
86 return NS_OK;
89 NS_IMETHODIMP
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
100 uint32_t index = 0;
101 while (index < mEnumeratorList.Length()) {
102 mEnumeratorList[index]->WindowRemoved(inInfo);
103 index++;
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;
117 delete inInfo;
119 return NS_OK;
122 nsWindowInfo* nsWindowMediator::GetInfoFor(nsIAppWindow* aWindow) {
123 nsWindowInfo *info, *listEnd;
125 if (!aWindow) return nullptr;
127 info = mOldestWindow;
128 listEnd = nullptr;
129 while (info != listEnd) {
130 if (info->mWindow.get() == aWindow) return info;
131 info = info->mYounger;
132 listEnd = mOldestWindow;
134 return nullptr;
137 nsWindowInfo* nsWindowMediator::GetInfoFor(nsIWidget* aWindow) {
138 nsWindowInfo *info, *listEnd;
140 if (!aWindow) return nullptr;
142 info = mOldestWindow;
143 listEnd = nullptr;
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;
153 return nullptr;
156 NS_IMETHODIMP
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);
166 return NS_OK;
169 NS_IMETHODIMP
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);
179 return NS_OK;
182 NS_IMETHODIMP
183 nsWindowMediator::GetZOrderAppWindowEnumerator(const char16_t* aWindowType,
184 bool aFrontToBack,
185 nsISimpleEnumerator** _retval) {
186 MOZ_RELEASE_ASSERT(NS_IsMainThread());
187 NS_ENSURE_ARG_POINTER(_retval);
188 NS_ENSURE_STATE(mReady);
190 RefPtr<nsAppShellWindowEnumerator> enumerator;
191 if (aFrontToBack)
192 enumerator = new nsASAppWindowFrontToBackEnumerator(aWindowType, *this);
193 else
194 enumerator = new nsASAppWindowBackToFrontEnumerator(aWindowType, *this);
196 enumerator.forget(_retval);
197 return NS_OK;
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
211 NS_IMETHODIMP
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);
226 return NS_OK;
228 return NS_ERROR_FAILURE;
231 return NS_OK;
234 NS_IMETHODIMP
235 nsWindowMediator::GetMostRecentBrowserWindow(mozIDOMWindowProxy** outWindow) {
236 nsresult rv = GetMostRecentWindow(u"navigator:browser", outWindow);
237 NS_ENSURE_SUCCESS(rv, rv);
239 #ifdef MOZ_WIDGET_ANDROID
240 if (!*outWindow) {
241 rv = GetMostRecentWindow(u"navigator:geckoview", outWindow);
242 NS_ENSURE_SUCCESS(rv, rv);
244 #endif
246 #ifdef MOZ_THUNDERBIRD
247 if (!*outWindow) {
248 rv = GetMostRecentWindow(u"mail:3pane", outWindow);
249 NS_ENSURE_SUCCESS(rv, rv);
251 #endif
253 return NS_OK;
256 NS_IMETHODIMP
257 nsWindowMediator::GetMostRecentNonPBWindow(const char16_t* aType,
258 mozIDOMWindowProxy** aWindow) {
259 MOZ_RELEASE_ASSERT(NS_IsMainThread());
260 NS_ENSURE_ARG_POINTER(aWindow);
261 *aWindow = nullptr;
263 nsWindowInfo* info = MostRecentWindowInfo(aType, true);
264 nsCOMPtr<nsPIDOMWindowOuter> domWindow;
265 if (info && info->mWindow) {
266 GetDOMWindow(info->mWindow, domWindow);
269 if (!domWindow) {
270 return NS_ERROR_FAILURE;
273 domWindow.forget(aWindow);
274 return NS_OK;
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)) {
292 continue;
294 if (searchInfo->mTimeStamp < lastTimeStamp) {
295 continue;
297 if (!searchInfo->mWindow) {
298 continue;
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()) {
305 continue;
308 nsCOMPtr<nsPIDOMWindowOuter> piwindow = docShell->GetWindow();
309 if (!piwindow || piwindow->Closed()) {
310 continue;
314 foundInfo = searchInfo;
315 lastTimeStamp = searchInfo->mTimeStamp;
318 return foundInfo;
321 NS_IMETHODIMP
322 nsWindowMediator::GetOuterWindowWithId(uint64_t aWindowID,
323 mozIDOMWindowProxy** aWindow) {
324 RefPtr<nsGlobalWindowOuter> window =
325 nsGlobalWindowOuter::GetOuterWindowWithId(aWindowID);
326 window.forget(aWindow);
327 return NS_OK;
330 NS_IMETHODIMP
331 nsWindowMediator::GetCurrentInnerWindowWithId(uint64_t aWindowID,
332 mozIDOMWindow** aWindow) {
333 RefPtr<nsGlobalWindowInner> window =
334 nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
336 // not found
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);
346 return NS_OK;
349 NS_IMETHODIMP
350 nsWindowMediator::UpdateWindowTimeStamp(nsIAppWindow* inWindow) {
351 MOZ_RELEASE_ASSERT(NS_IsMainThread());
352 NS_ENSURE_STATE(mReady);
353 nsWindowInfo* info = GetInfoFor(inWindow);
354 if (info) {
355 // increment the window's time stamp
356 info->mTimeStamp = ++mTimeStamp;
357 return NS_OK;
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.
368 NS_IMETHODIMP
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);
377 *outBelow = nullptr;
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;
388 bool found = false;
389 nsresult result = NS_OK;
391 *outPosition = inPosition;
392 *outAltered = false;
394 if (mSortingZOrder) { // don't fight SortZOrder()
395 *outBelow = inBelow;
396 NS_IF_ADDREF(*outBelow);
397 return NS_OK;
400 uint32_t inZ;
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
405 // z-order list
406 info = GetInfoFor(inBelow);
407 if (!info || (info->mYounger != info && info->mLower == info))
408 info = mTopmostWindow;
409 else
410 found = true;
412 if (!found) {
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.
425 do {
426 if (info->mZLevel <= inZ) break;
427 info = info->mLower;
428 } while (info != mTopmostWindow);
430 *outPosition = nsIWindowMediator::zLevelBelow;
431 belowWindow = info->mHigher->mWindow;
432 *outAltered = true;
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.
437 do {
438 info = info->mHigher;
439 if (info->mZLevel >= inZ) break;
440 } while (info != mTopmostWindow);
442 *outPosition = nsIWindowMediator::zLevelBelow;
443 belowWindow = info->mWindow;
444 *outAltered = true;
446 } else {
447 unsigned long relativeZ;
449 // check that we're in the right z-plane
450 if (found) {
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) {
456 do {
457 if (info->mZLevel <= inZ) break;
458 info = info->mLower;
459 } while (info != mTopmostWindow);
461 belowWindow = info->mHigher->mWindow;
462 *outAltered = true;
464 } else if (relativeZ < inZ) {
465 // nope. look for a higher window to be behind.
466 do {
467 info = info->mHigher;
468 if (info->mZLevel >= inZ) break;
469 } while (info != mTopmostWindow);
471 if (info->mZLevel >= inZ)
472 belowWindow = info->mWindow;
473 else
474 *outPosition = nsIWindowMediator::zLevelTop;
475 *outAltered = true;
476 } // else they're equal, so it's OK
480 if (NS_SUCCEEDED(result) && belowWindow) {
481 nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(belowWindow));
482 if (base)
483 base->GetMainWidget(outBelow);
484 else
485 result = NS_ERROR_NO_INTERFACE;
488 return result;
491 NS_IMETHODIMP
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) ||
500 !inWindow) {
501 return NS_ERROR_INVALID_ARG;
504 if (mSortingZOrder) // don't fight SortZOrder()
505 return NS_OK;
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) {
522 belowInfo = nullptr;
524 if (!belowInfo) {
525 if (inBelow)
526 return NS_ERROR_INVALID_ARG;
527 else
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;
541 return NS_OK;
544 NS_IMETHODIMP
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);
550 if (info) {
551 *_retval = info->mZLevel;
553 return NS_OK;
556 NS_IMETHODIMP
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;
568 if (lowered)
569 SortZOrderFrontToBack();
570 else
571 SortZOrderBackToFront();
573 return NS_OK;
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
582 done front to back.
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
586 was moved.
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
593 bool finished;
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. */
602 do {
603 finished = true;
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;
610 do {
611 prev = search;
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));
628 if (scanWidget)
629 scanWidget->PlaceBehind(eZPlacementBelow, prevWidget, false);
631 finished = false;
632 break;
634 scan = scan->mLower;
636 } while (!finished);
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
646 bool finished;
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. */
655 do {
656 finished = true;
657 lowest = mTopmostWindow->mHigher;
658 scan = lowest;
659 while (scan != mTopmostWindow) {
660 uint32_t scanZ = scan->mZLevel;
661 if (scanZ > scan->mHigher->mZLevel) { // out of order
662 search = scan;
663 do {
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));
684 if (scanWidget)
685 scanWidget->PlaceBehind(eZPlacementBelow, searchWidget, false);
686 finished = false;
687 break;
689 scan = scan->mHigher;
691 } while (!finished);
693 mSortingZOrder = false;
696 NS_IMPL_ISUPPORTS(nsWindowMediator, nsIWindowMediator, nsIObserver,
697 nsISupportsWeakReference)
699 NS_IMETHODIMP
700 nsWindowMediator::AddListener(nsIWindowMediatorListener* aListener) {
701 NS_ENSURE_ARG_POINTER(aListener);
703 mListeners.AppendElement(aListener);
705 return NS_OK;
708 NS_IMETHODIMP
709 nsWindowMediator::RemoveListener(nsIWindowMediatorListener* aListener) {
710 NS_ENSURE_ARG_POINTER(aListener);
712 mListeners.RemoveElement(aListener);
714 return NS_OK;
717 NS_IMETHODIMP
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);
723 mReady = false;
725 return NS_OK;