Backed out changeset 49aabddb2edb (bug 852687) for browser-chrome failures
[gecko.git] / xpfe / appshell / src / nsWindowMediator.cpp
blobc3d5c0c7d10e0982a6660858dc1684e088277d9f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsCOMPtr.h"
7 #include "nsString.h"
8 #include "nsReadableUtils.h"
9 #include "nsUnicharUtils.h"
10 #include "nsTArray.h"
11 #include "nsIBaseWindow.h"
12 #include "nsIWidget.h"
13 #include "nsIDOMWindow.h"
14 #include "nsIObserverService.h"
15 #include "nsIServiceManager.h"
16 #include "nsISimpleEnumerator.h"
17 #include "nsAppShellWindowEnumerator.h"
18 #include "nsWindowMediator.h"
19 #include "nsIWindowMediatorListener.h"
20 #include "nsXPIDLString.h"
21 #include "nsGlobalWindow.h"
23 #include "nsIDocShell.h"
24 #include "nsIInterfaceRequestor.h"
25 #include "nsIInterfaceRequestorUtils.h"
26 #include "nsIXULWindow.h"
28 using namespace mozilla;
30 static nsresult GetDOMWindow(nsIXULWindow* inWindow,
31 nsCOMPtr< nsIDOMWindow>& outDOMWindow);
33 static bool notifyOpenWindow(nsIWindowMediatorListener *aElement, void* aData);
34 static bool notifyCloseWindow(nsIWindowMediatorListener *aElement, void* aData);
35 static bool notifyWindowTitleChange(nsIWindowMediatorListener *aElement, void* aData);
37 // for notifyWindowTitleChange
38 struct WindowTitleData {
39 nsIXULWindow* mWindow;
40 const PRUnichar *mTitle;
43 nsresult
44 GetDOMWindow(nsIXULWindow* inWindow, nsCOMPtr<nsIDOMWindow>& outDOMWindow)
46 nsCOMPtr<nsIDocShell> docShell;
48 inWindow->GetDocShell(getter_AddRefs(docShell));
49 outDOMWindow = do_GetInterface(docShell);
50 return outDOMWindow ? NS_OK : NS_ERROR_FAILURE;
53 nsWindowMediator::nsWindowMediator() :
54 mEnumeratorList(), mOldestWindow(nullptr), mTopmostWindow(nullptr),
55 mTimeStamp(0), mSortingZOrder(false), mReady(false),
56 mListLock("nsWindowMediator.mListLock")
60 nsWindowMediator::~nsWindowMediator()
62 while (mOldestWindow)
63 UnregisterWindow(mOldestWindow);
66 nsresult nsWindowMediator::Init()
68 nsresult rv;
69 nsCOMPtr<nsIObserverService> obsSvc =
70 do_GetService("@mozilla.org/observer-service;1", &rv);
71 NS_ENSURE_SUCCESS(rv, rv);
72 rv = obsSvc->AddObserver(this, "xpcom-shutdown", true);
73 NS_ENSURE_SUCCESS(rv, rv);
75 mReady = true;
76 return NS_OK;
79 NS_IMETHODIMP nsWindowMediator::RegisterWindow(nsIXULWindow* inWindow)
81 NS_ENSURE_STATE(mReady);
83 if (GetInfoFor(inWindow)) {
84 NS_ERROR("multiple window registration");
85 return NS_ERROR_FAILURE;
88 mTimeStamp++;
90 // Create window info struct and add to list of windows
91 nsWindowInfo* windowInfo = new nsWindowInfo(inWindow, mTimeStamp);
92 if (!windowInfo)
93 return NS_ERROR_OUT_OF_MEMORY;
95 WindowTitleData winData = { inWindow, nullptr };
96 mListeners.EnumerateForwards(notifyOpenWindow, &winData);
98 MutexAutoLock lock(mListLock);
99 if (mOldestWindow)
100 windowInfo->InsertAfter(mOldestWindow->mOlder, nullptr);
101 else
102 mOldestWindow = windowInfo;
104 return NS_OK;
107 NS_IMETHODIMP
108 nsWindowMediator::UnregisterWindow(nsIXULWindow* inWindow)
110 NS_ENSURE_STATE(mReady);
111 MutexAutoLock lock(mListLock);
112 nsWindowInfo *info = GetInfoFor(inWindow);
113 if (info)
114 return UnregisterWindow(info);
115 return NS_ERROR_INVALID_ARG;
118 nsresult
119 nsWindowMediator::UnregisterWindow(nsWindowInfo *inInfo)
121 // Inform the iterators
122 uint32_t index = 0;
123 while (index < mEnumeratorList.Length()) {
124 mEnumeratorList[index]->WindowRemoved(inInfo);
125 index++;
128 WindowTitleData winData = { inInfo->mWindow.get(), nullptr };
129 mListeners.EnumerateForwards(notifyCloseWindow, &winData);
131 // Remove from the lists and free up
132 if (inInfo == mOldestWindow)
133 mOldestWindow = inInfo->mYounger;
134 if (inInfo == mTopmostWindow)
135 mTopmostWindow = inInfo->mLower;
136 inInfo->Unlink(true, true);
137 if (inInfo == mOldestWindow)
138 mOldestWindow = nullptr;
139 if (inInfo == mTopmostWindow)
140 mTopmostWindow = nullptr;
141 delete inInfo;
143 return NS_OK;
146 nsWindowInfo*
147 nsWindowMediator::GetInfoFor(nsIXULWindow *aWindow)
149 nsWindowInfo *info,
150 *listEnd;
152 if (!aWindow)
153 return nullptr;
155 info = mOldestWindow;
156 listEnd = nullptr;
157 while (info != listEnd) {
158 if (info->mWindow.get() == aWindow)
159 return info;
160 info = info->mYounger;
161 listEnd = mOldestWindow;
163 return nullptr;
166 nsWindowInfo*
167 nsWindowMediator::GetInfoFor(nsIWidget *aWindow)
169 nsWindowInfo *info,
170 *listEnd;
172 if (!aWindow)
173 return nullptr;
175 info = mOldestWindow;
176 listEnd = nullptr;
178 nsCOMPtr<nsIWidget> scanWidget;
179 while (info != listEnd) {
180 nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(info->mWindow));
181 if (base)
182 base->GetMainWidget(getter_AddRefs(scanWidget));
183 if (aWindow == scanWidget.get())
184 return info;
185 info = info->mYounger;
186 listEnd = mOldestWindow;
188 return nullptr;
191 NS_IMETHODIMP
192 nsWindowMediator::GetEnumerator(const PRUnichar* inType, nsISimpleEnumerator** outEnumerator)
194 NS_ENSURE_ARG_POINTER(outEnumerator);
195 NS_ENSURE_STATE(mReady);
196 MutexAutoLock lock(mListLock);
197 nsAppShellWindowEnumerator *enumerator = new nsASDOMWindowEarlyToLateEnumerator(inType, *this);
198 if (enumerator)
199 return enumerator->QueryInterface(NS_GET_IID(nsISimpleEnumerator) , (void**)outEnumerator);
201 return NS_ERROR_OUT_OF_MEMORY;
204 NS_IMETHODIMP
205 nsWindowMediator::GetXULWindowEnumerator(const PRUnichar* inType, nsISimpleEnumerator** outEnumerator)
207 NS_ENSURE_ARG_POINTER(outEnumerator);
208 NS_ENSURE_STATE(mReady);
209 MutexAutoLock lock(mListLock);
210 nsAppShellWindowEnumerator *enumerator = new nsASXULWindowEarlyToLateEnumerator(inType, *this);
211 if (enumerator)
212 return enumerator->QueryInterface(NS_GET_IID(nsISimpleEnumerator) , (void**)outEnumerator);
214 return NS_ERROR_OUT_OF_MEMORY;
217 NS_IMETHODIMP
218 nsWindowMediator::GetZOrderDOMWindowEnumerator(
219 const PRUnichar *aWindowType, bool aFrontToBack,
220 nsISimpleEnumerator **_retval)
222 NS_ENSURE_ARG_POINTER(_retval);
223 NS_ENSURE_STATE(mReady);
224 MutexAutoLock lock(mListLock);
225 nsAppShellWindowEnumerator *enumerator;
226 if (aFrontToBack)
227 enumerator = new nsASDOMWindowFrontToBackEnumerator(aWindowType, *this);
228 else
229 enumerator = new nsASDOMWindowBackToFrontEnumerator(aWindowType, *this);
230 if (enumerator)
231 return CallQueryInterface(enumerator, _retval);
233 return NS_ERROR_OUT_OF_MEMORY;
236 NS_IMETHODIMP
237 nsWindowMediator::GetZOrderXULWindowEnumerator(
238 const PRUnichar *aWindowType, bool aFrontToBack,
239 nsISimpleEnumerator **_retval)
241 NS_ENSURE_ARG_POINTER(_retval);
242 NS_ENSURE_STATE(mReady);
243 MutexAutoLock lock(mListLock);
244 nsAppShellWindowEnumerator *enumerator;
245 if (aFrontToBack)
246 enumerator = new nsASXULWindowFrontToBackEnumerator(aWindowType, *this);
247 else
248 enumerator = new nsASXULWindowBackToFrontEnumerator(aWindowType, *this);
249 if (enumerator)
250 return CallQueryInterface(enumerator, _retval);
252 return NS_ERROR_OUT_OF_MEMORY;
255 int32_t
256 nsWindowMediator::AddEnumerator(nsAppShellWindowEnumerator * inEnumerator)
258 return mEnumeratorList.AppendElement(inEnumerator) != nullptr;
261 int32_t
262 nsWindowMediator::RemoveEnumerator(nsAppShellWindowEnumerator * inEnumerator)
264 return mEnumeratorList.RemoveElement(inEnumerator);
267 // Returns the window of type inType ( if null return any window type ) which has the most recent
268 // time stamp
269 NS_IMETHODIMP
270 nsWindowMediator::GetMostRecentWindow(const PRUnichar* inType, nsIDOMWindow** outWindow)
272 NS_ENSURE_ARG_POINTER(outWindow);
273 *outWindow = nullptr;
274 if (!mReady)
275 return NS_OK;
277 // Find the most window with the highest time stamp that matches
278 // the requested type
280 MutexAutoLock lock(mListLock);
281 nsWindowInfo *info = MostRecentWindowInfo(inType);
283 if (info && info->mWindow) {
284 nsCOMPtr<nsIDOMWindow> DOMWindow;
285 if (NS_SUCCEEDED(GetDOMWindow(info->mWindow, DOMWindow))) {
286 *outWindow = DOMWindow;
287 NS_ADDREF(*outWindow);
288 return NS_OK;
290 return NS_ERROR_FAILURE;
293 return NS_OK;
296 nsWindowInfo*
297 nsWindowMediator::MostRecentWindowInfo(const PRUnichar* inType)
299 int32_t lastTimeStamp = -1;
300 nsAutoString typeString(inType);
301 bool allWindows = !inType || typeString.IsEmpty();
303 // Find the most window with the highest time stamp that matches
304 // the requested type
305 nsWindowInfo *searchInfo,
306 *listEnd,
307 *foundInfo = nullptr;
309 searchInfo = mOldestWindow;
310 listEnd = nullptr;
311 while (searchInfo != listEnd) {
312 if ((allWindows || searchInfo->TypeEquals(typeString)) &&
313 searchInfo->mTimeStamp >= lastTimeStamp) {
315 foundInfo = searchInfo;
316 lastTimeStamp = searchInfo->mTimeStamp;
318 searchInfo = searchInfo->mYounger;
319 listEnd = mOldestWindow;
321 return foundInfo;
324 NS_IMETHODIMP
325 nsWindowMediator::GetOuterWindowWithId(uint64_t aWindowID,
326 nsIDOMWindow** aWindow)
328 *aWindow = nsGlobalWindow::GetOuterWindowWithId(aWindowID);
329 NS_IF_ADDREF(*aWindow);
330 return NS_OK;
333 NS_IMETHODIMP
334 nsWindowMediator::UpdateWindowTimeStamp(nsIXULWindow* inWindow)
336 NS_ENSURE_STATE(mReady);
337 MutexAutoLock lock(mListLock);
338 nsWindowInfo *info = GetInfoFor(inWindow);
339 if (info) {
340 // increment the window's time stamp
341 info->mTimeStamp = ++mTimeStamp;
342 return NS_OK;
344 return NS_ERROR_FAILURE;
347 NS_IMETHODIMP
348 nsWindowMediator::UpdateWindowTitle(nsIXULWindow* inWindow,
349 const PRUnichar* inTitle)
351 NS_ENSURE_STATE(mReady);
352 MutexAutoLock lock(mListLock);
353 if (GetInfoFor(inWindow)) {
354 WindowTitleData winData = { inWindow, inTitle };
355 mListeners.EnumerateForwards(notifyWindowTitleChange, &winData);
358 return NS_OK;
361 /* This method's plan is to intervene only when absolutely necessary.
362 We will get requests to place our windows behind unknown windows.
363 For the most part, we need to leave those alone (turning them into
364 explicit requests to be on top breaks Windows.) So generally we
365 calculate a change as seldom as possible.
367 NS_IMETHODIMP
368 nsWindowMediator::CalculateZPosition(
369 nsIXULWindow *inWindow,
370 uint32_t inPosition,
371 nsIWidget *inBelow,
372 uint32_t *outPosition,
373 nsIWidget **outBelow,
374 bool *outAltered)
376 NS_ENSURE_ARG_POINTER(outBelow);
377 NS_ENSURE_STATE(mReady);
379 *outBelow = nullptr;
381 if (!inWindow || !outPosition || !outAltered)
382 return NS_ERROR_NULL_POINTER;
384 if (inPosition != nsIWindowMediator::zLevelTop &&
385 inPosition != nsIWindowMediator::zLevelBottom &&
386 inPosition != nsIWindowMediator::zLevelBelow)
387 return NS_ERROR_INVALID_ARG;
389 nsWindowInfo *info = mTopmostWindow;
390 nsIXULWindow *belowWindow = nullptr;
391 bool found = false;
392 nsresult result = NS_OK;
394 *outPosition = inPosition;
395 *outAltered = false;
397 if (mSortingZOrder) { // don't fight SortZOrder()
398 *outBelow = inBelow;
399 NS_IF_ADDREF(*outBelow);
400 return NS_OK;
403 uint32_t inZ;
404 GetZLevel(inWindow, &inZ);
406 MutexAutoLock lock(mListLock);
408 if (inPosition == nsIWindowMediator::zLevelBelow) {
409 // locate inBelow. use topmost if it can't be found or isn't in the
410 // z-order list
411 info = GetInfoFor(inBelow);
412 if (!info || (info->mYounger != info && info->mLower == info))
413 info = mTopmostWindow;
414 else
415 found = true;
417 if (!found) {
418 /* Treat unknown windows as a request to be on top.
419 Not as it should be, but that's what Windows gives us.
420 Note we change inPosition, but not *outPosition. This forces
421 us to go through the "on top" calculation just below, without
422 necessarily changing the output parameters. */
423 inPosition = nsIWindowMediator::zLevelTop;
427 if (inPosition == nsIWindowMediator::zLevelTop) {
428 if (mTopmostWindow && mTopmostWindow->mZLevel > inZ) {
429 // asked for topmost, can't have it. locate highest allowed position.
430 do {
431 if (info->mZLevel <= inZ)
432 break;
433 info = info->mLower;
434 } while (info != mTopmostWindow);
436 *outPosition = nsIWindowMediator::zLevelBelow;
437 belowWindow = info->mHigher->mWindow;
438 *outAltered = true;
440 } else if (inPosition == nsIWindowMediator::zLevelBottom) {
441 if (mTopmostWindow && mTopmostWindow->mHigher->mZLevel < inZ) {
442 // asked for bottommost, can't have it. locate lowest allowed position.
443 do {
444 info = info->mHigher;
445 if (info->mZLevel >= inZ)
446 break;
447 } while (info != mTopmostWindow);
449 *outPosition = nsIWindowMediator::zLevelBelow;
450 belowWindow = info->mWindow;
451 *outAltered = true;
453 } else {
454 unsigned long relativeZ;
456 // check that we're in the right z-plane
457 if (found) {
458 belowWindow = info->mWindow;
459 relativeZ = info->mZLevel;
460 if (relativeZ > inZ) {
461 // might be OK. is lower window, if any, lower?
462 if (info->mLower != info && info->mLower->mZLevel > inZ) {
463 do {
464 if (info->mZLevel <= inZ)
465 break;
466 info = info->mLower;
467 } while (info != mTopmostWindow);
469 belowWindow = info->mHigher->mWindow;
470 *outAltered = true;
472 } else if (relativeZ < inZ) {
473 // nope. look for a higher window to be behind.
474 do {
475 info = info->mHigher;
476 if (info->mZLevel >= inZ)
477 break;
478 } while (info != mTopmostWindow);
480 if (info->mZLevel >= inZ)
481 belowWindow = info->mWindow;
482 else
483 *outPosition = nsIWindowMediator::zLevelTop;
484 *outAltered = true;
485 } // else they're equal, so it's OK
489 if (NS_SUCCEEDED(result) && belowWindow) {
490 nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(belowWindow));
491 if (base)
492 base->GetMainWidget(outBelow);
493 else
494 result = NS_ERROR_NO_INTERFACE;
497 return result;
500 NS_IMETHODIMP
501 nsWindowMediator::SetZPosition(
502 nsIXULWindow *inWindow,
503 uint32_t inPosition,
504 nsIXULWindow *inBelow)
506 nsWindowInfo *inInfo,
507 *belowInfo;
509 if ((inPosition != nsIWindowMediator::zLevelTop &&
510 inPosition != nsIWindowMediator::zLevelBottom &&
511 inPosition != nsIWindowMediator::zLevelBelow) ||
512 !inWindow) {
513 return NS_ERROR_INVALID_ARG;
516 if (mSortingZOrder) // don't fight SortZOrder()
517 return NS_OK;
519 NS_ENSURE_STATE(mReady);
520 MutexAutoLock lock(mListLock);
522 /* Locate inWindow and unlink it from the z-order list.
523 It's important we look for it in the age list, not the z-order list.
524 This is because the former is guaranteed complete, while
525 now may be this window's first exposure to the latter. */
526 inInfo = GetInfoFor(inWindow);
527 if (!inInfo)
528 return NS_ERROR_INVALID_ARG;
530 // locate inBelow, place inWindow behind it
531 if (inPosition == nsIWindowMediator::zLevelBelow) {
532 belowInfo = GetInfoFor(inBelow);
533 // it had better also be in the z-order list
534 if (belowInfo &&
535 belowInfo->mYounger != belowInfo && belowInfo->mLower == belowInfo) {
536 belowInfo = nullptr;
538 if (!belowInfo) {
539 if (inBelow)
540 return NS_ERROR_INVALID_ARG;
541 else
542 inPosition = nsIWindowMediator::zLevelTop;
545 if (inPosition == nsIWindowMediator::zLevelTop ||
546 inPosition == nsIWindowMediator::zLevelBottom)
547 belowInfo = mTopmostWindow ? mTopmostWindow->mHigher : nullptr;
549 if (inInfo != belowInfo) {
550 inInfo->Unlink(false, true);
551 inInfo->InsertAfter(nullptr, belowInfo);
553 if (inPosition == nsIWindowMediator::zLevelTop)
554 mTopmostWindow = inInfo;
556 return NS_OK;
559 NS_IMETHODIMP
560 nsWindowMediator::GetZLevel(nsIXULWindow *aWindow, uint32_t *_retval)
562 NS_ENSURE_ARG_POINTER(_retval);
563 *_retval = nsIXULWindow::normalZ;
564 nsWindowInfo *info = GetInfoFor(aWindow);
565 if (info) {
566 *_retval = info->mZLevel;
567 } else {
568 NS_WARNING("getting z level of unregistered window");
569 // this goes off during window destruction
571 return NS_OK;
574 NS_IMETHODIMP
575 nsWindowMediator::SetZLevel(nsIXULWindow *aWindow, uint32_t aZLevel)
577 NS_ENSURE_STATE(mReady);
578 MutexAutoLock lock(mListLock);
580 nsWindowInfo *info = GetInfoFor(aWindow);
581 NS_ASSERTION(info, "setting z level of unregistered window");
582 if (!info)
583 return NS_ERROR_FAILURE;
585 if (info->mZLevel != aZLevel) {
586 bool lowered = info->mZLevel > aZLevel;
587 info->mZLevel = aZLevel;
588 if (lowered)
589 SortZOrderFrontToBack();
590 else
591 SortZOrderBackToFront();
593 return NS_OK;
596 /* Fix potentially out-of-order windows by performing an insertion sort
597 on the z-order list. The method will work no matter how broken the
598 list, but its assumed usage is immediately after one window's z level
599 has been changed, so one window is potentially out of place. Such a sort
600 is most efficiently done in a particular direction. Use this one
601 if a window's z level has just been reduced, so the sort is most efficiently
602 done front to back. Assumes caller has locked mListLock.
603 Note it's hardly worth going to all the trouble to write two versions
604 of this method except that if we choose the inefficient sorting direction,
605 on slow systems windows could visibly bubble around the window that
606 was moved.
608 void
609 nsWindowMediator::SortZOrderFrontToBack()
611 nsWindowInfo *scan, // scans list looking for problems
612 *search, // searches for correct placement for scan window
613 *prev, // previous search element
614 *lowest; // bottom-most window in list
615 bool finished;
617 if (!mTopmostWindow) // early during program execution there's no z list yet
618 return; // there's also only one window, so this is not dangerous
620 mSortingZOrder = true;
622 /* Step through the list from top to bottom. If we find a window which
623 should be moved down in the list, move it to its highest legal position. */
624 do {
625 finished = true;
626 lowest = mTopmostWindow->mHigher;
627 scan = mTopmostWindow;
628 while (scan != lowest) {
629 uint32_t scanZ = scan->mZLevel;
630 if (scanZ < scan->mLower->mZLevel) { // out of order
631 search = scan->mLower;
632 do {
633 prev = search;
634 search = search->mLower;
635 } while (prev != lowest && scanZ < search->mZLevel);
637 // reposition |scan| within the list
638 if (scan == mTopmostWindow)
639 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)
649 base->GetMainWidget(getter_AddRefs(scanWidget));
650 base = do_QueryInterface(prev->mWindow);
651 if (base)
652 base->GetMainWidget(getter_AddRefs(prevWidget));
653 if (scanWidget)
654 scanWidget->PlaceBehind(eZPlacementBelow, prevWidget, false);
656 finished = false;
657 break;
659 scan = scan->mLower;
661 } while (!finished);
663 mSortingZOrder = false;
666 // see comment for SortZOrderFrontToBack
667 void
668 nsWindowMediator::SortZOrderBackToFront()
670 nsWindowInfo *scan, // scans list looking for problems
671 *search, // searches for correct placement for scan window
672 *lowest; // bottom-most window in list
673 bool finished;
675 if (!mTopmostWindow) // early during program execution there's no z list yet
676 return; // there's also only one window, so this is not dangerous
678 mSortingZOrder = true;
680 /* Step through the list from bottom to top. If we find a window which
681 should be moved up in the list, move it to its lowest legal position. */
682 do {
683 finished = true;
684 lowest = mTopmostWindow->mHigher;
685 scan = lowest;
686 while (scan != mTopmostWindow) {
687 uint32_t scanZ = scan->mZLevel;
688 if (scanZ > scan->mHigher->mZLevel) { // out of order
689 search = scan;
690 do {
691 search = search->mHigher;
692 } while (search != lowest && scanZ > search->mZLevel);
694 // reposition |scan| within the list
695 if (scan != search && scan != search->mLower) {
696 scan->Unlink(false, true);
697 scan->InsertAfter(nullptr, search);
699 if (search == lowest)
700 mTopmostWindow = scan;
702 // fix actual window order
703 nsCOMPtr<nsIBaseWindow> base;
704 nsCOMPtr<nsIWidget> scanWidget;
705 nsCOMPtr<nsIWidget> searchWidget;
706 base = do_QueryInterface(scan->mWindow);
707 if (base)
708 base->GetMainWidget(getter_AddRefs(scanWidget));
709 if (mTopmostWindow != scan) {
710 base = do_QueryInterface(search->mWindow);
711 if (base)
712 base->GetMainWidget(getter_AddRefs(searchWidget));
714 if (scanWidget)
715 scanWidget->PlaceBehind(eZPlacementBelow, searchWidget, false);
716 finished = false;
717 break;
719 scan = scan->mHigher;
721 } while (!finished);
723 mSortingZOrder = false;
726 NS_IMPL_ISUPPORTS3(nsWindowMediator,
727 nsIWindowMediator,
728 nsIObserver,
729 nsISupportsWeakReference)
731 NS_IMETHODIMP
732 nsWindowMediator::AddListener(nsIWindowMediatorListener* aListener)
734 NS_ENSURE_ARG_POINTER(aListener);
736 mListeners.AppendObject(aListener);
738 return NS_OK;
741 NS_IMETHODIMP
742 nsWindowMediator::RemoveListener(nsIWindowMediatorListener* aListener)
744 NS_ENSURE_ARG_POINTER(aListener);
746 mListeners.RemoveObject(aListener);
748 return NS_OK;
751 NS_IMETHODIMP
752 nsWindowMediator::Observe(nsISupports* aSubject,
753 const char* aTopic,
754 const PRUnichar* aData)
756 if (!strcmp(aTopic, "xpcom-shutdown") && mReady) {
757 // Unregistering a window may cause its destructor to run, causing it to
758 // call into the window mediator, try to acquire mListLock, and deadlock.
759 // Our solution is to hold strong refs to all windows until we release
760 // mListLock.
761 nsTArray<nsCOMPtr<nsIXULWindow> > windows;
764 MutexAutoLock lock(mListLock);
765 while (mOldestWindow) {
766 windows.AppendElement(mOldestWindow->mWindow);
767 UnregisterWindow(mOldestWindow);
770 mReady = false;
772 return NS_OK;
775 bool
776 notifyOpenWindow(nsIWindowMediatorListener *aListener, void* aData)
778 WindowTitleData* winData = static_cast<WindowTitleData*>(aData);
779 aListener->OnOpenWindow(winData->mWindow);
781 return true;
784 bool
785 notifyCloseWindow(nsIWindowMediatorListener *aListener, void* aData)
787 WindowTitleData* winData = static_cast<WindowTitleData*>(aData);
788 aListener->OnCloseWindow(winData->mWindow);
790 return true;
793 bool
794 notifyWindowTitleChange(nsIWindowMediatorListener *aListener, void* aData)
796 WindowTitleData* titleData = reinterpret_cast<WindowTitleData*>(aData);
797 aListener->OnWindowTitleChange(titleData->mWindow, titleData->mTitle);
799 return true;