Bug 1859954 - Use XP_DARWIN rather than XP_MACOS in PHC r=glandium
[gecko.git] / xpfe / appshell / nsWindowMediator.cpp
blob0e5f38898cdc4ea5bbdb996778124e36990e41f2
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 "nsEnumeratorUtils.h"
8 #include "nsString.h"
9 #include "nsReadableUtils.h"
10 #include "nsUnicharUtils.h"
11 #include "nsTArray.h"
12 #include "nsIBaseWindow.h"
13 #include "nsIWidget.h"
14 #include "nsIObserverService.h"
15 #include "nsISimpleEnumerator.h"
16 #include "nsAppShellWindowEnumerator.h"
17 #include "nsWindowMediator.h"
18 #include "nsIWindowMediatorListener.h"
19 #include "nsGlobalWindowInner.h"
20 #include "nsGlobalWindowOuter.h"
21 #include "nsServiceManagerUtils.h"
23 #include "nsIDocShell.h"
24 #include "nsIInterfaceRequestor.h"
25 #include "nsIInterfaceRequestorUtils.h"
26 #include "nsIAppWindow.h"
28 using namespace mozilla;
30 nsresult nsWindowMediator::GetDOMWindow(
31 nsIAppWindow* inWindow, nsCOMPtr<nsPIDOMWindowOuter>& outDOMWindow) {
32 nsCOMPtr<nsIDocShell> docShell;
34 outDOMWindow = nullptr;
35 inWindow->GetDocShell(getter_AddRefs(docShell));
36 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
38 outDOMWindow = docShell->GetWindow();
39 return outDOMWindow ? NS_OK : NS_ERROR_FAILURE;
42 nsWindowMediator::nsWindowMediator()
43 : mOldestWindow(nullptr),
44 mTopmostWindow(nullptr),
45 mTimeStamp(0),
46 mSortingZOrder(false),
47 mReady(false) {}
49 nsWindowMediator::~nsWindowMediator() {
50 while (mOldestWindow) UnregisterWindow(mOldestWindow);
53 nsresult nsWindowMediator::Init() {
54 nsresult rv;
55 nsCOMPtr<nsIObserverService> obsSvc =
56 do_GetService("@mozilla.org/observer-service;1", &rv);
57 NS_ENSURE_SUCCESS(rv, rv);
58 rv = obsSvc->AddObserver(this, "xpcom-shutdown", true);
59 NS_ENSURE_SUCCESS(rv, rv);
61 mReady = true;
62 return NS_OK;
65 NS_IMETHODIMP nsWindowMediator::RegisterWindow(nsIAppWindow* inWindow) {
66 MOZ_RELEASE_ASSERT(NS_IsMainThread());
68 if (!mReady) {
69 NS_ERROR("Mediator is not initialized or about to die.");
70 return NS_ERROR_FAILURE;
73 if (GetInfoFor(inWindow)) {
74 NS_ERROR("multiple window registration");
75 return NS_ERROR_FAILURE;
78 mTimeStamp++;
80 // Create window info struct and add to list of windows
81 nsWindowInfo* windowInfo = new nsWindowInfo(inWindow, mTimeStamp);
83 for (const auto& listener : mListeners.ForwardRange()) {
84 listener->OnOpenWindow(inWindow);
87 if (mOldestWindow)
88 windowInfo->InsertAfter(mOldestWindow->mOlder, nullptr);
89 else
90 mOldestWindow = windowInfo;
92 return NS_OK;
95 NS_IMETHODIMP
96 nsWindowMediator::UnregisterWindow(nsIAppWindow* inWindow) {
97 MOZ_RELEASE_ASSERT(NS_IsMainThread());
98 MOZ_ASSERT(mReady);
99 NS_ENSURE_STATE(mReady);
100 nsWindowInfo* info = GetInfoFor(inWindow);
101 if (info) return UnregisterWindow(info);
102 return NS_ERROR_INVALID_ARG;
105 nsresult nsWindowMediator::UnregisterWindow(nsWindowInfo* inInfo) {
106 // Inform the iterators
107 uint32_t index = 0;
108 while (index < mEnumeratorList.Length()) {
109 mEnumeratorList[index]->WindowRemoved(inInfo);
110 index++;
113 nsIAppWindow* window = inInfo->mWindow.get();
114 for (const auto& listener : mListeners.ForwardRange()) {
115 listener->OnCloseWindow(window);
118 // Remove from the lists and free up
119 if (inInfo == mOldestWindow) mOldestWindow = inInfo->mYounger;
120 if (inInfo == mTopmostWindow) mTopmostWindow = inInfo->mLower;
121 inInfo->Unlink(true, true);
122 if (inInfo == mOldestWindow) mOldestWindow = nullptr;
123 if (inInfo == mTopmostWindow) mTopmostWindow = nullptr;
124 delete inInfo;
126 return NS_OK;
129 nsWindowInfo* nsWindowMediator::GetInfoFor(nsIAppWindow* aWindow) {
130 nsWindowInfo *info, *listEnd;
132 if (!aWindow) return nullptr;
134 info = mOldestWindow;
135 listEnd = nullptr;
136 while (info != listEnd) {
137 if (info->mWindow.get() == aWindow) return info;
138 info = info->mYounger;
139 listEnd = mOldestWindow;
141 return nullptr;
144 nsWindowInfo* nsWindowMediator::GetInfoFor(nsIWidget* aWindow) {
145 nsWindowInfo *info, *listEnd;
147 if (!aWindow) return nullptr;
149 info = mOldestWindow;
150 listEnd = nullptr;
152 nsCOMPtr<nsIWidget> scanWidget;
153 while (info != listEnd) {
154 nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(info->mWindow));
155 if (base) base->GetMainWidget(getter_AddRefs(scanWidget));
156 if (aWindow == scanWidget.get()) return info;
157 info = info->mYounger;
158 listEnd = mOldestWindow;
160 return nullptr;
163 NS_IMETHODIMP
164 nsWindowMediator::GetEnumerator(const char16_t* inType,
165 nsISimpleEnumerator** outEnumerator) {
166 MOZ_RELEASE_ASSERT(NS_IsMainThread());
167 NS_ENSURE_ARG_POINTER(outEnumerator);
168 if (!mReady) {
169 // If we get here with mReady false, we most likely did observe
170 // xpcom-shutdown. We will return an empty enumerator such that
171 // we make happy Javascripts calling late without throwing.
172 return NS_NewEmptyEnumerator(outEnumerator);
174 RefPtr<nsAppShellWindowEnumerator> enumerator =
175 new nsASDOMWindowEarlyToLateEnumerator(inType, *this);
176 enumerator.forget(outEnumerator);
177 return NS_OK;
180 NS_IMETHODIMP
181 nsWindowMediator::GetAppWindowEnumerator(const char16_t* inType,
182 nsISimpleEnumerator** outEnumerator) {
183 MOZ_RELEASE_ASSERT(NS_IsMainThread());
184 NS_ENSURE_ARG_POINTER(outEnumerator);
185 if (!mReady) {
186 // If we get here with mReady false, we most likely did observe
187 // xpcom-shutdown. We will return an empty enumerator such that
188 // we make happy Javascripts calling late without throwing.
189 return NS_NewEmptyEnumerator(outEnumerator);
191 RefPtr<nsAppShellWindowEnumerator> enumerator =
192 new nsASAppWindowEarlyToLateEnumerator(inType, *this);
193 enumerator.forget(outEnumerator);
194 return NS_OK;
197 NS_IMETHODIMP
198 nsWindowMediator::GetZOrderAppWindowEnumerator(const char16_t* aWindowType,
199 bool aFrontToBack,
200 nsISimpleEnumerator** _retval) {
201 MOZ_RELEASE_ASSERT(NS_IsMainThread());
202 NS_ENSURE_ARG_POINTER(_retval);
203 if (!mReady) {
204 // If we get here with mReady false, we most likely did observe
205 // xpcom-shutdown. We will return an empty enumerator such that
206 // we make happy Javascripts calling late without throwing.
207 return NS_NewEmptyEnumerator(_retval);
209 RefPtr<nsAppShellWindowEnumerator> enumerator;
210 if (aFrontToBack)
211 enumerator = new nsASAppWindowFrontToBackEnumerator(aWindowType, *this);
212 else
213 enumerator = new nsASAppWindowBackToFrontEnumerator(aWindowType, *this);
215 enumerator.forget(_retval);
216 return NS_OK;
219 void nsWindowMediator::AddEnumerator(nsAppShellWindowEnumerator* inEnumerator) {
220 mEnumeratorList.AppendElement(inEnumerator);
223 int32_t nsWindowMediator::RemoveEnumerator(
224 nsAppShellWindowEnumerator* inEnumerator) {
225 return mEnumeratorList.RemoveElement(inEnumerator);
228 // Returns the window of type inType ( if null return any window type ) which
229 // has the most recent time stamp
230 NS_IMETHODIMP
231 nsWindowMediator::GetMostRecentWindow(const char16_t* inType,
232 mozIDOMWindowProxy** outWindow) {
233 MOZ_RELEASE_ASSERT(NS_IsMainThread());
234 NS_ENSURE_ARG_POINTER(outWindow);
235 *outWindow = nullptr;
236 if (!mReady) return NS_OK;
238 // Find the most window with the highest time stamp that matches
239 // the requested type
240 nsWindowInfo* info = MostRecentWindowInfo(inType, false);
241 if (info && info->mWindow) {
242 nsCOMPtr<nsPIDOMWindowOuter> DOMWindow;
243 if (NS_SUCCEEDED(GetDOMWindow(info->mWindow, DOMWindow))) {
244 DOMWindow.forget(outWindow);
245 return NS_OK;
247 return NS_ERROR_FAILURE;
250 return NS_OK;
253 NS_IMETHODIMP
254 nsWindowMediator::GetMostRecentBrowserWindow(mozIDOMWindowProxy** outWindow) {
255 nsresult rv = GetMostRecentWindow(u"navigator:browser", outWindow);
256 NS_ENSURE_SUCCESS(rv, rv);
258 #ifdef MOZ_WIDGET_ANDROID
259 if (!*outWindow) {
260 rv = GetMostRecentWindow(u"navigator:geckoview", outWindow);
261 NS_ENSURE_SUCCESS(rv, rv);
263 #endif
265 #ifdef MOZ_THUNDERBIRD
266 if (!*outWindow) {
267 rv = GetMostRecentWindow(u"mail:3pane", outWindow);
268 NS_ENSURE_SUCCESS(rv, rv);
270 #endif
272 return NS_OK;
275 NS_IMETHODIMP
276 nsWindowMediator::GetMostRecentNonPBWindow(const char16_t* aType,
277 mozIDOMWindowProxy** aWindow) {
278 MOZ_RELEASE_ASSERT(NS_IsMainThread());
279 NS_ENSURE_ARG_POINTER(aWindow);
280 *aWindow = nullptr;
282 nsWindowInfo* info = MostRecentWindowInfo(aType, true);
283 nsCOMPtr<nsPIDOMWindowOuter> domWindow;
284 if (info && info->mWindow) {
285 GetDOMWindow(info->mWindow, domWindow);
288 if (!domWindow) {
289 return NS_ERROR_FAILURE;
292 domWindow.forget(aWindow);
293 return NS_OK;
296 nsWindowInfo* nsWindowMediator::MostRecentWindowInfo(
297 const char16_t* inType, bool aSkipPrivateBrowsingOrClosed) {
298 int32_t lastTimeStamp = -1;
299 nsAutoString typeString(inType);
300 bool allWindows = !inType || typeString.IsEmpty();
302 // Find the most recent window with the highest time stamp that matches
303 // the requested type and has the correct browsing mode.
304 nsWindowInfo* searchInfo = mOldestWindow;
305 nsWindowInfo* listEnd = nullptr;
306 nsWindowInfo* foundInfo = nullptr;
307 for (; searchInfo != listEnd; searchInfo = searchInfo->mYounger) {
308 listEnd = mOldestWindow;
310 if (!allWindows && !searchInfo->TypeEquals(typeString)) {
311 continue;
313 if (searchInfo->mTimeStamp < lastTimeStamp) {
314 continue;
316 if (!searchInfo->mWindow) {
317 continue;
319 if (aSkipPrivateBrowsingOrClosed) {
320 nsCOMPtr<nsIDocShell> docShell;
321 searchInfo->mWindow->GetDocShell(getter_AddRefs(docShell));
322 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
323 if (!loadContext || loadContext->UsePrivateBrowsing()) {
324 continue;
327 nsCOMPtr<nsPIDOMWindowOuter> piwindow = docShell->GetWindow();
328 if (!piwindow || piwindow->Closed()) {
329 continue;
333 foundInfo = searchInfo;
334 lastTimeStamp = searchInfo->mTimeStamp;
337 return foundInfo;
340 NS_IMETHODIMP
341 nsWindowMediator::GetOuterWindowWithId(uint64_t aWindowID,
342 mozIDOMWindowProxy** aWindow) {
343 RefPtr<nsGlobalWindowOuter> window =
344 nsGlobalWindowOuter::GetOuterWindowWithId(aWindowID);
345 window.forget(aWindow);
346 return NS_OK;
349 NS_IMETHODIMP
350 nsWindowMediator::GetCurrentInnerWindowWithId(uint64_t aWindowID,
351 mozIDOMWindow** aWindow) {
352 RefPtr<nsGlobalWindowInner> window =
353 nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
355 // not found
356 if (!window) return NS_OK;
358 nsCOMPtr<nsPIDOMWindowOuter> outer = window->GetOuterWindow();
359 NS_ENSURE_TRUE(outer, NS_ERROR_UNEXPECTED);
361 // outer is already using another inner, so it's same as not found
362 if (outer->GetCurrentInnerWindow() != window) return NS_OK;
364 window.forget(aWindow);
365 return NS_OK;
368 NS_IMETHODIMP
369 nsWindowMediator::UpdateWindowTimeStamp(nsIAppWindow* inWindow) {
370 MOZ_RELEASE_ASSERT(NS_IsMainThread());
371 MOZ_ASSERT(mReady);
372 NS_ENSURE_STATE(mReady);
373 nsWindowInfo* info = GetInfoFor(inWindow);
374 if (info) {
375 // increment the window's time stamp
376 info->mTimeStamp = ++mTimeStamp;
377 return NS_OK;
379 return NS_ERROR_FAILURE;
382 /* This method's plan is to intervene only when absolutely necessary.
383 We will get requests to place our windows behind unknown windows.
384 For the most part, we need to leave those alone (turning them into
385 explicit requests to be on top breaks Windows.) So generally we
386 calculate a change as seldom as possible.
388 NS_IMETHODIMP
389 nsWindowMediator::CalculateZPosition(nsIAppWindow* inWindow,
390 uint32_t inPosition, nsIWidget* inBelow,
391 uint32_t* outPosition,
392 nsIWidget** outBelow, bool* outAltered) {
393 MOZ_RELEASE_ASSERT(NS_IsMainThread());
394 NS_ENSURE_ARG_POINTER(outBelow);
395 MOZ_ASSERT(mReady);
396 NS_ENSURE_STATE(mReady);
398 *outBelow = nullptr;
400 if (!inWindow || !outPosition || !outAltered) return NS_ERROR_NULL_POINTER;
402 if (inPosition != nsIWindowMediator::zLevelTop &&
403 inPosition != nsIWindowMediator::zLevelBottom &&
404 inPosition != nsIWindowMediator::zLevelBelow)
405 return NS_ERROR_INVALID_ARG;
407 nsWindowInfo* info = mTopmostWindow;
408 nsIAppWindow* belowWindow = nullptr;
409 bool found = false;
410 nsresult result = NS_OK;
412 *outPosition = inPosition;
413 *outAltered = false;
415 if (mSortingZOrder) { // don't fight SortZOrder()
416 *outBelow = inBelow;
417 NS_IF_ADDREF(*outBelow);
418 return NS_OK;
421 uint32_t inZ;
422 GetZLevel(inWindow, &inZ);
424 if (inPosition == nsIWindowMediator::zLevelBelow) {
425 // locate inBelow. use topmost if it can't be found or isn't in the
426 // z-order list
427 info = GetInfoFor(inBelow);
428 if (!info || (info->mYounger != info && info->mLower == info))
429 info = mTopmostWindow;
430 else
431 found = true;
433 if (!found) {
434 /* Treat unknown windows as a request to be on top.
435 Not as it should be, but that's what Windows gives us.
436 Note we change inPosition, but not *outPosition. This forces
437 us to go through the "on top" calculation just below, without
438 necessarily changing the output parameters. */
439 inPosition = nsIWindowMediator::zLevelTop;
443 if (inPosition == nsIWindowMediator::zLevelTop) {
444 if (mTopmostWindow && mTopmostWindow->mZLevel > inZ) {
445 // asked for topmost, can't have it. locate highest allowed position.
446 do {
447 if (info->mZLevel <= inZ) break;
448 info = info->mLower;
449 } while (info != mTopmostWindow);
451 *outPosition = nsIWindowMediator::zLevelBelow;
452 belowWindow = info->mHigher->mWindow;
453 *outAltered = true;
455 } else if (inPosition == nsIWindowMediator::zLevelBottom) {
456 if (mTopmostWindow && mTopmostWindow->mHigher->mZLevel < inZ) {
457 // asked for bottommost, can't have it. locate lowest allowed position.
458 do {
459 info = info->mHigher;
460 if (info->mZLevel >= inZ) break;
461 } while (info != mTopmostWindow);
463 *outPosition = nsIWindowMediator::zLevelBelow;
464 belowWindow = info->mWindow;
465 *outAltered = true;
467 } else {
468 unsigned long relativeZ;
470 // check that we're in the right z-plane
471 if (found) {
472 belowWindow = info->mWindow;
473 relativeZ = info->mZLevel;
474 if (relativeZ > inZ) {
475 // might be OK. is lower window, if any, lower?
476 if (info->mLower != info && info->mLower->mZLevel > inZ) {
477 do {
478 if (info->mZLevel <= inZ) break;
479 info = info->mLower;
480 } while (info != mTopmostWindow);
482 belowWindow = info->mHigher->mWindow;
483 *outAltered = true;
485 } else if (relativeZ < inZ) {
486 // nope. look for a higher window to be behind.
487 do {
488 info = info->mHigher;
489 if (info->mZLevel >= inZ) break;
490 } while (info != mTopmostWindow);
492 if (info->mZLevel >= inZ)
493 belowWindow = info->mWindow;
494 else
495 *outPosition = nsIWindowMediator::zLevelTop;
496 *outAltered = true;
497 } // else they're equal, so it's OK
501 if (NS_SUCCEEDED(result) && belowWindow) {
502 nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(belowWindow));
503 if (base)
504 base->GetMainWidget(outBelow);
505 else
506 result = NS_ERROR_NO_INTERFACE;
509 return result;
512 NS_IMETHODIMP
513 nsWindowMediator::SetZPosition(nsIAppWindow* inWindow, uint32_t inPosition,
514 nsIAppWindow* inBelow) {
515 MOZ_RELEASE_ASSERT(NS_IsMainThread());
516 nsWindowInfo *inInfo, *belowInfo;
518 if ((inPosition != nsIWindowMediator::zLevelTop &&
519 inPosition != nsIWindowMediator::zLevelBottom &&
520 inPosition != nsIWindowMediator::zLevelBelow) ||
521 !inWindow) {
522 return NS_ERROR_INVALID_ARG;
525 if (mSortingZOrder) // don't fight SortZOrder()
526 return NS_OK;
528 MOZ_ASSERT(mReady);
529 NS_ENSURE_STATE(mReady);
531 /* Locate inWindow and unlink it from the z-order list.
532 It's important we look for it in the age list, not the z-order list.
533 This is because the former is guaranteed complete, while
534 now may be this window's first exposure to the latter. */
535 inInfo = GetInfoFor(inWindow);
536 if (!inInfo) return NS_ERROR_INVALID_ARG;
538 // locate inBelow, place inWindow behind it
539 if (inPosition == nsIWindowMediator::zLevelBelow) {
540 belowInfo = GetInfoFor(inBelow);
541 // it had better also be in the z-order list
542 if (belowInfo && belowInfo->mYounger != belowInfo &&
543 belowInfo->mLower == belowInfo) {
544 belowInfo = nullptr;
546 if (!belowInfo) {
547 if (inBelow)
548 return NS_ERROR_INVALID_ARG;
549 else
550 inPosition = nsIWindowMediator::zLevelTop;
553 if (inPosition == nsIWindowMediator::zLevelTop ||
554 inPosition == nsIWindowMediator::zLevelBottom)
555 belowInfo = mTopmostWindow ? mTopmostWindow->mHigher : nullptr;
557 if (inInfo != belowInfo) {
558 inInfo->Unlink(false, true);
559 inInfo->InsertAfter(nullptr, belowInfo);
561 if (inPosition == nsIWindowMediator::zLevelTop) mTopmostWindow = inInfo;
563 return NS_OK;
566 NS_IMETHODIMP
567 nsWindowMediator::GetZLevel(nsIAppWindow* aWindow, uint32_t* _retval) {
568 NS_ENSURE_ARG_POINTER(_retval);
569 *_retval = nsIAppWindow::normalZ;
570 // This can fail during window destruction.
571 nsWindowInfo* info = GetInfoFor(aWindow);
572 if (info) {
573 *_retval = info->mZLevel;
575 return NS_OK;
578 NS_IMETHODIMP
579 nsWindowMediator::SetZLevel(nsIAppWindow* aWindow, uint32_t aZLevel) {
580 MOZ_RELEASE_ASSERT(NS_IsMainThread());
581 MOZ_ASSERT(mReady);
582 NS_ENSURE_STATE(mReady);
584 nsWindowInfo* info = GetInfoFor(aWindow);
585 NS_ASSERTION(info, "setting z level of unregistered window");
586 if (!info) return NS_ERROR_FAILURE;
588 if (info->mZLevel != aZLevel) {
589 bool lowered = info->mZLevel > aZLevel;
590 info->mZLevel = aZLevel;
591 if (lowered)
592 SortZOrderFrontToBack();
593 else
594 SortZOrderBackToFront();
596 return NS_OK;
599 /* Fix potentially out-of-order windows by performing an insertion sort
600 on the z-order list. The method will work no matter how broken the
601 list, but its assumed usage is immediately after one window's z level
602 has been changed, so one window is potentially out of place. Such a sort
603 is most efficiently done in a particular direction. Use this one
604 if a window's z level has just been reduced, so the sort is most efficiently
605 done front to back.
606 Note it's hardly worth going to all the trouble to write two versions
607 of this method except that if we choose the inefficient sorting direction,
608 on slow systems windows could visibly bubble around the window that
609 was moved.
611 void nsWindowMediator::SortZOrderFrontToBack() {
612 nsWindowInfo *scan, // scans list looking for problems
613 *search, // searches for correct placement for scan window
614 *prev, // previous search element
615 *lowest; // bottom-most window in list
616 bool finished;
618 if (!mTopmostWindow) // early during program execution there's no z list yet
619 return; // there's also only one window, so this is not dangerous
621 mSortingZOrder = true;
623 /* Step through the list from top to bottom. If we find a window which
624 should be moved down in the list, move it to its highest legal position. */
625 do {
626 finished = true;
627 lowest = mTopmostWindow->mHigher;
628 scan = mTopmostWindow;
629 while (scan != lowest) {
630 uint32_t scanZ = scan->mZLevel;
631 if (scanZ < scan->mLower->mZLevel) { // out of order
632 search = scan->mLower;
633 do {
634 prev = search;
635 search = search->mLower;
636 } while (prev != lowest && scanZ < search->mZLevel);
638 // reposition |scan| within the list
639 if (scan == mTopmostWindow) mTopmostWindow = scan->mLower;
640 scan->Unlink(false, true);
641 scan->InsertAfter(nullptr, prev);
643 // fix actual window order
644 nsCOMPtr<nsIBaseWindow> base;
645 nsCOMPtr<nsIWidget> scanWidget;
646 nsCOMPtr<nsIWidget> prevWidget;
647 base = do_QueryInterface(scan->mWindow);
648 if (base) base->GetMainWidget(getter_AddRefs(scanWidget));
649 base = do_QueryInterface(prev->mWindow);
650 if (base) base->GetMainWidget(getter_AddRefs(prevWidget));
651 if (scanWidget)
652 scanWidget->PlaceBehind(eZPlacementBelow, prevWidget, false);
654 finished = false;
655 break;
657 scan = scan->mLower;
659 } while (!finished);
661 mSortingZOrder = false;
664 // see comment for SortZOrderFrontToBack
665 void nsWindowMediator::SortZOrderBackToFront() {
666 nsWindowInfo *scan, // scans list looking for problems
667 *search, // searches for correct placement for scan window
668 *lowest; // bottom-most window in list
669 bool finished;
671 if (!mTopmostWindow) // early during program execution there's no z list yet
672 return; // there's also only one window, so this is not dangerous
674 mSortingZOrder = true;
676 /* Step through the list from bottom to top. If we find a window which
677 should be moved up in the list, move it to its lowest legal position. */
678 do {
679 finished = true;
680 lowest = mTopmostWindow->mHigher;
681 scan = lowest;
682 while (scan != mTopmostWindow) {
683 uint32_t scanZ = scan->mZLevel;
684 if (scanZ > scan->mHigher->mZLevel) { // out of order
685 search = scan;
686 do {
687 search = search->mHigher;
688 } while (search != lowest && scanZ > search->mZLevel);
690 // reposition |scan| within the list
691 if (scan != search && scan != search->mLower) {
692 scan->Unlink(false, true);
693 scan->InsertAfter(nullptr, search);
695 if (search == lowest) mTopmostWindow = scan;
697 // fix actual window order
698 nsCOMPtr<nsIBaseWindow> base;
699 nsCOMPtr<nsIWidget> scanWidget;
700 nsCOMPtr<nsIWidget> searchWidget;
701 base = do_QueryInterface(scan->mWindow);
702 if (base) base->GetMainWidget(getter_AddRefs(scanWidget));
703 if (mTopmostWindow != scan) {
704 base = do_QueryInterface(search->mWindow);
705 if (base) base->GetMainWidget(getter_AddRefs(searchWidget));
707 if (scanWidget)
708 scanWidget->PlaceBehind(eZPlacementBelow, searchWidget, false);
709 finished = false;
710 break;
712 scan = scan->mHigher;
714 } while (!finished);
716 mSortingZOrder = false;
719 NS_IMPL_ISUPPORTS(nsWindowMediator, nsIWindowMediator, nsIObserver,
720 nsISupportsWeakReference)
722 NS_IMETHODIMP
723 nsWindowMediator::AddListener(nsIWindowMediatorListener* aListener) {
724 NS_ENSURE_ARG_POINTER(aListener);
726 mListeners.AppendElement(aListener);
728 return NS_OK;
731 NS_IMETHODIMP
732 nsWindowMediator::RemoveListener(nsIWindowMediatorListener* aListener) {
733 NS_ENSURE_ARG_POINTER(aListener);
735 mListeners.RemoveElement(aListener);
737 return NS_OK;
740 NS_IMETHODIMP
741 nsWindowMediator::Observe(nsISupports* aSubject, const char* aTopic,
742 const char16_t* aData) {
743 if (!strcmp(aTopic, "xpcom-shutdown") && mReady) {
744 MOZ_RELEASE_ASSERT(NS_IsMainThread());
745 while (mOldestWindow) UnregisterWindow(mOldestWindow);
746 mReady = false;
748 return NS_OK;