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