Bumping gaia.json for 1 gaia revision(s) a=gaia-bump
[gecko.git] / xpfe / appshell / nsXULWindow.cpp
blob98d47eb1770b90523a4c846f805a8ee26621d7be
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 // "windowtype" attribute
1395 windowElement->GetAttribute(WINDOWTYPE_ATTRIBUTE, attr);
1396 if (!attr.IsEmpty()) {
1397 mWindow->SetWindowClass(attr);
1400 // "id" attribute for icon
1401 windowElement->GetAttribute(NS_LITERAL_STRING("id"), attr);
1402 if (attr.IsEmpty()) {
1403 attr.AssignLiteral("default");
1405 mWindow->SetIcon(attr);
1407 // "drawtitle" attribute
1408 windowElement->GetAttribute(NS_LITERAL_STRING("drawtitle"), attr);
1409 mWindow->SetDrawsTitle(attr.LowerCaseEqualsLiteral("true"));
1411 // "toggletoolbar" attribute
1412 windowElement->GetAttribute(NS_LITERAL_STRING("toggletoolbar"), attr);
1413 mWindow->SetShowsToolbarButton(attr.LowerCaseEqualsLiteral("true"));
1415 // "fullscreenbutton" attribute
1416 windowElement->GetAttribute(NS_LITERAL_STRING("fullscreenbutton"), attr);
1417 mWindow->SetShowsFullScreenButton(attr.LowerCaseEqualsLiteral("true"));
1419 // "macanimationtype" attribute
1420 windowElement->GetAttribute(NS_LITERAL_STRING("macanimationtype"), attr);
1421 if (attr.EqualsLiteral("document")) {
1422 mWindow->SetWindowAnimationType(nsIWidget::eDocumentWindowAnimation);
1426 NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
1428 // can happen when the persistence timer fires at an inopportune time
1429 // during window shutdown
1430 if (!mDocShell)
1431 return NS_ERROR_FAILURE;
1433 nsCOMPtr<dom::Element> docShellElement = GetWindowDOMElement();
1434 if (!docShellElement)
1435 return NS_ERROR_FAILURE;
1437 nsAutoString persistString;
1438 docShellElement->GetAttribute(PERSIST_ATTRIBUTE, persistString);
1439 if (persistString.IsEmpty()) { // quick check which sometimes helps
1440 mPersistentAttributesDirty = 0;
1441 return NS_OK;
1444 // get our size, position and mode to persist
1445 nsIntRect rect;
1446 bool gotRestoredBounds = NS_SUCCEEDED(mWindow->GetRestoredBounds(rect));
1448 CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale();
1450 // make our position relative to our parent, if any
1451 nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow));
1452 if (parent && gotRestoredBounds) {
1453 int32_t parentX, parentY;
1454 if (NS_SUCCEEDED(parent->GetPosition(&parentX, &parentY))) {
1455 rect.x -= parentX;
1456 rect.y -= parentY;
1460 char sizeBuf[10];
1461 nsAutoString sizeString;
1462 nsAutoString windowElementId;
1463 nsCOMPtr<nsIDOMXULDocument> ownerXULDoc;
1465 // fetch docShellElement's ID and XUL owner document
1466 ownerXULDoc = do_QueryInterface(docShellElement->OwnerDoc());
1467 if (docShellElement->IsXUL()) {
1468 docShellElement->GetId(windowElementId);
1471 ErrorResult rv;
1472 // (only for size elements which are persisted)
1473 if ((mPersistentAttributesDirty & PAD_POSITION) && gotRestoredBounds) {
1474 if (persistString.Find("screenX") >= 0) {
1475 PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.x / scale.scale));
1476 sizeString.AssignWithConversion(sizeBuf);
1477 docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString, rv);
1478 if (ownerXULDoc) // force persistence in case the value didn't change
1479 ownerXULDoc->Persist(windowElementId, SCREENX_ATTRIBUTE);
1481 if (persistString.Find("screenY") >= 0) {
1482 PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.y / scale.scale));
1483 sizeString.AssignWithConversion(sizeBuf);
1484 docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString, rv);
1485 if (ownerXULDoc)
1486 ownerXULDoc->Persist(windowElementId, SCREENY_ATTRIBUTE);
1490 if ((mPersistentAttributesDirty & PAD_SIZE) && gotRestoredBounds) {
1491 if (persistString.Find("width") >= 0) {
1492 PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.width / scale.scale));
1493 sizeString.AssignWithConversion(sizeBuf);
1494 docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv);
1495 if (ownerXULDoc)
1496 ownerXULDoc->Persist(windowElementId, WIDTH_ATTRIBUTE);
1498 if (persistString.Find("height") >= 0) {
1499 PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(rect.height / scale.scale));
1500 sizeString.AssignWithConversion(sizeBuf);
1501 docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv);
1502 if (ownerXULDoc)
1503 ownerXULDoc->Persist(windowElementId, HEIGHT_ATTRIBUTE);
1507 if (mPersistentAttributesDirty & PAD_MISC) {
1508 int32_t sizeMode = mWindow->SizeMode();
1510 if (sizeMode != nsSizeMode_Minimized) {
1511 if (sizeMode == nsSizeMode_Maximized)
1512 sizeString.Assign(SIZEMODE_MAXIMIZED);
1513 else if (sizeMode == nsSizeMode_Fullscreen)
1514 sizeString.Assign(SIZEMODE_FULLSCREEN);
1515 else
1516 sizeString.Assign(SIZEMODE_NORMAL);
1517 docShellElement->SetAttribute(MODE_ATTRIBUTE, sizeString, rv);
1518 if (ownerXULDoc && persistString.Find("sizemode") >= 0)
1519 ownerXULDoc->Persist(windowElementId, MODE_ATTRIBUTE);
1521 if (persistString.Find("zlevel") >= 0) {
1522 uint32_t zLevel;
1523 nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1524 if (mediator) {
1525 mediator->GetZLevel(this, &zLevel);
1526 PR_snprintf(sizeBuf, sizeof(sizeBuf), "%lu", (unsigned long)zLevel);
1527 sizeString.AssignWithConversion(sizeBuf);
1528 docShellElement->SetAttribute(ZLEVEL_ATTRIBUTE, sizeString, rv);
1529 ownerXULDoc->Persist(windowElementId, ZLEVEL_ATTRIBUTE);
1534 mPersistentAttributesDirty = 0;
1535 return NS_OK;
1538 NS_IMETHODIMP nsXULWindow::GetWindowDOMWindow(nsIDOMWindow** aDOMWindow)
1540 NS_ENSURE_STATE(mDocShell);
1542 if (!mDOMWindow)
1543 mDOMWindow = mDocShell->GetWindow();
1544 NS_ENSURE_TRUE(mDOMWindow, NS_ERROR_FAILURE);
1546 *aDOMWindow = mDOMWindow;
1547 NS_ADDREF(*aDOMWindow);
1548 return NS_OK;
1551 dom::Element*
1552 nsXULWindow::GetWindowDOMElement() const
1554 NS_ENSURE_TRUE(mDocShell, nullptr);
1556 nsCOMPtr<nsIContentViewer> cv;
1557 mDocShell->GetContentViewer(getter_AddRefs(cv));
1558 NS_ENSURE_TRUE(cv, nullptr);
1560 const nsIDocument* document = cv->GetDocument();
1561 NS_ENSURE_TRUE(document, nullptr);
1563 return document->GetRootElement();
1566 nsresult nsXULWindow::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
1567 bool aPrimary, bool aTargetable, const nsAString& aID)
1569 nsContentShellInfo* shellInfo = nullptr;
1571 uint32_t i, count = mContentShells.Length();
1572 nsWeakPtr contentShellWeak = do_GetWeakReference(aContentShell);
1573 for (i = 0; i < count; i++) {
1574 nsContentShellInfo* info = mContentShells.ElementAt(i);
1575 if (info->id.Equals(aID)) {
1576 // We already exist. Do a replace.
1577 info->child = contentShellWeak;
1578 shellInfo = info;
1580 else if (info->child == contentShellWeak)
1581 info->child = nullptr;
1584 if (!shellInfo) {
1585 shellInfo = new nsContentShellInfo(aID, contentShellWeak);
1586 mContentShells.AppendElement(shellInfo);
1589 // Set the default content tree owner
1590 if (aPrimary) {
1591 NS_ENSURE_SUCCESS(EnsurePrimaryContentTreeOwner(), NS_ERROR_FAILURE);
1592 aContentShell->SetTreeOwner(mPrimaryContentTreeOwner);
1593 mPrimaryContentShell = aContentShell;
1595 else {
1596 NS_ENSURE_SUCCESS(EnsureContentTreeOwner(), NS_ERROR_FAILURE);
1597 aContentShell->SetTreeOwner(mContentTreeOwner);
1598 if (mPrimaryContentShell == aContentShell)
1599 mPrimaryContentShell = nullptr;
1602 if (aTargetable) {
1603 #ifdef DEBUG
1604 int32_t debugCount = mTargetableShells.Count();
1605 int32_t debugCounter;
1606 for (debugCounter = debugCount - 1; debugCounter >= 0; --debugCounter) {
1607 nsCOMPtr<nsIDocShellTreeItem> curItem =
1608 do_QueryReferent(mTargetableShells[debugCounter]);
1609 NS_ASSERTION(!SameCOMIdentity(curItem, aContentShell),
1610 "Adding already existing item to mTargetableShells");
1612 #endif
1614 // put the new shell at the start of the targetable shells list if either
1615 // it's the new primary shell or there is no existing primary shell (which
1616 // means that chances are this one just stopped being primary). If we
1617 // really cared, we could keep track of the "last no longer primary shell"
1618 // explicitly, but it probably doesn't matter enough: the difference would
1619 // only be felt in a situation where all shells were non-primary, which
1620 // doesn't happen much. In a situation where there is one and only one
1621 // primary shell, and in which shells get unmarked as primary before some
1622 // other shell gets marked as primary, this effectively stores the list of
1623 // targetable shells in "most recently primary first" order.
1624 bool inserted;
1625 if (aPrimary || !mPrimaryContentShell) {
1626 inserted = mTargetableShells.InsertObjectAt(contentShellWeak, 0);
1627 } else {
1628 inserted = mTargetableShells.AppendObject(contentShellWeak);
1630 NS_ENSURE_TRUE(inserted, NS_ERROR_OUT_OF_MEMORY);
1633 return NS_OK;
1636 nsresult nsXULWindow::ContentShellRemoved(nsIDocShellTreeItem* aContentShell)
1638 if (mPrimaryContentShell == aContentShell) {
1639 mPrimaryContentShell = nullptr;
1642 int32_t i, count = mContentShells.Length();
1643 for (i = count - 1; i >= 0; --i) {
1644 nsContentShellInfo* info = mContentShells.ElementAt(i);
1645 nsCOMPtr<nsIDocShellTreeItem> curItem = do_QueryReferent(info->child);
1646 if (!curItem || SameCOMIdentity(curItem, aContentShell)) {
1647 mContentShells.RemoveElementAt(i);
1648 delete info;
1652 count = mTargetableShells.Count();
1653 for (i = count - 1; i >= 0; --i) {
1654 nsCOMPtr<nsIDocShellTreeItem> curItem =
1655 do_QueryReferent(mTargetableShells[i]);
1656 if (!curItem || SameCOMIdentity(curItem, aContentShell)) {
1657 mTargetableShells.RemoveObjectAt(i);
1661 return NS_OK;
1664 NS_IMETHODIMP nsXULWindow::SizeShellTo(nsIDocShellTreeItem* aShellItem,
1665 int32_t aCX, int32_t aCY)
1667 // XXXTAB This is wrong, we should actually reflow based on the passed in
1668 // shell. For now we are hacking and doing delta sizing. This is bad
1669 // because it assumes all size we add will go to the shell which probably
1670 // won't happen.
1672 nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem));
1673 NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
1675 int32_t width = 0;
1676 int32_t height = 0;
1677 shellAsWin->GetSize(&width, &height);
1679 int32_t widthDelta = aCX - width;
1680 int32_t heightDelta = aCY - height;
1682 if (widthDelta || heightDelta) {
1683 int32_t winCX = 0;
1684 int32_t winCY = 0;
1686 GetSize(&winCX, &winCY);
1687 // There's no point in trying to make the window smaller than the
1688 // desired docshell size --- that's not likely to work. This whole
1689 // function assumes that the outer docshell is adding some constant
1690 // "border" chrome to aShellItem.
1691 winCX = std::max(winCX + widthDelta, aCX);
1692 winCY = std::max(winCY + heightDelta, aCY);
1693 SetSize(winCX, winCY, true);
1696 return NS_OK;
1699 NS_IMETHODIMP nsXULWindow::ExitModalLoop(nsresult aStatus)
1701 if (mContinueModalLoop)
1702 EnableParent(true);
1703 mContinueModalLoop = false;
1704 mModalStatus = aStatus;
1705 return NS_OK;
1708 // top-level function to create a new window
1709 NS_IMETHODIMP nsXULWindow::CreateNewWindow(int32_t aChromeFlags,
1710 nsITabParent *aOpeningTab,
1711 nsIXULWindow **_retval)
1713 NS_ENSURE_ARG_POINTER(_retval);
1715 if (aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)
1716 return CreateNewChromeWindow(aChromeFlags, aOpeningTab, _retval);
1717 return CreateNewContentWindow(aChromeFlags, aOpeningTab, _retval);
1720 NS_IMETHODIMP nsXULWindow::CreateNewChromeWindow(int32_t aChromeFlags,
1721 nsITabParent *aOpeningTab,
1722 nsIXULWindow **_retval)
1724 nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
1725 NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
1727 // Just do a normal create of a window and return.
1729 nsCOMPtr<nsIXULWindow> newWindow;
1730 appShell->CreateTopLevelWindow(this, nullptr, aChromeFlags,
1731 nsIAppShellService::SIZE_TO_CONTENT,
1732 nsIAppShellService::SIZE_TO_CONTENT,
1733 aOpeningTab,
1734 getter_AddRefs(newWindow));
1736 NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE);
1738 *_retval = newWindow;
1739 NS_ADDREF(*_retval);
1741 return NS_OK;
1744 NS_IMETHODIMP nsXULWindow::CreateNewContentWindow(int32_t aChromeFlags,
1745 nsITabParent *aOpeningTab,
1746 nsIXULWindow **_retval)
1748 nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
1749 NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
1751 // We need to create a new top level window and then enter a nested
1752 // loop. Eventually the new window will be told that it has loaded,
1753 // at which time we know it is safe to spin out of the nested loop
1754 // and allow the opening code to proceed.
1756 nsCOMPtr<nsIURI> uri;
1758 nsAdoptingCString urlStr = Preferences::GetCString("browser.chromeURL");
1759 if (urlStr.IsEmpty()) {
1760 urlStr.AssignLiteral("chrome://navigator/content/navigator.xul");
1763 nsCOMPtr<nsIIOService> service(do_GetService(NS_IOSERVICE_CONTRACTID));
1764 if (service) {
1765 service->NewURI(urlStr, nullptr, nullptr, getter_AddRefs(uri));
1767 NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
1769 // We need to create a chrome window to contain the content window we're about
1770 // to pass back. The subject principal needs to be system while we're creating
1771 // it to make things work right, so force a system caller. See bug 799348
1772 // comment 13 for a description of what happens when we don't.
1773 nsCOMPtr<nsIXULWindow> newWindow;
1775 AutoNoJSAPI nojsapi;
1776 appShell->CreateTopLevelWindow(this, uri,
1777 aChromeFlags, 615, 480,
1778 aOpeningTab,
1779 getter_AddRefs(newWindow));
1780 NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE);
1783 // Specify that we want the window to remain locked until the chrome has loaded.
1784 nsXULWindow *xulWin = static_cast<nsXULWindow*>
1785 (static_cast<nsIXULWindow*>
1786 (newWindow));
1788 xulWin->LockUntilChromeLoad();
1791 AutoNoJSAPI nojsapi;
1792 nsIThread *thread = NS_GetCurrentThread();
1793 while (xulWin->IsLocked()) {
1794 if (!NS_ProcessNextEvent(thread))
1795 break;
1799 // If aOpeningTab is not null, it means that we're creating a new window
1800 // with a remote browser, which doesn't have a primary docshell. In that
1801 // case, we check for the chrome window docshell and make sure that a new
1802 // remote tab was opened and stashed in that docshell.
1803 if (aOpeningTab) {
1804 NS_ENSURE_STATE(xulWin->mDocShell);
1805 NS_ENSURE_STATE(xulWin->mDocShell->GetOpenedRemote());
1806 } else {
1807 NS_ENSURE_STATE(xulWin->mPrimaryContentShell);
1810 *_retval = newWindow;
1811 NS_ADDREF(*_retval);
1813 return NS_OK;
1816 void nsXULWindow::EnableParent(bool aEnable)
1818 nsCOMPtr<nsIBaseWindow> parentWindow;
1819 nsCOMPtr<nsIWidget> parentWidget;
1821 parentWindow = do_QueryReferent(mParentWindow);
1822 if (parentWindow)
1823 parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
1824 if (parentWidget)
1825 parentWidget->Enable(aEnable);
1828 // Constrain the window to its proper z-level
1829 bool nsXULWindow::ConstrainToZLevel(bool aImmediate,
1830 nsWindowZ *aPlacement,
1831 nsIWidget *aReqBelow,
1832 nsIWidget **aActualBelow)
1834 #if 0
1835 /* Do we have a parent window? This means our z-order is already constrained,
1836 since we're a dependent window. Our window list isn't hierarchical,
1837 so we can't properly calculate placement for such a window.
1838 Should we just abort? */
1839 nsCOMPtr<nsIBaseWindow> parentWindow = do_QueryReferent(mParentWindow);
1840 if (parentWindow)
1841 return false;
1842 #endif
1844 nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1845 if (!mediator)
1846 return false;
1848 bool altered;
1849 uint32_t position,
1850 newPosition,
1851 zLevel;
1852 nsIXULWindow *us = this;
1854 altered = false;
1855 mediator->GetZLevel(this, &zLevel);
1857 // translate from WidgetGUIEvent to nsIWindowMediator constants
1858 position = nsIWindowMediator::zLevelTop;
1859 if (*aPlacement == nsWindowZBottom || zLevel == nsIXULWindow::lowestZ)
1860 position = nsIWindowMediator::zLevelBottom;
1861 else if (*aPlacement == nsWindowZRelative)
1862 position = nsIWindowMediator::zLevelBelow;
1864 if (NS_SUCCEEDED(mediator->CalculateZPosition(us, position, aReqBelow,
1865 &newPosition, aActualBelow, &altered))) {
1866 /* If we were asked to move to the top but constrained to remain
1867 below one of our other windows, first move all windows in that
1868 window's layer and above to the top. This allows the user to
1869 click a window which can't be topmost and still bring mozilla
1870 to the foreground. */
1871 if (altered &&
1872 (position == nsIWindowMediator::zLevelTop ||
1873 (position == nsIWindowMediator::zLevelBelow && aReqBelow == 0)))
1874 PlaceWindowLayersBehind(zLevel + 1, nsIXULWindow::highestZ, 0);
1876 if (*aPlacement != nsWindowZBottom &&
1877 position == nsIWindowMediator::zLevelBottom)
1878 altered = true;
1879 if (altered || aImmediate) {
1880 if (newPosition == nsIWindowMediator::zLevelTop)
1881 *aPlacement = nsWindowZTop;
1882 else if (newPosition == nsIWindowMediator::zLevelBottom)
1883 *aPlacement = nsWindowZBottom;
1884 else
1885 *aPlacement = nsWindowZRelative;
1887 if (aImmediate) {
1888 nsCOMPtr<nsIBaseWindow> ourBase = do_QueryObject(this);
1889 if (ourBase) {
1890 nsCOMPtr<nsIWidget> ourWidget;
1891 ourBase->GetMainWidget(getter_AddRefs(ourWidget));
1892 ourWidget->PlaceBehind(*aPlacement == nsWindowZBottom ?
1893 eZPlacementBottom : eZPlacementBelow,
1894 *aActualBelow, false);
1899 /* CalculateZPosition can tell us to be below nothing, because it tries
1900 not to change something it doesn't recognize. A request to verify
1901 being below an unrecognized window, then, is treated as a request
1902 to come to the top (below null) */
1903 nsCOMPtr<nsIXULWindow> windowAbove;
1904 if (newPosition == nsIWindowMediator::zLevelBelow && *aActualBelow) {
1905 windowAbove = (*aActualBelow)->GetWidgetListener()->GetXULWindow();
1908 mediator->SetZPosition(us, newPosition, windowAbove);
1911 return altered;
1914 /* Re-z-position all windows in the layers from aLowLevel to aHighLevel,
1915 inclusive, to be behind aBehind. aBehind of null means on top.
1916 Note this method actually does nothing to our relative window positions.
1917 (And therefore there's no need to inform WindowMediator we're moving
1918 things, because we aren't.) This method is useful for, say, moving
1919 a range of layers of our own windows relative to windows belonging to
1920 external applications.
1922 void nsXULWindow::PlaceWindowLayersBehind(uint32_t aLowLevel,
1923 uint32_t aHighLevel,
1924 nsIXULWindow *aBehind)
1926 // step through windows in z-order from top to bottommost window
1928 nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1929 if (!mediator)
1930 return;
1932 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
1933 mediator->GetZOrderXULWindowEnumerator(0, true,
1934 getter_AddRefs(windowEnumerator));
1935 if (!windowEnumerator)
1936 return;
1938 // each window will be moved behind previousHighWidget, itself
1939 // a moving target. initialize it.
1940 nsCOMPtr<nsIWidget> previousHighWidget;
1941 if (aBehind) {
1942 nsCOMPtr<nsIBaseWindow> highBase(do_QueryInterface(aBehind));
1943 if (highBase)
1944 highBase->GetMainWidget(getter_AddRefs(previousHighWidget));
1947 // get next lower window
1948 bool more;
1949 while (windowEnumerator->HasMoreElements(&more), more) {
1950 uint32_t nextZ; // z-level of nextWindow
1951 nsCOMPtr<nsISupports> nextWindow;
1952 windowEnumerator->GetNext(getter_AddRefs(nextWindow));
1953 nsCOMPtr<nsIXULWindow> nextXULWindow(do_QueryInterface(nextWindow));
1954 nextXULWindow->GetZLevel(&nextZ);
1955 if (nextZ < aLowLevel)
1956 break; // we've processed all windows through aLowLevel
1958 // move it just below its next higher window
1959 nsCOMPtr<nsIBaseWindow> nextBase(do_QueryInterface(nextXULWindow));
1960 if (nextBase) {
1961 nsCOMPtr<nsIWidget> nextWidget;
1962 nextBase->GetMainWidget(getter_AddRefs(nextWidget));
1963 if (nextZ <= aHighLevel)
1964 nextWidget->PlaceBehind(eZPlacementBelow, previousHighWidget, false);
1965 previousHighWidget = nextWidget;
1970 void nsXULWindow::SetContentScrollbarVisibility(bool aVisible)
1972 nsCOMPtr<nsPIDOMWindow> contentWin(do_GetInterface(mPrimaryContentShell));
1973 if (contentWin) {
1974 mozilla::ErrorResult rv;
1975 nsRefPtr<nsGlobalWindow> window = static_cast<nsGlobalWindow*>(contentWin.get());
1976 nsRefPtr<mozilla::dom::BarProp> scrollbars = window->GetScrollbars(rv);
1977 if (scrollbars) {
1978 scrollbars->SetVisible(aVisible, rv);
1983 bool nsXULWindow::GetContentScrollbarVisibility()
1985 // This code already exists in dom/src/base/nsBarProp.cpp, but we
1986 // can't safely get to that from here as this function is called
1987 // while the DOM window is being set up, and we need the DOM window
1988 // to get to that code.
1989 nsCOMPtr<nsIScrollable> scroller(do_QueryInterface(mPrimaryContentShell));
1991 if (scroller) {
1992 int32_t prefValue;
1993 scroller->GetDefaultScrollbarPreferences(
1994 nsIScrollable::ScrollOrientation_Y, &prefValue);
1995 if (prefValue == nsIScrollable::Scrollbar_Never) // try the other way
1996 scroller->GetDefaultScrollbarPreferences(
1997 nsIScrollable::ScrollOrientation_X, &prefValue);
1999 if (prefValue == nsIScrollable::Scrollbar_Never)
2000 return false;
2003 return true;
2006 // during spinup, attributes that haven't been loaded yet can't be dirty
2007 void nsXULWindow::PersistentAttributesDirty(uint32_t aDirtyFlags)
2009 mPersistentAttributesDirty |= aDirtyFlags & mPersistentAttributesMask;
2012 NS_IMETHODIMP nsXULWindow::ApplyChromeFlags()
2014 nsCOMPtr<dom::Element> window = GetWindowDOMElement();
2015 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
2017 if (mChromeLoaded) {
2018 // The two calls in this block don't need to happen early because they
2019 // don't cause a global restyle on the document. Not only that, but the
2020 // scrollbar stuff needs a content area to toggle the scrollbars on anyway.
2021 // So just don't do these until mChromeLoaded is true.
2023 // Scrollbars have their own special treatment.
2024 SetContentScrollbarVisibility(mChromeFlags &
2025 nsIWebBrowserChrome::CHROME_SCROLLBARS ?
2026 true : false);
2029 /* the other flags are handled together. we have style rules
2030 in navigator.css that trigger visibility based on
2031 the 'chromehidden' attribute of the <window> tag. */
2032 nsAutoString newvalue;
2034 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_MENUBAR))
2035 newvalue.AppendLiteral("menubar ");
2037 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_TOOLBAR))
2038 newvalue.AppendLiteral("toolbar ");
2040 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_LOCATIONBAR))
2041 newvalue.AppendLiteral("location ");
2043 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR))
2044 newvalue.AppendLiteral("directories ");
2046 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_STATUSBAR))
2047 newvalue.AppendLiteral("status ");
2049 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_EXTRA))
2050 newvalue.AppendLiteral("extrachrome ");
2052 // Note that if we're not actually changing the value this will be a no-op,
2053 // so no need to compare to the old value.
2054 ErrorResult rv;
2055 window->SetAttribute(NS_LITERAL_STRING("chromehidden"), newvalue, rv);
2057 return NS_OK;
2060 NS_IMETHODIMP nsXULWindow::GetXULBrowserWindow(nsIXULBrowserWindow * *aXULBrowserWindow)
2062 NS_IF_ADDREF(*aXULBrowserWindow = mXULBrowserWindow);
2063 return NS_OK;
2066 NS_IMETHODIMP nsXULWindow::SetXULBrowserWindow(nsIXULBrowserWindow * aXULBrowserWindow)
2068 mXULBrowserWindow = aXULBrowserWindow;
2069 return NS_OK;
2072 //*****************************************************************************
2073 //*** nsContentShellInfo: Object Management
2074 //*****************************************************************************
2076 nsContentShellInfo::nsContentShellInfo(const nsAString& aID,
2077 nsIWeakReference* aContentShell)
2078 : id(aID),
2079 child(aContentShell)
2081 MOZ_COUNT_CTOR(nsContentShellInfo);
2084 nsContentShellInfo::~nsContentShellInfo()
2086 MOZ_COUNT_DTOR(nsContentShellInfo);
2087 //XXX Set Tree Owner to null if the tree owner is nsXULWindow->mContentTreeOwner