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