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