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