1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpfe/appshell/src/nsWindowMediator.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,820 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsCOMPtr.h" 1.10 +#include "nsString.h" 1.11 +#include "nsReadableUtils.h" 1.12 +#include "nsUnicharUtils.h" 1.13 +#include "nsTArray.h" 1.14 +#include "nsIBaseWindow.h" 1.15 +#include "nsIWidget.h" 1.16 +#include "nsIDOMWindow.h" 1.17 +#include "nsIObserverService.h" 1.18 +#include "nsIServiceManager.h" 1.19 +#include "nsISimpleEnumerator.h" 1.20 +#include "nsAppShellWindowEnumerator.h" 1.21 +#include "nsWindowMediator.h" 1.22 +#include "nsIWindowMediatorListener.h" 1.23 +#include "nsXPIDLString.h" 1.24 +#include "nsGlobalWindow.h" 1.25 + 1.26 +#include "nsIDocShell.h" 1.27 +#include "nsIInterfaceRequestor.h" 1.28 +#include "nsIInterfaceRequestorUtils.h" 1.29 +#include "nsIXULWindow.h" 1.30 + 1.31 +using namespace mozilla; 1.32 + 1.33 +static bool notifyOpenWindow(nsIWindowMediatorListener *aElement, void* aData); 1.34 +static bool notifyCloseWindow(nsIWindowMediatorListener *aElement, void* aData); 1.35 +static bool notifyWindowTitleChange(nsIWindowMediatorListener *aElement, void* aData); 1.36 + 1.37 +// for notifyWindowTitleChange 1.38 +struct WindowTitleData { 1.39 + nsIXULWindow* mWindow; 1.40 + const char16_t *mTitle; 1.41 +}; 1.42 + 1.43 +nsresult 1.44 +nsWindowMediator::GetDOMWindow(nsIXULWindow* inWindow, 1.45 + nsCOMPtr<nsIDOMWindow>& outDOMWindow) 1.46 +{ 1.47 + nsCOMPtr<nsIDocShell> docShell; 1.48 + 1.49 + inWindow->GetDocShell(getter_AddRefs(docShell)); 1.50 + outDOMWindow = do_GetInterface(docShell); 1.51 + return outDOMWindow ? NS_OK : NS_ERROR_FAILURE; 1.52 +} 1.53 + 1.54 +nsWindowMediator::nsWindowMediator() : 1.55 + mEnumeratorList(), mOldestWindow(nullptr), mTopmostWindow(nullptr), 1.56 + mTimeStamp(0), mSortingZOrder(false), mReady(false), 1.57 + mListLock("nsWindowMediator.mListLock") 1.58 +{ 1.59 +} 1.60 + 1.61 +nsWindowMediator::~nsWindowMediator() 1.62 +{ 1.63 + while (mOldestWindow) 1.64 + UnregisterWindow(mOldestWindow); 1.65 +} 1.66 + 1.67 +nsresult nsWindowMediator::Init() 1.68 +{ 1.69 + nsresult rv; 1.70 + nsCOMPtr<nsIObserverService> obsSvc = 1.71 + do_GetService("@mozilla.org/observer-service;1", &rv); 1.72 + NS_ENSURE_SUCCESS(rv, rv); 1.73 + rv = obsSvc->AddObserver(this, "xpcom-shutdown", true); 1.74 + NS_ENSURE_SUCCESS(rv, rv); 1.75 + 1.76 + mReady = true; 1.77 + return NS_OK; 1.78 +} 1.79 + 1.80 +NS_IMETHODIMP nsWindowMediator::RegisterWindow(nsIXULWindow* inWindow) 1.81 +{ 1.82 + NS_ENSURE_STATE(mReady); 1.83 + 1.84 + if (GetInfoFor(inWindow)) { 1.85 + NS_ERROR("multiple window registration"); 1.86 + return NS_ERROR_FAILURE; 1.87 + } 1.88 + 1.89 + mTimeStamp++; 1.90 + 1.91 + // Create window info struct and add to list of windows 1.92 + nsWindowInfo* windowInfo = new nsWindowInfo(inWindow, mTimeStamp); 1.93 + if (!windowInfo) 1.94 + return NS_ERROR_OUT_OF_MEMORY; 1.95 + 1.96 + WindowTitleData winData = { inWindow, nullptr }; 1.97 + mListeners.EnumerateForwards(notifyOpenWindow, &winData); 1.98 + 1.99 + MutexAutoLock lock(mListLock); 1.100 + if (mOldestWindow) 1.101 + windowInfo->InsertAfter(mOldestWindow->mOlder, nullptr); 1.102 + else 1.103 + mOldestWindow = windowInfo; 1.104 + 1.105 + return NS_OK; 1.106 +} 1.107 + 1.108 +NS_IMETHODIMP 1.109 +nsWindowMediator::UnregisterWindow(nsIXULWindow* inWindow) 1.110 +{ 1.111 + NS_ENSURE_STATE(mReady); 1.112 + MutexAutoLock lock(mListLock); 1.113 + nsWindowInfo *info = GetInfoFor(inWindow); 1.114 + if (info) 1.115 + return UnregisterWindow(info); 1.116 + return NS_ERROR_INVALID_ARG; 1.117 +} 1.118 + 1.119 +nsresult 1.120 +nsWindowMediator::UnregisterWindow(nsWindowInfo *inInfo) 1.121 +{ 1.122 + // Inform the iterators 1.123 + uint32_t index = 0; 1.124 + while (index < mEnumeratorList.Length()) { 1.125 + mEnumeratorList[index]->WindowRemoved(inInfo); 1.126 + index++; 1.127 + } 1.128 + 1.129 + WindowTitleData winData = { inInfo->mWindow.get(), nullptr }; 1.130 + mListeners.EnumerateForwards(notifyCloseWindow, &winData); 1.131 + 1.132 + // Remove from the lists and free up 1.133 + if (inInfo == mOldestWindow) 1.134 + mOldestWindow = inInfo->mYounger; 1.135 + if (inInfo == mTopmostWindow) 1.136 + mTopmostWindow = inInfo->mLower; 1.137 + inInfo->Unlink(true, true); 1.138 + if (inInfo == mOldestWindow) 1.139 + mOldestWindow = nullptr; 1.140 + if (inInfo == mTopmostWindow) 1.141 + mTopmostWindow = nullptr; 1.142 + delete inInfo; 1.143 + 1.144 + return NS_OK; 1.145 +} 1.146 + 1.147 +nsWindowInfo* 1.148 +nsWindowMediator::GetInfoFor(nsIXULWindow *aWindow) 1.149 +{ 1.150 + nsWindowInfo *info, 1.151 + *listEnd; 1.152 + 1.153 + if (!aWindow) 1.154 + return nullptr; 1.155 + 1.156 + info = mOldestWindow; 1.157 + listEnd = nullptr; 1.158 + while (info != listEnd) { 1.159 + if (info->mWindow.get() == aWindow) 1.160 + return info; 1.161 + info = info->mYounger; 1.162 + listEnd = mOldestWindow; 1.163 + } 1.164 + return nullptr; 1.165 +} 1.166 + 1.167 +nsWindowInfo* 1.168 +nsWindowMediator::GetInfoFor(nsIWidget *aWindow) 1.169 +{ 1.170 + nsWindowInfo *info, 1.171 + *listEnd; 1.172 + 1.173 + if (!aWindow) 1.174 + return nullptr; 1.175 + 1.176 + info = mOldestWindow; 1.177 + listEnd = nullptr; 1.178 + 1.179 + nsCOMPtr<nsIWidget> scanWidget; 1.180 + while (info != listEnd) { 1.181 + nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(info->mWindow)); 1.182 + if (base) 1.183 + base->GetMainWidget(getter_AddRefs(scanWidget)); 1.184 + if (aWindow == scanWidget.get()) 1.185 + return info; 1.186 + info = info->mYounger; 1.187 + listEnd = mOldestWindow; 1.188 + } 1.189 + return nullptr; 1.190 +} 1.191 + 1.192 +NS_IMETHODIMP 1.193 +nsWindowMediator::GetEnumerator(const char16_t* inType, nsISimpleEnumerator** outEnumerator) 1.194 +{ 1.195 + NS_ENSURE_ARG_POINTER(outEnumerator); 1.196 + NS_ENSURE_STATE(mReady); 1.197 + MutexAutoLock lock(mListLock); 1.198 + nsAppShellWindowEnumerator *enumerator = new nsASDOMWindowEarlyToLateEnumerator(inType, *this); 1.199 + if (enumerator) 1.200 + return enumerator->QueryInterface(NS_GET_IID(nsISimpleEnumerator) , (void**)outEnumerator); 1.201 + 1.202 + return NS_ERROR_OUT_OF_MEMORY; 1.203 +} 1.204 + 1.205 +NS_IMETHODIMP 1.206 +nsWindowMediator::GetXULWindowEnumerator(const char16_t* inType, nsISimpleEnumerator** outEnumerator) 1.207 +{ 1.208 + NS_ENSURE_ARG_POINTER(outEnumerator); 1.209 + NS_ENSURE_STATE(mReady); 1.210 + MutexAutoLock lock(mListLock); 1.211 + nsAppShellWindowEnumerator *enumerator = new nsASXULWindowEarlyToLateEnumerator(inType, *this); 1.212 + if (enumerator) 1.213 + return enumerator->QueryInterface(NS_GET_IID(nsISimpleEnumerator) , (void**)outEnumerator); 1.214 + 1.215 + return NS_ERROR_OUT_OF_MEMORY; 1.216 +} 1.217 + 1.218 +NS_IMETHODIMP 1.219 +nsWindowMediator::GetZOrderDOMWindowEnumerator( 1.220 + const char16_t *aWindowType, bool aFrontToBack, 1.221 + nsISimpleEnumerator **_retval) 1.222 +{ 1.223 + NS_ENSURE_ARG_POINTER(_retval); 1.224 + NS_ENSURE_STATE(mReady); 1.225 + MutexAutoLock lock(mListLock); 1.226 + nsAppShellWindowEnumerator *enumerator; 1.227 + if (aFrontToBack) 1.228 + enumerator = new nsASDOMWindowFrontToBackEnumerator(aWindowType, *this); 1.229 + else 1.230 + enumerator = new nsASDOMWindowBackToFrontEnumerator(aWindowType, *this); 1.231 + if (enumerator) 1.232 + return CallQueryInterface(enumerator, _retval); 1.233 + 1.234 + return NS_ERROR_OUT_OF_MEMORY; 1.235 +} 1.236 + 1.237 +NS_IMETHODIMP 1.238 +nsWindowMediator::GetZOrderXULWindowEnumerator( 1.239 + const char16_t *aWindowType, bool aFrontToBack, 1.240 + nsISimpleEnumerator **_retval) 1.241 +{ 1.242 + NS_ENSURE_ARG_POINTER(_retval); 1.243 + NS_ENSURE_STATE(mReady); 1.244 + MutexAutoLock lock(mListLock); 1.245 + nsAppShellWindowEnumerator *enumerator; 1.246 + if (aFrontToBack) 1.247 + enumerator = new nsASXULWindowFrontToBackEnumerator(aWindowType, *this); 1.248 + else 1.249 + enumerator = new nsASXULWindowBackToFrontEnumerator(aWindowType, *this); 1.250 + if (enumerator) 1.251 + return CallQueryInterface(enumerator, _retval); 1.252 + 1.253 + return NS_ERROR_OUT_OF_MEMORY; 1.254 +} 1.255 + 1.256 +int32_t 1.257 +nsWindowMediator::AddEnumerator(nsAppShellWindowEnumerator * inEnumerator) 1.258 +{ 1.259 + return mEnumeratorList.AppendElement(inEnumerator) != nullptr; 1.260 +} 1.261 + 1.262 +int32_t 1.263 +nsWindowMediator::RemoveEnumerator(nsAppShellWindowEnumerator * inEnumerator) 1.264 +{ 1.265 + return mEnumeratorList.RemoveElement(inEnumerator); 1.266 +} 1.267 + 1.268 +// Returns the window of type inType ( if null return any window type ) which has the most recent 1.269 +// time stamp 1.270 +NS_IMETHODIMP 1.271 +nsWindowMediator::GetMostRecentWindow(const char16_t* inType, nsIDOMWindow** outWindow) 1.272 +{ 1.273 + NS_ENSURE_ARG_POINTER(outWindow); 1.274 + *outWindow = nullptr; 1.275 + if (!mReady) 1.276 + return NS_OK; 1.277 + 1.278 + // Find the most window with the highest time stamp that matches 1.279 + // the requested type 1.280 + 1.281 + MutexAutoLock lock(mListLock); 1.282 + nsWindowInfo *info = MostRecentWindowInfo(inType); 1.283 + 1.284 + if (info && info->mWindow) { 1.285 + nsCOMPtr<nsIDOMWindow> DOMWindow; 1.286 + if (NS_SUCCEEDED(GetDOMWindow(info->mWindow, DOMWindow))) { 1.287 + *outWindow = DOMWindow; 1.288 + NS_ADDREF(*outWindow); 1.289 + return NS_OK; 1.290 + } 1.291 + return NS_ERROR_FAILURE; 1.292 + } 1.293 + 1.294 + return NS_OK; 1.295 +} 1.296 + 1.297 +nsWindowInfo* 1.298 +nsWindowMediator::MostRecentWindowInfo(const char16_t* inType) 1.299 +{ 1.300 + int32_t lastTimeStamp = -1; 1.301 + nsAutoString typeString(inType); 1.302 + bool allWindows = !inType || typeString.IsEmpty(); 1.303 + 1.304 + // Find the most window with the highest time stamp that matches 1.305 + // the requested type 1.306 + nsWindowInfo *searchInfo, 1.307 + *listEnd, 1.308 + *foundInfo = nullptr; 1.309 + 1.310 + searchInfo = mOldestWindow; 1.311 + listEnd = nullptr; 1.312 + while (searchInfo != listEnd) { 1.313 + if ((allWindows || searchInfo->TypeEquals(typeString)) && 1.314 + searchInfo->mTimeStamp >= lastTimeStamp) { 1.315 + 1.316 + foundInfo = searchInfo; 1.317 + lastTimeStamp = searchInfo->mTimeStamp; 1.318 + } 1.319 + searchInfo = searchInfo->mYounger; 1.320 + listEnd = mOldestWindow; 1.321 + } 1.322 + return foundInfo; 1.323 +} 1.324 + 1.325 +NS_IMETHODIMP 1.326 +nsWindowMediator::GetOuterWindowWithId(uint64_t aWindowID, 1.327 + nsIDOMWindow** aWindow) 1.328 +{ 1.329 + *aWindow = nsGlobalWindow::GetOuterWindowWithId(aWindowID); 1.330 + NS_IF_ADDREF(*aWindow); 1.331 + return NS_OK; 1.332 +} 1.333 + 1.334 +NS_IMETHODIMP 1.335 +nsWindowMediator::GetCurrentInnerWindowWithId(uint64_t aWindowID, 1.336 + nsIDOMWindow** aWindow) 1.337 +{ 1.338 + nsCOMPtr<nsPIDOMWindow> inner = nsGlobalWindow::GetInnerWindowWithId(aWindowID); 1.339 + 1.340 + // not found 1.341 + if (!inner) 1.342 + return NS_OK; 1.343 + 1.344 + nsCOMPtr<nsPIDOMWindow> outer = inner->GetOuterWindow(); 1.345 + NS_ENSURE_TRUE(outer, NS_ERROR_UNEXPECTED); 1.346 + 1.347 + // outer is already using another inner, so it's same as not found 1.348 + if (outer->GetCurrentInnerWindow() != inner) 1.349 + return NS_OK; 1.350 + 1.351 + nsCOMPtr<nsIDOMWindow> ret = do_QueryInterface(outer); 1.352 + ret.forget(aWindow); 1.353 + return NS_OK; 1.354 +} 1.355 + 1.356 +NS_IMETHODIMP 1.357 +nsWindowMediator::UpdateWindowTimeStamp(nsIXULWindow* inWindow) 1.358 +{ 1.359 + NS_ENSURE_STATE(mReady); 1.360 + MutexAutoLock lock(mListLock); 1.361 + nsWindowInfo *info = GetInfoFor(inWindow); 1.362 + if (info) { 1.363 + // increment the window's time stamp 1.364 + info->mTimeStamp = ++mTimeStamp; 1.365 + return NS_OK; 1.366 + } 1.367 + return NS_ERROR_FAILURE; 1.368 +} 1.369 + 1.370 +NS_IMETHODIMP 1.371 +nsWindowMediator::UpdateWindowTitle(nsIXULWindow* inWindow, 1.372 + const char16_t* inTitle) 1.373 +{ 1.374 + NS_ENSURE_STATE(mReady); 1.375 + MutexAutoLock lock(mListLock); 1.376 + if (GetInfoFor(inWindow)) { 1.377 + WindowTitleData winData = { inWindow, inTitle }; 1.378 + mListeners.EnumerateForwards(notifyWindowTitleChange, &winData); 1.379 + } 1.380 + 1.381 + return NS_OK; 1.382 +} 1.383 + 1.384 +/* This method's plan is to intervene only when absolutely necessary. 1.385 + We will get requests to place our windows behind unknown windows. 1.386 + For the most part, we need to leave those alone (turning them into 1.387 + explicit requests to be on top breaks Windows.) So generally we 1.388 + calculate a change as seldom as possible. 1.389 +*/ 1.390 +NS_IMETHODIMP 1.391 +nsWindowMediator::CalculateZPosition( 1.392 + nsIXULWindow *inWindow, 1.393 + uint32_t inPosition, 1.394 + nsIWidget *inBelow, 1.395 + uint32_t *outPosition, 1.396 + nsIWidget **outBelow, 1.397 + bool *outAltered) 1.398 +{ 1.399 + NS_ENSURE_ARG_POINTER(outBelow); 1.400 + NS_ENSURE_STATE(mReady); 1.401 + 1.402 + *outBelow = nullptr; 1.403 + 1.404 + if (!inWindow || !outPosition || !outAltered) 1.405 + return NS_ERROR_NULL_POINTER; 1.406 + 1.407 + if (inPosition != nsIWindowMediator::zLevelTop && 1.408 + inPosition != nsIWindowMediator::zLevelBottom && 1.409 + inPosition != nsIWindowMediator::zLevelBelow) 1.410 + return NS_ERROR_INVALID_ARG; 1.411 + 1.412 + nsWindowInfo *info = mTopmostWindow; 1.413 + nsIXULWindow *belowWindow = nullptr; 1.414 + bool found = false; 1.415 + nsresult result = NS_OK; 1.416 + 1.417 + *outPosition = inPosition; 1.418 + *outAltered = false; 1.419 + 1.420 + if (mSortingZOrder) { // don't fight SortZOrder() 1.421 + *outBelow = inBelow; 1.422 + NS_IF_ADDREF(*outBelow); 1.423 + return NS_OK; 1.424 + } 1.425 + 1.426 + uint32_t inZ; 1.427 + GetZLevel(inWindow, &inZ); 1.428 + 1.429 + MutexAutoLock lock(mListLock); 1.430 + 1.431 + if (inPosition == nsIWindowMediator::zLevelBelow) { 1.432 + // locate inBelow. use topmost if it can't be found or isn't in the 1.433 + // z-order list 1.434 + info = GetInfoFor(inBelow); 1.435 + if (!info || (info->mYounger != info && info->mLower == info)) 1.436 + info = mTopmostWindow; 1.437 + else 1.438 + found = true; 1.439 + 1.440 + if (!found) { 1.441 + /* Treat unknown windows as a request to be on top. 1.442 + Not as it should be, but that's what Windows gives us. 1.443 + Note we change inPosition, but not *outPosition. This forces 1.444 + us to go through the "on top" calculation just below, without 1.445 + necessarily changing the output parameters. */ 1.446 + inPosition = nsIWindowMediator::zLevelTop; 1.447 + } 1.448 + } 1.449 + 1.450 + if (inPosition == nsIWindowMediator::zLevelTop) { 1.451 + if (mTopmostWindow && mTopmostWindow->mZLevel > inZ) { 1.452 + // asked for topmost, can't have it. locate highest allowed position. 1.453 + do { 1.454 + if (info->mZLevel <= inZ) 1.455 + break; 1.456 + info = info->mLower; 1.457 + } while (info != mTopmostWindow); 1.458 + 1.459 + *outPosition = nsIWindowMediator::zLevelBelow; 1.460 + belowWindow = info->mHigher->mWindow; 1.461 + *outAltered = true; 1.462 + } 1.463 + } else if (inPosition == nsIWindowMediator::zLevelBottom) { 1.464 + if (mTopmostWindow && mTopmostWindow->mHigher->mZLevel < inZ) { 1.465 + // asked for bottommost, can't have it. locate lowest allowed position. 1.466 + do { 1.467 + info = info->mHigher; 1.468 + if (info->mZLevel >= inZ) 1.469 + break; 1.470 + } while (info != mTopmostWindow); 1.471 + 1.472 + *outPosition = nsIWindowMediator::zLevelBelow; 1.473 + belowWindow = info->mWindow; 1.474 + *outAltered = true; 1.475 + } 1.476 + } else { 1.477 + unsigned long relativeZ; 1.478 + 1.479 + // check that we're in the right z-plane 1.480 + if (found) { 1.481 + belowWindow = info->mWindow; 1.482 + relativeZ = info->mZLevel; 1.483 + if (relativeZ > inZ) { 1.484 + // might be OK. is lower window, if any, lower? 1.485 + if (info->mLower != info && info->mLower->mZLevel > inZ) { 1.486 + do { 1.487 + if (info->mZLevel <= inZ) 1.488 + break; 1.489 + info = info->mLower; 1.490 + } while (info != mTopmostWindow); 1.491 + 1.492 + belowWindow = info->mHigher->mWindow; 1.493 + *outAltered = true; 1.494 + } 1.495 + } else if (relativeZ < inZ) { 1.496 + // nope. look for a higher window to be behind. 1.497 + do { 1.498 + info = info->mHigher; 1.499 + if (info->mZLevel >= inZ) 1.500 + break; 1.501 + } while (info != mTopmostWindow); 1.502 + 1.503 + if (info->mZLevel >= inZ) 1.504 + belowWindow = info->mWindow; 1.505 + else 1.506 + *outPosition = nsIWindowMediator::zLevelTop; 1.507 + *outAltered = true; 1.508 + } // else they're equal, so it's OK 1.509 + } 1.510 + } 1.511 + 1.512 + if (NS_SUCCEEDED(result) && belowWindow) { 1.513 + nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(belowWindow)); 1.514 + if (base) 1.515 + base->GetMainWidget(outBelow); 1.516 + else 1.517 + result = NS_ERROR_NO_INTERFACE; 1.518 + } 1.519 + 1.520 + return result; 1.521 +} 1.522 + 1.523 +NS_IMETHODIMP 1.524 +nsWindowMediator::SetZPosition( 1.525 + nsIXULWindow *inWindow, 1.526 + uint32_t inPosition, 1.527 + nsIXULWindow *inBelow) 1.528 +{ 1.529 + nsWindowInfo *inInfo, 1.530 + *belowInfo; 1.531 + 1.532 + if ((inPosition != nsIWindowMediator::zLevelTop && 1.533 + inPosition != nsIWindowMediator::zLevelBottom && 1.534 + inPosition != nsIWindowMediator::zLevelBelow) || 1.535 + !inWindow) { 1.536 + return NS_ERROR_INVALID_ARG; 1.537 + } 1.538 + 1.539 + if (mSortingZOrder) // don't fight SortZOrder() 1.540 + return NS_OK; 1.541 + 1.542 + NS_ENSURE_STATE(mReady); 1.543 + MutexAutoLock lock(mListLock); 1.544 + 1.545 + /* Locate inWindow and unlink it from the z-order list. 1.546 + It's important we look for it in the age list, not the z-order list. 1.547 + This is because the former is guaranteed complete, while 1.548 + now may be this window's first exposure to the latter. */ 1.549 + inInfo = GetInfoFor(inWindow); 1.550 + if (!inInfo) 1.551 + return NS_ERROR_INVALID_ARG; 1.552 + 1.553 + // locate inBelow, place inWindow behind it 1.554 + if (inPosition == nsIWindowMediator::zLevelBelow) { 1.555 + belowInfo = GetInfoFor(inBelow); 1.556 + // it had better also be in the z-order list 1.557 + if (belowInfo && 1.558 + belowInfo->mYounger != belowInfo && belowInfo->mLower == belowInfo) { 1.559 + belowInfo = nullptr; 1.560 + } 1.561 + if (!belowInfo) { 1.562 + if (inBelow) 1.563 + return NS_ERROR_INVALID_ARG; 1.564 + else 1.565 + inPosition = nsIWindowMediator::zLevelTop; 1.566 + } 1.567 + } 1.568 + if (inPosition == nsIWindowMediator::zLevelTop || 1.569 + inPosition == nsIWindowMediator::zLevelBottom) 1.570 + belowInfo = mTopmostWindow ? mTopmostWindow->mHigher : nullptr; 1.571 + 1.572 + if (inInfo != belowInfo) { 1.573 + inInfo->Unlink(false, true); 1.574 + inInfo->InsertAfter(nullptr, belowInfo); 1.575 + } 1.576 + if (inPosition == nsIWindowMediator::zLevelTop) 1.577 + mTopmostWindow = inInfo; 1.578 + 1.579 + return NS_OK; 1.580 +} 1.581 + 1.582 +NS_IMETHODIMP 1.583 +nsWindowMediator::GetZLevel(nsIXULWindow *aWindow, uint32_t *_retval) 1.584 +{ 1.585 + NS_ENSURE_ARG_POINTER(_retval); 1.586 + *_retval = nsIXULWindow::normalZ; 1.587 + nsWindowInfo *info = GetInfoFor(aWindow); 1.588 + if (info) { 1.589 + *_retval = info->mZLevel; 1.590 + } else { 1.591 + NS_WARNING("getting z level of unregistered window"); 1.592 + // this goes off during window destruction 1.593 + } 1.594 + return NS_OK; 1.595 +} 1.596 + 1.597 +NS_IMETHODIMP 1.598 +nsWindowMediator::SetZLevel(nsIXULWindow *aWindow, uint32_t aZLevel) 1.599 +{ 1.600 + NS_ENSURE_STATE(mReady); 1.601 + MutexAutoLock lock(mListLock); 1.602 + 1.603 + nsWindowInfo *info = GetInfoFor(aWindow); 1.604 + NS_ASSERTION(info, "setting z level of unregistered window"); 1.605 + if (!info) 1.606 + return NS_ERROR_FAILURE; 1.607 + 1.608 + if (info->mZLevel != aZLevel) { 1.609 + bool lowered = info->mZLevel > aZLevel; 1.610 + info->mZLevel = aZLevel; 1.611 + if (lowered) 1.612 + SortZOrderFrontToBack(); 1.613 + else 1.614 + SortZOrderBackToFront(); 1.615 + } 1.616 + return NS_OK; 1.617 +} 1.618 + 1.619 +/* Fix potentially out-of-order windows by performing an insertion sort 1.620 + on the z-order list. The method will work no matter how broken the 1.621 + list, but its assumed usage is immediately after one window's z level 1.622 + has been changed, so one window is potentially out of place. Such a sort 1.623 + is most efficiently done in a particular direction. Use this one 1.624 + if a window's z level has just been reduced, so the sort is most efficiently 1.625 + done front to back. Assumes caller has locked mListLock. 1.626 + Note it's hardly worth going to all the trouble to write two versions 1.627 + of this method except that if we choose the inefficient sorting direction, 1.628 + on slow systems windows could visibly bubble around the window that 1.629 + was moved. 1.630 +*/ 1.631 +void 1.632 +nsWindowMediator::SortZOrderFrontToBack() 1.633 +{ 1.634 + nsWindowInfo *scan, // scans list looking for problems 1.635 + *search, // searches for correct placement for scan window 1.636 + *prev, // previous search element 1.637 + *lowest; // bottom-most window in list 1.638 + bool finished; 1.639 + 1.640 + if (!mTopmostWindow) // early during program execution there's no z list yet 1.641 + return; // there's also only one window, so this is not dangerous 1.642 + 1.643 + mSortingZOrder = true; 1.644 + 1.645 + /* Step through the list from top to bottom. If we find a window which 1.646 + should be moved down in the list, move it to its highest legal position. */ 1.647 + do { 1.648 + finished = true; 1.649 + lowest = mTopmostWindow->mHigher; 1.650 + scan = mTopmostWindow; 1.651 + while (scan != lowest) { 1.652 + uint32_t scanZ = scan->mZLevel; 1.653 + if (scanZ < scan->mLower->mZLevel) { // out of order 1.654 + search = scan->mLower; 1.655 + do { 1.656 + prev = search; 1.657 + search = search->mLower; 1.658 + } while (prev != lowest && scanZ < search->mZLevel); 1.659 + 1.660 + // reposition |scan| within the list 1.661 + if (scan == mTopmostWindow) 1.662 + mTopmostWindow = scan->mLower; 1.663 + scan->Unlink(false, true); 1.664 + scan->InsertAfter(nullptr, prev); 1.665 + 1.666 + // fix actual window order 1.667 + nsCOMPtr<nsIBaseWindow> base; 1.668 + nsCOMPtr<nsIWidget> scanWidget; 1.669 + nsCOMPtr<nsIWidget> prevWidget; 1.670 + base = do_QueryInterface(scan->mWindow); 1.671 + if (base) 1.672 + base->GetMainWidget(getter_AddRefs(scanWidget)); 1.673 + base = do_QueryInterface(prev->mWindow); 1.674 + if (base) 1.675 + base->GetMainWidget(getter_AddRefs(prevWidget)); 1.676 + if (scanWidget) 1.677 + scanWidget->PlaceBehind(eZPlacementBelow, prevWidget, false); 1.678 + 1.679 + finished = false; 1.680 + break; 1.681 + } 1.682 + scan = scan->mLower; 1.683 + } 1.684 + } while (!finished); 1.685 + 1.686 + mSortingZOrder = false; 1.687 +} 1.688 + 1.689 +// see comment for SortZOrderFrontToBack 1.690 +void 1.691 +nsWindowMediator::SortZOrderBackToFront() 1.692 +{ 1.693 + nsWindowInfo *scan, // scans list looking for problems 1.694 + *search, // searches for correct placement for scan window 1.695 + *lowest; // bottom-most window in list 1.696 + bool finished; 1.697 + 1.698 + if (!mTopmostWindow) // early during program execution there's no z list yet 1.699 + return; // there's also only one window, so this is not dangerous 1.700 + 1.701 + mSortingZOrder = true; 1.702 + 1.703 + /* Step through the list from bottom to top. If we find a window which 1.704 + should be moved up in the list, move it to its lowest legal position. */ 1.705 + do { 1.706 + finished = true; 1.707 + lowest = mTopmostWindow->mHigher; 1.708 + scan = lowest; 1.709 + while (scan != mTopmostWindow) { 1.710 + uint32_t scanZ = scan->mZLevel; 1.711 + if (scanZ > scan->mHigher->mZLevel) { // out of order 1.712 + search = scan; 1.713 + do { 1.714 + search = search->mHigher; 1.715 + } while (search != lowest && scanZ > search->mZLevel); 1.716 + 1.717 + // reposition |scan| within the list 1.718 + if (scan != search && scan != search->mLower) { 1.719 + scan->Unlink(false, true); 1.720 + scan->InsertAfter(nullptr, search); 1.721 + } 1.722 + if (search == lowest) 1.723 + mTopmostWindow = scan; 1.724 + 1.725 + // fix actual window order 1.726 + nsCOMPtr<nsIBaseWindow> base; 1.727 + nsCOMPtr<nsIWidget> scanWidget; 1.728 + nsCOMPtr<nsIWidget> searchWidget; 1.729 + base = do_QueryInterface(scan->mWindow); 1.730 + if (base) 1.731 + base->GetMainWidget(getter_AddRefs(scanWidget)); 1.732 + if (mTopmostWindow != scan) { 1.733 + base = do_QueryInterface(search->mWindow); 1.734 + if (base) 1.735 + base->GetMainWidget(getter_AddRefs(searchWidget)); 1.736 + } 1.737 + if (scanWidget) 1.738 + scanWidget->PlaceBehind(eZPlacementBelow, searchWidget, false); 1.739 + finished = false; 1.740 + break; 1.741 + } 1.742 + scan = scan->mHigher; 1.743 + } 1.744 + } while (!finished); 1.745 + 1.746 + mSortingZOrder = false; 1.747 +} 1.748 + 1.749 +NS_IMPL_ISUPPORTS(nsWindowMediator, 1.750 + nsIWindowMediator, 1.751 + nsIObserver, 1.752 + nsISupportsWeakReference) 1.753 + 1.754 +NS_IMETHODIMP 1.755 +nsWindowMediator::AddListener(nsIWindowMediatorListener* aListener) 1.756 +{ 1.757 + NS_ENSURE_ARG_POINTER(aListener); 1.758 + 1.759 + mListeners.AppendObject(aListener); 1.760 + 1.761 + return NS_OK; 1.762 +} 1.763 + 1.764 +NS_IMETHODIMP 1.765 +nsWindowMediator::RemoveListener(nsIWindowMediatorListener* aListener) 1.766 +{ 1.767 + NS_ENSURE_ARG_POINTER(aListener); 1.768 + 1.769 + mListeners.RemoveObject(aListener); 1.770 + 1.771 + return NS_OK; 1.772 +} 1.773 + 1.774 +NS_IMETHODIMP 1.775 +nsWindowMediator::Observe(nsISupports* aSubject, 1.776 + const char* aTopic, 1.777 + const char16_t* aData) 1.778 +{ 1.779 + if (!strcmp(aTopic, "xpcom-shutdown") && mReady) { 1.780 + // Unregistering a window may cause its destructor to run, causing it to 1.781 + // call into the window mediator, try to acquire mListLock, and deadlock. 1.782 + // Our solution is to hold strong refs to all windows until we release 1.783 + // mListLock. 1.784 + nsTArray<nsCOMPtr<nsIXULWindow> > windows; 1.785 + 1.786 + { 1.787 + MutexAutoLock lock(mListLock); 1.788 + while (mOldestWindow) { 1.789 + windows.AppendElement(mOldestWindow->mWindow); 1.790 + UnregisterWindow(mOldestWindow); 1.791 + } 1.792 + } 1.793 + mReady = false; 1.794 + } 1.795 + return NS_OK; 1.796 +} 1.797 + 1.798 +bool 1.799 +notifyOpenWindow(nsIWindowMediatorListener *aListener, void* aData) 1.800 +{ 1.801 + WindowTitleData* winData = static_cast<WindowTitleData*>(aData); 1.802 + aListener->OnOpenWindow(winData->mWindow); 1.803 + 1.804 + return true; 1.805 +} 1.806 + 1.807 +bool 1.808 +notifyCloseWindow(nsIWindowMediatorListener *aListener, void* aData) 1.809 +{ 1.810 + WindowTitleData* winData = static_cast<WindowTitleData*>(aData); 1.811 + aListener->OnCloseWindow(winData->mWindow); 1.812 + 1.813 + return true; 1.814 +} 1.815 + 1.816 +bool 1.817 +notifyWindowTitleChange(nsIWindowMediatorListener *aListener, void* aData) 1.818 +{ 1.819 + WindowTitleData* titleData = reinterpret_cast<WindowTitleData*>(aData); 1.820 + aListener->OnWindowTitleChange(titleData->mWindow, titleData->mTitle); 1.821 + 1.822 + return true; 1.823 +}