xpfe/appshell/src/nsXULWindow.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:303c1c769668
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 "prprf.h"
18 #include "nsCRT.h"
19 #include "nsThreadUtils.h"
20 #include "nsNetCID.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 "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"
55
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"
63
64 using namespace mozilla;
65 using dom::AutoNoJSAPI;
66
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")
71
72 #define WINDOWTYPE_ATTRIBUTE NS_LITERAL_STRING("windowtype")
73
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")
81
82
83 //*****************************************************************************
84 //*** nsXULWindow: Object Management
85 //*****************************************************************************
86
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 }
111
112 nsXULWindow::~nsXULWindow()
113 {
114 Destroy();
115 }
116
117 //*****************************************************************************
118 // nsXULWindow::nsISupports
119 //*****************************************************************************
120
121 NS_IMPL_ADDREF(nsXULWindow)
122 NS_IMPL_RELEASE(nsXULWindow)
123
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
134
135 //*****************************************************************************
136 // nsXULWindow::nsIIntefaceRequestor
137 //*****************************************************************************
138
139 NS_IMETHODIMP nsXULWindow::GetInterface(const nsIID& aIID, void** aSink)
140 {
141 nsresult rv;
142
143 NS_ENSURE_ARG_POINTER(aSink);
144
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;
170
171 if (aIID.Equals(NS_GET_IID(nsIEmbeddingSiteWindow)) &&
172 NS_SUCCEEDED(EnsureContentTreeOwner()) &&
173 NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink)))
174 return NS_OK;
175
176 return QueryInterface(aIID, aSink);
177 }
178
179 //*****************************************************************************
180 // nsXULWindow::nsIXULWindow
181 //*****************************************************************************
182
183 NS_IMETHODIMP nsXULWindow::GetDocShell(nsIDocShell** aDocShell)
184 {
185 NS_ENSURE_ARG_POINTER(aDocShell);
186
187 *aDocShell = mDocShell;
188 NS_IF_ADDREF(*aDocShell);
189 return NS_OK;
190 }
191
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 }
201
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;
207
208 uint32_t zLevel;
209 mediator->GetZLevel(this, &zLevel);
210 if (zLevel == aLevel)
211 return NS_OK;
212
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 }
221
222 // do it
223 mediator->SetZLevel(this, aLevel);
224 PersistentAttributesDirty(PAD_MISC);
225 SavePersistentAttributes();
226
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);
237
238 event->SetTrusted(true);
239
240 bool defaultActionEnabled;
241 doc->DispatchEvent(event, &defaultActionEnabled);
242 }
243 }
244 }
245 return NS_OK;
246 }
247
248 NS_IMETHODIMP nsXULWindow::GetContextFlags(uint32_t *aContextFlags)
249 {
250 NS_ENSURE_ARG_POINTER(aContextFlags);
251 *aContextFlags = mContextFlags;
252 return NS_OK;
253 }
254
255 NS_IMETHODIMP nsXULWindow::SetContextFlags(uint32_t aContextFlags)
256 {
257 mContextFlags = aContextFlags;
258 return NS_OK;
259 }
260
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. */
269
270 // however, it's pointless to ask if the window isn't set up yet
271 if (!mChromeLoaded)
272 return NS_OK;
273
274 if (GetContentScrollbarVisibility())
275 *aChromeFlags |= nsIWebBrowserChrome::CHROME_SCROLLBARS;
276 else
277 *aChromeFlags &= ~nsIWebBrowserChrome::CHROME_SCROLLBARS;
278
279 return NS_OK;
280 }
281
282 NS_IMETHODIMP nsXULWindow::SetChromeFlags(uint32_t aChromeFlags)
283 {
284 NS_ASSERTION(!mChromeFlagsFrozen,
285 "SetChromeFlags() after AssumeChromeFlagsAreFrozen()!");
286
287 mChromeFlags = aChromeFlags;
288 if (mChromeLoaded)
289 NS_ENSURE_SUCCESS(ApplyChromeFlags(), NS_ERROR_FAILURE);
290 return NS_OK;
291 }
292
293 NS_IMETHODIMP nsXULWindow::AssumeChromeFlagsAreFrozen()
294 {
295 mChromeFlagsFrozen = true;
296 return NS_OK;
297 }
298
299 NS_IMETHODIMP nsXULWindow::SetIntrinsicallySized(bool aIntrinsicallySized)
300 {
301 mIntrinsicallySized = aIntrinsicallySized;
302 return NS_OK;
303 }
304
305 NS_IMETHODIMP nsXULWindow::GetIntrinsicallySized(bool* aIntrinsicallySized)
306 {
307 NS_ENSURE_ARG_POINTER(aIntrinsicallySized);
308
309 *aIntrinsicallySized = mIntrinsicallySized;
310 return NS_OK;
311 }
312
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 }
320
321 NS_IMETHODIMP nsXULWindow::GetContentShellById(const char16_t* aID,
322 nsIDocShellTreeItem** aDocShellTreeItem)
323 {
324 NS_ENSURE_ARG_POINTER(aDocShellTreeItem);
325 *aDocShellTreeItem = nullptr;
326
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 }
339
340 NS_IMETHODIMP nsXULWindow::AddChildWindow(nsIXULWindow *aChild)
341 {
342 // we're not really keeping track of this right now
343 return NS_OK;
344 }
345
346 NS_IMETHODIMP nsXULWindow::RemoveChildWindow(nsIXULWindow *aChild)
347 {
348 // we're not really keeping track of this right now
349 return NS_OK;
350 }
351
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;
357
358 window->SetModal(true);
359 mContinueModalLoop = true;
360 EnableParent(false);
361
362 {
363 AutoNoJSAPI nojsapi;
364 nsIThread *thread = NS_GetCurrentThread();
365 while (mContinueModalLoop) {
366 if (!NS_ProcessNextEvent(thread))
367 break;
368 }
369 }
370
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 */
384
385 return mModalStatus;
386 }
387
388 //*****************************************************************************
389 // nsXULWindow::nsIBaseWindow
390 //*****************************************************************************
391
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 }
399
400 NS_IMETHODIMP nsXULWindow::Create()
401 {
402 //XXX First Check In
403 NS_ASSERTION(false, "Not Yet Implemented");
404 return NS_OK;
405 }
406
407 NS_IMETHODIMP nsXULWindow::Destroy()
408 {
409 if (!mWindow)
410 return NS_OK;
411
412 // Ensure we don't reenter this code
413 if (mDestroying)
414 return NS_OK;
415
416 mozilla::AutoRestore<bool> guard(mDestroying);
417 mDestroying = true;
418
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));
423
424 nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow));
425 if (parentWindow)
426 parentWindow->RemoveChildWindow(this);
427
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
431
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...
435
436 nsCOMPtr<nsIXULWindow> placeHolder = this;
437
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);
445
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
472
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 }
479
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;
488
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 }
506
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?");
516
517 if (obssvc)
518 obssvc->NotifyObservers(nullptr, "xul-window-destroyed", nullptr);
519 }
520
521 return NS_OK;
522 }
523
524 NS_IMETHODIMP nsXULWindow::GetUnscaledDevicePixelsPerCSSPixel(double *aScale)
525 {
526 *aScale = mWindow ? mWindow->GetDefaultScale().scale : 1.0;
527 return NS_OK;
528 }
529
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 }
548
549 NS_IMETHODIMP nsXULWindow::GetPosition(int32_t* aX, int32_t* aY)
550 {
551 return GetPositionAndSize(aX, aY, nullptr, nullptr);
552 }
553
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);
560
561 mIntrinsicallySized = false;
562
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 }
580
581 NS_IMETHODIMP nsXULWindow::GetSize(int32_t* aCX, int32_t* aCY)
582 {
583 return GetPositionAndSize(nullptr, nullptr, aCX, aCY);
584 }
585
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);
593
594 mIntrinsicallySized = false;
595
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 }
614
615 NS_IMETHODIMP nsXULWindow::GetPositionAndSize(int32_t* x, int32_t* y, int32_t* cx,
616 int32_t* cy)
617 {
618 nsIntRect rect;
619
620 if (!mWindow)
621 return NS_ERROR_FAILURE;
622
623 mWindow->GetScreenBounds(rect);
624
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;
633
634 return NS_OK;
635 }
636
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;
644
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 }
650
651 if (!aScreen && !aRelative)
652 return NS_ERROR_INVALID_ARG;
653
654 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1", &result);
655 if (NS_FAILED(result))
656 return result;
657
658 nsCOMPtr<nsIScreen> screen;
659
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 }
697
698 if (aScreen && screen) {
699 screen->GetAvailRectDisplayPix(&left, &top, &width, &height);
700 screenCoordinates = true;
701 }
702
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 }
719
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 }
726
727 NS_IMETHODIMP nsXULWindow::GetParentWidget(nsIWidget** aParentWidget)
728 {
729 NS_ENSURE_ARG_POINTER(aParentWidget);
730 NS_ENSURE_STATE(mWindow);
731
732 NS_IF_ADDREF(*aParentWidget = mWindow->GetParent());
733 return NS_OK;
734 }
735
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 }
742
743 NS_IMETHODIMP nsXULWindow::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
744 {
745 NS_ENSURE_ARG_POINTER(aParentNativeWindow);
746
747 nsCOMPtr<nsIWidget> parentWidget;
748 NS_ENSURE_SUCCESS(GetParentWidget(getter_AddRefs(parentWidget)), NS_ERROR_FAILURE);
749
750 if (parentWidget) {
751 *aParentNativeWindow = parentWidget->GetNativeData(NS_NATIVE_WIDGET);
752 }
753
754 return NS_OK;
755 }
756
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 }
763
764 NS_IMETHODIMP nsXULWindow::GetNativeHandle(nsAString& aNativeHandle)
765 {
766 nsCOMPtr<nsIWidget> mainWidget;
767 NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(mainWidget)), NS_ERROR_FAILURE);
768
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 }
776
777 return NS_OK;
778 }
779
780 NS_IMETHODIMP nsXULWindow::GetVisibility(bool* aVisibility)
781 {
782 NS_ENSURE_ARG_POINTER(aVisibility);
783
784 // Always claim to be visible for now. See bug
785 // https://bugzilla.mozilla.org/show_bug.cgi?id=306245.
786
787 *aVisibility = true;
788
789 return NS_OK;
790 }
791
792 NS_IMETHODIMP nsXULWindow::SetVisibility(bool aVisibility)
793 {
794 if (!mChromeLoaded) {
795 mShowAfterLoad = aVisibility;
796 return NS_OK;
797 }
798
799 if (mDebuting) {
800 return NS_OK;
801 }
802 mDebuting = true; // (Show / Focus is recursive)
803
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);
814
815 nsCOMPtr<nsIWindowMediator> windowMediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
816 if (windowMediator)
817 windowMediator->UpdateWindowTimeStamp(static_cast<nsIXULWindow*>(this));
818
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 }
826
827 mDebuting = false;
828 return NS_OK;
829 }
830
831 NS_IMETHODIMP nsXULWindow::GetEnabled(bool *aEnabled)
832 {
833 NS_ENSURE_ARG_POINTER(aEnabled);
834
835 if (mWindow) {
836 *aEnabled = mWindow->IsEnabled();
837 return NS_OK;
838 }
839
840 *aEnabled = true; // better guess than most
841 return NS_ERROR_FAILURE;
842 }
843
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 }
852
853 NS_IMETHODIMP nsXULWindow::GetMainWidget(nsIWidget** aMainWidget)
854 {
855 NS_ENSURE_ARG_POINTER(aMainWidget);
856
857 *aMainWidget = mWindow;
858 NS_IF_ADDREF(*aMainWidget);
859 return NS_OK;
860 }
861
862 NS_IMETHODIMP nsXULWindow::SetFocus()
863 {
864 //XXX First Check In
865 NS_ASSERTION(false, "Not Yet Implemented");
866 return NS_OK;
867 }
868
869 NS_IMETHODIMP nsXULWindow::GetTitle(char16_t** aTitle)
870 {
871 NS_ENSURE_ARG_POINTER(aTitle);
872
873 *aTitle = ToNewUnicode(mTitle);
874 if (!*aTitle)
875 return NS_ERROR_OUT_OF_MEMORY;
876 return NS_OK;
877 }
878
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);
885
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;
890
891 windowMediator->UpdateWindowTitle(static_cast<nsIXULWindow*>(this), aTitle);
892
893 return NS_OK;
894 }
895
896
897 //*****************************************************************************
898 // nsXULWindow: Helpers
899 //*****************************************************************************
900
901 NS_IMETHODIMP nsXULWindow::EnsureChromeTreeOwner()
902 {
903 if (mChromeTreeOwner)
904 return NS_OK;
905
906 mChromeTreeOwner = new nsChromeTreeOwner();
907 NS_ENSURE_TRUE(mChromeTreeOwner, NS_ERROR_OUT_OF_MEMORY);
908
909 NS_ADDREF(mChromeTreeOwner);
910 mChromeTreeOwner->XULWindow(this);
911
912 return NS_OK;
913 }
914
915 NS_IMETHODIMP nsXULWindow::EnsureContentTreeOwner()
916 {
917 if (mContentTreeOwner)
918 return NS_OK;
919
920 mContentTreeOwner = new nsContentTreeOwner(false);
921 NS_ENSURE_TRUE(mContentTreeOwner, NS_ERROR_FAILURE);
922
923 NS_ADDREF(mContentTreeOwner);
924 mContentTreeOwner->XULWindow(this);
925
926 return NS_OK;
927 }
928
929 NS_IMETHODIMP nsXULWindow::EnsurePrimaryContentTreeOwner()
930 {
931 if (mPrimaryContentTreeOwner)
932 return NS_OK;
933
934 mPrimaryContentTreeOwner = new nsContentTreeOwner(true);
935 NS_ENSURE_TRUE(mPrimaryContentTreeOwner, NS_ERROR_FAILURE);
936
937 NS_ADDREF(mPrimaryContentTreeOwner);
938 mPrimaryContentTreeOwner->XULWindow(this);
939
940 return NS_OK;
941 }
942
943 NS_IMETHODIMP nsXULWindow::EnsurePrompter()
944 {
945 if (mPrompter)
946 return NS_OK;
947
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 }
958
959 NS_IMETHODIMP nsXULWindow::EnsureAuthPrompter()
960 {
961 if (mAuthPrompter)
962 return NS_OK;
963
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 }
973
974 void nsXULWindow::OnChromeLoaded()
975 {
976 nsresult rv = EnsureContentTreeOwner();
977
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 }
1000
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();
1013
1014 if (mCenterAfterLoad && !positionSet)
1015 Center(parentWindow, parentWindow ? false : true, false);
1016
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 }
1025
1026 bool nsXULWindow::LoadPositionFromXUL()
1027 {
1028 bool gotPosition = false;
1029
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;
1034
1035 nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
1036 NS_ENSURE_TRUE(windowElement, false);
1037
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;
1044
1045 GetPositionAndSize(&currX, &currY, &currWidth, &currHeight);
1046
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);
1054
1055 // Obtain the position information from the <xul:window> element.
1056 int32_t specX = currX;
1057 int32_t specY = currY;
1058 nsAutoString posString;
1059
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 }
1072
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 }
1097
1098 return gotPosition;
1099 }
1100
1101 bool nsXULWindow::LoadSizeFromXUL()
1102 {
1103 bool gotSize = false;
1104
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;
1109
1110 nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
1111 NS_ENSURE_TRUE(windowElement, false);
1112
1113 int32_t currWidth = 0;
1114 int32_t currHeight = 0;
1115 nsresult errorCode;
1116 int32_t temp;
1117
1118 NS_ASSERTION(mWindow, "we expected to have a window already");
1119
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);
1125
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;
1130
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 }
1143
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 }
1162
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 }
1169
1170 return gotSize;
1171 }
1172
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;
1180
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;
1187
1188 nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
1189 NS_ENSURE_TRUE(windowElement, false);
1190
1191 nsAutoString stateString;
1192
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;
1207
1208 if (stateString.Equals(SIZEMODE_MAXIMIZED))
1209 sizeMode = nsSizeMode_Maximized;
1210 else
1211 sizeMode = nsSizeMode_Fullscreen;
1212 }
1213 }
1214
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 }
1230
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;
1239
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 }
1248
1249 return gotState;
1250 }
1251
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;
1262
1263 bool keepTrying;
1264 int bouncedX = 0, // bounced off vertical edge of screen
1265 bouncedY = 0; // bounced off horizontal edge
1266
1267 // look for any other windows of this type
1268 nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1269 if (!wm)
1270 return;
1271
1272 nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
1273 if (!windowElement)
1274 return;
1275
1276 nsCOMPtr<nsIXULWindow> ourXULWindow(this);
1277
1278 nsAutoString windowType;
1279 windowElement->GetAttribute(WINDOWTYPE_ATTRIBUTE, windowType);
1280
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;
1286
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 }
1306
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));
1312
1313 if (!windowList)
1314 break;
1315
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;
1322
1323 nsCOMPtr<nsISupports> supportsWindow;
1324 windowList->GetNext(getter_AddRefs(supportsWindow));
1325
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 }
1336
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;
1344
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 }
1351
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 }
1357
1358 // if we hit the bottom then bounce to the top
1359 if (aRequestedY + aSpecHeight > screenBottom) {
1360 aRequestedY = screenTop;
1361 ++bouncedY;
1362 }
1363 }
1364
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 }
1375
1376 void nsXULWindow::SyncAttributesToWidget()
1377 {
1378 nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
1379 if (!windowElement)
1380 return;
1381
1382 nsAutoString attr;
1383
1384 // "hidechrome" attribute
1385 if (windowElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidechrome,
1386 nsGkAtoms::_true, eCaseMatters)) {
1387 mWindow->HideWindowChrome(true);
1388 }
1389
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 }
1396
1397 // "accelerated" attribute
1398 bool isAccelerated = windowElement->HasAttribute(NS_LITERAL_STRING("accelerated"));
1399 mWindow->SetLayersAcceleration(isAccelerated);
1400
1401 // "windowtype" attribute
1402 windowElement->GetAttribute(WINDOWTYPE_ATTRIBUTE, attr);
1403 if (!attr.IsEmpty()) {
1404 mWindow->SetWindowClass(attr);
1405 }
1406
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);
1413
1414 // "drawtitle" attribute
1415 windowElement->GetAttribute(NS_LITERAL_STRING("drawtitle"), attr);
1416 mWindow->SetDrawsTitle(attr.LowerCaseEqualsLiteral("true"));
1417
1418 // "toggletoolbar" attribute
1419 windowElement->GetAttribute(NS_LITERAL_STRING("toggletoolbar"), attr);
1420 mWindow->SetShowsToolbarButton(attr.LowerCaseEqualsLiteral("true"));
1421
1422 // "fullscreenbutton" attribute
1423 windowElement->GetAttribute(NS_LITERAL_STRING("fullscreenbutton"), attr);
1424 mWindow->SetShowsFullScreenButton(attr.LowerCaseEqualsLiteral("true"));
1425
1426 // "macanimationtype" attribute
1427 windowElement->GetAttribute(NS_LITERAL_STRING("macanimationtype"), attr);
1428 if (attr.EqualsLiteral("document")) {
1429 mWindow->SetWindowAnimationType(nsIWidget::eDocumentWindowAnimation);
1430 }
1431 }
1432
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;
1439
1440 nsCOMPtr<dom::Element> docShellElement = GetWindowDOMElement();
1441 if (!docShellElement)
1442 return NS_ERROR_FAILURE;
1443
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 }
1450
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);
1454
1455 int32_t sizeMode = mWindow->SizeMode();
1456 CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale();
1457
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 }
1467
1468 char sizeBuf[10];
1469 nsAutoString sizeString;
1470 nsAutoString windowElementId;
1471 nsCOMPtr<nsIDOMXULDocument> ownerXULDoc;
1472
1473 // fetch docShellElement's ID and XUL owner document
1474 ownerXULDoc = do_QueryInterface(docShellElement->OwnerDoc());
1475 if (docShellElement->IsXUL()) {
1476 docShellElement->GetId(windowElementId);
1477 }
1478
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 }
1498
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 }
1516
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 }
1541
1542 mPersistentAttributesDirty = 0;
1543 return NS_OK;
1544 }
1545
1546 NS_IMETHODIMP nsXULWindow::GetWindowDOMWindow(nsIDOMWindow** aDOMWindow)
1547 {
1548 NS_ENSURE_STATE(mDocShell);
1549
1550 if (!mDOMWindow)
1551 mDOMWindow = do_GetInterface(mDocShell);
1552 NS_ENSURE_TRUE(mDOMWindow, NS_ERROR_FAILURE);
1553
1554 *aDOMWindow = mDOMWindow;
1555 NS_ADDREF(*aDOMWindow);
1556 return NS_OK;
1557 }
1558
1559 dom::Element*
1560 nsXULWindow::GetWindowDOMElement() const
1561 {
1562 NS_ENSURE_TRUE(mDocShell, nullptr);
1563
1564 nsCOMPtr<nsIContentViewer> cv;
1565 mDocShell->GetContentViewer(getter_AddRefs(cv));
1566 NS_ENSURE_TRUE(cv, nullptr);
1567
1568 const nsIDocument* document = cv->GetDocument();
1569 NS_ENSURE_TRUE(document, nullptr);
1570
1571 return document->GetRootElement();
1572 }
1573
1574 nsresult nsXULWindow::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
1575 bool aPrimary, bool aTargetable, const nsAString& aID)
1576 {
1577 nsContentShellInfo* shellInfo = nullptr;
1578
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 }
1591
1592 if (!shellInfo) {
1593 shellInfo = new nsContentShellInfo(aID, contentShellWeak);
1594 mContentShells.AppendElement(shellInfo);
1595 }
1596
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 }
1609
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
1621
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 }
1640
1641 return NS_OK;
1642 }
1643
1644 nsresult nsXULWindow::ContentShellRemoved(nsIDocShellTreeItem* aContentShell)
1645 {
1646 if (mPrimaryContentShell == aContentShell) {
1647 mPrimaryContentShell = nullptr;
1648 }
1649
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 }
1659
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 }
1668
1669 return NS_OK;
1670 }
1671
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.
1679
1680 nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(aShellItem));
1681 NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
1682
1683 int32_t width = 0;
1684 int32_t height = 0;
1685 shellAsWin->GetSize(&width, &height);
1686
1687 int32_t widthDelta = aCX - width;
1688 int32_t heightDelta = aCY - height;
1689
1690 if (widthDelta || heightDelta) {
1691 int32_t winCX = 0;
1692 int32_t winCY = 0;
1693
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 }
1703
1704 return NS_OK;
1705 }
1706
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 }
1715
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);
1721
1722 if (aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)
1723 return CreateNewChromeWindow(aChromeFlags, _retval);
1724 return CreateNewContentWindow(aChromeFlags, _retval);
1725 }
1726
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);
1732
1733 // Just do a normal create of a window and return.
1734
1735 nsCOMPtr<nsIXULWindow> newWindow;
1736 appShell->CreateTopLevelWindow(this, nullptr, aChromeFlags,
1737 nsIAppShellService::SIZE_TO_CONTENT,
1738 nsIAppShellService::SIZE_TO_CONTENT,
1739 getter_AddRefs(newWindow));
1740
1741 NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE);
1742
1743 *_retval = newWindow;
1744 NS_ADDREF(*_retval);
1745
1746 return NS_OK;
1747 }
1748
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);
1754
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.
1759
1760 nsCOMPtr<nsIURI> uri;
1761
1762 nsAdoptingCString urlStr = Preferences::GetCString("browser.chromeURL");
1763 if (urlStr.IsEmpty()) {
1764 urlStr.AssignLiteral("chrome://navigator/content/navigator.xul");
1765 }
1766
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);
1772
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 }
1785
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));
1790
1791 xulWin->LockUntilChromeLoad();
1792
1793 {
1794 AutoNoJSAPI nojsapi;
1795 nsIThread *thread = NS_GetCurrentThread();
1796 while (xulWin->IsLocked()) {
1797 if (!NS_ProcessNextEvent(thread))
1798 break;
1799 }
1800 }
1801
1802 NS_ENSURE_STATE(xulWin->mPrimaryContentShell);
1803
1804 *_retval = newWindow;
1805 NS_ADDREF(*_retval);
1806
1807 return NS_OK;
1808 }
1809
1810 void nsXULWindow::EnableParent(bool aEnable)
1811 {
1812 nsCOMPtr<nsIBaseWindow> parentWindow;
1813 nsCOMPtr<nsIWidget> parentWidget;
1814
1815 parentWindow = do_QueryReferent(mParentWindow);
1816 if (parentWindow)
1817 parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
1818 if (parentWidget)
1819 parentWidget->Enable(aEnable);
1820 }
1821
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
1837
1838 nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1839 if (!mediator)
1840 return false;
1841
1842 bool altered;
1843 uint32_t position,
1844 newPosition,
1845 zLevel;
1846 nsIXULWindow *us = this;
1847
1848 altered = false;
1849 mediator->GetZLevel(this, &zLevel);
1850
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;
1857
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);
1869
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;
1880
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 }
1892
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 }
1901
1902 mediator->SetZPosition(us, newPosition, windowAbove);
1903 }
1904
1905 return altered;
1906 }
1907
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
1921
1922 nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
1923 if (!mediator)
1924 return;
1925
1926 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
1927 mediator->GetZOrderXULWindowEnumerator(0, true,
1928 getter_AddRefs(windowEnumerator));
1929 if (!windowEnumerator)
1930 return;
1931
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 }
1940
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
1951
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 }
1963
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 }
1976
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));
1984
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);
1992
1993 if (prefValue == nsIScrollable::Scrollbar_Never)
1994 return false;
1995 }
1996
1997 return true;
1998 }
1999
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 }
2005
2006 NS_IMETHODIMP nsXULWindow::ApplyChromeFlags()
2007 {
2008 nsCOMPtr<dom::Element> window = GetWindowDOMElement();
2009 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
2010
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.
2016
2017 // Scrollbars have their own special treatment.
2018 SetContentScrollbarVisibility(mChromeFlags &
2019 nsIWebBrowserChrome::CHROME_SCROLLBARS ?
2020 true : false);
2021 }
2022
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;
2027
2028 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_MENUBAR))
2029 newvalue.AppendLiteral("menubar ");
2030
2031 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_TOOLBAR))
2032 newvalue.AppendLiteral("toolbar ");
2033
2034 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_LOCATIONBAR))
2035 newvalue.AppendLiteral("location ");
2036
2037 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR))
2038 newvalue.AppendLiteral("directories ");
2039
2040 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_STATUSBAR))
2041 newvalue.AppendLiteral("status ");
2042
2043 if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_EXTRA))
2044 newvalue.AppendLiteral("extrachrome ");
2045
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);
2050
2051 return NS_OK;
2052 }
2053
2054 NS_IMETHODIMP nsXULWindow::GetXULBrowserWindow(nsIXULBrowserWindow * *aXULBrowserWindow)
2055 {
2056 NS_IF_ADDREF(*aXULBrowserWindow = mXULBrowserWindow);
2057 return NS_OK;
2058 }
2059
2060 NS_IMETHODIMP nsXULWindow::SetXULBrowserWindow(nsIXULBrowserWindow * aXULBrowserWindow)
2061 {
2062 mXULBrowserWindow = aXULBrowserWindow;
2063 return NS_OK;
2064 }
2065
2066 //*****************************************************************************
2067 //*** nsContentShellInfo: Object Management
2068 //*****************************************************************************
2069
2070 nsContentShellInfo::nsContentShellInfo(const nsAString& aID,
2071 nsIWeakReference* aContentShell)
2072 : id(aID),
2073 child(aContentShell)
2074 {
2075 MOZ_COUNT_CTOR(nsContentShellInfo);
2076 }
2077
2078 nsContentShellInfo::~nsContentShellInfo()
2079 {
2080 MOZ_COUNT_DTOR(nsContentShellInfo);
2081 //XXX Set Tree Owner to null if the tree owner is nsXULWindow->mContentTreeOwner
2082 }

mercurial