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.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim:set ts=2 sw=2 sts=2 ci et: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "mozilla/MathAlgorithms.h" |
michael@0 | 8 | |
michael@0 | 9 | // Local includes |
michael@0 | 10 | #include "nsXULWindow.h" |
michael@0 | 11 | #include <algorithm> |
michael@0 | 12 | |
michael@0 | 13 | // Helper classes |
michael@0 | 14 | #include "nsPrintfCString.h" |
michael@0 | 15 | #include "nsString.h" |
michael@0 | 16 | #include "nsWidgetsCID.h" |
michael@0 | 17 | #include "prprf.h" |
michael@0 | 18 | #include "nsCRT.h" |
michael@0 | 19 | #include "nsThreadUtils.h" |
michael@0 | 20 | #include "nsNetCID.h" |
michael@0 | 21 | |
michael@0 | 22 | //Interfaces needed to be included |
michael@0 | 23 | #include "nsIAppShell.h" |
michael@0 | 24 | #include "nsIAppShellService.h" |
michael@0 | 25 | #include "nsIServiceManager.h" |
michael@0 | 26 | #include "nsIContentViewer.h" |
michael@0 | 27 | #include "nsIDocument.h" |
michael@0 | 28 | #include "nsIDOMDocument.h" |
michael@0 | 29 | #include "nsIDOMXULDocument.h" |
michael@0 | 30 | #include "nsIDOMElement.h" |
michael@0 | 31 | #include "nsIDOMXULElement.h" |
michael@0 | 32 | #include "nsPIDOMWindow.h" |
michael@0 | 33 | #include "nsIDOMScreen.h" |
michael@0 | 34 | #include "nsIEmbeddingSiteWindow.h" |
michael@0 | 35 | #include "nsIInterfaceRequestor.h" |
michael@0 | 36 | #include "nsIInterfaceRequestorUtils.h" |
michael@0 | 37 | #include "nsIIOService.h" |
michael@0 | 38 | #include "nsIMarkupDocumentViewer.h" |
michael@0 | 39 | #include "nsIObserverService.h" |
michael@0 | 40 | #include "nsIWindowMediator.h" |
michael@0 | 41 | #include "nsIScreenManager.h" |
michael@0 | 42 | #include "nsIScreen.h" |
michael@0 | 43 | #include "nsIScrollable.h" |
michael@0 | 44 | #include "nsIScriptSecurityManager.h" |
michael@0 | 45 | #include "nsIWindowWatcher.h" |
michael@0 | 46 | #include "nsIURI.h" |
michael@0 | 47 | #include "nsIDOMCSSStyleDeclaration.h" |
michael@0 | 48 | #include "nsAppShellCID.h" |
michael@0 | 49 | #include "nsReadableUtils.h" |
michael@0 | 50 | #include "nsStyleConsts.h" |
michael@0 | 51 | #include "nsPresContext.h" |
michael@0 | 52 | #include "nsContentUtils.h" |
michael@0 | 53 | #include "nsWebShellWindow.h" // get rid of this one, too... |
michael@0 | 54 | #include "nsGlobalWindow.h" |
michael@0 | 55 | |
michael@0 | 56 | #include "prenv.h" |
michael@0 | 57 | #include "mozilla/AutoRestore.h" |
michael@0 | 58 | #include "mozilla/Preferences.h" |
michael@0 | 59 | #include "mozilla/dom/BarProps.h" |
michael@0 | 60 | #include "mozilla/dom/Element.h" |
michael@0 | 61 | #include "mozilla/dom/Event.h" |
michael@0 | 62 | #include "mozilla/dom/ScriptSettings.h" |
michael@0 | 63 | |
michael@0 | 64 | using namespace mozilla; |
michael@0 | 65 | using dom::AutoNoJSAPI; |
michael@0 | 66 | |
michael@0 | 67 | #define SIZEMODE_NORMAL NS_LITERAL_STRING("normal") |
michael@0 | 68 | #define SIZEMODE_MAXIMIZED NS_LITERAL_STRING("maximized") |
michael@0 | 69 | #define SIZEMODE_MINIMIZED NS_LITERAL_STRING("minimized") |
michael@0 | 70 | #define SIZEMODE_FULLSCREEN NS_LITERAL_STRING("fullscreen") |
michael@0 | 71 | |
michael@0 | 72 | #define WINDOWTYPE_ATTRIBUTE NS_LITERAL_STRING("windowtype") |
michael@0 | 73 | |
michael@0 | 74 | #define PERSIST_ATTRIBUTE NS_LITERAL_STRING("persist") |
michael@0 | 75 | #define SCREENX_ATTRIBUTE NS_LITERAL_STRING("screenX") |
michael@0 | 76 | #define SCREENY_ATTRIBUTE NS_LITERAL_STRING("screenY") |
michael@0 | 77 | #define WIDTH_ATTRIBUTE NS_LITERAL_STRING("width") |
michael@0 | 78 | #define HEIGHT_ATTRIBUTE NS_LITERAL_STRING("height") |
michael@0 | 79 | #define MODE_ATTRIBUTE NS_LITERAL_STRING("sizemode") |
michael@0 | 80 | #define ZLEVEL_ATTRIBUTE NS_LITERAL_STRING("zlevel") |
michael@0 | 81 | |
michael@0 | 82 | |
michael@0 | 83 | //***************************************************************************** |
michael@0 | 84 | //*** nsXULWindow: Object Management |
michael@0 | 85 | //***************************************************************************** |
michael@0 | 86 | |
michael@0 | 87 | nsXULWindow::nsXULWindow(uint32_t aChromeFlags) |
michael@0 | 88 | : mChromeTreeOwner(nullptr), |
michael@0 | 89 | mContentTreeOwner(nullptr), |
michael@0 | 90 | mPrimaryContentTreeOwner(nullptr), |
michael@0 | 91 | mModalStatus(NS_OK), |
michael@0 | 92 | mContinueModalLoop(false), |
michael@0 | 93 | mDebuting(false), |
michael@0 | 94 | mChromeLoaded(false), |
michael@0 | 95 | mShowAfterLoad(false), |
michael@0 | 96 | mIntrinsicallySized(false), |
michael@0 | 97 | mCenterAfterLoad(false), |
michael@0 | 98 | mIsHiddenWindow(false), |
michael@0 | 99 | mLockedUntilChromeLoad(false), |
michael@0 | 100 | mIgnoreXULSize(false), |
michael@0 | 101 | mIgnoreXULPosition(false), |
michael@0 | 102 | mChromeFlagsFrozen(false), |
michael@0 | 103 | mIgnoreXULSizeMode(false), |
michael@0 | 104 | mDestroying(false), |
michael@0 | 105 | mContextFlags(0), |
michael@0 | 106 | mPersistentAttributesDirty(0), |
michael@0 | 107 | mPersistentAttributesMask(0), |
michael@0 | 108 | mChromeFlags(aChromeFlags) |
michael@0 | 109 | { |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | nsXULWindow::~nsXULWindow() |
michael@0 | 113 | { |
michael@0 | 114 | Destroy(); |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | //***************************************************************************** |
michael@0 | 118 | // nsXULWindow::nsISupports |
michael@0 | 119 | //***************************************************************************** |
michael@0 | 120 | |
michael@0 | 121 | NS_IMPL_ADDREF(nsXULWindow) |
michael@0 | 122 | NS_IMPL_RELEASE(nsXULWindow) |
michael@0 | 123 | |
michael@0 | 124 | NS_INTERFACE_MAP_BEGIN(nsXULWindow) |
michael@0 | 125 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULWindow) |
michael@0 | 126 | NS_INTERFACE_MAP_ENTRY(nsIXULWindow) |
michael@0 | 127 | NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) |
michael@0 | 128 | NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) |
michael@0 | 129 | NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) |
michael@0 | 130 | if (aIID.Equals(NS_GET_IID(nsXULWindow))) |
michael@0 | 131 | foundInterface = reinterpret_cast<nsISupports*>(this); |
michael@0 | 132 | else |
michael@0 | 133 | NS_INTERFACE_MAP_END |
michael@0 | 134 | |
michael@0 | 135 | //***************************************************************************** |
michael@0 | 136 | // nsXULWindow::nsIIntefaceRequestor |
michael@0 | 137 | //***************************************************************************** |
michael@0 | 138 | |
michael@0 | 139 | NS_IMETHODIMP nsXULWindow::GetInterface(const nsIID& aIID, void** aSink) |
michael@0 | 140 | { |
michael@0 | 141 | nsresult rv; |
michael@0 | 142 | |
michael@0 | 143 | NS_ENSURE_ARG_POINTER(aSink); |
michael@0 | 144 | |
michael@0 | 145 | if (aIID.Equals(NS_GET_IID(nsIPrompt))) { |
michael@0 | 146 | rv = EnsurePrompter(); |
michael@0 | 147 | if (NS_FAILED(rv)) return rv; |
michael@0 | 148 | return mPrompter->QueryInterface(aIID, aSink); |
michael@0 | 149 | } |
michael@0 | 150 | if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) { |
michael@0 | 151 | rv = EnsureAuthPrompter(); |
michael@0 | 152 | if (NS_FAILED(rv)) return rv; |
michael@0 | 153 | return mAuthPrompter->QueryInterface(aIID, aSink); |
michael@0 | 154 | } |
michael@0 | 155 | if (aIID.Equals(NS_GET_IID(nsIDOMWindow))) { |
michael@0 | 156 | return GetWindowDOMWindow(reinterpret_cast<nsIDOMWindow**>(aSink)); |
michael@0 | 157 | } |
michael@0 | 158 | if (aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) { |
michael@0 | 159 | nsIDOMWindow* domWindow = nullptr; |
michael@0 | 160 | rv = GetWindowDOMWindow(&domWindow); |
michael@0 | 161 | nsIDOMWindowInternal* domWindowInternal = |
michael@0 | 162 | static_cast<nsIDOMWindowInternal*>(domWindow); |
michael@0 | 163 | *aSink = domWindowInternal; |
michael@0 | 164 | return rv; |
michael@0 | 165 | } |
michael@0 | 166 | if (aIID.Equals(NS_GET_IID(nsIWebBrowserChrome)) && |
michael@0 | 167 | NS_SUCCEEDED(EnsureContentTreeOwner()) && |
michael@0 | 168 | NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink))) |
michael@0 | 169 | return NS_OK; |
michael@0 | 170 | |
michael@0 | 171 | if (aIID.Equals(NS_GET_IID(nsIEmbeddingSiteWindow)) && |
michael@0 | 172 | NS_SUCCEEDED(EnsureContentTreeOwner()) && |
michael@0 | 173 | NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink))) |
michael@0 | 174 | return NS_OK; |
michael@0 | 175 | |
michael@0 | 176 | return QueryInterface(aIID, aSink); |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | //***************************************************************************** |
michael@0 | 180 | // nsXULWindow::nsIXULWindow |
michael@0 | 181 | //***************************************************************************** |
michael@0 | 182 | |
michael@0 | 183 | NS_IMETHODIMP nsXULWindow::GetDocShell(nsIDocShell** aDocShell) |
michael@0 | 184 | { |
michael@0 | 185 | NS_ENSURE_ARG_POINTER(aDocShell); |
michael@0 | 186 | |
michael@0 | 187 | *aDocShell = mDocShell; |
michael@0 | 188 | NS_IF_ADDREF(*aDocShell); |
michael@0 | 189 | return NS_OK; |
michael@0 | 190 | } |
michael@0 | 191 | |
michael@0 | 192 | NS_IMETHODIMP nsXULWindow::GetZLevel(uint32_t *outLevel) |
michael@0 | 193 | { |
michael@0 | 194 | nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); |
michael@0 | 195 | if (mediator) |
michael@0 | 196 | mediator->GetZLevel(this, outLevel); |
michael@0 | 197 | else |
michael@0 | 198 | *outLevel = normalZ; |
michael@0 | 199 | return NS_OK; |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | NS_IMETHODIMP nsXULWindow::SetZLevel(uint32_t aLevel) |
michael@0 | 203 | { |
michael@0 | 204 | nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); |
michael@0 | 205 | if (!mediator) |
michael@0 | 206 | return NS_ERROR_FAILURE; |
michael@0 | 207 | |
michael@0 | 208 | uint32_t zLevel; |
michael@0 | 209 | mediator->GetZLevel(this, &zLevel); |
michael@0 | 210 | if (zLevel == aLevel) |
michael@0 | 211 | return NS_OK; |
michael@0 | 212 | |
michael@0 | 213 | /* refuse to raise a maximized window above the normal browser level, |
michael@0 | 214 | for fear it could hide newly opened browser windows */ |
michael@0 | 215 | if (aLevel > nsIXULWindow::normalZ && mWindow) { |
michael@0 | 216 | int32_t sizeMode = mWindow->SizeMode(); |
michael@0 | 217 | if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) { |
michael@0 | 218 | return NS_ERROR_FAILURE; |
michael@0 | 219 | } |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | // do it |
michael@0 | 223 | mediator->SetZLevel(this, aLevel); |
michael@0 | 224 | PersistentAttributesDirty(PAD_MISC); |
michael@0 | 225 | SavePersistentAttributes(); |
michael@0 | 226 | |
michael@0 | 227 | nsCOMPtr<nsIContentViewer> cv; |
michael@0 | 228 | mDocShell->GetContentViewer(getter_AddRefs(cv)); |
michael@0 | 229 | if (cv) { |
michael@0 | 230 | nsCOMPtr<nsIDocument> doc = cv->GetDocument(); |
michael@0 | 231 | if (doc) { |
michael@0 | 232 | ErrorResult rv; |
michael@0 | 233 | nsRefPtr<dom::Event> event = |
michael@0 | 234 | doc->CreateEvent(NS_LITERAL_STRING("Events"),rv); |
michael@0 | 235 | if (event) { |
michael@0 | 236 | event->InitEvent(NS_LITERAL_STRING("windowZLevel"), true, false); |
michael@0 | 237 | |
michael@0 | 238 | event->SetTrusted(true); |
michael@0 | 239 | |
michael@0 | 240 | bool defaultActionEnabled; |
michael@0 | 241 | doc->DispatchEvent(event, &defaultActionEnabled); |
michael@0 | 242 | } |
michael@0 | 243 | } |
michael@0 | 244 | } |
michael@0 | 245 | return NS_OK; |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | NS_IMETHODIMP nsXULWindow::GetContextFlags(uint32_t *aContextFlags) |
michael@0 | 249 | { |
michael@0 | 250 | NS_ENSURE_ARG_POINTER(aContextFlags); |
michael@0 | 251 | *aContextFlags = mContextFlags; |
michael@0 | 252 | return NS_OK; |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | NS_IMETHODIMP nsXULWindow::SetContextFlags(uint32_t aContextFlags) |
michael@0 | 256 | { |
michael@0 | 257 | mContextFlags = aContextFlags; |
michael@0 | 258 | return NS_OK; |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | NS_IMETHODIMP nsXULWindow::GetChromeFlags(uint32_t *aChromeFlags) |
michael@0 | 262 | { |
michael@0 | 263 | NS_ENSURE_ARG_POINTER(aChromeFlags); |
michael@0 | 264 | *aChromeFlags = mChromeFlags; |
michael@0 | 265 | /* mChromeFlags is kept up to date, except for scrollbar visibility. |
michael@0 | 266 | That can be changed directly by the content DOM window, which |
michael@0 | 267 | doesn't know to update the chrome window. So that we must check |
michael@0 | 268 | separately. */ |
michael@0 | 269 | |
michael@0 | 270 | // however, it's pointless to ask if the window isn't set up yet |
michael@0 | 271 | if (!mChromeLoaded) |
michael@0 | 272 | return NS_OK; |
michael@0 | 273 | |
michael@0 | 274 | if (GetContentScrollbarVisibility()) |
michael@0 | 275 | *aChromeFlags |= nsIWebBrowserChrome::CHROME_SCROLLBARS; |
michael@0 | 276 | else |
michael@0 | 277 | *aChromeFlags &= ~nsIWebBrowserChrome::CHROME_SCROLLBARS; |
michael@0 | 278 | |
michael@0 | 279 | return NS_OK; |
michael@0 | 280 | } |
michael@0 | 281 | |
michael@0 | 282 | NS_IMETHODIMP nsXULWindow::SetChromeFlags(uint32_t aChromeFlags) |
michael@0 | 283 | { |
michael@0 | 284 | NS_ASSERTION(!mChromeFlagsFrozen, |
michael@0 | 285 | "SetChromeFlags() after AssumeChromeFlagsAreFrozen()!"); |
michael@0 | 286 | |
michael@0 | 287 | mChromeFlags = aChromeFlags; |
michael@0 | 288 | if (mChromeLoaded) |
michael@0 | 289 | NS_ENSURE_SUCCESS(ApplyChromeFlags(), NS_ERROR_FAILURE); |
michael@0 | 290 | return NS_OK; |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | NS_IMETHODIMP nsXULWindow::AssumeChromeFlagsAreFrozen() |
michael@0 | 294 | { |
michael@0 | 295 | mChromeFlagsFrozen = true; |
michael@0 | 296 | return NS_OK; |
michael@0 | 297 | } |
michael@0 | 298 | |
michael@0 | 299 | NS_IMETHODIMP nsXULWindow::SetIntrinsicallySized(bool aIntrinsicallySized) |
michael@0 | 300 | { |
michael@0 | 301 | mIntrinsicallySized = aIntrinsicallySized; |
michael@0 | 302 | return NS_OK; |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | NS_IMETHODIMP nsXULWindow::GetIntrinsicallySized(bool* aIntrinsicallySized) |
michael@0 | 306 | { |
michael@0 | 307 | NS_ENSURE_ARG_POINTER(aIntrinsicallySized); |
michael@0 | 308 | |
michael@0 | 309 | *aIntrinsicallySized = mIntrinsicallySized; |
michael@0 | 310 | return NS_OK; |
michael@0 | 311 | } |
michael@0 | 312 | |
michael@0 | 313 | NS_IMETHODIMP nsXULWindow::GetPrimaryContentShell(nsIDocShellTreeItem** |
michael@0 | 314 | aDocShellTreeItem) |
michael@0 | 315 | { |
michael@0 | 316 | NS_ENSURE_ARG_POINTER(aDocShellTreeItem); |
michael@0 | 317 | NS_IF_ADDREF(*aDocShellTreeItem = mPrimaryContentShell); |
michael@0 | 318 | return NS_OK; |
michael@0 | 319 | } |
michael@0 | 320 | |
michael@0 | 321 | NS_IMETHODIMP nsXULWindow::GetContentShellById(const char16_t* aID, |
michael@0 | 322 | nsIDocShellTreeItem** aDocShellTreeItem) |
michael@0 | 323 | { |
michael@0 | 324 | NS_ENSURE_ARG_POINTER(aDocShellTreeItem); |
michael@0 | 325 | *aDocShellTreeItem = nullptr; |
michael@0 | 326 | |
michael@0 | 327 | uint32_t count = mContentShells.Length(); |
michael@0 | 328 | for (uint32_t i = 0; i < count; i++) { |
michael@0 | 329 | nsContentShellInfo* shellInfo = mContentShells.ElementAt(i); |
michael@0 | 330 | if (shellInfo->id.Equals(aID)) { |
michael@0 | 331 | *aDocShellTreeItem = nullptr; |
michael@0 | 332 | if (shellInfo->child) |
michael@0 | 333 | CallQueryReferent(shellInfo->child.get(), aDocShellTreeItem); |
michael@0 | 334 | return NS_OK; |
michael@0 | 335 | } |
michael@0 | 336 | } |
michael@0 | 337 | return NS_ERROR_FAILURE; |
michael@0 | 338 | } |
michael@0 | 339 | |
michael@0 | 340 | NS_IMETHODIMP nsXULWindow::AddChildWindow(nsIXULWindow *aChild) |
michael@0 | 341 | { |
michael@0 | 342 | // we're not really keeping track of this right now |
michael@0 | 343 | return NS_OK; |
michael@0 | 344 | } |
michael@0 | 345 | |
michael@0 | 346 | NS_IMETHODIMP nsXULWindow::RemoveChildWindow(nsIXULWindow *aChild) |
michael@0 | 347 | { |
michael@0 | 348 | // we're not really keeping track of this right now |
michael@0 | 349 | return NS_OK; |
michael@0 | 350 | } |
michael@0 | 351 | |
michael@0 | 352 | NS_IMETHODIMP nsXULWindow::ShowModal() |
michael@0 | 353 | { |
michael@0 | 354 | // Store locally so it doesn't die on us |
michael@0 | 355 | nsCOMPtr<nsIWidget> window = mWindow; |
michael@0 | 356 | nsCOMPtr<nsIXULWindow> tempRef = this; |
michael@0 | 357 | |
michael@0 | 358 | window->SetModal(true); |
michael@0 | 359 | mContinueModalLoop = true; |
michael@0 | 360 | EnableParent(false); |
michael@0 | 361 | |
michael@0 | 362 | { |
michael@0 | 363 | AutoNoJSAPI nojsapi; |
michael@0 | 364 | nsIThread *thread = NS_GetCurrentThread(); |
michael@0 | 365 | while (mContinueModalLoop) { |
michael@0 | 366 | if (!NS_ProcessNextEvent(thread)) |
michael@0 | 367 | break; |
michael@0 | 368 | } |
michael@0 | 369 | } |
michael@0 | 370 | |
michael@0 | 371 | mContinueModalLoop = false; |
michael@0 | 372 | window->SetModal(false); |
michael@0 | 373 | /* Note there's no EnableParent(true) here to match the false one |
michael@0 | 374 | above. That's done in ExitModalLoop. It's important that the parent |
michael@0 | 375 | be re-enabled before this window is made invisible; to do otherwise |
michael@0 | 376 | causes bizarre z-ordering problems. At this point, the window is |
michael@0 | 377 | already invisible. |
michael@0 | 378 | No known current implementation of Enable would have a problem with |
michael@0 | 379 | re-enabling the parent twice, so we could do it again here without |
michael@0 | 380 | breaking any current implementation. But that's unnecessary if the |
michael@0 | 381 | modal loop is always exited using ExitModalLoop (the other way would be |
michael@0 | 382 | to change the protected member variable directly.) |
michael@0 | 383 | */ |
michael@0 | 384 | |
michael@0 | 385 | return mModalStatus; |
michael@0 | 386 | } |
michael@0 | 387 | |
michael@0 | 388 | //***************************************************************************** |
michael@0 | 389 | // nsXULWindow::nsIBaseWindow |
michael@0 | 390 | //***************************************************************************** |
michael@0 | 391 | |
michael@0 | 392 | NS_IMETHODIMP nsXULWindow::InitWindow(nativeWindow aParentNativeWindow, |
michael@0 | 393 | nsIWidget* parentWidget, int32_t x, int32_t y, int32_t cx, int32_t cy) |
michael@0 | 394 | { |
michael@0 | 395 | //XXX First Check In |
michael@0 | 396 | NS_ASSERTION(false, "Not Yet Implemented"); |
michael@0 | 397 | return NS_OK; |
michael@0 | 398 | } |
michael@0 | 399 | |
michael@0 | 400 | NS_IMETHODIMP nsXULWindow::Create() |
michael@0 | 401 | { |
michael@0 | 402 | //XXX First Check In |
michael@0 | 403 | NS_ASSERTION(false, "Not Yet Implemented"); |
michael@0 | 404 | return NS_OK; |
michael@0 | 405 | } |
michael@0 | 406 | |
michael@0 | 407 | NS_IMETHODIMP nsXULWindow::Destroy() |
michael@0 | 408 | { |
michael@0 | 409 | if (!mWindow) |
michael@0 | 410 | return NS_OK; |
michael@0 | 411 | |
michael@0 | 412 | // Ensure we don't reenter this code |
michael@0 | 413 | if (mDestroying) |
michael@0 | 414 | return NS_OK; |
michael@0 | 415 | |
michael@0 | 416 | mozilla::AutoRestore<bool> guard(mDestroying); |
michael@0 | 417 | mDestroying = true; |
michael@0 | 418 | |
michael@0 | 419 | nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); |
michael@0 | 420 | NS_ASSERTION(appShell, "Couldn't get appShell... xpcom shutdown?"); |
michael@0 | 421 | if (appShell) |
michael@0 | 422 | appShell->UnregisterTopLevelWindow(static_cast<nsIXULWindow*>(this)); |
michael@0 | 423 | |
michael@0 | 424 | nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow)); |
michael@0 | 425 | if (parentWindow) |
michael@0 | 426 | parentWindow->RemoveChildWindow(this); |
michael@0 | 427 | |
michael@0 | 428 | // let's make sure the window doesn't get deleted out from under us |
michael@0 | 429 | // while we are trying to close....this can happen if the docshell |
michael@0 | 430 | // we close ends up being the last owning reference to this xulwindow |
michael@0 | 431 | |
michael@0 | 432 | // XXXTAB This shouldn't be an issue anymore because the ownership model |
michael@0 | 433 | // only goes in one direction. When webshell container is fully removed |
michael@0 | 434 | // try removing this... |
michael@0 | 435 | |
michael@0 | 436 | nsCOMPtr<nsIXULWindow> placeHolder = this; |
michael@0 | 437 | |
michael@0 | 438 | // Remove modality (if any) and hide while destroying. More than |
michael@0 | 439 | // a convenience, the hide prevents user interaction with the partially |
michael@0 | 440 | // destroyed window. This is especially necessary when the eldest window |
michael@0 | 441 | // in a stack of modal windows is destroyed first. It happens. |
michael@0 | 442 | ExitModalLoop(NS_OK); |
michael@0 | 443 | if (mWindow) |
michael@0 | 444 | mWindow->Show(false); |
michael@0 | 445 | |
michael@0 | 446 | #if defined(XP_WIN) |
michael@0 | 447 | // We need to explicitly set the focus on Windows, but |
michael@0 | 448 | // only if the parent is visible. |
michael@0 | 449 | nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow)); |
michael@0 | 450 | if (parent) { |
michael@0 | 451 | nsCOMPtr<nsIWidget> parentWidget; |
michael@0 | 452 | parent->GetMainWidget(getter_AddRefs(parentWidget)); |
michael@0 | 453 | if (!parentWidget || parentWidget->IsVisible()) { |
michael@0 | 454 | nsCOMPtr<nsIBaseWindow> baseHiddenWindow; |
michael@0 | 455 | if (appShell) { |
michael@0 | 456 | nsCOMPtr<nsIXULWindow> hiddenWindow; |
michael@0 | 457 | appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow)); |
michael@0 | 458 | if (hiddenWindow) |
michael@0 | 459 | baseHiddenWindow = do_GetInterface(hiddenWindow); |
michael@0 | 460 | } |
michael@0 | 461 | // somebody screwed up somewhere. hiddenwindow shouldn't be anybody's |
michael@0 | 462 | // parent. still, when it happens, skip activating it. |
michael@0 | 463 | if (baseHiddenWindow != parent) { |
michael@0 | 464 | nsCOMPtr<nsIWidget> parentWidget; |
michael@0 | 465 | parent->GetMainWidget(getter_AddRefs(parentWidget)); |
michael@0 | 466 | if (parentWidget) |
michael@0 | 467 | parentWidget->PlaceBehind(eZPlacementTop, 0, true); |
michael@0 | 468 | } |
michael@0 | 469 | } |
michael@0 | 470 | } |
michael@0 | 471 | #endif |
michael@0 | 472 | |
michael@0 | 473 | mDOMWindow = nullptr; |
michael@0 | 474 | if (mDocShell) { |
michael@0 | 475 | nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell)); |
michael@0 | 476 | shellAsWin->Destroy(); |
michael@0 | 477 | mDocShell = nullptr; // this can cause reentrancy of this function |
michael@0 | 478 | } |
michael@0 | 479 | |
michael@0 | 480 | // Remove our ref on the content shells |
michael@0 | 481 | uint32_t count = mContentShells.Length(); |
michael@0 | 482 | for (uint32_t i = 0; i < count; i++) { |
michael@0 | 483 | nsContentShellInfo* shellInfo = mContentShells.ElementAt(i); |
michael@0 | 484 | delete shellInfo; |
michael@0 | 485 | } |
michael@0 | 486 | mContentShells.Clear(); |
michael@0 | 487 | mPrimaryContentShell = nullptr; |
michael@0 | 488 | |
michael@0 | 489 | if (mContentTreeOwner) { |
michael@0 | 490 | mContentTreeOwner->XULWindow(nullptr); |
michael@0 | 491 | NS_RELEASE(mContentTreeOwner); |
michael@0 | 492 | } |
michael@0 | 493 | if (mPrimaryContentTreeOwner) { |
michael@0 | 494 | mPrimaryContentTreeOwner->XULWindow(nullptr); |
michael@0 | 495 | NS_RELEASE(mPrimaryContentTreeOwner); |
michael@0 | 496 | } |
michael@0 | 497 | if (mChromeTreeOwner) { |
michael@0 | 498 | mChromeTreeOwner->XULWindow(nullptr); |
michael@0 | 499 | NS_RELEASE(mChromeTreeOwner); |
michael@0 | 500 | } |
michael@0 | 501 | if (mWindow) { |
michael@0 | 502 | mWindow->SetWidgetListener(nullptr); // nsWebShellWindow hackery |
michael@0 | 503 | mWindow->Destroy(); |
michael@0 | 504 | mWindow = nullptr; |
michael@0 | 505 | } |
michael@0 | 506 | |
michael@0 | 507 | if (!mIsHiddenWindow) { |
michael@0 | 508 | /* Inform appstartup we've destroyed this window and it could |
michael@0 | 509 | quit now if it wanted. This must happen at least after mDocShell |
michael@0 | 510 | is destroyed, because onunload handlers fire then, and those being |
michael@0 | 511 | script, anything could happen. A new window could open, even. |
michael@0 | 512 | See bug 130719. */ |
michael@0 | 513 | nsCOMPtr<nsIObserverService> obssvc = |
michael@0 | 514 | do_GetService("@mozilla.org/observer-service;1"); |
michael@0 | 515 | NS_ASSERTION(obssvc, "Couldn't get observer service?"); |
michael@0 | 516 | |
michael@0 | 517 | if (obssvc) |
michael@0 | 518 | obssvc->NotifyObservers(nullptr, "xul-window-destroyed", nullptr); |
michael@0 | 519 | } |
michael@0 | 520 | |
michael@0 | 521 | return NS_OK; |
michael@0 | 522 | } |
michael@0 | 523 | |
michael@0 | 524 | NS_IMETHODIMP nsXULWindow::GetUnscaledDevicePixelsPerCSSPixel(double *aScale) |
michael@0 | 525 | { |
michael@0 | 526 | *aScale = mWindow ? mWindow->GetDefaultScale().scale : 1.0; |
michael@0 | 527 | return NS_OK; |
michael@0 | 528 | } |
michael@0 | 529 | |
michael@0 | 530 | NS_IMETHODIMP nsXULWindow::SetPosition(int32_t aX, int32_t aY) |
michael@0 | 531 | { |
michael@0 | 532 | // Don't reset the window's size mode here - platforms that don't want to move |
michael@0 | 533 | // maximized windows should reset it in their respective Move implementation. |
michael@0 | 534 | CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); |
michael@0 | 535 | double invScale = 1.0 / scale.scale; |
michael@0 | 536 | nsresult rv = mWindow->Move(aX * invScale, aY * invScale); |
michael@0 | 537 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
michael@0 | 538 | if (!mChromeLoaded) { |
michael@0 | 539 | // If we're called before the chrome is loaded someone obviously wants this |
michael@0 | 540 | // window at this position. We don't persist this one-time position. |
michael@0 | 541 | mIgnoreXULPosition = true; |
michael@0 | 542 | return NS_OK; |
michael@0 | 543 | } |
michael@0 | 544 | PersistentAttributesDirty(PAD_POSITION); |
michael@0 | 545 | SavePersistentAttributes(); |
michael@0 | 546 | return NS_OK; |
michael@0 | 547 | } |
michael@0 | 548 | |
michael@0 | 549 | NS_IMETHODIMP nsXULWindow::GetPosition(int32_t* aX, int32_t* aY) |
michael@0 | 550 | { |
michael@0 | 551 | return GetPositionAndSize(aX, aY, nullptr, nullptr); |
michael@0 | 552 | } |
michael@0 | 553 | |
michael@0 | 554 | NS_IMETHODIMP nsXULWindow::SetSize(int32_t aCX, int32_t aCY, bool aRepaint) |
michael@0 | 555 | { |
michael@0 | 556 | /* any attempt to set the window's size or position overrides the window's |
michael@0 | 557 | zoom state. this is important when these two states are competing while |
michael@0 | 558 | the window is being opened. but it should probably just always be so. */ |
michael@0 | 559 | mWindow->SetSizeMode(nsSizeMode_Normal); |
michael@0 | 560 | |
michael@0 | 561 | mIntrinsicallySized = false; |
michael@0 | 562 | |
michael@0 | 563 | CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); |
michael@0 | 564 | double invScale = 1.0 / scale.scale; |
michael@0 | 565 | nsresult rv = mWindow->Resize(aCX * invScale, aCY * invScale, aRepaint); |
michael@0 | 566 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
michael@0 | 567 | if (!mChromeLoaded) { |
michael@0 | 568 | // If we're called before the chrome is loaded someone obviously wants this |
michael@0 | 569 | // window at this size & in the normal size mode (since it is the only mode |
michael@0 | 570 | // in which setting dimensions makes sense). We don't persist this one-time |
michael@0 | 571 | // size. |
michael@0 | 572 | mIgnoreXULSize = true; |
michael@0 | 573 | mIgnoreXULSizeMode = true; |
michael@0 | 574 | return NS_OK; |
michael@0 | 575 | } |
michael@0 | 576 | PersistentAttributesDirty(PAD_SIZE); |
michael@0 | 577 | SavePersistentAttributes(); |
michael@0 | 578 | return NS_OK; |
michael@0 | 579 | } |
michael@0 | 580 | |
michael@0 | 581 | NS_IMETHODIMP nsXULWindow::GetSize(int32_t* aCX, int32_t* aCY) |
michael@0 | 582 | { |
michael@0 | 583 | return GetPositionAndSize(nullptr, nullptr, aCX, aCY); |
michael@0 | 584 | } |
michael@0 | 585 | |
michael@0 | 586 | NS_IMETHODIMP nsXULWindow::SetPositionAndSize(int32_t aX, int32_t aY, |
michael@0 | 587 | int32_t aCX, int32_t aCY, bool aRepaint) |
michael@0 | 588 | { |
michael@0 | 589 | /* any attempt to set the window's size or position overrides the window's |
michael@0 | 590 | zoom state. this is important when these two states are competing while |
michael@0 | 591 | the window is being opened. but it should probably just always be so. */ |
michael@0 | 592 | mWindow->SetSizeMode(nsSizeMode_Normal); |
michael@0 | 593 | |
michael@0 | 594 | mIntrinsicallySized = false; |
michael@0 | 595 | |
michael@0 | 596 | CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); |
michael@0 | 597 | double invScale = 1.0 / scale.scale; |
michael@0 | 598 | nsresult rv = mWindow->Resize(aX * invScale, aY * invScale, |
michael@0 | 599 | aCX * invScale, aCY * invScale, |
michael@0 | 600 | aRepaint); |
michael@0 | 601 | NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); |
michael@0 | 602 | if (!mChromeLoaded) { |
michael@0 | 603 | // If we're called before the chrome is loaded someone obviously wants this |
michael@0 | 604 | // window at this size and position. We don't persist this one-time setting. |
michael@0 | 605 | mIgnoreXULPosition = true; |
michael@0 | 606 | mIgnoreXULSize = true; |
michael@0 | 607 | mIgnoreXULSizeMode = true; |
michael@0 | 608 | return NS_OK; |
michael@0 | 609 | } |
michael@0 | 610 | PersistentAttributesDirty(PAD_POSITION | PAD_SIZE); |
michael@0 | 611 | SavePersistentAttributes(); |
michael@0 | 612 | return NS_OK; |
michael@0 | 613 | } |
michael@0 | 614 | |
michael@0 | 615 | NS_IMETHODIMP nsXULWindow::GetPositionAndSize(int32_t* x, int32_t* y, int32_t* cx, |
michael@0 | 616 | int32_t* cy) |
michael@0 | 617 | { |
michael@0 | 618 | nsIntRect rect; |
michael@0 | 619 | |
michael@0 | 620 | if (!mWindow) |
michael@0 | 621 | return NS_ERROR_FAILURE; |
michael@0 | 622 | |
michael@0 | 623 | mWindow->GetScreenBounds(rect); |
michael@0 | 624 | |
michael@0 | 625 | if (x) |
michael@0 | 626 | *x = rect.x; |
michael@0 | 627 | if (y) |
michael@0 | 628 | *y = rect.y; |
michael@0 | 629 | if (cx) |
michael@0 | 630 | *cx = rect.width; |
michael@0 | 631 | if (cy) |
michael@0 | 632 | *cy = rect.height; |
michael@0 | 633 | |
michael@0 | 634 | return NS_OK; |
michael@0 | 635 | } |
michael@0 | 636 | |
michael@0 | 637 | NS_IMETHODIMP nsXULWindow::Center(nsIXULWindow *aRelative, bool aScreen, bool aAlert) |
michael@0 | 638 | { |
michael@0 | 639 | int32_t left, top, width, height, |
michael@0 | 640 | ourWidth, ourHeight; |
michael@0 | 641 | bool screenCoordinates = false, |
michael@0 | 642 | windowCoordinates = false; |
michael@0 | 643 | nsresult result; |
michael@0 | 644 | |
michael@0 | 645 | if (!mChromeLoaded) { |
michael@0 | 646 | // note we lose the parameters. at time of writing, this isn't a problem. |
michael@0 | 647 | mCenterAfterLoad = true; |
michael@0 | 648 | return NS_OK; |
michael@0 | 649 | } |
michael@0 | 650 | |
michael@0 | 651 | if (!aScreen && !aRelative) |
michael@0 | 652 | return NS_ERROR_INVALID_ARG; |
michael@0 | 653 | |
michael@0 | 654 | nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1", &result); |
michael@0 | 655 | if (NS_FAILED(result)) |
michael@0 | 656 | return result; |
michael@0 | 657 | |
michael@0 | 658 | nsCOMPtr<nsIScreen> screen; |
michael@0 | 659 | |
michael@0 | 660 | if (aRelative) { |
michael@0 | 661 | nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(aRelative, &result)); |
michael@0 | 662 | if (base) { |
michael@0 | 663 | // get window rect |
michael@0 | 664 | result = base->GetPositionAndSize(&left, &top, &width, &height); |
michael@0 | 665 | if (NS_SUCCEEDED(result)) { |
michael@0 | 666 | double scale; |
michael@0 | 667 | if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) { |
michael@0 | 668 | // convert device-pixel coordinates to global display pixels |
michael@0 | 669 | left = NSToIntRound(left / scale); |
michael@0 | 670 | top = NSToIntRound(top / scale); |
michael@0 | 671 | width = NSToIntRound(width / scale); |
michael@0 | 672 | height = NSToIntRound(height / scale); |
michael@0 | 673 | } |
michael@0 | 674 | // if centering on screen, convert that to the corresponding screen |
michael@0 | 675 | if (aScreen) |
michael@0 | 676 | screenmgr->ScreenForRect(left, top, width, height, getter_AddRefs(screen)); |
michael@0 | 677 | else |
michael@0 | 678 | windowCoordinates = true; |
michael@0 | 679 | } else { |
michael@0 | 680 | // something's wrong with the reference window. |
michael@0 | 681 | // fall back to the primary screen |
michael@0 | 682 | aRelative = 0; |
michael@0 | 683 | aScreen = true; |
michael@0 | 684 | } |
michael@0 | 685 | } |
michael@0 | 686 | } |
michael@0 | 687 | if (!aRelative) { |
michael@0 | 688 | if (!mOpenerScreenRect.IsEmpty()) { |
michael@0 | 689 | // FIXME - check if these are device or display pixels |
michael@0 | 690 | screenmgr->ScreenForRect(mOpenerScreenRect.x, mOpenerScreenRect.y, |
michael@0 | 691 | mOpenerScreenRect.width, mOpenerScreenRect.height, |
michael@0 | 692 | getter_AddRefs(screen)); |
michael@0 | 693 | } else { |
michael@0 | 694 | screenmgr->GetPrimaryScreen(getter_AddRefs(screen)); |
michael@0 | 695 | } |
michael@0 | 696 | } |
michael@0 | 697 | |
michael@0 | 698 | if (aScreen && screen) { |
michael@0 | 699 | screen->GetAvailRectDisplayPix(&left, &top, &width, &height); |
michael@0 | 700 | screenCoordinates = true; |
michael@0 | 701 | } |
michael@0 | 702 | |
michael@0 | 703 | if (screenCoordinates || windowCoordinates) { |
michael@0 | 704 | NS_ASSERTION(mWindow, "what, no window?"); |
michael@0 | 705 | CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); |
michael@0 | 706 | GetSize(&ourWidth, &ourHeight); |
michael@0 | 707 | ourWidth = NSToIntRound(ourWidth / scale.scale); |
michael@0 | 708 | ourHeight = NSToIntRound(ourHeight / scale.scale); |
michael@0 | 709 | left += (width - ourWidth) / 2; |
michael@0 | 710 | top += (height - ourHeight) / (aAlert ? 3 : 2); |
michael@0 | 711 | if (windowCoordinates) { |
michael@0 | 712 | mWindow->ConstrainPosition(false, &left, &top); |
michael@0 | 713 | } |
michael@0 | 714 | SetPosition(left * scale.scale, top * scale.scale); |
michael@0 | 715 | return NS_OK; |
michael@0 | 716 | } |
michael@0 | 717 | return NS_ERROR_FAILURE; |
michael@0 | 718 | } |
michael@0 | 719 | |
michael@0 | 720 | NS_IMETHODIMP nsXULWindow::Repaint(bool aForce) |
michael@0 | 721 | { |
michael@0 | 722 | //XXX First Check In |
michael@0 | 723 | NS_ASSERTION(false, "Not Yet Implemented"); |
michael@0 | 724 | return NS_OK; |
michael@0 | 725 | } |
michael@0 | 726 | |
michael@0 | 727 | NS_IMETHODIMP nsXULWindow::GetParentWidget(nsIWidget** aParentWidget) |
michael@0 | 728 | { |
michael@0 | 729 | NS_ENSURE_ARG_POINTER(aParentWidget); |
michael@0 | 730 | NS_ENSURE_STATE(mWindow); |
michael@0 | 731 | |
michael@0 | 732 | NS_IF_ADDREF(*aParentWidget = mWindow->GetParent()); |
michael@0 | 733 | return NS_OK; |
michael@0 | 734 | } |
michael@0 | 735 | |
michael@0 | 736 | NS_IMETHODIMP nsXULWindow::SetParentWidget(nsIWidget* aParentWidget) |
michael@0 | 737 | { |
michael@0 | 738 | //XXX First Check In |
michael@0 | 739 | NS_ASSERTION(false, "Not Yet Implemented"); |
michael@0 | 740 | return NS_OK; |
michael@0 | 741 | } |
michael@0 | 742 | |
michael@0 | 743 | NS_IMETHODIMP nsXULWindow::GetParentNativeWindow(nativeWindow* aParentNativeWindow) |
michael@0 | 744 | { |
michael@0 | 745 | NS_ENSURE_ARG_POINTER(aParentNativeWindow); |
michael@0 | 746 | |
michael@0 | 747 | nsCOMPtr<nsIWidget> parentWidget; |
michael@0 | 748 | NS_ENSURE_SUCCESS(GetParentWidget(getter_AddRefs(parentWidget)), NS_ERROR_FAILURE); |
michael@0 | 749 | |
michael@0 | 750 | if (parentWidget) { |
michael@0 | 751 | *aParentNativeWindow = parentWidget->GetNativeData(NS_NATIVE_WIDGET); |
michael@0 | 752 | } |
michael@0 | 753 | |
michael@0 | 754 | return NS_OK; |
michael@0 | 755 | } |
michael@0 | 756 | |
michael@0 | 757 | NS_IMETHODIMP nsXULWindow::SetParentNativeWindow(nativeWindow aParentNativeWindow) |
michael@0 | 758 | { |
michael@0 | 759 | //XXX First Check In |
michael@0 | 760 | NS_ASSERTION(false, "Not Yet Implemented"); |
michael@0 | 761 | return NS_OK; |
michael@0 | 762 | } |
michael@0 | 763 | |
michael@0 | 764 | NS_IMETHODIMP nsXULWindow::GetNativeHandle(nsAString& aNativeHandle) |
michael@0 | 765 | { |
michael@0 | 766 | nsCOMPtr<nsIWidget> mainWidget; |
michael@0 | 767 | NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(mainWidget)), NS_ERROR_FAILURE); |
michael@0 | 768 | |
michael@0 | 769 | if (mainWidget) { |
michael@0 | 770 | nativeWindow nativeWindowPtr = mainWidget->GetNativeData(NS_NATIVE_WINDOW); |
michael@0 | 771 | /* the nativeWindow pointer is converted to and exposed as a string. This |
michael@0 | 772 | is a more reliable way not to lose information (as opposed to JS |
michael@0 | 773 | |Number| for instance) */ |
michael@0 | 774 | aNativeHandle = NS_ConvertASCIItoUTF16(nsPrintfCString("0x%p", nativeWindowPtr)); |
michael@0 | 775 | } |
michael@0 | 776 | |
michael@0 | 777 | return NS_OK; |
michael@0 | 778 | } |
michael@0 | 779 | |
michael@0 | 780 | NS_IMETHODIMP nsXULWindow::GetVisibility(bool* aVisibility) |
michael@0 | 781 | { |
michael@0 | 782 | NS_ENSURE_ARG_POINTER(aVisibility); |
michael@0 | 783 | |
michael@0 | 784 | // Always claim to be visible for now. See bug |
michael@0 | 785 | // https://bugzilla.mozilla.org/show_bug.cgi?id=306245. |
michael@0 | 786 | |
michael@0 | 787 | *aVisibility = true; |
michael@0 | 788 | |
michael@0 | 789 | return NS_OK; |
michael@0 | 790 | } |
michael@0 | 791 | |
michael@0 | 792 | NS_IMETHODIMP nsXULWindow::SetVisibility(bool aVisibility) |
michael@0 | 793 | { |
michael@0 | 794 | if (!mChromeLoaded) { |
michael@0 | 795 | mShowAfterLoad = aVisibility; |
michael@0 | 796 | return NS_OK; |
michael@0 | 797 | } |
michael@0 | 798 | |
michael@0 | 799 | if (mDebuting) { |
michael@0 | 800 | return NS_OK; |
michael@0 | 801 | } |
michael@0 | 802 | mDebuting = true; // (Show / Focus is recursive) |
michael@0 | 803 | |
michael@0 | 804 | //XXXTAB Do we really need to show docshell and the window? Isn't |
michael@0 | 805 | // the window good enough? |
michael@0 | 806 | nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell)); |
michael@0 | 807 | shellAsWin->SetVisibility(aVisibility); |
michael@0 | 808 | // Store locally so it doesn't die on us. 'Show' can result in the window |
michael@0 | 809 | // being closed with nsXULWindow::Destroy being called. That would set |
michael@0 | 810 | // mWindow to null and posibly destroy the nsIWidget while its Show method |
michael@0 | 811 | // is on the stack. We need to keep it alive until Show finishes. |
michael@0 | 812 | nsCOMPtr<nsIWidget> window = mWindow; |
michael@0 | 813 | window->Show(aVisibility); |
michael@0 | 814 | |
michael@0 | 815 | nsCOMPtr<nsIWindowMediator> windowMediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); |
michael@0 | 816 | if (windowMediator) |
michael@0 | 817 | windowMediator->UpdateWindowTimeStamp(static_cast<nsIXULWindow*>(this)); |
michael@0 | 818 | |
michael@0 | 819 | // notify observers so that we can hide the splash screen if possible |
michael@0 | 820 | nsCOMPtr<nsIObserverService> obssvc |
michael@0 | 821 | (do_GetService("@mozilla.org/observer-service;1")); |
michael@0 | 822 | NS_ASSERTION(obssvc, "Couldn't get observer service."); |
michael@0 | 823 | if (obssvc) { |
michael@0 | 824 | obssvc->NotifyObservers(nullptr, "xul-window-visible", nullptr); |
michael@0 | 825 | } |
michael@0 | 826 | |
michael@0 | 827 | mDebuting = false; |
michael@0 | 828 | return NS_OK; |
michael@0 | 829 | } |
michael@0 | 830 | |
michael@0 | 831 | NS_IMETHODIMP nsXULWindow::GetEnabled(bool *aEnabled) |
michael@0 | 832 | { |
michael@0 | 833 | NS_ENSURE_ARG_POINTER(aEnabled); |
michael@0 | 834 | |
michael@0 | 835 | if (mWindow) { |
michael@0 | 836 | *aEnabled = mWindow->IsEnabled(); |
michael@0 | 837 | return NS_OK; |
michael@0 | 838 | } |
michael@0 | 839 | |
michael@0 | 840 | *aEnabled = true; // better guess than most |
michael@0 | 841 | return NS_ERROR_FAILURE; |
michael@0 | 842 | } |
michael@0 | 843 | |
michael@0 | 844 | NS_IMETHODIMP nsXULWindow::SetEnabled(bool aEnable) |
michael@0 | 845 | { |
michael@0 | 846 | if (mWindow) { |
michael@0 | 847 | mWindow->Enable(aEnable); |
michael@0 | 848 | return NS_OK; |
michael@0 | 849 | } |
michael@0 | 850 | return NS_ERROR_FAILURE; |
michael@0 | 851 | } |
michael@0 | 852 | |
michael@0 | 853 | NS_IMETHODIMP nsXULWindow::GetMainWidget(nsIWidget** aMainWidget) |
michael@0 | 854 | { |
michael@0 | 855 | NS_ENSURE_ARG_POINTER(aMainWidget); |
michael@0 | 856 | |
michael@0 | 857 | *aMainWidget = mWindow; |
michael@0 | 858 | NS_IF_ADDREF(*aMainWidget); |
michael@0 | 859 | return NS_OK; |
michael@0 | 860 | } |
michael@0 | 861 | |
michael@0 | 862 | NS_IMETHODIMP nsXULWindow::SetFocus() |
michael@0 | 863 | { |
michael@0 | 864 | //XXX First Check In |
michael@0 | 865 | NS_ASSERTION(false, "Not Yet Implemented"); |
michael@0 | 866 | return NS_OK; |
michael@0 | 867 | } |
michael@0 | 868 | |
michael@0 | 869 | NS_IMETHODIMP nsXULWindow::GetTitle(char16_t** aTitle) |
michael@0 | 870 | { |
michael@0 | 871 | NS_ENSURE_ARG_POINTER(aTitle); |
michael@0 | 872 | |
michael@0 | 873 | *aTitle = ToNewUnicode(mTitle); |
michael@0 | 874 | if (!*aTitle) |
michael@0 | 875 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 876 | return NS_OK; |
michael@0 | 877 | } |
michael@0 | 878 | |
michael@0 | 879 | NS_IMETHODIMP nsXULWindow::SetTitle(const char16_t* aTitle) |
michael@0 | 880 | { |
michael@0 | 881 | NS_ENSURE_STATE(mWindow); |
michael@0 | 882 | mTitle.Assign(aTitle); |
michael@0 | 883 | mTitle.StripChars("\n\r"); |
michael@0 | 884 | NS_ENSURE_SUCCESS(mWindow->SetTitle(mTitle), NS_ERROR_FAILURE); |
michael@0 | 885 | |
michael@0 | 886 | // Tell the window mediator that a title has changed |
michael@0 | 887 | nsCOMPtr<nsIWindowMediator> windowMediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); |
michael@0 | 888 | if (!windowMediator) |
michael@0 | 889 | return NS_OK; |
michael@0 | 890 | |
michael@0 | 891 | windowMediator->UpdateWindowTitle(static_cast<nsIXULWindow*>(this), aTitle); |
michael@0 | 892 | |
michael@0 | 893 | return NS_OK; |
michael@0 | 894 | } |
michael@0 | 895 | |
michael@0 | 896 | |
michael@0 | 897 | //***************************************************************************** |
michael@0 | 898 | // nsXULWindow: Helpers |
michael@0 | 899 | //***************************************************************************** |
michael@0 | 900 | |
michael@0 | 901 | NS_IMETHODIMP nsXULWindow::EnsureChromeTreeOwner() |
michael@0 | 902 | { |
michael@0 | 903 | if (mChromeTreeOwner) |
michael@0 | 904 | return NS_OK; |
michael@0 | 905 | |
michael@0 | 906 | mChromeTreeOwner = new nsChromeTreeOwner(); |
michael@0 | 907 | NS_ENSURE_TRUE(mChromeTreeOwner, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 908 | |
michael@0 | 909 | NS_ADDREF(mChromeTreeOwner); |
michael@0 | 910 | mChromeTreeOwner->XULWindow(this); |
michael@0 | 911 | |
michael@0 | 912 | return NS_OK; |
michael@0 | 913 | } |
michael@0 | 914 | |
michael@0 | 915 | NS_IMETHODIMP nsXULWindow::EnsureContentTreeOwner() |
michael@0 | 916 | { |
michael@0 | 917 | if (mContentTreeOwner) |
michael@0 | 918 | return NS_OK; |
michael@0 | 919 | |
michael@0 | 920 | mContentTreeOwner = new nsContentTreeOwner(false); |
michael@0 | 921 | NS_ENSURE_TRUE(mContentTreeOwner, NS_ERROR_FAILURE); |
michael@0 | 922 | |
michael@0 | 923 | NS_ADDREF(mContentTreeOwner); |
michael@0 | 924 | mContentTreeOwner->XULWindow(this); |
michael@0 | 925 | |
michael@0 | 926 | return NS_OK; |
michael@0 | 927 | } |
michael@0 | 928 | |
michael@0 | 929 | NS_IMETHODIMP nsXULWindow::EnsurePrimaryContentTreeOwner() |
michael@0 | 930 | { |
michael@0 | 931 | if (mPrimaryContentTreeOwner) |
michael@0 | 932 | return NS_OK; |
michael@0 | 933 | |
michael@0 | 934 | mPrimaryContentTreeOwner = new nsContentTreeOwner(true); |
michael@0 | 935 | NS_ENSURE_TRUE(mPrimaryContentTreeOwner, NS_ERROR_FAILURE); |
michael@0 | 936 | |
michael@0 | 937 | NS_ADDREF(mPrimaryContentTreeOwner); |
michael@0 | 938 | mPrimaryContentTreeOwner->XULWindow(this); |
michael@0 | 939 | |
michael@0 | 940 | return NS_OK; |
michael@0 | 941 | } |
michael@0 | 942 | |
michael@0 | 943 | NS_IMETHODIMP nsXULWindow::EnsurePrompter() |
michael@0 | 944 | { |
michael@0 | 945 | if (mPrompter) |
michael@0 | 946 | return NS_OK; |
michael@0 | 947 | |
michael@0 | 948 | nsCOMPtr<nsIDOMWindow> ourWindow; |
michael@0 | 949 | nsresult rv = GetWindowDOMWindow(getter_AddRefs(ourWindow)); |
michael@0 | 950 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 951 | nsCOMPtr<nsIWindowWatcher> wwatch = |
michael@0 | 952 | do_GetService(NS_WINDOWWATCHER_CONTRACTID); |
michael@0 | 953 | if (wwatch) |
michael@0 | 954 | wwatch->GetNewPrompter(ourWindow, getter_AddRefs(mPrompter)); |
michael@0 | 955 | } |
michael@0 | 956 | return mPrompter ? NS_OK : NS_ERROR_FAILURE; |
michael@0 | 957 | } |
michael@0 | 958 | |
michael@0 | 959 | NS_IMETHODIMP nsXULWindow::EnsureAuthPrompter() |
michael@0 | 960 | { |
michael@0 | 961 | if (mAuthPrompter) |
michael@0 | 962 | return NS_OK; |
michael@0 | 963 | |
michael@0 | 964 | nsCOMPtr<nsIDOMWindow> ourWindow; |
michael@0 | 965 | nsresult rv = GetWindowDOMWindow(getter_AddRefs(ourWindow)); |
michael@0 | 966 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 967 | nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); |
michael@0 | 968 | if (wwatch) |
michael@0 | 969 | wwatch->GetNewAuthPrompter(ourWindow, getter_AddRefs(mAuthPrompter)); |
michael@0 | 970 | } |
michael@0 | 971 | return mAuthPrompter ? NS_OK : NS_ERROR_FAILURE; |
michael@0 | 972 | } |
michael@0 | 973 | |
michael@0 | 974 | void nsXULWindow::OnChromeLoaded() |
michael@0 | 975 | { |
michael@0 | 976 | nsresult rv = EnsureContentTreeOwner(); |
michael@0 | 977 | |
michael@0 | 978 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 979 | mChromeLoaded = true; |
michael@0 | 980 | ApplyChromeFlags(); |
michael@0 | 981 | SyncAttributesToWidget(); |
michael@0 | 982 | if (!mIgnoreXULSize) |
michael@0 | 983 | LoadSizeFromXUL(); |
michael@0 | 984 | if (mIntrinsicallySized) { |
michael@0 | 985 | // (if LoadSizeFromXUL set the size, mIntrinsicallySized will be false) |
michael@0 | 986 | nsCOMPtr<nsIContentViewer> cv; |
michael@0 | 987 | mDocShell->GetContentViewer(getter_AddRefs(cv)); |
michael@0 | 988 | nsCOMPtr<nsIMarkupDocumentViewer> markupViewer = do_QueryInterface(cv); |
michael@0 | 989 | if (markupViewer) { |
michael@0 | 990 | nsCOMPtr<nsIDocShellTreeItem> docShellAsItem = do_QueryInterface(mDocShell); |
michael@0 | 991 | nsCOMPtr<nsIDocShellTreeOwner> treeOwner; |
michael@0 | 992 | docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner)); |
michael@0 | 993 | if (treeOwner) { |
michael@0 | 994 | int32_t width, height; |
michael@0 | 995 | markupViewer->GetContentSize(&width, &height); |
michael@0 | 996 | treeOwner->SizeShellTo(docShellAsItem, width, height); |
michael@0 | 997 | } |
michael@0 | 998 | } |
michael@0 | 999 | } |
michael@0 | 1000 | |
michael@0 | 1001 | bool positionSet = !mIgnoreXULPosition; |
michael@0 | 1002 | nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow)); |
michael@0 | 1003 | #if defined(XP_UNIX) && !defined(XP_MACOSX) |
michael@0 | 1004 | // don't override WM placement on unix for independent, top-level windows |
michael@0 | 1005 | // (however, we think the benefits of intelligent dependent window placement |
michael@0 | 1006 | // trump that override.) |
michael@0 | 1007 | if (!parentWindow) |
michael@0 | 1008 | positionSet = false; |
michael@0 | 1009 | #endif |
michael@0 | 1010 | if (positionSet) |
michael@0 | 1011 | positionSet = LoadPositionFromXUL(); |
michael@0 | 1012 | LoadMiscPersistentAttributesFromXUL(); |
michael@0 | 1013 | |
michael@0 | 1014 | if (mCenterAfterLoad && !positionSet) |
michael@0 | 1015 | Center(parentWindow, parentWindow ? false : true, false); |
michael@0 | 1016 | |
michael@0 | 1017 | if (mShowAfterLoad) { |
michael@0 | 1018 | SetVisibility(true); |
michael@0 | 1019 | // At this point the window may have been closed during Show(), so |
michael@0 | 1020 | // nsXULWindow::Destroy may already have been called. Take care! |
michael@0 | 1021 | } |
michael@0 | 1022 | } |
michael@0 | 1023 | mPersistentAttributesMask |= PAD_POSITION | PAD_SIZE | PAD_MISC; |
michael@0 | 1024 | } |
michael@0 | 1025 | |
michael@0 | 1026 | bool nsXULWindow::LoadPositionFromXUL() |
michael@0 | 1027 | { |
michael@0 | 1028 | bool gotPosition = false; |
michael@0 | 1029 | |
michael@0 | 1030 | // if we're the hidden window, don't try to validate our size/position. We're |
michael@0 | 1031 | // special. |
michael@0 | 1032 | if (mIsHiddenWindow) |
michael@0 | 1033 | return false; |
michael@0 | 1034 | |
michael@0 | 1035 | nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement(); |
michael@0 | 1036 | NS_ENSURE_TRUE(windowElement, false); |
michael@0 | 1037 | |
michael@0 | 1038 | int32_t currX = 0; |
michael@0 | 1039 | int32_t currY = 0; |
michael@0 | 1040 | int32_t currWidth = 0; |
michael@0 | 1041 | int32_t currHeight = 0; |
michael@0 | 1042 | nsresult errorCode; |
michael@0 | 1043 | int32_t temp; |
michael@0 | 1044 | |
michael@0 | 1045 | GetPositionAndSize(&currX, &currY, &currWidth, &currHeight); |
michael@0 | 1046 | |
michael@0 | 1047 | // Convert to global display pixels for consistent window management across |
michael@0 | 1048 | // screens with diverse resolutions |
michael@0 | 1049 | CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); |
michael@0 | 1050 | currX = NSToIntRound(currX / scale.scale); |
michael@0 | 1051 | currY = NSToIntRound(currY / scale.scale); |
michael@0 | 1052 | currWidth = NSToIntRound(currWidth / scale.scale); |
michael@0 | 1053 | currHeight = NSToIntRound(currHeight / scale.scale); |
michael@0 | 1054 | |
michael@0 | 1055 | // Obtain the position information from the <xul:window> element. |
michael@0 | 1056 | int32_t specX = currX; |
michael@0 | 1057 | int32_t specY = currY; |
michael@0 | 1058 | nsAutoString posString; |
michael@0 | 1059 | |
michael@0 | 1060 | windowElement->GetAttribute(SCREENX_ATTRIBUTE, posString); |
michael@0 | 1061 | temp = posString.ToInteger(&errorCode); |
michael@0 | 1062 | if (NS_SUCCEEDED(errorCode)) { |
michael@0 | 1063 | specX = temp; |
michael@0 | 1064 | gotPosition = true; |
michael@0 | 1065 | } |
michael@0 | 1066 | windowElement->GetAttribute(SCREENY_ATTRIBUTE, posString); |
michael@0 | 1067 | temp = posString.ToInteger(&errorCode); |
michael@0 | 1068 | if (NS_SUCCEEDED(errorCode)) { |
michael@0 | 1069 | specY = temp; |
michael@0 | 1070 | gotPosition = true; |
michael@0 | 1071 | } |
michael@0 | 1072 | |
michael@0 | 1073 | if (gotPosition) { |
michael@0 | 1074 | // our position will be relative to our parent, if any |
michael@0 | 1075 | nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow)); |
michael@0 | 1076 | if (parent) { |
michael@0 | 1077 | int32_t parentX, parentY; |
michael@0 | 1078 | if (NS_SUCCEEDED(parent->GetPosition(&parentX, &parentY))) { |
michael@0 | 1079 | double scale; |
michael@0 | 1080 | if (NS_SUCCEEDED(parent->GetUnscaledDevicePixelsPerCSSPixel(&scale))) { |
michael@0 | 1081 | parentX = NSToIntRound(parentX / scale); |
michael@0 | 1082 | parentY = NSToIntRound(parentY / scale); |
michael@0 | 1083 | } |
michael@0 | 1084 | specX += parentX; |
michael@0 | 1085 | specY += parentY; |
michael@0 | 1086 | } |
michael@0 | 1087 | } |
michael@0 | 1088 | else { |
michael@0 | 1089 | StaggerPosition(specX, specY, currWidth, currHeight); |
michael@0 | 1090 | } |
michael@0 | 1091 | } |
michael@0 | 1092 | mWindow->ConstrainPosition(false, &specX, &specY); |
michael@0 | 1093 | if (specX != currX || specY != currY) { |
michael@0 | 1094 | CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); |
michael@0 | 1095 | SetPosition(specX * scale.scale, specY * scale.scale); |
michael@0 | 1096 | } |
michael@0 | 1097 | |
michael@0 | 1098 | return gotPosition; |
michael@0 | 1099 | } |
michael@0 | 1100 | |
michael@0 | 1101 | bool nsXULWindow::LoadSizeFromXUL() |
michael@0 | 1102 | { |
michael@0 | 1103 | bool gotSize = false; |
michael@0 | 1104 | |
michael@0 | 1105 | // if we're the hidden window, don't try to validate our size/position. We're |
michael@0 | 1106 | // special. |
michael@0 | 1107 | if (mIsHiddenWindow) |
michael@0 | 1108 | return false; |
michael@0 | 1109 | |
michael@0 | 1110 | nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement(); |
michael@0 | 1111 | NS_ENSURE_TRUE(windowElement, false); |
michael@0 | 1112 | |
michael@0 | 1113 | int32_t currWidth = 0; |
michael@0 | 1114 | int32_t currHeight = 0; |
michael@0 | 1115 | nsresult errorCode; |
michael@0 | 1116 | int32_t temp; |
michael@0 | 1117 | |
michael@0 | 1118 | NS_ASSERTION(mWindow, "we expected to have a window already"); |
michael@0 | 1119 | |
michael@0 | 1120 | CSSToLayoutDeviceScale scale = mWindow ? mWindow->GetDefaultScale() |
michael@0 | 1121 | : CSSToLayoutDeviceScale(1.0); |
michael@0 | 1122 | GetSize(&currWidth, &currHeight); |
michael@0 | 1123 | currWidth = NSToIntRound(currWidth / scale.scale); |
michael@0 | 1124 | currHeight = NSToIntRound(currHeight / scale.scale); |
michael@0 | 1125 | |
michael@0 | 1126 | // Obtain the position and sizing information from the <xul:window> element. |
michael@0 | 1127 | int32_t specWidth = currWidth; |
michael@0 | 1128 | int32_t specHeight = currHeight; |
michael@0 | 1129 | nsAutoString sizeString; |
michael@0 | 1130 | |
michael@0 | 1131 | windowElement->GetAttribute(WIDTH_ATTRIBUTE, sizeString); |
michael@0 | 1132 | temp = sizeString.ToInteger(&errorCode); |
michael@0 | 1133 | if (NS_SUCCEEDED(errorCode) && temp > 0) { |
michael@0 | 1134 | specWidth = std::max(temp, 100); |
michael@0 | 1135 | gotSize = true; |
michael@0 | 1136 | } |
michael@0 | 1137 | windowElement->GetAttribute(HEIGHT_ATTRIBUTE, sizeString); |
michael@0 | 1138 | temp = sizeString.ToInteger(&errorCode); |
michael@0 | 1139 | if (NS_SUCCEEDED(errorCode) && temp > 0) { |
michael@0 | 1140 | specHeight = std::max(temp, 100); |
michael@0 | 1141 | gotSize = true; |
michael@0 | 1142 | } |
michael@0 | 1143 | |
michael@0 | 1144 | if (gotSize) { |
michael@0 | 1145 | // constrain to screen size |
michael@0 | 1146 | nsCOMPtr<nsIDOMWindow> domWindow; |
michael@0 | 1147 | GetWindowDOMWindow(getter_AddRefs(domWindow)); |
michael@0 | 1148 | if (domWindow) { |
michael@0 | 1149 | nsCOMPtr<nsIDOMScreen> screen; |
michael@0 | 1150 | domWindow->GetScreen(getter_AddRefs(screen)); |
michael@0 | 1151 | if (screen) { |
michael@0 | 1152 | int32_t screenWidth; |
michael@0 | 1153 | int32_t screenHeight; |
michael@0 | 1154 | screen->GetAvailWidth(&screenWidth); |
michael@0 | 1155 | screen->GetAvailHeight(&screenHeight); |
michael@0 | 1156 | if (specWidth > screenWidth) |
michael@0 | 1157 | specWidth = screenWidth; |
michael@0 | 1158 | if (specHeight > screenHeight) |
michael@0 | 1159 | specHeight = screenHeight; |
michael@0 | 1160 | } |
michael@0 | 1161 | } |
michael@0 | 1162 | |
michael@0 | 1163 | mIntrinsicallySized = false; |
michael@0 | 1164 | if (specWidth != currWidth || specHeight != currHeight) { |
michael@0 | 1165 | CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); |
michael@0 | 1166 | SetSize(specWidth * scale.scale, specHeight * scale.scale, false); |
michael@0 | 1167 | } |
michael@0 | 1168 | } |
michael@0 | 1169 | |
michael@0 | 1170 | return gotSize; |
michael@0 | 1171 | } |
michael@0 | 1172 | |
michael@0 | 1173 | /* Miscellaneous persistent attributes are attributes named in the |
michael@0 | 1174 | |persist| attribute, other than size and position. Those are special |
michael@0 | 1175 | because it's important to load those before one of the misc |
michael@0 | 1176 | attributes (sizemode) and they require extra processing. */ |
michael@0 | 1177 | bool nsXULWindow::LoadMiscPersistentAttributesFromXUL() |
michael@0 | 1178 | { |
michael@0 | 1179 | bool gotState = false; |
michael@0 | 1180 | |
michael@0 | 1181 | /* There are no misc attributes of interest to the hidden window. |
michael@0 | 1182 | It's especially important not to try to validate that window's |
michael@0 | 1183 | size or position, because some platforms (Mac OS X) need to |
michael@0 | 1184 | make it visible and offscreen. */ |
michael@0 | 1185 | if (mIsHiddenWindow) |
michael@0 | 1186 | return false; |
michael@0 | 1187 | |
michael@0 | 1188 | nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement(); |
michael@0 | 1189 | NS_ENSURE_TRUE(windowElement, false); |
michael@0 | 1190 | |
michael@0 | 1191 | nsAutoString stateString; |
michael@0 | 1192 | |
michael@0 | 1193 | // sizemode |
michael@0 | 1194 | windowElement->GetAttribute(MODE_ATTRIBUTE, stateString); |
michael@0 | 1195 | int32_t sizeMode = nsSizeMode_Normal; |
michael@0 | 1196 | /* ignore request to minimize, to not confuse novices |
michael@0 | 1197 | if (stateString.Equals(SIZEMODE_MINIMIZED)) |
michael@0 | 1198 | sizeMode = nsSizeMode_Minimized; |
michael@0 | 1199 | */ |
michael@0 | 1200 | if (!mIgnoreXULSizeMode && |
michael@0 | 1201 | (stateString.Equals(SIZEMODE_MAXIMIZED) || stateString.Equals(SIZEMODE_FULLSCREEN))) { |
michael@0 | 1202 | /* Honor request to maximize only if the window is sizable. |
michael@0 | 1203 | An unsizable, unmaximizable, yet maximized window confuses |
michael@0 | 1204 | Windows OS and is something of a travesty, anyway. */ |
michael@0 | 1205 | if (mChromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) { |
michael@0 | 1206 | mIntrinsicallySized = false; |
michael@0 | 1207 | |
michael@0 | 1208 | if (stateString.Equals(SIZEMODE_MAXIMIZED)) |
michael@0 | 1209 | sizeMode = nsSizeMode_Maximized; |
michael@0 | 1210 | else |
michael@0 | 1211 | sizeMode = nsSizeMode_Fullscreen; |
michael@0 | 1212 | } |
michael@0 | 1213 | } |
michael@0 | 1214 | |
michael@0 | 1215 | // If we are told to ignore the size mode attribute update the |
michael@0 | 1216 | // document so the attribute and window are in sync. |
michael@0 | 1217 | if (mIgnoreXULSizeMode) { |
michael@0 | 1218 | nsAutoString sizeString; |
michael@0 | 1219 | if (sizeMode == nsSizeMode_Maximized) |
michael@0 | 1220 | sizeString.Assign(SIZEMODE_MAXIMIZED); |
michael@0 | 1221 | else if (sizeMode == nsSizeMode_Fullscreen) |
michael@0 | 1222 | sizeString.Assign(SIZEMODE_FULLSCREEN); |
michael@0 | 1223 | else if (sizeMode == nsSizeMode_Normal) |
michael@0 | 1224 | sizeString.Assign(SIZEMODE_NORMAL); |
michael@0 | 1225 | if (!sizeString.IsEmpty()) { |
michael@0 | 1226 | ErrorResult rv; |
michael@0 | 1227 | windowElement->SetAttribute(MODE_ATTRIBUTE, sizeString, rv); |
michael@0 | 1228 | } |
michael@0 | 1229 | } |
michael@0 | 1230 | |
michael@0 | 1231 | if (sizeMode == nsSizeMode_Fullscreen) { |
michael@0 | 1232 | nsCOMPtr<nsIDOMWindow> ourWindow; |
michael@0 | 1233 | GetWindowDOMWindow(getter_AddRefs(ourWindow)); |
michael@0 | 1234 | ourWindow->SetFullScreen(true); |
michael@0 | 1235 | } else { |
michael@0 | 1236 | mWindow->SetSizeMode(sizeMode); |
michael@0 | 1237 | } |
michael@0 | 1238 | gotState = true; |
michael@0 | 1239 | |
michael@0 | 1240 | // zlevel |
michael@0 | 1241 | windowElement->GetAttribute(ZLEVEL_ATTRIBUTE, stateString); |
michael@0 | 1242 | if (!stateString.IsEmpty()) { |
michael@0 | 1243 | nsresult errorCode; |
michael@0 | 1244 | int32_t zLevel = stateString.ToInteger(&errorCode); |
michael@0 | 1245 | if (NS_SUCCEEDED(errorCode) && zLevel >= lowestZ && zLevel <= highestZ) |
michael@0 | 1246 | SetZLevel(zLevel); |
michael@0 | 1247 | } |
michael@0 | 1248 | |
michael@0 | 1249 | return gotState; |
michael@0 | 1250 | } |
michael@0 | 1251 | |
michael@0 | 1252 | /* Stagger windows of the same type so they don't appear on top of each other. |
michael@0 | 1253 | This code does have a scary double loop -- it'll keep passing through |
michael@0 | 1254 | the entire list of open windows until it finds a non-collision. Doesn't |
michael@0 | 1255 | seem to be a problem, but it deserves watching. |
michael@0 | 1256 | */ |
michael@0 | 1257 | void nsXULWindow::StaggerPosition(int32_t &aRequestedX, int32_t &aRequestedY, |
michael@0 | 1258 | int32_t aSpecWidth, int32_t aSpecHeight) |
michael@0 | 1259 | { |
michael@0 | 1260 | const int32_t kOffset = 22; |
michael@0 | 1261 | const uint32_t kSlop = 4; |
michael@0 | 1262 | |
michael@0 | 1263 | bool keepTrying; |
michael@0 | 1264 | int bouncedX = 0, // bounced off vertical edge of screen |
michael@0 | 1265 | bouncedY = 0; // bounced off horizontal edge |
michael@0 | 1266 | |
michael@0 | 1267 | // look for any other windows of this type |
michael@0 | 1268 | nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); |
michael@0 | 1269 | if (!wm) |
michael@0 | 1270 | return; |
michael@0 | 1271 | |
michael@0 | 1272 | nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement(); |
michael@0 | 1273 | if (!windowElement) |
michael@0 | 1274 | return; |
michael@0 | 1275 | |
michael@0 | 1276 | nsCOMPtr<nsIXULWindow> ourXULWindow(this); |
michael@0 | 1277 | |
michael@0 | 1278 | nsAutoString windowType; |
michael@0 | 1279 | windowElement->GetAttribute(WINDOWTYPE_ATTRIBUTE, windowType); |
michael@0 | 1280 | |
michael@0 | 1281 | int32_t screenTop = 0, // it's pointless to initialize these ... |
michael@0 | 1282 | screenRight = 0, // ... but to prevent oversalubrious and ... |
michael@0 | 1283 | screenBottom = 0, // ... underbright compilers from ... |
michael@0 | 1284 | screenLeft = 0; // ... issuing warnings. |
michael@0 | 1285 | bool gotScreen = false; |
michael@0 | 1286 | |
michael@0 | 1287 | { // fetch screen coordinates |
michael@0 | 1288 | nsCOMPtr<nsIScreenManager> screenMgr(do_GetService( |
michael@0 | 1289 | "@mozilla.org/gfx/screenmanager;1")); |
michael@0 | 1290 | if (screenMgr) { |
michael@0 | 1291 | nsCOMPtr<nsIScreen> ourScreen; |
michael@0 | 1292 | // the coordinates here are already display pixels |
michael@0 | 1293 | screenMgr->ScreenForRect(aRequestedX, aRequestedY, |
michael@0 | 1294 | aSpecWidth, aSpecHeight, |
michael@0 | 1295 | getter_AddRefs(ourScreen)); |
michael@0 | 1296 | if (ourScreen) { |
michael@0 | 1297 | int32_t screenWidth, screenHeight; |
michael@0 | 1298 | ourScreen->GetAvailRectDisplayPix(&screenLeft, &screenTop, |
michael@0 | 1299 | &screenWidth, &screenHeight); |
michael@0 | 1300 | screenBottom = screenTop + screenHeight; |
michael@0 | 1301 | screenRight = screenLeft + screenWidth; |
michael@0 | 1302 | gotScreen = true; |
michael@0 | 1303 | } |
michael@0 | 1304 | } |
michael@0 | 1305 | } |
michael@0 | 1306 | |
michael@0 | 1307 | // One full pass through all windows of this type, repeat until no collisions. |
michael@0 | 1308 | do { |
michael@0 | 1309 | keepTrying = false; |
michael@0 | 1310 | nsCOMPtr<nsISimpleEnumerator> windowList; |
michael@0 | 1311 | wm->GetXULWindowEnumerator(windowType.get(), getter_AddRefs(windowList)); |
michael@0 | 1312 | |
michael@0 | 1313 | if (!windowList) |
michael@0 | 1314 | break; |
michael@0 | 1315 | |
michael@0 | 1316 | // One full pass through all windows of this type, offset and stop on collision. |
michael@0 | 1317 | do { |
michael@0 | 1318 | bool more; |
michael@0 | 1319 | windowList->HasMoreElements(&more); |
michael@0 | 1320 | if (!more) |
michael@0 | 1321 | break; |
michael@0 | 1322 | |
michael@0 | 1323 | nsCOMPtr<nsISupports> supportsWindow; |
michael@0 | 1324 | windowList->GetNext(getter_AddRefs(supportsWindow)); |
michael@0 | 1325 | |
michael@0 | 1326 | nsCOMPtr<nsIXULWindow> listXULWindow(do_QueryInterface(supportsWindow)); |
michael@0 | 1327 | if (listXULWindow != ourXULWindow) { |
michael@0 | 1328 | int32_t listX, listY; |
michael@0 | 1329 | nsCOMPtr<nsIBaseWindow> listBaseWindow(do_QueryInterface(supportsWindow)); |
michael@0 | 1330 | listBaseWindow->GetPosition(&listX, &listY); |
michael@0 | 1331 | double scale; |
michael@0 | 1332 | if (NS_SUCCEEDED(listBaseWindow->GetUnscaledDevicePixelsPerCSSPixel(&scale))) { |
michael@0 | 1333 | listX = NSToIntRound(listX / scale); |
michael@0 | 1334 | listY = NSToIntRound(listY / scale); |
michael@0 | 1335 | } |
michael@0 | 1336 | |
michael@0 | 1337 | if (Abs(listX - aRequestedX) <= kSlop && Abs(listY - aRequestedY) <= kSlop) { |
michael@0 | 1338 | // collision! offset and start over |
michael@0 | 1339 | if (bouncedX & 0x1) |
michael@0 | 1340 | aRequestedX -= kOffset; |
michael@0 | 1341 | else |
michael@0 | 1342 | aRequestedX += kOffset; |
michael@0 | 1343 | aRequestedY += kOffset; |
michael@0 | 1344 | |
michael@0 | 1345 | if (gotScreen) { |
michael@0 | 1346 | // if we're moving to the right and we need to bounce... |
michael@0 | 1347 | if (!(bouncedX & 0x1) && ((aRequestedX + aSpecWidth) > screenRight)) { |
michael@0 | 1348 | aRequestedX = screenRight - aSpecWidth; |
michael@0 | 1349 | ++bouncedX; |
michael@0 | 1350 | } |
michael@0 | 1351 | |
michael@0 | 1352 | // if we're moving to the left and we need to bounce... |
michael@0 | 1353 | if ((bouncedX & 0x1) && aRequestedX < screenLeft) { |
michael@0 | 1354 | aRequestedX = screenLeft; |
michael@0 | 1355 | ++bouncedX; |
michael@0 | 1356 | } |
michael@0 | 1357 | |
michael@0 | 1358 | // if we hit the bottom then bounce to the top |
michael@0 | 1359 | if (aRequestedY + aSpecHeight > screenBottom) { |
michael@0 | 1360 | aRequestedY = screenTop; |
michael@0 | 1361 | ++bouncedY; |
michael@0 | 1362 | } |
michael@0 | 1363 | } |
michael@0 | 1364 | |
michael@0 | 1365 | /* loop around again, |
michael@0 | 1366 | but it's time to give up once we've covered the screen. |
michael@0 | 1367 | there's a potential infinite loop with lots of windows. */ |
michael@0 | 1368 | keepTrying = bouncedX < 2 || bouncedY == 0; |
michael@0 | 1369 | break; |
michael@0 | 1370 | } |
michael@0 | 1371 | } |
michael@0 | 1372 | } while(1); |
michael@0 | 1373 | } while (keepTrying); |
michael@0 | 1374 | } |
michael@0 | 1375 | |
michael@0 | 1376 | void nsXULWindow::SyncAttributesToWidget() |
michael@0 | 1377 | { |
michael@0 | 1378 | nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement(); |
michael@0 | 1379 | if (!windowElement) |
michael@0 | 1380 | return; |
michael@0 | 1381 | |
michael@0 | 1382 | nsAutoString attr; |
michael@0 | 1383 | |
michael@0 | 1384 | // "hidechrome" attribute |
michael@0 | 1385 | if (windowElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidechrome, |
michael@0 | 1386 | nsGkAtoms::_true, eCaseMatters)) { |
michael@0 | 1387 | mWindow->HideWindowChrome(true); |
michael@0 | 1388 | } |
michael@0 | 1389 | |
michael@0 | 1390 | // "chromemargin" attribute |
michael@0 | 1391 | nsIntMargin margins; |
michael@0 | 1392 | windowElement->GetAttribute(NS_LITERAL_STRING("chromemargin"), attr); |
michael@0 | 1393 | if (nsContentUtils::ParseIntMarginValue(attr, margins)) { |
michael@0 | 1394 | mWindow->SetNonClientMargins(margins); |
michael@0 | 1395 | } |
michael@0 | 1396 | |
michael@0 | 1397 | // "accelerated" attribute |
michael@0 | 1398 | bool isAccelerated = windowElement->HasAttribute(NS_LITERAL_STRING("accelerated")); |
michael@0 | 1399 | mWindow->SetLayersAcceleration(isAccelerated); |
michael@0 | 1400 | |
michael@0 | 1401 | // "windowtype" attribute |
michael@0 | 1402 | windowElement->GetAttribute(WINDOWTYPE_ATTRIBUTE, attr); |
michael@0 | 1403 | if (!attr.IsEmpty()) { |
michael@0 | 1404 | mWindow->SetWindowClass(attr); |
michael@0 | 1405 | } |
michael@0 | 1406 | |
michael@0 | 1407 | // "id" attribute for icon |
michael@0 | 1408 | windowElement->GetAttribute(NS_LITERAL_STRING("id"), attr); |
michael@0 | 1409 | if (attr.IsEmpty()) { |
michael@0 | 1410 | attr.AssignLiteral("default"); |
michael@0 | 1411 | } |
michael@0 | 1412 | mWindow->SetIcon(attr); |
michael@0 | 1413 | |
michael@0 | 1414 | // "drawtitle" attribute |
michael@0 | 1415 | windowElement->GetAttribute(NS_LITERAL_STRING("drawtitle"), attr); |
michael@0 | 1416 | mWindow->SetDrawsTitle(attr.LowerCaseEqualsLiteral("true")); |
michael@0 | 1417 | |
michael@0 | 1418 | // "toggletoolbar" attribute |
michael@0 | 1419 | windowElement->GetAttribute(NS_LITERAL_STRING("toggletoolbar"), attr); |
michael@0 | 1420 | mWindow->SetShowsToolbarButton(attr.LowerCaseEqualsLiteral("true")); |
michael@0 | 1421 | |
michael@0 | 1422 | // "fullscreenbutton" attribute |
michael@0 | 1423 | windowElement->GetAttribute(NS_LITERAL_STRING("fullscreenbutton"), attr); |
michael@0 | 1424 | mWindow->SetShowsFullScreenButton(attr.LowerCaseEqualsLiteral("true")); |
michael@0 | 1425 | |
michael@0 | 1426 | // "macanimationtype" attribute |
michael@0 | 1427 | windowElement->GetAttribute(NS_LITERAL_STRING("macanimationtype"), attr); |
michael@0 | 1428 | if (attr.EqualsLiteral("document")) { |
michael@0 | 1429 | mWindow->SetWindowAnimationType(nsIWidget::eDocumentWindowAnimation); |
michael@0 | 1430 | } |
michael@0 | 1431 | } |
michael@0 | 1432 | |
michael@0 | 1433 | NS_IMETHODIMP nsXULWindow::SavePersistentAttributes() |
michael@0 | 1434 | { |
michael@0 | 1435 | // can happen when the persistence timer fires at an inopportune time |
michael@0 | 1436 | // during window shutdown |
michael@0 | 1437 | if (!mDocShell) |
michael@0 | 1438 | return NS_ERROR_FAILURE; |
michael@0 | 1439 | |
michael@0 | 1440 | nsCOMPtr<dom::Element> docShellElement = GetWindowDOMElement(); |
michael@0 | 1441 | if (!docShellElement) |
michael@0 | 1442 | return NS_ERROR_FAILURE; |
michael@0 | 1443 | |
michael@0 | 1444 | nsAutoString persistString; |
michael@0 | 1445 | docShellElement->GetAttribute(PERSIST_ATTRIBUTE, persistString); |
michael@0 | 1446 | if (persistString.IsEmpty()) { // quick check which sometimes helps |
michael@0 | 1447 | mPersistentAttributesDirty = 0; |
michael@0 | 1448 | return NS_OK; |
michael@0 | 1449 | } |
michael@0 | 1450 | |
michael@0 | 1451 | // get our size, position and mode to persist |
michael@0 | 1452 | int32_t x, y, cx, cy; |
michael@0 | 1453 | NS_ENSURE_SUCCESS(GetPositionAndSize(&x, &y, &cx, &cy), NS_ERROR_FAILURE); |
michael@0 | 1454 | |
michael@0 | 1455 | int32_t sizeMode = mWindow->SizeMode(); |
michael@0 | 1456 | CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); |
michael@0 | 1457 | |
michael@0 | 1458 | // make our position relative to our parent, if any |
michael@0 | 1459 | nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow)); |
michael@0 | 1460 | if (parent) { |
michael@0 | 1461 | int32_t parentX, parentY; |
michael@0 | 1462 | if (NS_SUCCEEDED(parent->GetPosition(&parentX, &parentY))) { |
michael@0 | 1463 | x -= parentX; |
michael@0 | 1464 | y -= parentY; |
michael@0 | 1465 | } |
michael@0 | 1466 | } |
michael@0 | 1467 | |
michael@0 | 1468 | char sizeBuf[10]; |
michael@0 | 1469 | nsAutoString sizeString; |
michael@0 | 1470 | nsAutoString windowElementId; |
michael@0 | 1471 | nsCOMPtr<nsIDOMXULDocument> ownerXULDoc; |
michael@0 | 1472 | |
michael@0 | 1473 | // fetch docShellElement's ID and XUL owner document |
michael@0 | 1474 | ownerXULDoc = do_QueryInterface(docShellElement->OwnerDoc()); |
michael@0 | 1475 | if (docShellElement->IsXUL()) { |
michael@0 | 1476 | docShellElement->GetId(windowElementId); |
michael@0 | 1477 | } |
michael@0 | 1478 | |
michael@0 | 1479 | ErrorResult rv; |
michael@0 | 1480 | // (only for size elements which are persisted) |
michael@0 | 1481 | if ((mPersistentAttributesDirty & PAD_POSITION) && |
michael@0 | 1482 | sizeMode == nsSizeMode_Normal) { |
michael@0 | 1483 | if (persistString.Find("screenX") >= 0) { |
michael@0 | 1484 | PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(x / scale.scale)); |
michael@0 | 1485 | sizeString.AssignWithConversion(sizeBuf); |
michael@0 | 1486 | docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString, rv); |
michael@0 | 1487 | if (ownerXULDoc) // force persistence in case the value didn't change |
michael@0 | 1488 | ownerXULDoc->Persist(windowElementId, SCREENX_ATTRIBUTE); |
michael@0 | 1489 | } |
michael@0 | 1490 | if (persistString.Find("screenY") >= 0) { |
michael@0 | 1491 | PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(y / scale.scale)); |
michael@0 | 1492 | sizeString.AssignWithConversion(sizeBuf); |
michael@0 | 1493 | docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString, rv); |
michael@0 | 1494 | if (ownerXULDoc) |
michael@0 | 1495 | ownerXULDoc->Persist(windowElementId, SCREENY_ATTRIBUTE); |
michael@0 | 1496 | } |
michael@0 | 1497 | } |
michael@0 | 1498 | |
michael@0 | 1499 | if ((mPersistentAttributesDirty & PAD_SIZE) && |
michael@0 | 1500 | sizeMode == nsSizeMode_Normal) { |
michael@0 | 1501 | if (persistString.Find("width") >= 0) { |
michael@0 | 1502 | PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(cx / scale.scale)); |
michael@0 | 1503 | sizeString.AssignWithConversion(sizeBuf); |
michael@0 | 1504 | docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv); |
michael@0 | 1505 | if (ownerXULDoc) |
michael@0 | 1506 | ownerXULDoc->Persist(windowElementId, WIDTH_ATTRIBUTE); |
michael@0 | 1507 | } |
michael@0 | 1508 | if (persistString.Find("height") >= 0) { |
michael@0 | 1509 | PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(cy / scale.scale)); |
michael@0 | 1510 | sizeString.AssignWithConversion(sizeBuf); |
michael@0 | 1511 | docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv); |
michael@0 | 1512 | if (ownerXULDoc) |
michael@0 | 1513 | ownerXULDoc->Persist(windowElementId, HEIGHT_ATTRIBUTE); |
michael@0 | 1514 | } |
michael@0 | 1515 | } |
michael@0 | 1516 | |
michael@0 | 1517 | if (mPersistentAttributesDirty & PAD_MISC) { |
michael@0 | 1518 | if (sizeMode != nsSizeMode_Minimized) { |
michael@0 | 1519 | if (sizeMode == nsSizeMode_Maximized) |
michael@0 | 1520 | sizeString.Assign(SIZEMODE_MAXIMIZED); |
michael@0 | 1521 | else if (sizeMode == nsSizeMode_Fullscreen) |
michael@0 | 1522 | sizeString.Assign(SIZEMODE_FULLSCREEN); |
michael@0 | 1523 | else |
michael@0 | 1524 | sizeString.Assign(SIZEMODE_NORMAL); |
michael@0 | 1525 | docShellElement->SetAttribute(MODE_ATTRIBUTE, sizeString, rv); |
michael@0 | 1526 | if (ownerXULDoc && persistString.Find("sizemode") >= 0) |
michael@0 | 1527 | ownerXULDoc->Persist(windowElementId, MODE_ATTRIBUTE); |
michael@0 | 1528 | } |
michael@0 | 1529 | if (persistString.Find("zlevel") >= 0) { |
michael@0 | 1530 | uint32_t zLevel; |
michael@0 | 1531 | nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); |
michael@0 | 1532 | if (mediator) { |
michael@0 | 1533 | mediator->GetZLevel(this, &zLevel); |
michael@0 | 1534 | PR_snprintf(sizeBuf, sizeof(sizeBuf), "%lu", (unsigned long)zLevel); |
michael@0 | 1535 | sizeString.AssignWithConversion(sizeBuf); |
michael@0 | 1536 | docShellElement->SetAttribute(ZLEVEL_ATTRIBUTE, sizeString, rv); |
michael@0 | 1537 | ownerXULDoc->Persist(windowElementId, ZLEVEL_ATTRIBUTE); |
michael@0 | 1538 | } |
michael@0 | 1539 | } |
michael@0 | 1540 | } |
michael@0 | 1541 | |
michael@0 | 1542 | mPersistentAttributesDirty = 0; |
michael@0 | 1543 | return NS_OK; |
michael@0 | 1544 | } |
michael@0 | 1545 | |
michael@0 | 1546 | NS_IMETHODIMP nsXULWindow::GetWindowDOMWindow(nsIDOMWindow** aDOMWindow) |
michael@0 | 1547 | { |
michael@0 | 1548 | NS_ENSURE_STATE(mDocShell); |
michael@0 | 1549 | |
michael@0 | 1550 | if (!mDOMWindow) |
michael@0 | 1551 | mDOMWindow = do_GetInterface(mDocShell); |
michael@0 | 1552 | NS_ENSURE_TRUE(mDOMWindow, NS_ERROR_FAILURE); |
michael@0 | 1553 | |
michael@0 | 1554 | *aDOMWindow = mDOMWindow; |
michael@0 | 1555 | NS_ADDREF(*aDOMWindow); |
michael@0 | 1556 | return NS_OK; |
michael@0 | 1557 | } |
michael@0 | 1558 | |
michael@0 | 1559 | dom::Element* |
michael@0 | 1560 | nsXULWindow::GetWindowDOMElement() const |
michael@0 | 1561 | { |
michael@0 | 1562 | NS_ENSURE_TRUE(mDocShell, nullptr); |
michael@0 | 1563 | |
michael@0 | 1564 | nsCOMPtr<nsIContentViewer> cv; |
michael@0 | 1565 | mDocShell->GetContentViewer(getter_AddRefs(cv)); |
michael@0 | 1566 | NS_ENSURE_TRUE(cv, nullptr); |
michael@0 | 1567 | |
michael@0 | 1568 | const nsIDocument* document = cv->GetDocument(); |
michael@0 | 1569 | NS_ENSURE_TRUE(document, nullptr); |
michael@0 | 1570 | |
michael@0 | 1571 | return document->GetRootElement(); |
michael@0 | 1572 | } |
michael@0 | 1573 | |
michael@0 | 1574 | nsresult nsXULWindow::ContentShellAdded(nsIDocShellTreeItem* aContentShell, |
michael@0 | 1575 | bool aPrimary, bool aTargetable, const nsAString& aID) |
michael@0 | 1576 | { |
michael@0 | 1577 | nsContentShellInfo* shellInfo = nullptr; |
michael@0 | 1578 | |
michael@0 | 1579 | uint32_t i, count = mContentShells.Length(); |
michael@0 | 1580 | nsWeakPtr contentShellWeak = do_GetWeakReference(aContentShell); |
michael@0 | 1581 | for (i = 0; i < count; i++) { |
michael@0 | 1582 | nsContentShellInfo* info = mContentShells.ElementAt(i); |
michael@0 | 1583 | if (info->id.Equals(aID)) { |
michael@0 | 1584 | // We already exist. Do a replace. |
michael@0 | 1585 | info->child = contentShellWeak; |
michael@0 | 1586 | shellInfo = info; |
michael@0 | 1587 | } |
michael@0 | 1588 | else if (info->child == contentShellWeak) |
michael@0 | 1589 | info->child = nullptr; |
michael@0 | 1590 | } |
michael@0 | 1591 | |
michael@0 | 1592 | if (!shellInfo) { |
michael@0 | 1593 | shellInfo = new nsContentShellInfo(aID, contentShellWeak); |
michael@0 | 1594 | mContentShells.AppendElement(shellInfo); |
michael@0 | 1595 | } |
michael@0 | 1596 | |
michael@0 | 1597 | // Set the default content tree owner |
michael@0 | 1598 | if (aPrimary) { |
michael@0 | 1599 | NS_ENSURE_SUCCESS(EnsurePrimaryContentTreeOwner(), NS_ERROR_FAILURE); |
michael@0 | 1600 | aContentShell->SetTreeOwner(mPrimaryContentTreeOwner); |
michael@0 | 1601 | mPrimaryContentShell = aContentShell; |
michael@0 | 1602 | } |
michael@0 | 1603 | else { |
michael@0 | 1604 | NS_ENSURE_SUCCESS(EnsureContentTreeOwner(), NS_ERROR_FAILURE); |
michael@0 | 1605 | aContentShell->SetTreeOwner(mContentTreeOwner); |
michael@0 | 1606 | if (mPrimaryContentShell == aContentShell) |
michael@0 | 1607 | mPrimaryContentShell = nullptr; |
michael@0 | 1608 | } |
michael@0 | 1609 | |
michael@0 | 1610 | if (aTargetable) { |
michael@0 | 1611 | #ifdef DEBUG |
michael@0 | 1612 | int32_t debugCount = mTargetableShells.Count(); |
michael@0 | 1613 | int32_t debugCounter; |
michael@0 | 1614 | for (debugCounter = debugCount - 1; debugCounter >= 0; --debugCounter) { |
michael@0 | 1615 | nsCOMPtr<nsIDocShellTreeItem> curItem = |
michael@0 | 1616 | do_QueryReferent(mTargetableShells[debugCounter]); |
michael@0 | 1617 | NS_ASSERTION(!SameCOMIdentity(curItem, aContentShell), |
michael@0 | 1618 | "Adding already existing item to mTargetableShells"); |
michael@0 | 1619 | } |
michael@0 | 1620 | #endif |
michael@0 | 1621 | |
michael@0 | 1622 | // put the new shell at the start of the targetable shells list if either |
michael@0 | 1623 | // it's the new primary shell or there is no existing primary shell (which |
michael@0 | 1624 | // means that chances are this one just stopped being primary). If we |
michael@0 | 1625 | // really cared, we could keep track of the "last no longer primary shell" |
michael@0 | 1626 | // explicitly, but it probably doesn't matter enough: the difference would |
michael@0 | 1627 | // only be felt in a situation where all shells were non-primary, which |
michael@0 | 1628 | // doesn't happen much. In a situation where there is one and only one |
michael@0 | 1629 | // primary shell, and in which shells get unmarked as primary before some |
michael@0 | 1630 | // other shell gets marked as primary, this effectively stores the list of |
michael@0 | 1631 | // targetable shells in "most recently primary first" order. |
michael@0 | 1632 | bool inserted; |
michael@0 | 1633 | if (aPrimary || !mPrimaryContentShell) { |
michael@0 | 1634 | inserted = mTargetableShells.InsertObjectAt(contentShellWeak, 0); |
michael@0 | 1635 | } else { |
michael@0 | 1636 | inserted = mTargetableShells.AppendObject(contentShellWeak); |
michael@0 | 1637 | } |
michael@0 | 1638 | NS_ENSURE_TRUE(inserted, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 1639 | } |
michael@0 | 1640 | |
michael@0 | 1641 | return NS_OK; |
michael@0 | 1642 | } |
michael@0 | 1643 | |
michael@0 | 1644 | nsresult nsXULWindow::ContentShellRemoved(nsIDocShellTreeItem* aContentShell) |
michael@0 | 1645 | { |
michael@0 | 1646 | if (mPrimaryContentShell == aContentShell) { |
michael@0 | 1647 | mPrimaryContentShell = nullptr; |
michael@0 | 1648 | } |
michael@0 | 1649 | |
michael@0 | 1650 | int32_t i, count = mContentShells.Length(); |
michael@0 | 1651 | for (i = count - 1; i >= 0; --i) { |
michael@0 | 1652 | nsContentShellInfo* info = mContentShells.ElementAt(i); |
michael@0 | 1653 | nsCOMPtr<nsIDocShellTreeItem> curItem = do_QueryReferent(info->child); |
michael@0 | 1654 | if (!curItem || SameCOMIdentity(curItem, aContentShell)) { |
michael@0 | 1655 | mContentShells.RemoveElementAt(i); |
michael@0 | 1656 | delete info; |
michael@0 | 1657 | } |
michael@0 | 1658 | } |
michael@0 | 1659 | |
michael@0 | 1660 | count = mTargetableShells.Count(); |
michael@0 | 1661 | for (i = count - 1; i >= 0; --i) { |
michael@0 | 1662 | nsCOMPtr<nsIDocShellTreeItem> curItem = |
michael@0 | 1663 | do_QueryReferent(mTargetableShells[i]); |
michael@0 | 1664 | if (!curItem || SameCOMIdentity(curItem, aContentShell)) { |
michael@0 | 1665 | mTargetableShells.RemoveObjectAt(i); |
michael@0 | 1666 | } |
michael@0 | 1667 | } |
michael@0 | 1668 | |
michael@0 | 1669 | return NS_OK; |
michael@0 | 1670 | } |
michael@0 | 1671 | |
michael@0 | 1672 | NS_IMETHODIMP nsXULWindow::SizeShellTo(nsIDocShellTreeItem* aShellItem, |
michael@0 | 1673 | int32_t aCX, int32_t aCY) |
michael@0 | 1674 | { |
michael@0 | 1675 | // XXXTAB This is wrong, we should actually reflow based on the passed in |
michael@0 | 1676 | // shell. For now we are hacking and doing delta sizing. This is bad |
michael@0 | 1677 | // because it assumes all size we add will go to the shell which probably |
michael@0 | 1678 | // won't happen. |
michael@0 | 1679 | |
michael@0 | 1680 | nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem)); |
michael@0 | 1681 | NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE); |
michael@0 | 1682 | |
michael@0 | 1683 | int32_t width = 0; |
michael@0 | 1684 | int32_t height = 0; |
michael@0 | 1685 | shellAsWin->GetSize(&width, &height); |
michael@0 | 1686 | |
michael@0 | 1687 | int32_t widthDelta = aCX - width; |
michael@0 | 1688 | int32_t heightDelta = aCY - height; |
michael@0 | 1689 | |
michael@0 | 1690 | if (widthDelta || heightDelta) { |
michael@0 | 1691 | int32_t winCX = 0; |
michael@0 | 1692 | int32_t winCY = 0; |
michael@0 | 1693 | |
michael@0 | 1694 | GetSize(&winCX, &winCY); |
michael@0 | 1695 | // There's no point in trying to make the window smaller than the |
michael@0 | 1696 | // desired docshell size --- that's not likely to work. This whole |
michael@0 | 1697 | // function assumes that the outer docshell is adding some constant |
michael@0 | 1698 | // "border" chrome to aShellItem. |
michael@0 | 1699 | winCX = std::max(winCX + widthDelta, aCX); |
michael@0 | 1700 | winCY = std::max(winCY + heightDelta, aCY); |
michael@0 | 1701 | SetSize(winCX, winCY, true); |
michael@0 | 1702 | } |
michael@0 | 1703 | |
michael@0 | 1704 | return NS_OK; |
michael@0 | 1705 | } |
michael@0 | 1706 | |
michael@0 | 1707 | NS_IMETHODIMP nsXULWindow::ExitModalLoop(nsresult aStatus) |
michael@0 | 1708 | { |
michael@0 | 1709 | if (mContinueModalLoop) |
michael@0 | 1710 | EnableParent(true); |
michael@0 | 1711 | mContinueModalLoop = false; |
michael@0 | 1712 | mModalStatus = aStatus; |
michael@0 | 1713 | return NS_OK; |
michael@0 | 1714 | } |
michael@0 | 1715 | |
michael@0 | 1716 | // top-level function to create a new window |
michael@0 | 1717 | NS_IMETHODIMP nsXULWindow::CreateNewWindow(int32_t aChromeFlags, |
michael@0 | 1718 | nsIXULWindow **_retval) |
michael@0 | 1719 | { |
michael@0 | 1720 | NS_ENSURE_ARG_POINTER(_retval); |
michael@0 | 1721 | |
michael@0 | 1722 | if (aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME) |
michael@0 | 1723 | return CreateNewChromeWindow(aChromeFlags, _retval); |
michael@0 | 1724 | return CreateNewContentWindow(aChromeFlags, _retval); |
michael@0 | 1725 | } |
michael@0 | 1726 | |
michael@0 | 1727 | NS_IMETHODIMP nsXULWindow::CreateNewChromeWindow(int32_t aChromeFlags, |
michael@0 | 1728 | nsIXULWindow **_retval) |
michael@0 | 1729 | { |
michael@0 | 1730 | nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); |
michael@0 | 1731 | NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE); |
michael@0 | 1732 | |
michael@0 | 1733 | // Just do a normal create of a window and return. |
michael@0 | 1734 | |
michael@0 | 1735 | nsCOMPtr<nsIXULWindow> newWindow; |
michael@0 | 1736 | appShell->CreateTopLevelWindow(this, nullptr, aChromeFlags, |
michael@0 | 1737 | nsIAppShellService::SIZE_TO_CONTENT, |
michael@0 | 1738 | nsIAppShellService::SIZE_TO_CONTENT, |
michael@0 | 1739 | getter_AddRefs(newWindow)); |
michael@0 | 1740 | |
michael@0 | 1741 | NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE); |
michael@0 | 1742 | |
michael@0 | 1743 | *_retval = newWindow; |
michael@0 | 1744 | NS_ADDREF(*_retval); |
michael@0 | 1745 | |
michael@0 | 1746 | return NS_OK; |
michael@0 | 1747 | } |
michael@0 | 1748 | |
michael@0 | 1749 | NS_IMETHODIMP nsXULWindow::CreateNewContentWindow(int32_t aChromeFlags, |
michael@0 | 1750 | nsIXULWindow **_retval) |
michael@0 | 1751 | { |
michael@0 | 1752 | nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); |
michael@0 | 1753 | NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE); |
michael@0 | 1754 | |
michael@0 | 1755 | // We need to create a new top level window and then enter a nested |
michael@0 | 1756 | // loop. Eventually the new window will be told that it has loaded, |
michael@0 | 1757 | // at which time we know it is safe to spin out of the nested loop |
michael@0 | 1758 | // and allow the opening code to proceed. |
michael@0 | 1759 | |
michael@0 | 1760 | nsCOMPtr<nsIURI> uri; |
michael@0 | 1761 | |
michael@0 | 1762 | nsAdoptingCString urlStr = Preferences::GetCString("browser.chromeURL"); |
michael@0 | 1763 | if (urlStr.IsEmpty()) { |
michael@0 | 1764 | urlStr.AssignLiteral("chrome://navigator/content/navigator.xul"); |
michael@0 | 1765 | } |
michael@0 | 1766 | |
michael@0 | 1767 | nsCOMPtr<nsIIOService> service(do_GetService(NS_IOSERVICE_CONTRACTID)); |
michael@0 | 1768 | if (service) { |
michael@0 | 1769 | service->NewURI(urlStr, nullptr, nullptr, getter_AddRefs(uri)); |
michael@0 | 1770 | } |
michael@0 | 1771 | NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); |
michael@0 | 1772 | |
michael@0 | 1773 | // We need to create a chrome window to contain the content window we're about |
michael@0 | 1774 | // to pass back. The subject principal needs to be system while we're creating |
michael@0 | 1775 | // it to make things work right, so force a system caller. See bug 799348 |
michael@0 | 1776 | // comment 13 for a description of what happens when we don't. |
michael@0 | 1777 | nsCOMPtr<nsIXULWindow> newWindow; |
michael@0 | 1778 | { |
michael@0 | 1779 | AutoNoJSAPI nojsapi; |
michael@0 | 1780 | appShell->CreateTopLevelWindow(this, uri, |
michael@0 | 1781 | aChromeFlags, 615, 480, |
michael@0 | 1782 | getter_AddRefs(newWindow)); |
michael@0 | 1783 | NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE); |
michael@0 | 1784 | } |
michael@0 | 1785 | |
michael@0 | 1786 | // Specify that we want the window to remain locked until the chrome has loaded. |
michael@0 | 1787 | nsXULWindow *xulWin = static_cast<nsXULWindow*> |
michael@0 | 1788 | (static_cast<nsIXULWindow*> |
michael@0 | 1789 | (newWindow)); |
michael@0 | 1790 | |
michael@0 | 1791 | xulWin->LockUntilChromeLoad(); |
michael@0 | 1792 | |
michael@0 | 1793 | { |
michael@0 | 1794 | AutoNoJSAPI nojsapi; |
michael@0 | 1795 | nsIThread *thread = NS_GetCurrentThread(); |
michael@0 | 1796 | while (xulWin->IsLocked()) { |
michael@0 | 1797 | if (!NS_ProcessNextEvent(thread)) |
michael@0 | 1798 | break; |
michael@0 | 1799 | } |
michael@0 | 1800 | } |
michael@0 | 1801 | |
michael@0 | 1802 | NS_ENSURE_STATE(xulWin->mPrimaryContentShell); |
michael@0 | 1803 | |
michael@0 | 1804 | *_retval = newWindow; |
michael@0 | 1805 | NS_ADDREF(*_retval); |
michael@0 | 1806 | |
michael@0 | 1807 | return NS_OK; |
michael@0 | 1808 | } |
michael@0 | 1809 | |
michael@0 | 1810 | void nsXULWindow::EnableParent(bool aEnable) |
michael@0 | 1811 | { |
michael@0 | 1812 | nsCOMPtr<nsIBaseWindow> parentWindow; |
michael@0 | 1813 | nsCOMPtr<nsIWidget> parentWidget; |
michael@0 | 1814 | |
michael@0 | 1815 | parentWindow = do_QueryReferent(mParentWindow); |
michael@0 | 1816 | if (parentWindow) |
michael@0 | 1817 | parentWindow->GetMainWidget(getter_AddRefs(parentWidget)); |
michael@0 | 1818 | if (parentWidget) |
michael@0 | 1819 | parentWidget->Enable(aEnable); |
michael@0 | 1820 | } |
michael@0 | 1821 | |
michael@0 | 1822 | // Constrain the window to its proper z-level |
michael@0 | 1823 | bool nsXULWindow::ConstrainToZLevel(bool aImmediate, |
michael@0 | 1824 | nsWindowZ *aPlacement, |
michael@0 | 1825 | nsIWidget *aReqBelow, |
michael@0 | 1826 | nsIWidget **aActualBelow) |
michael@0 | 1827 | { |
michael@0 | 1828 | #if 0 |
michael@0 | 1829 | /* Do we have a parent window? This means our z-order is already constrained, |
michael@0 | 1830 | since we're a dependent window. Our window list isn't hierarchical, |
michael@0 | 1831 | so we can't properly calculate placement for such a window. |
michael@0 | 1832 | Should we just abort? */ |
michael@0 | 1833 | nsCOMPtr<nsIBaseWindow> parentWindow = do_QueryReferent(mParentWindow); |
michael@0 | 1834 | if (parentWindow) |
michael@0 | 1835 | return false; |
michael@0 | 1836 | #endif |
michael@0 | 1837 | |
michael@0 | 1838 | nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); |
michael@0 | 1839 | if (!mediator) |
michael@0 | 1840 | return false; |
michael@0 | 1841 | |
michael@0 | 1842 | bool altered; |
michael@0 | 1843 | uint32_t position, |
michael@0 | 1844 | newPosition, |
michael@0 | 1845 | zLevel; |
michael@0 | 1846 | nsIXULWindow *us = this; |
michael@0 | 1847 | |
michael@0 | 1848 | altered = false; |
michael@0 | 1849 | mediator->GetZLevel(this, &zLevel); |
michael@0 | 1850 | |
michael@0 | 1851 | // translate from WidgetGUIEvent to nsIWindowMediator constants |
michael@0 | 1852 | position = nsIWindowMediator::zLevelTop; |
michael@0 | 1853 | if (*aPlacement == nsWindowZBottom || zLevel == nsIXULWindow::lowestZ) |
michael@0 | 1854 | position = nsIWindowMediator::zLevelBottom; |
michael@0 | 1855 | else if (*aPlacement == nsWindowZRelative) |
michael@0 | 1856 | position = nsIWindowMediator::zLevelBelow; |
michael@0 | 1857 | |
michael@0 | 1858 | if (NS_SUCCEEDED(mediator->CalculateZPosition(us, position, aReqBelow, |
michael@0 | 1859 | &newPosition, aActualBelow, &altered))) { |
michael@0 | 1860 | /* If we were asked to move to the top but constrained to remain |
michael@0 | 1861 | below one of our other windows, first move all windows in that |
michael@0 | 1862 | window's layer and above to the top. This allows the user to |
michael@0 | 1863 | click a window which can't be topmost and still bring mozilla |
michael@0 | 1864 | to the foreground. */ |
michael@0 | 1865 | if (altered && |
michael@0 | 1866 | (position == nsIWindowMediator::zLevelTop || |
michael@0 | 1867 | (position == nsIWindowMediator::zLevelBelow && aReqBelow == 0))) |
michael@0 | 1868 | PlaceWindowLayersBehind(zLevel + 1, nsIXULWindow::highestZ, 0); |
michael@0 | 1869 | |
michael@0 | 1870 | if (*aPlacement != nsWindowZBottom && |
michael@0 | 1871 | position == nsIWindowMediator::zLevelBottom) |
michael@0 | 1872 | altered = true; |
michael@0 | 1873 | if (altered || aImmediate) { |
michael@0 | 1874 | if (newPosition == nsIWindowMediator::zLevelTop) |
michael@0 | 1875 | *aPlacement = nsWindowZTop; |
michael@0 | 1876 | else if (newPosition == nsIWindowMediator::zLevelBottom) |
michael@0 | 1877 | *aPlacement = nsWindowZBottom; |
michael@0 | 1878 | else |
michael@0 | 1879 | *aPlacement = nsWindowZRelative; |
michael@0 | 1880 | |
michael@0 | 1881 | if (aImmediate) { |
michael@0 | 1882 | nsCOMPtr<nsIBaseWindow> ourBase = do_QueryObject(this); |
michael@0 | 1883 | if (ourBase) { |
michael@0 | 1884 | nsCOMPtr<nsIWidget> ourWidget; |
michael@0 | 1885 | ourBase->GetMainWidget(getter_AddRefs(ourWidget)); |
michael@0 | 1886 | ourWidget->PlaceBehind(*aPlacement == nsWindowZBottom ? |
michael@0 | 1887 | eZPlacementBottom : eZPlacementBelow, |
michael@0 | 1888 | *aActualBelow, false); |
michael@0 | 1889 | } |
michael@0 | 1890 | } |
michael@0 | 1891 | } |
michael@0 | 1892 | |
michael@0 | 1893 | /* CalculateZPosition can tell us to be below nothing, because it tries |
michael@0 | 1894 | not to change something it doesn't recognize. A request to verify |
michael@0 | 1895 | being below an unrecognized window, then, is treated as a request |
michael@0 | 1896 | to come to the top (below null) */ |
michael@0 | 1897 | nsCOMPtr<nsIXULWindow> windowAbove; |
michael@0 | 1898 | if (newPosition == nsIWindowMediator::zLevelBelow && *aActualBelow) { |
michael@0 | 1899 | windowAbove = (*aActualBelow)->GetWidgetListener()->GetXULWindow(); |
michael@0 | 1900 | } |
michael@0 | 1901 | |
michael@0 | 1902 | mediator->SetZPosition(us, newPosition, windowAbove); |
michael@0 | 1903 | } |
michael@0 | 1904 | |
michael@0 | 1905 | return altered; |
michael@0 | 1906 | } |
michael@0 | 1907 | |
michael@0 | 1908 | /* Re-z-position all windows in the layers from aLowLevel to aHighLevel, |
michael@0 | 1909 | inclusive, to be behind aBehind. aBehind of null means on top. |
michael@0 | 1910 | Note this method actually does nothing to our relative window positions. |
michael@0 | 1911 | (And therefore there's no need to inform WindowMediator we're moving |
michael@0 | 1912 | things, because we aren't.) This method is useful for, say, moving |
michael@0 | 1913 | a range of layers of our own windows relative to windows belonging to |
michael@0 | 1914 | external applications. |
michael@0 | 1915 | */ |
michael@0 | 1916 | void nsXULWindow::PlaceWindowLayersBehind(uint32_t aLowLevel, |
michael@0 | 1917 | uint32_t aHighLevel, |
michael@0 | 1918 | nsIXULWindow *aBehind) |
michael@0 | 1919 | { |
michael@0 | 1920 | // step through windows in z-order from top to bottommost window |
michael@0 | 1921 | |
michael@0 | 1922 | nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); |
michael@0 | 1923 | if (!mediator) |
michael@0 | 1924 | return; |
michael@0 | 1925 | |
michael@0 | 1926 | nsCOMPtr<nsISimpleEnumerator> windowEnumerator; |
michael@0 | 1927 | mediator->GetZOrderXULWindowEnumerator(0, true, |
michael@0 | 1928 | getter_AddRefs(windowEnumerator)); |
michael@0 | 1929 | if (!windowEnumerator) |
michael@0 | 1930 | return; |
michael@0 | 1931 | |
michael@0 | 1932 | // each window will be moved behind previousHighWidget, itself |
michael@0 | 1933 | // a moving target. initialize it. |
michael@0 | 1934 | nsCOMPtr<nsIWidget> previousHighWidget; |
michael@0 | 1935 | if (aBehind) { |
michael@0 | 1936 | nsCOMPtr<nsIBaseWindow> highBase(do_QueryInterface(aBehind)); |
michael@0 | 1937 | if (highBase) |
michael@0 | 1938 | highBase->GetMainWidget(getter_AddRefs(previousHighWidget)); |
michael@0 | 1939 | } |
michael@0 | 1940 | |
michael@0 | 1941 | // get next lower window |
michael@0 | 1942 | bool more; |
michael@0 | 1943 | while (windowEnumerator->HasMoreElements(&more), more) { |
michael@0 | 1944 | uint32_t nextZ; // z-level of nextWindow |
michael@0 | 1945 | nsCOMPtr<nsISupports> nextWindow; |
michael@0 | 1946 | windowEnumerator->GetNext(getter_AddRefs(nextWindow)); |
michael@0 | 1947 | nsCOMPtr<nsIXULWindow> nextXULWindow(do_QueryInterface(nextWindow)); |
michael@0 | 1948 | nextXULWindow->GetZLevel(&nextZ); |
michael@0 | 1949 | if (nextZ < aLowLevel) |
michael@0 | 1950 | break; // we've processed all windows through aLowLevel |
michael@0 | 1951 | |
michael@0 | 1952 | // move it just below its next higher window |
michael@0 | 1953 | nsCOMPtr<nsIBaseWindow> nextBase(do_QueryInterface(nextXULWindow)); |
michael@0 | 1954 | if (nextBase) { |
michael@0 | 1955 | nsCOMPtr<nsIWidget> nextWidget; |
michael@0 | 1956 | nextBase->GetMainWidget(getter_AddRefs(nextWidget)); |
michael@0 | 1957 | if (nextZ <= aHighLevel) |
michael@0 | 1958 | nextWidget->PlaceBehind(eZPlacementBelow, previousHighWidget, false); |
michael@0 | 1959 | previousHighWidget = nextWidget; |
michael@0 | 1960 | } |
michael@0 | 1961 | } |
michael@0 | 1962 | } |
michael@0 | 1963 | |
michael@0 | 1964 | void nsXULWindow::SetContentScrollbarVisibility(bool aVisible) |
michael@0 | 1965 | { |
michael@0 | 1966 | nsCOMPtr<nsPIDOMWindow> contentWin(do_GetInterface(mPrimaryContentShell)); |
michael@0 | 1967 | if (contentWin) { |
michael@0 | 1968 | mozilla::ErrorResult rv; |
michael@0 | 1969 | nsRefPtr<nsGlobalWindow> window = static_cast<nsGlobalWindow*>(contentWin.get()); |
michael@0 | 1970 | nsRefPtr<mozilla::dom::BarProp> scrollbars = window->GetScrollbars(rv); |
michael@0 | 1971 | if (scrollbars) { |
michael@0 | 1972 | scrollbars->SetVisible(aVisible, rv); |
michael@0 | 1973 | } |
michael@0 | 1974 | } |
michael@0 | 1975 | } |
michael@0 | 1976 | |
michael@0 | 1977 | bool nsXULWindow::GetContentScrollbarVisibility() |
michael@0 | 1978 | { |
michael@0 | 1979 | // This code already exists in dom/src/base/nsBarProp.cpp, but we |
michael@0 | 1980 | // can't safely get to that from here as this function is called |
michael@0 | 1981 | // while the DOM window is being set up, and we need the DOM window |
michael@0 | 1982 | // to get to that code. |
michael@0 | 1983 | nsCOMPtr<nsIScrollable> scroller(do_QueryInterface(mPrimaryContentShell)); |
michael@0 | 1984 | |
michael@0 | 1985 | if (scroller) { |
michael@0 | 1986 | int32_t prefValue; |
michael@0 | 1987 | scroller->GetDefaultScrollbarPreferences( |
michael@0 | 1988 | nsIScrollable::ScrollOrientation_Y, &prefValue); |
michael@0 | 1989 | if (prefValue == nsIScrollable::Scrollbar_Never) // try the other way |
michael@0 | 1990 | scroller->GetDefaultScrollbarPreferences( |
michael@0 | 1991 | nsIScrollable::ScrollOrientation_X, &prefValue); |
michael@0 | 1992 | |
michael@0 | 1993 | if (prefValue == nsIScrollable::Scrollbar_Never) |
michael@0 | 1994 | return false; |
michael@0 | 1995 | } |
michael@0 | 1996 | |
michael@0 | 1997 | return true; |
michael@0 | 1998 | } |
michael@0 | 1999 | |
michael@0 | 2000 | // during spinup, attributes that haven't been loaded yet can't be dirty |
michael@0 | 2001 | void nsXULWindow::PersistentAttributesDirty(uint32_t aDirtyFlags) |
michael@0 | 2002 | { |
michael@0 | 2003 | mPersistentAttributesDirty |= aDirtyFlags & mPersistentAttributesMask; |
michael@0 | 2004 | } |
michael@0 | 2005 | |
michael@0 | 2006 | NS_IMETHODIMP nsXULWindow::ApplyChromeFlags() |
michael@0 | 2007 | { |
michael@0 | 2008 | nsCOMPtr<dom::Element> window = GetWindowDOMElement(); |
michael@0 | 2009 | NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); |
michael@0 | 2010 | |
michael@0 | 2011 | if (mChromeLoaded) { |
michael@0 | 2012 | // The two calls in this block don't need to happen early because they |
michael@0 | 2013 | // don't cause a global restyle on the document. Not only that, but the |
michael@0 | 2014 | // scrollbar stuff needs a content area to toggle the scrollbars on anyway. |
michael@0 | 2015 | // So just don't do these until mChromeLoaded is true. |
michael@0 | 2016 | |
michael@0 | 2017 | // Scrollbars have their own special treatment. |
michael@0 | 2018 | SetContentScrollbarVisibility(mChromeFlags & |
michael@0 | 2019 | nsIWebBrowserChrome::CHROME_SCROLLBARS ? |
michael@0 | 2020 | true : false); |
michael@0 | 2021 | } |
michael@0 | 2022 | |
michael@0 | 2023 | /* the other flags are handled together. we have style rules |
michael@0 | 2024 | in navigator.css that trigger visibility based on |
michael@0 | 2025 | the 'chromehidden' attribute of the <window> tag. */ |
michael@0 | 2026 | nsAutoString newvalue; |
michael@0 | 2027 | |
michael@0 | 2028 | if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_MENUBAR)) |
michael@0 | 2029 | newvalue.AppendLiteral("menubar "); |
michael@0 | 2030 | |
michael@0 | 2031 | if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_TOOLBAR)) |
michael@0 | 2032 | newvalue.AppendLiteral("toolbar "); |
michael@0 | 2033 | |
michael@0 | 2034 | if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_LOCATIONBAR)) |
michael@0 | 2035 | newvalue.AppendLiteral("location "); |
michael@0 | 2036 | |
michael@0 | 2037 | if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR)) |
michael@0 | 2038 | newvalue.AppendLiteral("directories "); |
michael@0 | 2039 | |
michael@0 | 2040 | if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_STATUSBAR)) |
michael@0 | 2041 | newvalue.AppendLiteral("status "); |
michael@0 | 2042 | |
michael@0 | 2043 | if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_EXTRA)) |
michael@0 | 2044 | newvalue.AppendLiteral("extrachrome "); |
michael@0 | 2045 | |
michael@0 | 2046 | // Note that if we're not actually changing the value this will be a no-op, |
michael@0 | 2047 | // so no need to compare to the old value. |
michael@0 | 2048 | ErrorResult rv; |
michael@0 | 2049 | window->SetAttribute(NS_LITERAL_STRING("chromehidden"), newvalue, rv); |
michael@0 | 2050 | |
michael@0 | 2051 | return NS_OK; |
michael@0 | 2052 | } |
michael@0 | 2053 | |
michael@0 | 2054 | NS_IMETHODIMP nsXULWindow::GetXULBrowserWindow(nsIXULBrowserWindow * *aXULBrowserWindow) |
michael@0 | 2055 | { |
michael@0 | 2056 | NS_IF_ADDREF(*aXULBrowserWindow = mXULBrowserWindow); |
michael@0 | 2057 | return NS_OK; |
michael@0 | 2058 | } |
michael@0 | 2059 | |
michael@0 | 2060 | NS_IMETHODIMP nsXULWindow::SetXULBrowserWindow(nsIXULBrowserWindow * aXULBrowserWindow) |
michael@0 | 2061 | { |
michael@0 | 2062 | mXULBrowserWindow = aXULBrowserWindow; |
michael@0 | 2063 | return NS_OK; |
michael@0 | 2064 | } |
michael@0 | 2065 | |
michael@0 | 2066 | //***************************************************************************** |
michael@0 | 2067 | //*** nsContentShellInfo: Object Management |
michael@0 | 2068 | //***************************************************************************** |
michael@0 | 2069 | |
michael@0 | 2070 | nsContentShellInfo::nsContentShellInfo(const nsAString& aID, |
michael@0 | 2071 | nsIWeakReference* aContentShell) |
michael@0 | 2072 | : id(aID), |
michael@0 | 2073 | child(aContentShell) |
michael@0 | 2074 | { |
michael@0 | 2075 | MOZ_COUNT_CTOR(nsContentShellInfo); |
michael@0 | 2076 | } |
michael@0 | 2077 | |
michael@0 | 2078 | nsContentShellInfo::~nsContentShellInfo() |
michael@0 | 2079 | { |
michael@0 | 2080 | MOZ_COUNT_DTOR(nsContentShellInfo); |
michael@0 | 2081 | //XXX Set Tree Owner to null if the tree owner is nsXULWindow->mContentTreeOwner |
michael@0 | 2082 | } |