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/. */
8 #include "mozilla/MathAlgorithms.h"
11 #include "AppWindow.h"
15 #include "nsPrintfCString.h"
17 #include "nsWidgetsCID.h"
18 #include "nsThreadUtils.h"
20 #include "nsQueryObject.h"
21 #include "mozilla/ProfilerLabels.h"
22 #include "mozilla/Sprintf.h"
23 #include "mozilla/Try.h"
25 // Interfaces needed to be included
26 #include "nsGlobalWindowOuter.h"
27 #include "nsIAppShell.h"
28 #include "nsIAppShellService.h"
29 #include "nsIDocumentViewer.h"
30 #include "mozilla/dom/Document.h"
31 #include "mozilla/dom/CanonicalBrowsingContext.h"
32 #include "nsPIDOMWindow.h"
34 #include "nsIInterfaceRequestor.h"
35 #include "nsIInterfaceRequestorUtils.h"
36 #include "nsIIOService.h"
37 #include "nsIObserverService.h"
38 #include "nsIOpenWindowInfo.h"
39 #include "nsIWindowMediator.h"
40 #include "nsIScreenManager.h"
41 #include "nsIScreen.h"
42 #include "nsIWindowWatcher.h"
44 #include "nsAppShellCID.h"
45 #include "nsReadableUtils.h"
46 #include "nsStyleConsts.h"
47 #include "nsPresContext.h"
48 #include "nsContentUtils.h"
49 #include "nsXULTooltipListener.h"
50 #include "nsXULPopupManager.h"
51 #include "nsFocusManager.h"
52 #include "nsContentList.h"
53 #include "nsIDOMWindowUtils.h"
54 #include "nsServiceManagerUtils.h"
57 #include "mozilla/AppShutdown.h"
58 #include "mozilla/AutoRestore.h"
59 #include "mozilla/Preferences.h"
60 #include "mozilla/PresShell.h"
61 #include "mozilla/Services.h"
62 #include "mozilla/SpinEventLoopUntil.h"
63 #include "mozilla/dom/BarProps.h"
64 #include "mozilla/dom/DOMRect.h"
65 #include "mozilla/dom/Element.h"
66 #include "mozilla/dom/Event.h"
67 #include "mozilla/dom/ScriptSettings.h"
68 #include "mozilla/dom/BrowserHost.h"
69 #include "mozilla/dom/BrowserParent.h"
70 #include "mozilla/dom/LoadURIOptionsBinding.h"
71 #include "mozilla/intl/LocaleService.h"
72 #include "mozilla/EventDispatcher.h"
75 # include "mozilla/PreXULSkeletonUI.h"
76 # include "mozilla/WindowsVersion.h"
77 # include "nsIWindowsUIUtils.h"
80 #include "mozilla/dom/DocumentL10n.h"
82 #if defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
83 # include "mozilla/widget/NativeMenuSupport.h"
84 # define USE_NATIVE_MENUS
87 #define SIZEMODE_NORMAL u"normal"_ns
88 #define SIZEMODE_MAXIMIZED u"maximized"_ns
89 #define SIZEMODE_MINIMIZED u"minimized"_ns
90 #define SIZEMODE_FULLSCREEN u"fullscreen"_ns
92 #define SIZE_PERSISTENCE_TIMEOUT 500 // msec
94 //*****************************************************************************
95 //*** AppWindow: Object Management
96 //*****************************************************************************
100 using dom::AutoNoJSAPI
;
101 using dom::BrowserHost
;
102 using dom::BrowsingContext
;
104 using dom::DocumentL10n
;
106 using dom::EventTarget
;
107 using dom::LoadURIOptions
;
110 AppWindow::AppWindow(uint32_t aChromeFlags
)
111 : mChromeTreeOwner(nullptr),
112 mContentTreeOwner(nullptr),
113 mPrimaryContentTreeOwner(nullptr),
115 mFullscreenChangeState(FullscreenChangeState::NotChanging
),
116 mContinueModalLoop(false),
118 mChromeLoaded(false),
119 mSizingShellFromXUL(false),
120 mShowAfterLoad(false),
121 mIntrinsicallySized(false),
122 mCenterAfterLoad(false),
123 mIsHiddenWindow(false),
124 mLockedUntilChromeLoad(false),
125 mIgnoreXULSize(false),
126 mIgnoreXULPosition(false),
127 mChromeFlagsFrozen(false),
128 mIgnoreXULSizeMode(false),
131 mDominantClientSize(false),
132 mChromeFlags(aChromeFlags
),
133 mWidgetListenerDelegate(this) {}
135 AppWindow::~AppWindow() {
143 //*****************************************************************************
144 // AppWindow::nsISupports
145 //*****************************************************************************
147 NS_IMPL_ADDREF(AppWindow
)
148 NS_IMPL_RELEASE(AppWindow
)
150 NS_INTERFACE_MAP_BEGIN(AppWindow
)
151 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIAppWindow
)
152 NS_INTERFACE_MAP_ENTRY(nsIAppWindow
)
153 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow
)
154 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor
)
155 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
156 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener
)
157 NS_INTERFACE_MAP_ENTRY_CONCRETE(AppWindow
)
160 nsresult
AppWindow::Initialize(nsIAppWindow
* aParent
, nsIAppWindow
* aOpener
,
161 int32_t aInitialWidth
, int32_t aInitialHeight
,
162 bool aIsHiddenWindow
,
163 widget::InitData
& widgetInitData
) {
165 nsCOMPtr
<nsIWidget
> parentWidget
;
167 mIsHiddenWindow
= aIsHiddenWindow
;
169 DesktopIntPoint initialPos
;
170 nsCOMPtr
<nsIBaseWindow
> base(do_QueryInterface(aOpener
));
172 LayoutDeviceIntRect rect
= base
->GetPositionAndSize();
174 DesktopIntRect::Round(rect
/ base
->DevicePixelsPerDesktopPixel());
175 if (!mOpenerScreenRect
.IsEmpty()) {
176 initialPos
= mOpenerScreenRect
.TopLeft();
177 ConstrainToOpenerScreen(&initialPos
.x
.value
, &initialPos
.y
.value
);
181 // XXX: need to get the default window size from prefs...
182 // Doesn't come from prefs... will come from CSS/XUL/RDF
183 DesktopIntRect
deskRect(initialPos
,
184 DesktopIntSize(aInitialWidth
, aInitialHeight
));
186 // Create top level window
187 if (gfxPlatform::IsHeadless()) {
188 mWindow
= nsIWidget::CreateHeadlessWidget();
190 mWindow
= nsIWidget::CreateTopLevelWindow();
193 return NS_ERROR_FAILURE
;
196 /* This next bit is troublesome. We carry two different versions of a pointer
197 to our parent window. One is the parent window's widget, which is passed
198 to our own widget. The other is a weak reference we keep here to our
199 parent AppWindow. The former is useful to the widget, and we can't
200 trust its treatment of the parent reference because they're platform-
201 specific. The latter is useful to this class.
202 A better implementation would be one in which the parent keeps strong
203 references to its children and closes them before it allows itself
204 to be closed. This would mimic the behaviour of OSes that support
205 top-level child windows in OSes that do not. Later.
207 nsCOMPtr
<nsIBaseWindow
> parentAsWin(do_QueryInterface(aParent
));
209 parentAsWin
->GetMainWidget(getter_AddRefs(parentWidget
));
210 mParentWindow
= do_GetWeakReference(aParent
);
213 mWindow
->SetWidgetListener(&mWidgetListenerDelegate
);
214 rv
= mWindow
->Create(parentWidget
.get(), // Parent nsIWidget
215 deskRect
, // Widget dimensions
216 &widgetInitData
); // Widget initialization data
217 NS_ENSURE_SUCCESS(rv
, rv
);
219 LayoutDeviceIntRect r
= mWindow
->GetClientBounds();
220 // Match the default background color of content. Previously important on
221 // Windows, but no longer has any effect there.
222 mWindow
->SetBackgroundColor(NS_RGB(255, 255, 255));
224 // All Chrome BCs exist within the same BrowsingContextGroup, so we don't need
225 // to pass in the opener window here. The opener is set later, if needed, by
227 RefPtr
<BrowsingContext
> browsingContext
=
228 BrowsingContext::CreateIndependent(BrowsingContext::Type::Chrome
);
231 mDocShell
= nsDocShell::Create(browsingContext
);
232 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_FAILURE
);
234 // Make sure to set the item type on the docshell _before_ calling
235 // InitWindow() so it knows what type it is.
236 NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE
);
238 mDocShell
->SetTreeOwner(mChromeTreeOwner
);
242 mDocShell
->InitWindow(mWindow
, r
.X(), r
.Y(), r
.Width(), r
.Height()),
245 // Attach a WebProgress listener.during initialization...
246 mDocShell
->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_NETWORK
);
248 mWindow
->MaybeDispatchInitialFocusEvent();
253 //*****************************************************************************
254 // AppWindow::nsIIntefaceRequestor
255 //*****************************************************************************
257 NS_IMETHODIMP
AppWindow::GetInterface(const nsIID
& aIID
, void** aSink
) {
260 NS_ENSURE_ARG_POINTER(aSink
);
262 if (aIID
.Equals(NS_GET_IID(nsIPrompt
))) {
263 rv
= EnsurePrompter();
264 if (NS_FAILED(rv
)) return rv
;
265 return mPrompter
->QueryInterface(aIID
, aSink
);
267 if (aIID
.Equals(NS_GET_IID(nsIAuthPrompt
))) {
268 rv
= EnsureAuthPrompter();
269 if (NS_FAILED(rv
)) return rv
;
270 return mAuthPrompter
->QueryInterface(aIID
, aSink
);
272 if (aIID
.Equals(NS_GET_IID(mozIDOMWindowProxy
))) {
273 return GetWindowDOMWindow(reinterpret_cast<mozIDOMWindowProxy
**>(aSink
));
275 if (aIID
.Equals(NS_GET_IID(nsIDOMWindow
))) {
276 nsCOMPtr
<mozIDOMWindowProxy
> window
= nullptr;
277 rv
= GetWindowDOMWindow(getter_AddRefs(window
));
278 nsCOMPtr
<nsIDOMWindow
> domWindow
= do_QueryInterface(window
);
279 domWindow
.forget(aSink
);
282 if (aIID
.Equals(NS_GET_IID(nsIWebBrowserChrome
)) &&
283 NS_SUCCEEDED(EnsureContentTreeOwner()) &&
284 NS_SUCCEEDED(mContentTreeOwner
->QueryInterface(aIID
, aSink
))) {
288 return QueryInterface(aIID
, aSink
);
291 //*****************************************************************************
292 // AppWindow::nsIAppWindow
293 //*****************************************************************************
295 NS_IMETHODIMP
AppWindow::GetDocShell(nsIDocShell
** aDocShell
) {
296 NS_ENSURE_ARG_POINTER(aDocShell
);
298 *aDocShell
= mDocShell
;
299 NS_IF_ADDREF(*aDocShell
);
303 NS_IMETHODIMP
AppWindow::GetChromeFlags(uint32_t* aChromeFlags
) {
304 NS_ENSURE_ARG_POINTER(aChromeFlags
);
305 *aChromeFlags
= mChromeFlags
;
309 NS_IMETHODIMP
AppWindow::SetChromeFlags(uint32_t aChromeFlags
) {
310 NS_ASSERTION(!mChromeFlagsFrozen
,
311 "SetChromeFlags() after AssumeChromeFlagsAreFrozen()!");
313 mChromeFlags
= aChromeFlags
;
320 NS_IMETHODIMP
AppWindow::AssumeChromeFlagsAreFrozen() {
321 mChromeFlagsFrozen
= true;
325 NS_IMETHODIMP
AppWindow::SetIntrinsicallySized(bool aIntrinsicallySized
) {
326 mIntrinsicallySized
= aIntrinsicallySized
;
330 NS_IMETHODIMP
AppWindow::GetIntrinsicallySized(bool* aIntrinsicallySized
) {
331 NS_ENSURE_ARG_POINTER(aIntrinsicallySized
);
333 *aIntrinsicallySized
= mIntrinsicallySized
;
337 NS_IMETHODIMP
AppWindow::GetPrimaryContentShell(
338 nsIDocShellTreeItem
** aDocShellTreeItem
) {
339 NS_ENSURE_ARG_POINTER(aDocShellTreeItem
);
340 NS_IF_ADDREF(*aDocShellTreeItem
= mPrimaryContentShell
);
345 AppWindow::RemoteTabAdded(nsIRemoteTab
* aTab
, bool aPrimary
) {
347 mPrimaryBrowserParent
= aTab
;
348 mPrimaryContentShell
= nullptr;
349 } else if (mPrimaryBrowserParent
== aTab
) {
350 mPrimaryBrowserParent
= nullptr;
357 AppWindow::RemoteTabRemoved(nsIRemoteTab
* aTab
) {
358 if (aTab
== mPrimaryBrowserParent
) {
359 mPrimaryBrowserParent
= nullptr;
366 AppWindow::GetPrimaryRemoteTab(nsIRemoteTab
** aTab
) {
367 nsCOMPtr
<nsIRemoteTab
> tab
= mPrimaryBrowserParent
;
373 AppWindow::GetPrimaryContentBrowsingContext(
374 mozilla::dom::BrowsingContext
** aBc
) {
375 if (mPrimaryBrowserParent
) {
376 return mPrimaryBrowserParent
->GetBrowsingContext(aBc
);
378 if (mPrimaryContentShell
) {
379 return mPrimaryContentShell
->GetBrowsingContextXPCOM(aBc
);
385 static LayoutDeviceIntSize
GetOuterToInnerSizeDifference(nsIWidget
* aWindow
) {
387 return LayoutDeviceIntSize();
389 return aWindow
->ClientToWindowSizeDifference();
392 static CSSIntSize
GetOuterToInnerSizeDifferenceInCSSPixels(
393 nsIWidget
* aWindow
, CSSToLayoutDeviceScale aScale
) {
394 LayoutDeviceIntSize devPixelSize
= GetOuterToInnerSizeDifference(aWindow
);
395 return RoundedToInt(devPixelSize
/ aScale
);
399 AppWindow::GetOuterToInnerHeightDifferenceInCSSPixels(uint32_t* aResult
) {
400 *aResult
= GetOuterToInnerSizeDifferenceInCSSPixels(
401 mWindow
, UnscaledDevicePixelsPerCSSPixel())
407 AppWindow::GetOuterToInnerWidthDifferenceInCSSPixels(uint32_t* aResult
) {
408 *aResult
= GetOuterToInnerSizeDifferenceInCSSPixels(
409 mWindow
, UnscaledDevicePixelsPerCSSPixel())
414 nsTArray
<RefPtr
<mozilla::LiveResizeListener
>>
415 AppWindow::GetLiveResizeListeners() {
416 nsTArray
<RefPtr
<mozilla::LiveResizeListener
>> listeners
;
417 if (mPrimaryBrowserParent
) {
418 BrowserHost
* host
= BrowserHost::GetFrom(mPrimaryBrowserParent
.get());
419 RefPtr
<mozilla::LiveResizeListener
> actor
= host
->GetActor();
421 listeners
.AppendElement(actor
);
427 NS_IMETHODIMP
AppWindow::ShowModal() {
428 AUTO_PROFILER_LABEL("AppWindow::ShowModal", OTHER
);
430 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
)) {
431 MOZ_ASSERT_UNREACHABLE(
432 "Trying to show modal window after shutdown started.");
433 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN
;
436 // Store locally so it doesn't die on us
437 nsCOMPtr
<nsIWidget
> window
= mWindow
;
438 nsCOMPtr
<nsIAppWindow
> tempRef
= this;
440 #ifdef USE_NATIVE_MENUS
441 if (!gfxPlatform::IsHeadless()) {
442 // On macOS, for modals created early in startup. (e.g.
443 // ProfileManager/ProfileDowngrade) this creates a fallback menu for the
444 // menu bar which only contains a "Quit" menu item. This allows the user to
445 // quit the application in a regular way with cmd+Q.
446 widget::NativeMenuSupport::CreateNativeMenuBar(mWindow
, nullptr);
450 window
->SetModal(true);
451 mContinueModalLoop
= true;
456 SpinEventLoopUntil("AppWindow::ShowModal"_ns
, [&]() {
458 AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed
))) {
459 // TODO: Bug 1699041 would apply also here: Should we return an error
460 // if we are bailing out from a pre-existing modal dialog for shutdown?
461 ExitModalLoop(NS_OK
);
463 return !mContinueModalLoop
;
467 mContinueModalLoop
= false;
468 window
->SetModal(false);
469 /* Note there's no EnableParent(true) here to match the false one
470 above. That's done in ExitModalLoop. It's important that the parent
471 be re-enabled before this window is made invisible; to do otherwise
472 causes bizarre z-ordering problems. At this point, the window is
474 No known current implementation of Enable would have a problem with
475 re-enabling the parent twice, so we could do it again here without
476 breaking any current implementation. But that's unnecessary if the
477 modal loop is always exited using ExitModalLoop (the other way would be
478 to change the protected member variable directly.)
484 NS_IMETHODIMP
AppWindow::RollupAllPopups() {
485 if (nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance()) {
491 //*****************************************************************************
492 // AppWindow::nsIBaseWindow
493 //*****************************************************************************
495 NS_IMETHODIMP
AppWindow::InitWindow(nsIWidget
* parentWidget
, int32_t x
,
496 int32_t y
, int32_t cx
, int32_t cy
) {
497 // XXX First Check In
498 NS_ASSERTION(false, "Not Yet Implemented");
502 NS_IMETHODIMP
AppWindow::Destroy() {
503 nsCOMPtr
<nsIAppWindow
> kungFuDeathGrip(this);
506 mDocShell
->RemoveProgressListener(this);
511 SavePersistentAttributes();
515 if (!mWindow
) return NS_OK
;
517 // Ensure we don't reenter this code
518 if (mDestroying
) return NS_OK
;
520 mozilla::AutoRestore
<bool> guard(mDestroying
);
523 nsCOMPtr
<nsIAppShellService
> appShell(
524 do_GetService(NS_APPSHELLSERVICE_CONTRACTID
));
525 NS_ASSERTION(appShell
, "Couldn't get appShell... xpcom shutdown?");
527 appShell
->UnregisterTopLevelWindow(static_cast<nsIAppWindow
*>(this));
530 // Remove modality (if any) and hide while destroying. More than
531 // a convenience, the hide prevents user interaction with the partially
532 // destroyed window. This is especially necessary when the eldest window
533 // in a stack of modal windows is destroyed first. It happens.
534 ExitModalLoop(NS_OK
);
535 // XXX: Skip unmapping the window on Linux due to GLX hangs on the compositor
536 // thread with NVIDIA driver 310.32. We don't need to worry about user
537 // interactions with destroyed windows on X11 either.
538 #ifndef MOZ_WIDGET_GTK
539 if (mWindow
) mWindow
->Show(false);
542 RemoveTooltipSupport();
544 mDOMWindow
= nullptr;
546 RefPtr
<BrowsingContext
> bc(mDocShell
->GetBrowsingContext());
547 mDocShell
->Destroy();
549 mDocShell
= nullptr; // this can cause reentrancy of this function
552 mPrimaryContentShell
= nullptr;
554 if (mContentTreeOwner
) {
555 mContentTreeOwner
->AppWindow(nullptr);
556 NS_RELEASE(mContentTreeOwner
);
558 if (mPrimaryContentTreeOwner
) {
559 mPrimaryContentTreeOwner
->AppWindow(nullptr);
560 NS_RELEASE(mPrimaryContentTreeOwner
);
562 if (mChromeTreeOwner
) {
563 mChromeTreeOwner
->AppWindow(nullptr);
564 NS_RELEASE(mChromeTreeOwner
);
567 mWindow
->SetWidgetListener(nullptr); // nsWebShellWindow hackery
572 if (!mIsHiddenWindow
&& mRegistered
) {
573 /* Inform appstartup we've destroyed this window and it could
574 quit now if it wanted. This must happen at least after mDocShell
575 is destroyed, because onunload handlers fire then, and those being
576 script, anything could happen. A new window could open, even.
578 nsCOMPtr
<nsIObserverService
> obssvc
= services::GetObserverService();
579 NS_ASSERTION(obssvc
, "Couldn't get observer service?");
582 obssvc
->NotifyObservers(nullptr, "xul-window-destroyed", nullptr);
588 NS_IMETHODIMP
AppWindow::GetDevicePixelsPerDesktopPixel(double* aScale
) {
589 *aScale
= mWindow
? mWindow
->GetDesktopToDeviceScale().scale
: 1.0;
593 double AppWindow::GetWidgetCSSToDeviceScale() {
594 return mWindow
? mWindow
->GetDefaultScale().scale
: 1.0;
597 NS_IMETHODIMP
AppWindow::SetPositionDesktopPix(int32_t aX
, int32_t aY
) {
598 return MoveResize(Some(DesktopIntPoint(aX
, aY
)), Nothing(), false);
601 // The parameters here are device pixels; do the best we can to convert to
602 // desktop px, using the window's current scale factor (if available).
603 NS_IMETHODIMP
AppWindow::SetPosition(int32_t aX
, int32_t aY
) {
604 // Don't reset the window's size mode here - platforms that don't want to move
605 // maximized windows should reset it in their respective Move implementation.
606 return MoveResize(Some(LayoutDeviceIntPoint(aX
, aY
)), Nothing(), false);
609 NS_IMETHODIMP
AppWindow::GetPosition(int32_t* aX
, int32_t* aY
) {
610 return GetPositionAndSize(aX
, aY
, nullptr, nullptr);
613 NS_IMETHODIMP
AppWindow::SetSize(int32_t aCX
, int32_t aCY
, bool aRepaint
) {
614 /* any attempt to set the window's size or position overrides the window's
615 zoom state. this is important when these two states are competing while
616 the window is being opened. but it should probably just always be so. */
617 return MoveResize(Nothing(), Some(LayoutDeviceIntSize(aCX
, aCY
)), aRepaint
);
620 NS_IMETHODIMP
AppWindow::GetSize(int32_t* aCX
, int32_t* aCY
) {
621 return GetPositionAndSize(nullptr, nullptr, aCX
, aCY
);
624 NS_IMETHODIMP
AppWindow::SetPositionAndSize(int32_t aX
, int32_t aY
, int32_t aCX
,
625 int32_t aCY
, uint32_t aFlags
) {
626 /* any attempt to set the window's size or position overrides the window's
627 zoom state. this is important when these two states are competing while
628 the window is being opened. but it should probably just always be so. */
629 return MoveResize(Some(LayoutDeviceIntPoint(aX
, aY
)),
630 Some(LayoutDeviceIntSize(aCX
, aCY
)),
631 !!(aFlags
& nsIBaseWindow::eRepaint
));
634 NS_IMETHODIMP
AppWindow::GetPositionAndSize(int32_t* x
, int32_t* y
, int32_t* cx
,
636 if (!mWindow
) return NS_ERROR_FAILURE
;
638 LayoutDeviceIntRect rect
= mWindow
->GetScreenBounds();
640 if (x
) *x
= rect
.X();
641 if (y
) *y
= rect
.Y();
642 if (cx
) *cx
= rect
.Width();
643 if (cy
) *cy
= rect
.Height();
649 AppWindow::SetDimensions(DimensionRequest
&& aRequest
) {
650 if (aRequest
.mDimensionKind
== DimensionKind::Inner
) {
651 // For the chrome the inner size is the root shell size, and for the
652 // content it's the primary content size. We lack an indicator here that
653 // would allow us to distinguish between the two.
654 return NS_ERROR_NOT_IMPLEMENTED
;
657 MOZ_TRY(aRequest
.SupplementFrom(this));
658 return aRequest
.ApplyOuterTo(this);
662 AppWindow::GetDimensions(DimensionKind aDimensionKind
, int32_t* aX
, int32_t* aY
,
663 int32_t* aCX
, int32_t* aCY
) {
664 if (aDimensionKind
== DimensionKind::Inner
) {
665 // For the chrome the inner size is the root shell size, and for the
666 // content it's the primary content size. We lack an indicator here that
667 // would allow us to distinguish between the two.
668 return NS_ERROR_NOT_IMPLEMENTED
;
670 return GetPositionAndSize(aX
, aY
, aCX
, aCY
);
673 nsresult
AppWindow::MoveResize(const Maybe
<LayoutDeviceIntPoint
>& aPosition
,
674 const Maybe
<LayoutDeviceIntSize
>& aSize
,
676 NS_ENSURE_STATE(mWindow
);
677 DesktopToLayoutDeviceScale scale
= mWindow
->GetDesktopToDeviceScale();
678 return MoveResize(aPosition
? Some(*aPosition
/ scale
) : Nothing(),
679 aSize
? Some(*aSize
/ scale
) : Nothing(), aRepaint
);
682 nsresult
AppWindow::MoveResize(const Maybe
<DesktopPoint
>& aPosition
,
683 const Maybe
<DesktopSize
>& aSize
, bool aRepaint
) {
684 NS_ENSURE_STATE(mWindow
);
685 PersistentAttributes dirtyAttributes
;
687 if (!aPosition
&& !aSize
) {
688 MOZ_ASSERT_UNREACHABLE("Doing nothing?");
689 return NS_ERROR_UNEXPECTED
;
693 mWindow
->SetSizeMode(nsSizeMode_Normal
);
694 mIntrinsicallySized
= false;
695 mDominantClientSize
= false;
698 if (aPosition
&& aSize
) {
699 mWindow
->Resize(aPosition
->x
, aPosition
->y
, aSize
->width
, aSize
->height
,
701 dirtyAttributes
= {PersistentAttribute::Size
,
702 PersistentAttribute::Position
};
704 mWindow
->Resize(aSize
->width
, aSize
->height
, aRepaint
);
705 dirtyAttributes
= {PersistentAttribute::Size
};
706 } else if (aPosition
) {
707 mWindow
->Move(aPosition
->x
, aPosition
->y
);
708 dirtyAttributes
= {PersistentAttribute::Position
};
711 if (mSizingShellFromXUL
) {
712 // If we're invoked for sizing from XUL, we want to neither ignore anything
713 // nor persist anything, since it's already the value in XUL.
716 if (!mChromeLoaded
) {
717 // If we're called before the chrome is loaded someone obviously wants this
718 // window at this size & in the normal size mode (since it is the only mode
719 // in which setting dimensions makes sense). We don't persist this one-time
722 mIgnoreXULPosition
= true;
725 mIgnoreXULSize
= true;
726 mIgnoreXULSizeMode
= true;
731 PersistentAttributesDirty(dirtyAttributes
, Sync
);
735 NS_IMETHODIMP
AppWindow::Center(nsIAppWindow
* aRelative
, bool aScreen
,
738 bool screenCoordinates
= false, windowCoordinates
= false;
741 if (!mChromeLoaded
) {
742 // note we lose the parameters. at time of writing, this isn't a problem.
743 mCenterAfterLoad
= true;
747 if (!aScreen
&& !aRelative
) {
748 return NS_ERROR_INVALID_ARG
;
751 nsCOMPtr
<nsIScreenManager
> screenmgr
=
752 do_GetService("@mozilla.org/gfx/screenmanager;1", &result
);
753 if (NS_FAILED(result
)) {
757 nsCOMPtr
<nsIScreen
> screen
;
760 nsCOMPtr
<nsIBaseWindow
> base(do_QueryInterface(aRelative
));
762 rect
= RoundedToInt(base
->GetPositionAndSize() /
763 base
->DevicePixelsPerDesktopPixel());
764 // if centering on screen, convert that to the corresponding screen
766 screen
= screenmgr
->ScreenForRect(rect
);
768 windowCoordinates
= true;
773 if (!mOpenerScreenRect
.IsEmpty()) {
774 screen
= screenmgr
->ScreenForRect(mOpenerScreenRect
);
776 screenmgr
->GetPrimaryScreen(getter_AddRefs(screen
));
780 if (aScreen
&& screen
) {
781 rect
= screen
->GetAvailRectDisplayPix();
782 screenCoordinates
= true;
785 if (!screenCoordinates
&& !windowCoordinates
) {
786 return NS_ERROR_FAILURE
;
789 NS_ASSERTION(mWindow
, "what, no window?");
790 const LayoutDeviceIntSize ourDevSize
= GetSize();
791 const DesktopIntSize ourSize
=
792 RoundedToInt(ourDevSize
/ DevicePixelsPerDesktopPixel());
795 DesktopIntPoint((rect
.width
- ourSize
.width
) / 2,
796 (rect
.height
- ourSize
.height
) / (aAlert
? 3 : 2));
797 if (windowCoordinates
) {
798 mWindow
->ConstrainPosition(newPos
);
801 SetPositionDesktopPix(newPos
.x
, newPos
.y
);
803 // If moving the window caused it to change size, re-do the centering.
804 if (GetSize() != ourDevSize
) {
805 return Center(aRelative
, aScreen
, aAlert
);
810 NS_IMETHODIMP
AppWindow::Repaint(bool aForce
) {
811 // XXX First Check In
812 NS_ASSERTION(false, "Not Yet Implemented");
816 NS_IMETHODIMP
AppWindow::GetParentWidget(nsIWidget
** aParentWidget
) {
817 NS_ENSURE_ARG_POINTER(aParentWidget
);
818 NS_ENSURE_STATE(mWindow
);
820 NS_IF_ADDREF(*aParentWidget
= mWindow
->GetParent());
824 NS_IMETHODIMP
AppWindow::SetParentWidget(nsIWidget
* aParentWidget
) {
825 // XXX First Check In
826 NS_ASSERTION(false, "Not Yet Implemented");
830 NS_IMETHODIMP
AppWindow::GetNativeHandle(nsAString
& aNativeHandle
) {
831 nsCOMPtr
<nsIWidget
> mainWidget
;
832 NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(mainWidget
)),
836 nativeWindow nativeWindowPtr
= mainWidget
->GetNativeData(NS_NATIVE_WINDOW
);
837 /* the nativeWindow pointer is converted to and exposed as a string. This
838 is a more reliable way not to lose information (as opposed to JS
839 |Number| for instance) */
841 NS_ConvertASCIItoUTF16(nsPrintfCString("0x%p", nativeWindowPtr
));
847 NS_IMETHODIMP
AppWindow::GetVisibility(bool* aVisibility
) {
848 NS_ENSURE_ARG_POINTER(aVisibility
);
850 // Always claim to be visible for now. See bug
851 // https://bugzilla.mozilla.org/show_bug.cgi?id=306245.
858 NS_IMETHODIMP
AppWindow::SetVisibility(bool aVisibility
) {
859 if (!mChromeLoaded
) {
860 mShowAfterLoad
= aVisibility
;
868 NS_ENSURE_STATE(mDocShell
);
870 mDebuting
= true; // (Show / Focus is recursive)
872 // XXXTAB Do we really need to show docshell and the window? Isn't
873 // the window good enough?
874 mDocShell
->SetVisibility(aVisibility
);
875 // Store locally so it doesn't die on us. 'Show' can result in the window
876 // being closed with AppWindow::Destroy being called. That would set
877 // mWindow to null and possibly destroy the nsIWidget while its Show method
878 // is on the stack. We need to keep it alive until Show finishes.
879 nsCOMPtr
<nsIWidget
> window
= mWindow
;
880 window
->Show(aVisibility
);
882 // NOTE(emilio): A bit hacky, but we need to synchronously trigger resizes
883 // for remote frames here if we're a sized popup (mDominantClientSize=true).
885 // This is because what we do to show a popup window with a specified size is
886 // to wait until the chrome loads (and gets sized, and thus laid out at a
887 // particular pre-size), then size the window, and call Show(), which ends up
890 // After bug 1917458, that remote browser resize would happen asynchronously,
891 // which means content might be able to observe the old size unexpectedly.
892 if (aVisibility
&& mDominantClientSize
) {
893 if (RefPtr doc
= mDocShell
->GetDocument()) {
894 doc
->SynchronouslyUpdateRemoteBrowserDimensions();
898 nsCOMPtr
<nsIWindowMediator
> windowMediator(
899 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
));
901 windowMediator
->UpdateWindowTimeStamp(static_cast<nsIAppWindow
*>(this));
903 // notify observers so that we can hide the splash screen if possible
904 nsCOMPtr
<nsIObserverService
> obssvc
= services::GetObserverService();
905 NS_ASSERTION(obssvc
, "Couldn't get observer service.");
907 obssvc
->NotifyObservers(static_cast<nsIAppWindow
*>(this),
908 "xul-window-visible", nullptr);
915 NS_IMETHODIMP
AppWindow::GetEnabled(bool* aEnabled
) {
916 NS_ENSURE_ARG_POINTER(aEnabled
);
919 *aEnabled
= mWindow
->IsEnabled();
923 *aEnabled
= true; // better guess than most
924 return NS_ERROR_FAILURE
;
927 NS_IMETHODIMP
AppWindow::SetEnabled(bool aEnable
) {
929 mWindow
->Enable(aEnable
);
932 return NS_ERROR_FAILURE
;
935 NS_IMETHODIMP
AppWindow::GetMainWidget(nsIWidget
** aMainWidget
) {
936 NS_ENSURE_ARG_POINTER(aMainWidget
);
937 NS_IF_ADDREF(*aMainWidget
= mWindow
);
941 NS_IMETHODIMP
AppWindow::GetTitle(nsAString
& aTitle
) {
946 NS_IMETHODIMP
AppWindow::SetTitle(const nsAString
& aTitle
) {
947 NS_ENSURE_STATE(mWindow
);
948 mTitle
.Assign(aTitle
);
950 NS_ENSURE_SUCCESS(mWindow
->SetTitle(mTitle
), NS_ERROR_FAILURE
);
954 //*****************************************************************************
955 // AppWindow: Helpers
956 //*****************************************************************************
958 NS_IMETHODIMP
AppWindow::EnsureChromeTreeOwner() {
959 if (mChromeTreeOwner
) return NS_OK
;
961 mChromeTreeOwner
= new nsChromeTreeOwner();
962 NS_ADDREF(mChromeTreeOwner
);
963 mChromeTreeOwner
->AppWindow(this);
968 NS_IMETHODIMP
AppWindow::EnsureContentTreeOwner() {
969 if (mContentTreeOwner
) return NS_OK
;
971 mContentTreeOwner
= new nsContentTreeOwner(false);
972 NS_ADDREF(mContentTreeOwner
);
973 mContentTreeOwner
->AppWindow(this);
978 NS_IMETHODIMP
AppWindow::EnsurePrimaryContentTreeOwner() {
979 if (mPrimaryContentTreeOwner
) return NS_OK
;
981 mPrimaryContentTreeOwner
= new nsContentTreeOwner(true);
982 NS_ADDREF(mPrimaryContentTreeOwner
);
983 mPrimaryContentTreeOwner
->AppWindow(this);
988 NS_IMETHODIMP
AppWindow::EnsurePrompter() {
989 if (mPrompter
) return NS_OK
;
991 nsCOMPtr
<mozIDOMWindowProxy
> ourWindow
;
992 nsresult rv
= GetWindowDOMWindow(getter_AddRefs(ourWindow
));
993 if (NS_SUCCEEDED(rv
)) {
994 nsCOMPtr
<nsIWindowWatcher
> wwatch
=
995 do_GetService(NS_WINDOWWATCHER_CONTRACTID
);
996 if (wwatch
) wwatch
->GetNewPrompter(ourWindow
, getter_AddRefs(mPrompter
));
998 return mPrompter
? NS_OK
: NS_ERROR_FAILURE
;
1001 NS_IMETHODIMP
AppWindow::EnsureAuthPrompter() {
1002 if (mAuthPrompter
) return NS_OK
;
1004 nsCOMPtr
<mozIDOMWindowProxy
> ourWindow
;
1005 nsresult rv
= GetWindowDOMWindow(getter_AddRefs(ourWindow
));
1006 if (NS_SUCCEEDED(rv
)) {
1007 nsCOMPtr
<nsIWindowWatcher
> wwatch(
1008 do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
1010 wwatch
->GetNewAuthPrompter(ourWindow
, getter_AddRefs(mAuthPrompter
));
1012 return mAuthPrompter
? NS_OK
: NS_ERROR_FAILURE
;
1015 NS_IMETHODIMP
AppWindow::GetAvailScreenSize(int32_t* aAvailWidth
,
1016 int32_t* aAvailHeight
) {
1017 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
;
1018 GetWindowDOMWindow(getter_AddRefs(domWindow
));
1019 NS_ENSURE_STATE(domWindow
);
1021 auto* window
= nsGlobalWindowOuter::Cast(domWindow
);
1023 RefPtr
<nsScreen
> screen
= window
->GetScreen();
1024 NS_ENSURE_STATE(screen
);
1026 *aAvailWidth
= screen
->AvailWidth();
1027 *aAvailHeight
= screen
->AvailHeight();
1031 // Rounds window size to 1000x1000, or, if there isn't enough available
1032 // screen space, to a multiple of 200x100.
1033 NS_IMETHODIMP
AppWindow::ForceRoundedDimensions() {
1034 if (mIsHiddenWindow
) {
1038 CSSToLayoutDeviceScale scale
= UnscaledDevicePixelsPerCSSPixel();
1040 CSSIntSize availSizeCSS
;
1041 GetAvailScreenSize(&availSizeCSS
.width
, &availSizeCSS
.height
);
1043 // To get correct chrome size, we have to resize the window to a proper
1044 // size first. So, here, we size it to its available size.
1045 SetSpecifiedSize(availSizeCSS
.width
, availSizeCSS
.height
);
1047 // Get the current window size for calculating chrome UI size.
1048 CSSIntSize windowSizeCSS
= RoundedToInt(GetSize() / scale
);
1050 // Get the content size for calculating chrome UI size.
1051 LayoutDeviceIntSize contentSizeDev
;
1052 GetPrimaryContentSize(&contentSizeDev
.width
, &contentSizeDev
.height
);
1053 CSSIntSize contentSizeCSS
= RoundedToInt(contentSizeDev
/ scale
);
1055 // Calculate the chrome UI size.
1056 CSSIntSize chromeSizeCSS
= windowSizeCSS
- contentSizeCSS
;
1058 CSSIntSize targetSizeCSS
;
1059 // Here, we use the available screen dimensions as the input dimensions to
1060 // force the window to be rounded as the maximum available content size.
1061 nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(
1062 chromeSizeCSS
.width
, chromeSizeCSS
.height
, availSizeCSS
.width
,
1063 availSizeCSS
.height
, availSizeCSS
.width
, availSizeCSS
.height
,
1064 false, // aSetOuterWidth
1065 false, // aSetOuterHeight
1066 &targetSizeCSS
.width
, &targetSizeCSS
.height
);
1068 LayoutDeviceIntSize targetSizeDev
= RoundedToInt(targetSizeCSS
* scale
);
1070 SetPrimaryContentSize(targetSizeDev
.width
, targetSizeDev
.height
);
1075 void AppWindow::OnChromeLoaded() {
1076 nsresult rv
= EnsureContentTreeOwner();
1078 if (NS_SUCCEEDED(rv
)) {
1079 mChromeLoaded
= true;
1081 SyncAttributesToWidget();
1084 if (mShowAfterLoad
) {
1085 SetVisibility(true);
1087 AddTooltipSupport();
1089 // At this point the window may have been closed already during Show() or
1090 // SyncAttributesToWidget(), so AppWindow::Destroy may already have been
1091 // called. Take care!
1093 mPersistentAttributesMask
+= AllPersistentAttributes();
1096 bool AppWindow::NeedsTooltipListener() {
1097 nsCOMPtr
<dom::Element
> docShellElement
= GetWindowDOMElement();
1098 if (!docShellElement
|| docShellElement
->IsXULElement()) {
1099 // Tooltips in XUL are handled by each element.
1102 // All other non-XUL document types need a tooltip listener.
1106 void AppWindow::AddTooltipSupport() {
1107 if (!NeedsTooltipListener()) {
1110 nsXULTooltipListener
* listener
= nsXULTooltipListener::GetInstance();
1115 nsCOMPtr
<dom::Element
> docShellElement
= GetWindowDOMElement();
1116 MOZ_ASSERT(docShellElement
);
1117 listener
->AddTooltipSupport(docShellElement
);
1120 void AppWindow::RemoveTooltipSupport() {
1121 if (!NeedsTooltipListener()) {
1124 nsXULTooltipListener
* listener
= nsXULTooltipListener::GetInstance();
1129 nsCOMPtr
<dom::Element
> docShellElement
= GetWindowDOMElement();
1130 MOZ_ASSERT(docShellElement
);
1131 listener
->RemoveTooltipSupport(docShellElement
);
1134 static Maybe
<int32_t> ReadIntAttribute(const Element
& aElement
,
1136 nsAtom
* aSecondary
= nullptr) {
1137 nsAutoString attrString
;
1138 if (!aElement
.GetAttr(aPrimary
, attrString
)) {
1140 return ReadIntAttribute(aElement
, aSecondary
);
1145 nsresult res
= NS_OK
;
1146 int32_t ret
= attrString
.ToInteger(&res
);
1147 return NS_SUCCEEDED(res
) ? Some(ret
) : Nothing();
1150 // If aSpecWidth and/or aSpecHeight are > 0, we will use these CSS px sizes
1151 // to fit to the screen when staggering windows; if they're negative,
1152 // we use the window's current size instead.
1153 bool AppWindow::LoadPositionFromXUL(int32_t aSpecWidth
, int32_t aSpecHeight
) {
1154 // if we're the hidden window, don't try to validate our size/position. We're
1156 if (mIsHiddenWindow
) {
1160 // If we're not in the normal sizemode, don't move the window around.
1161 if (mWindow
->SizeMode() != nsSizeMode_Normal
) {
1165 RefPtr
<dom::Element
> root
= GetWindowDOMElement();
1166 NS_ENSURE_TRUE(root
, false);
1168 const LayoutDeviceIntRect devRect
= GetPositionAndSize();
1170 // Convert to global display pixels for consistent window management across
1171 // screens with diverse resolutions
1172 const DesktopIntPoint curPoint
=
1173 RoundedToInt(devRect
.TopLeft() / DevicePixelsPerDesktopPixel());
1175 // For size, use specified value if > 0, else current value
1176 CSSIntSize
cssSize(aSpecWidth
, aSpecHeight
);
1178 CSSIntSize currentSize
=
1179 RoundedToInt(devRect
.Size() / UnscaledDevicePixelsPerCSSPixel());
1180 if (aSpecHeight
<= 0) {
1181 cssSize
.height
= currentSize
.height
;
1183 if (aSpecWidth
<= 0) {
1184 cssSize
.width
= currentSize
.width
;
1188 // Obtain the position information from the <xul:window> element.
1189 DesktopIntPoint specPoint
= curPoint
;
1190 bool gotPosition
= false;
1192 // Also read lowercase screenx/y because the front-end sometimes sets these
1193 // via setAttribute on HTML documents like about:blank, and stuff gets
1196 // TODO(emilio): We should probably rename screenX/Y to screen-x/y to
1197 // prevent this impedance mismatch.
1199 ReadIntAttribute(*root
, nsGkAtoms::screenX
, nsGkAtoms::screenx
)) {
1200 specPoint
.x
= *attr
;
1205 ReadIntAttribute(*root
, nsGkAtoms::screenY
, nsGkAtoms::screeny
)) {
1206 specPoint
.y
= *attr
;
1211 // Our position will be relative to our parent, if any
1212 nsCOMPtr
<nsIBaseWindow
> parent(do_QueryReferent(mParentWindow
));
1214 const DesktopIntPoint parentPos
= RoundedToInt(
1215 parent
->GetPosition() / parent
->DevicePixelsPerDesktopPixel());
1216 specPoint
+= parentPos
;
1218 StaggerPosition(specPoint
.x
.value
, specPoint
.y
.value
, cssSize
.width
,
1222 mWindow
->ConstrainPosition(specPoint
);
1223 if (specPoint
!= curPoint
) {
1224 SetPositionDesktopPix(specPoint
.x
, specPoint
.y
);
1229 static Maybe
<int32_t> ReadSize(const Element
& aElement
, nsAtom
* aAttr
,
1230 nsAtom
* aMinAttr
, nsAtom
* aMaxAttr
) {
1231 Maybe
<int32_t> attr
= ReadIntAttribute(aElement
, aAttr
);
1237 std::max(100, ReadIntAttribute(aElement
, aMinAttr
).valueOr(100));
1238 int32_t max
= ReadIntAttribute(aElement
, aMaxAttr
)
1239 .valueOr(std::numeric_limits
<int32_t>::max());
1241 return Some(std::clamp(*attr
, min
, max
));
1244 bool AppWindow::LoadSizeFromXUL(int32_t& aSpecWidth
, int32_t& aSpecHeight
) {
1245 bool gotSize
= false;
1247 // if we're the hidden window, don't try to validate our size/position. We're
1249 if (mIsHiddenWindow
) {
1253 nsCOMPtr
<dom::Element
> windowElement
= GetWindowDOMElement();
1254 NS_ENSURE_TRUE(windowElement
, false);
1256 // Obtain the sizing information from the <xul:window> element.
1260 if (auto width
= ReadSize(*windowElement
, nsGkAtoms::width
,
1261 nsGkAtoms::minwidth
, nsGkAtoms::maxwidth
)) {
1262 aSpecWidth
= *width
;
1266 if (auto height
= ReadSize(*windowElement
, nsGkAtoms::height
,
1267 nsGkAtoms::minheight
, nsGkAtoms::maxheight
)) {
1268 aSpecHeight
= *height
;
1275 void AppWindow::SetSpecifiedSize(int32_t aSpecWidth
, int32_t aSpecHeight
) {
1276 // These are in CSS pixels of the main window.
1277 // TODO(emilio): In my testing we usually have a pres context around, can we
1278 // just use it? That'd simplify the coordinate calculations.
1280 int32_t screenWidth
;
1281 int32_t screenHeight
;
1283 if (NS_SUCCEEDED(GetAvailScreenSize(&screenWidth
, &screenHeight
))) {
1284 if (aSpecWidth
> screenWidth
) {
1285 aSpecWidth
= screenWidth
;
1287 if (aSpecHeight
> screenHeight
) {
1288 aSpecHeight
= screenHeight
;
1293 NS_ASSERTION(mWindow
, "we expected to have a window already");
1295 mIntrinsicallySized
= false;
1297 // Convert specified values to device pixels, and resize
1298 auto newSize
= RoundedToInt(CSSIntSize(aSpecWidth
, aSpecHeight
) *
1299 UnscaledDevicePixelsPerCSSPixel());
1301 // Note: Because of the asynchronous resizing on Linux we have to call
1302 // SetSize even when the size doesn't appear to change. A previous call that
1303 // has yet to complete can still change the size. We want the latest call to
1304 // define the final size.
1305 SetSize(newSize
.width
, newSize
.height
, false);
1308 /* Miscellaneous persistent attributes are attributes named in the
1309 |persist| attribute, other than size and position. Those are special
1310 because it's important to load those before one of the misc
1311 attributes (sizemode) and they require extra processing. */
1312 bool AppWindow::UpdateWindowStateFromMiscXULAttributes() {
1313 /* There are no misc attributes of interest to the hidden window.
1314 It's especially important not to try to validate that window's
1315 size or position, because some platforms (Mac OS X) need to
1316 make it visible and offscreen. */
1317 if (mIsHiddenWindow
) {
1321 nsCOMPtr
<dom::Element
> windowElement
= GetWindowDOMElement();
1322 NS_ENSURE_TRUE(windowElement
, false);
1324 nsAutoString stateString
;
1325 nsSizeMode sizeMode
= nsSizeMode_Normal
;
1327 // If we are told to ignore the size mode attribute, force
1329 if (mIgnoreXULSizeMode
) {
1330 windowElement
->SetAttr(nsGkAtoms::sizemode
, SIZEMODE_NORMAL
,
1333 // Otherwise, read sizemode from DOM and, if the window is resizable,
1335 windowElement
->GetAttr(nsGkAtoms::sizemode
, stateString
);
1336 if ((stateString
.Equals(SIZEMODE_MAXIMIZED
) ||
1337 stateString
.Equals(SIZEMODE_FULLSCREEN
))) {
1338 /* Honor request to maximize only if the window is sizable.
1339 An unsizable, unmaximizable, yet maximized window confuses
1340 Windows OS and is something of a travesty, anyway. */
1341 if (mChromeFlags
& nsIWebBrowserChrome::CHROME_WINDOW_RESIZE
) {
1342 mIntrinsicallySized
= false;
1344 sizeMode
= stateString
.Equals(SIZEMODE_MAXIMIZED
)
1345 ? nsSizeMode_Maximized
1346 : nsSizeMode_Fullscreen
;
1351 if (sizeMode
== nsSizeMode_Fullscreen
) {
1352 nsCOMPtr
<mozIDOMWindowProxy
> ourWindow
;
1353 GetWindowDOMWindow(getter_AddRefs(ourWindow
));
1354 auto* piWindow
= nsPIDOMWindowOuter::From(ourWindow
);
1355 piWindow
->SetFullScreen(true);
1357 // For maximized windows, ignore the XUL size and position attributes,
1358 // as setting them would set the window back to normal sizemode.
1359 if (sizeMode
== nsSizeMode_Maximized
) {
1360 mIgnoreXULSize
= true;
1361 mIgnoreXULPosition
= true;
1363 mWindow
->SetSizeMode(sizeMode
);
1368 /* Stagger windows of the same type so they don't appear on top of each other.
1369 This code does have a scary double loop -- it'll keep passing through
1370 the entire list of open windows until it finds a non-collision. Doesn't
1371 seem to be a problem, but it deserves watching.
1372 The aRequested{X,Y} parameters here are in desktop pixels;
1373 the aSpec{Width,Height} parameters are CSS pixel dimensions.
1375 void AppWindow::StaggerPosition(int32_t& aRequestedX
, int32_t& aRequestedY
,
1376 int32_t aSpecWidth
, int32_t aSpecHeight
) {
1377 // These "constants" will be converted from CSS to desktop pixels
1378 // for the appropriate screen, assuming we find a screen to use...
1379 // hence they're not actually declared const here.
1380 int32_t kOffset
= 22;
1384 int bouncedX
= 0, // bounced off vertical edge of screen
1385 bouncedY
= 0; // bounced off horizontal edge
1387 // look for any other windows of this type
1388 nsCOMPtr
<nsIWindowMediator
> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
));
1391 nsCOMPtr
<dom::Element
> windowElement
= GetWindowDOMElement();
1392 if (!windowElement
) return;
1394 nsCOMPtr
<nsIAppWindow
> ourAppWindow(this);
1396 nsAutoString windowType
;
1397 windowElement
->GetAttr(nsGkAtoms::windowtype
, windowType
);
1399 DesktopIntRect screenRect
;
1400 bool gotScreen
= false;
1402 { // fetch screen coordinates
1403 nsCOMPtr
<nsIScreenManager
> screenMgr(
1404 do_GetService("@mozilla.org/gfx/screenmanager;1"));
1406 nsCOMPtr
<nsIScreen
> ourScreen
;
1407 // The coordinates here are already display pixels
1408 // XXX aSpecWidth and aSpecHeight are CSS pixels!
1409 screenMgr
->ScreenForRect(aRequestedX
, aRequestedY
, aSpecWidth
,
1410 aSpecHeight
, getter_AddRefs(ourScreen
));
1412 screenRect
= ourScreen
->GetAvailRectDisplayPix();
1414 // Get the screen's scaling factors and convert staggering constants
1415 // from CSS px to desktop pixel units
1416 auto scale
= ourScreen
->GetCSSToDesktopScale();
1417 kOffset
= (CSSCoord(kOffset
) * scale
).Rounded();
1418 kSlop
= (CSSCoord(kSlop
) * scale
).Rounded();
1419 // Convert dimensions from CSS to desktop pixels
1420 aSpecWidth
= (CSSCoord(aSpecWidth
) * scale
).Rounded();
1421 aSpecHeight
= (CSSCoord(aSpecHeight
) * scale
).Rounded();
1427 // One full pass through all windows of this type, repeat until no collisions.
1430 nsCOMPtr
<nsISimpleEnumerator
> windowList
;
1431 wm
->GetAppWindowEnumerator(windowType
.get(), getter_AddRefs(windowList
));
1433 if (!windowList
) break;
1435 // One full pass through all windows of this type, offset and stop on
1439 windowList
->HasMoreElements(&more
);
1442 nsCOMPtr
<nsISupports
> supportsWindow
;
1443 windowList
->GetNext(getter_AddRefs(supportsWindow
));
1445 nsCOMPtr
<nsIAppWindow
> listAppWindow(do_QueryInterface(supportsWindow
));
1446 if (listAppWindow
!= ourAppWindow
) {
1447 int32_t listX
, listY
;
1448 nsCOMPtr
<nsIBaseWindow
> listBaseWindow(
1449 do_QueryInterface(supportsWindow
));
1450 listBaseWindow
->GetPosition(&listX
, &listY
);
1453 listBaseWindow
->GetDevicePixelsPerDesktopPixel(&scale
))) {
1454 listX
= NSToIntRound(listX
/ scale
);
1455 listY
= NSToIntRound(listY
/ scale
);
1458 if (Abs(listX
- aRequestedX
) <= kSlop
&&
1459 Abs(listY
- aRequestedY
) <= kSlop
) {
1460 // collision! offset and start over
1462 aRequestedX
-= kOffset
;
1464 aRequestedX
+= kOffset
;
1465 aRequestedY
+= kOffset
;
1468 // if we're moving to the right and we need to bounce...
1469 if (!(bouncedX
& 0x1) &&
1470 ((aRequestedX
+ aSpecWidth
) > screenRect
.XMost())) {
1471 aRequestedX
= screenRect
.XMost() - aSpecWidth
;
1475 // if we're moving to the left and we need to bounce...
1476 if ((bouncedX
& 0x1) && aRequestedX
< screenRect
.X()) {
1477 aRequestedX
= screenRect
.X();
1481 // if we hit the bottom then bounce to the top
1482 if (aRequestedY
+ aSpecHeight
> screenRect
.YMost()) {
1483 aRequestedY
= screenRect
.Y();
1488 /* loop around again,
1489 but it's time to give up once we've covered the screen.
1490 there's a potential infinite loop with lots of windows. */
1491 keepTrying
= bouncedX
< 2 || bouncedY
== 0;
1496 } while (keepTrying
);
1499 void AppWindow::SyncAttributesToWidget() {
1500 nsCOMPtr
<dom::Element
> windowElement
= GetWindowDOMElement();
1501 if (!windowElement
) return;
1503 MOZ_DIAGNOSTIC_ASSERT(mWindow
, "No widget on SyncAttributesToWidget?");
1507 // Some attributes can change the client size (e.g. customtitlebar on Windows
1508 // and MacOS). But we might want to keep it.
1509 const LayoutDeviceIntSize oldClientSize
= mWindow
->GetClientSize();
1510 // We have to check now whether we want to restore the client size, as any
1511 // change in size will reset its state.
1512 bool maintainClientSize
= mDominantClientSize
;
1514 // "hidechrome" attribute
1515 // FIXME(emilio): This should arguably be
1516 // HideWindowChrome(windowElement->GetBoolAttr(...)), but that has
1517 // side-effects in some platforms.
1518 if (windowElement
->GetBoolAttr(nsGkAtoms::hidechrome
)) {
1519 mWindow
->HideWindowChrome(true);
1521 NS_ENSURE_TRUE_VOID(mWindow
);
1523 // "customtitlebar" attribute
1524 // FIXME(emilio): This should arguably be
1525 // SetCustomTitlebar(windowElement->GetBoolAttr(...)), but that breaks with
1526 // the early blank window which sets the custom titlebar via
1527 // nsIDOMWindowUtils...
1528 if (windowElement
->GetBoolAttr(nsGkAtoms::customtitlebar
)) {
1529 mWindow
->SetCustomTitlebar(true);
1532 NS_ENSURE_TRUE_VOID(mWindow
);
1534 mWindow
->SetMicaBackdrop(windowElement
->GetBoolAttr(nsGkAtoms::windowsmica
));
1535 NS_ENSURE_TRUE_VOID(mWindow
);
1537 // "windowtype", "windowclass", "windowname" attributes
1538 nsAutoString windowClassAttr
, windowNameAttr
;
1539 windowElement
->GetAttr(nsGkAtoms::windowtype
, attr
);
1540 windowElement
->GetAttribute(u
"windowclass"_ns
, windowClassAttr
);
1541 windowElement
->GetAttribute(u
"windowname"_ns
, windowNameAttr
);
1542 mWindow
->SetWindowClass(attr
, windowClassAttr
, windowNameAttr
);
1544 NS_ENSURE_TRUE_VOID(mWindow
);
1546 // Only change blank window status once we're loaded, so that a
1547 // partially-loaded browser window doesn't start painting early.
1548 if (mChromeLoaded
) {
1549 mWindow
->SetIsEarlyBlankWindow(attr
.EqualsLiteral("navigator:blank"));
1550 NS_ENSURE_TRUE_VOID(mWindow
);
1554 windowElement
->GetAttribute(u
"icon"_ns
, attr
);
1555 if (!attr
.IsEmpty()) {
1556 mWindow
->SetIcon(attr
);
1557 NS_ENSURE_TRUE_VOID(mWindow
);
1560 // "drawtitle" attribute
1561 mWindow
->SetDrawsTitle(windowElement
->GetBoolAttr(nsGkAtoms::drawtitle
));
1562 NS_ENSURE_TRUE_VOID(mWindow
);
1564 // "toggletoolbar" attribute
1565 mWindow
->SetShowsToolbarButton(
1566 windowElement
->HasAttribute(u
"toggletoolbar"_ns
));
1567 NS_ENSURE_TRUE_VOID(mWindow
);
1569 // "macnativefullscreen" attribute
1570 mWindow
->SetSupportsNativeFullscreen(
1571 windowElement
->HasAttribute(u
"macnativefullscreen"_ns
));
1572 NS_ENSURE_TRUE_VOID(mWindow
);
1574 // "macanimationtype" attribute
1575 windowElement
->GetAttribute(u
"macanimationtype"_ns
, attr
);
1576 if (attr
.EqualsLiteral("document")) {
1577 mWindow
->SetWindowAnimationType(nsIWidget::eDocumentWindowAnimation
);
1580 // Check if the client size did change and if we want to restore it.
1581 if (maintainClientSize
&& mWindow
->SizeMode() == nsSizeMode_Normal
&&
1582 oldClientSize
!= mWindow
->GetClientSize()) {
1583 mWindow
->ResizeClient(oldClientSize
/ mWindow
->GetDesktopToDeviceScale(),
1585 mDominantClientSize
= true;
1589 enum class ConversionDirection
{
1594 static void ConvertWindowSize(nsIAppWindow
* aWin
, const nsAtom
* aAttr
,
1595 ConversionDirection aDirection
,
1596 nsAString
& aInOutString
) {
1598 MOZ_ASSERT(aAttr
== nsGkAtoms::width
|| aAttr
== nsGkAtoms::height
);
1601 int32_t size
= aInOutString
.ToInteger(&rv
);
1602 if (NS_FAILED(rv
)) {
1606 int32_t sizeDiff
= aAttr
== nsGkAtoms::width
1607 ? aWin
->GetOuterToInnerWidthDifferenceInCSSPixels()
1608 : aWin
->GetOuterToInnerHeightDifferenceInCSSPixels();
1614 int32_t multiplier
= aDirection
== ConversionDirection::InnerToOuter
? 1 : -1;
1616 CopyASCIItoUTF16(nsPrintfCString("%d", size
+ multiplier
* sizeDiff
),
1620 nsresult
AppWindow::GetPersistentValue(const nsAtom
* aAttr
, nsAString
& aValue
) {
1621 if (!XRE_IsParentProcess()) {
1622 // The XULStore is only available in the parent process.
1623 return NS_ERROR_UNEXPECTED
;
1626 nsCOMPtr
<dom::Element
> docShellElement
= GetWindowDOMElement();
1627 if (!docShellElement
) {
1628 return NS_ERROR_FAILURE
;
1631 nsAutoString windowElementId
;
1632 docShellElement
->GetId(windowElementId
);
1633 // Elements must have an ID to be persisted.
1634 if (windowElementId
.IsEmpty()) {
1638 RefPtr
<dom::Document
> ownerDoc
= docShellElement
->OwnerDoc();
1639 nsIURI
* docURI
= ownerDoc
->GetDocumentURI();
1641 return NS_ERROR_FAILURE
;
1643 nsAutoCString utf8uri
;
1644 nsresult rv
= docURI
->GetSpec(utf8uri
);
1645 NS_ENSURE_SUCCESS(rv
, rv
);
1646 NS_ConvertUTF8toUTF16
uri(utf8uri
);
1649 mLocalStore
= do_GetService("@mozilla.org/xul/xulstore;1");
1650 if (NS_WARN_IF(!mLocalStore
)) {
1651 return NS_ERROR_NOT_INITIALIZED
;
1655 rv
= mLocalStore
->GetValue(uri
, windowElementId
, nsDependentAtomString(aAttr
),
1657 if (NS_WARN_IF(NS_FAILED(rv
))) {
1661 if (aAttr
== nsGkAtoms::width
|| aAttr
== nsGkAtoms::height
) {
1662 // Convert attributes from outer size to inner size for top-level
1663 // windows, see bug 1444525 & co.
1664 ConvertWindowSize(this, aAttr
, ConversionDirection::OuterToInner
, aValue
);
1670 nsresult
AppWindow::GetDocXulStoreKeys(nsString
& aUriSpec
,
1671 nsString
& aWindowElementId
) {
1672 nsCOMPtr
<dom::Element
> docShellElement
= GetWindowDOMElement();
1673 if (!docShellElement
) {
1674 return NS_ERROR_FAILURE
;
1677 docShellElement
->GetId(aWindowElementId
);
1678 // Match the behavior of XULPersist and only persist values if the element
1680 if (aWindowElementId
.IsEmpty()) {
1684 RefPtr
<dom::Document
> ownerDoc
= docShellElement
->OwnerDoc();
1685 nsIURI
* docURI
= ownerDoc
->GetDocumentURI();
1687 return NS_ERROR_FAILURE
;
1690 nsAutoCString utf8uri
;
1691 nsresult rv
= docURI
->GetSpec(utf8uri
);
1692 if (NS_WARN_IF(NS_FAILED(rv
))) {
1696 aUriSpec
= NS_ConvertUTF8toUTF16(utf8uri
);
1701 nsresult
AppWindow::MaybeSaveEarlyWindowPersistentValues(
1702 const LayoutDeviceIntRect
& aRect
) {
1705 nsAutoString windowElementId
;
1706 nsresult rv
= GetDocXulStoreKeys(uri
, windowElementId
);
1708 if (NS_WARN_IF(NS_FAILED(rv
))) {
1712 if (!windowElementId
.EqualsLiteral("main-window") ||
1713 !uri
.EqualsLiteral("chrome://browser/content/browser.xhtml")) {
1717 SkeletonUISettings settings
;
1719 settings
.screenX
= aRect
.X();
1720 settings
.screenY
= aRect
.Y();
1721 settings
.width
= aRect
.Width();
1722 settings
.height
= aRect
.Height();
1724 settings
.maximized
= mWindow
->SizeMode() == nsSizeMode_Maximized
;
1725 settings
.cssToDevPixelScaling
= UnscaledDevicePixelsPerCSSPixel().scale
;
1727 nsCOMPtr
<dom::Element
> windowElement
= GetWindowDOMElement();
1728 Document
* doc
= windowElement
->GetComposedDoc();
1729 Element
* urlbarEl
= doc
->GetElementById(u
"urlbar"_ns
);
1731 nsCOMPtr
<nsPIDOMWindowOuter
> window
= mDocShell
->GetWindow();
1732 nsCOMPtr
<nsIDOMWindowUtils
> utils
=
1733 nsGlobalWindowOuter::Cast(window
)->WindowUtils();
1734 RefPtr
<dom::DOMRect
> urlbarRect
;
1735 rv
= utils
->GetBoundsWithoutFlushing(urlbarEl
, getter_AddRefs(urlbarRect
));
1736 if (NS_WARN_IF(NS_FAILED(rv
))) {
1740 double urlbarX
= urlbarRect
->X();
1741 double urlbarWidth
= urlbarRect
->Width();
1743 // Hard-coding the following values and this behavior in general is rather
1744 // fragile, and can easily get out of sync with the actual front-end values.
1745 // This is not intended as a long-term solution, but only as the relatively
1746 // straightforward implementation of an experimental feature. If we want to
1747 // ship the skeleton UI to all users, we should strongly consider a more
1748 // robust solution than this. The vertical position of the urlbar will be
1750 nsAutoString attributeValue
;
1751 urlbarEl
->GetAttribute(u
"breakout-extend"_ns
, attributeValue
);
1752 // Scale down the urlbar if it is focused
1753 if (attributeValue
.EqualsLiteral("true")) {
1754 // defined in browser.inc.css as 2px
1755 int urlbarBreakoutExtend
= 2;
1756 // defined in urlbar-searchbar.inc.css as 5px
1757 int urlbarMarginInline
= 5;
1759 // breakout-extend measurements are defined in urlbar-searchbar.inc.css
1760 urlbarX
+= (double)(urlbarBreakoutExtend
+ urlbarMarginInline
);
1761 urlbarWidth
-= (double)(2 * (urlbarBreakoutExtend
+ urlbarMarginInline
));
1763 CSSPixelSpan urlbar
;
1764 urlbar
.start
= urlbarX
;
1765 urlbar
.end
= urlbar
.start
+ urlbarWidth
;
1766 settings
.urlbarSpan
= urlbar
;
1768 Element
* navbar
= doc
->GetElementById(u
"nav-bar"_ns
);
1770 Element
* searchbarEl
= doc
->GetElementById(u
"searchbar"_ns
);
1771 CSSPixelSpan searchbar
;
1772 if (navbar
->Contains(searchbarEl
)) {
1773 RefPtr
<dom::DOMRect
> searchbarRect
;
1774 rv
= utils
->GetBoundsWithoutFlushing(searchbarEl
,
1775 getter_AddRefs(searchbarRect
));
1776 if (NS_WARN_IF(NS_FAILED(rv
))) {
1779 searchbar
.start
= searchbarRect
->X();
1780 searchbar
.end
= searchbar
.start
+ searchbarRect
->Width();
1782 // There is no searchbar in the UI
1783 searchbar
.start
= 0;
1786 settings
.searchbarSpan
= searchbar
;
1788 nsAutoString bookmarksVisibility
;
1789 Preferences::GetString("browser.toolbars.bookmarks.visibility",
1790 bookmarksVisibility
);
1791 settings
.bookmarksToolbarShown
=
1792 bookmarksVisibility
.EqualsLiteral("always") ||
1793 bookmarksVisibility
.EqualsLiteral("newtab");
1795 Element
* menubar
= doc
->GetElementById(u
"toolbar-menubar"_ns
);
1796 menubar
->GetAttribute(u
"autohide"_ns
, attributeValue
);
1797 settings
.menubarShown
= attributeValue
.EqualsLiteral("false");
1800 nsCOMPtr
<nsIHTMLCollection
> toolbarSprings
= navbar
->GetElementsByTagNameNS(
1801 u
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"_ns
,
1802 u
"toolbarspring"_ns
, err
);
1804 return NS_ERROR_FAILURE
;
1806 mozilla::Vector
<CSSPixelSpan
> springs
;
1807 for (size_t i
= 0; i
< toolbarSprings
->Length(); i
++) {
1808 RefPtr
<Element
> springEl
= toolbarSprings
->Item(i
);
1809 RefPtr
<dom::DOMRect
> springRect
;
1810 rv
= utils
->GetBoundsWithoutFlushing(springEl
, getter_AddRefs(springRect
));
1811 if (NS_WARN_IF(NS_FAILED(rv
))) {
1814 CSSPixelSpan spring
;
1815 spring
.start
= springRect
->X();
1816 spring
.end
= spring
.start
+ springRect
->Width();
1817 if (!settings
.springs
.append(spring
)) {
1818 return NS_ERROR_FAILURE
;
1822 settings
.rtlEnabled
= intl::LocaleService::GetInstance()->IsAppLocaleRTL();
1824 bool isInTabletMode
= false;
1825 bool const autoTouchModePref
=
1826 Preferences::GetBool("browser.touchmode.auto", false);
1827 if (autoTouchModePref
) {
1828 nsCOMPtr
<nsIWindowsUIUtils
> uiUtils(
1829 do_GetService("@mozilla.org/windows-ui-utils;1"));
1830 if (!NS_WARN_IF(!uiUtils
)) {
1831 // We switch to the touch-optimized layout in both Win10 and Win11 tablet-
1832 // modes, since only the input mechanism is relevant. (See bug 1819421.)
1833 if (IsWin11OrLater()) {
1834 uiUtils
->GetInWin11TabletMode(&isInTabletMode
);
1836 uiUtils
->GetInWin10TabletMode(&isInTabletMode
);
1841 if (isInTabletMode
) {
1842 settings
.uiDensity
= SkeletonUIDensity::Touch
;
1844 int uiDensityPref
= Preferences::GetInt("browser.uidensity", 0);
1845 switch (uiDensityPref
) {
1847 settings
.uiDensity
= SkeletonUIDensity::Default
;
1851 settings
.uiDensity
= SkeletonUIDensity::Compact
;
1855 settings
.uiDensity
= SkeletonUIDensity::Touch
;
1861 settings
.verticalTabs
= Preferences::GetBool("sidebar.verticalTabs", false);
1863 Unused
<< PersistPreXULSkeletonUIValues(settings
);
1869 nsresult
AppWindow::SetPersistentValue(const nsAtom
* aAttr
,
1870 const nsAString
& aValue
) {
1871 if (!XRE_IsParentProcess()) {
1872 // The XULStore is only available in the parent process.
1873 return NS_ERROR_UNEXPECTED
;
1877 nsAutoString windowElementId
;
1878 nsresult rv
= GetDocXulStoreKeys(uri
, windowElementId
);
1880 if (NS_FAILED(rv
) || windowElementId
.IsEmpty()) {
1884 nsAutoString
maybeConvertedValue(aValue
);
1885 if (aAttr
== nsGkAtoms::width
|| aAttr
== nsGkAtoms::height
) {
1886 // Make sure we store the <window> attributes as outer window size, see
1887 // bug 1444525 & co.
1888 ConvertWindowSize(this, aAttr
, ConversionDirection::InnerToOuter
,
1889 maybeConvertedValue
);
1893 mLocalStore
= do_GetService("@mozilla.org/xul/xulstore;1");
1894 if (NS_WARN_IF(!mLocalStore
)) {
1895 return NS_ERROR_NOT_INITIALIZED
;
1899 return mLocalStore
->SetValue(
1900 uri
, windowElementId
, nsDependentAtomString(aAttr
), maybeConvertedValue
);
1903 void AppWindow::MaybeSavePersistentPositionAndSize(
1904 PersistentAttributes aAttributes
, Element
& aRootElement
,
1905 const nsAString
& aPersistString
, bool aShouldPersist
) {
1906 if ((aAttributes
& PersistentAttributes
{PersistentAttribute::Position
,
1907 PersistentAttribute::Size
})
1912 // get our size, position and mode to persist
1913 LayoutDeviceIntRect rect
;
1914 if (NS_FAILED(mWindow
->GetRestoredBounds(rect
))) {
1918 // we use CSS pixels for size, but desktop pixels for position
1919 CSSToLayoutDeviceScale sizeScale
= UnscaledDevicePixelsPerCSSPixel();
1920 DesktopToLayoutDeviceScale posScale
= DevicePixelsPerDesktopPixel();
1922 // make our position relative to our parent, if any
1923 nsCOMPtr
<nsIBaseWindow
> parent(do_QueryReferent(mParentWindow
));
1925 int32_t parentX
, parentY
;
1926 if (NS_SUCCEEDED(parent
->GetPosition(&parentX
, &parentY
))) {
1927 rect
.MoveBy(-parentX
, -parentY
);
1931 nsAutoString sizeString
;
1932 // (only for size elements which are persisted)
1933 if (aAttributes
.contains(PersistentAttribute::Position
)) {
1934 if (aPersistString
.Find(u
"screenX") >= 0) {
1935 sizeString
.Truncate();
1936 sizeString
.AppendInt(NSToIntRound(rect
.X() / posScale
.scale
));
1937 aRootElement
.SetAttr(nsGkAtoms::screenX
, sizeString
, IgnoreErrors());
1938 if (aShouldPersist
) {
1939 Unused
<< SetPersistentValue(nsGkAtoms::screenX
, sizeString
);
1942 if (aPersistString
.Find(u
"screenY") >= 0) {
1943 sizeString
.Truncate();
1944 sizeString
.AppendInt(NSToIntRound(rect
.Y() / posScale
.scale
));
1945 aRootElement
.SetAttr(nsGkAtoms::screenY
, sizeString
, IgnoreErrors());
1946 if (aShouldPersist
) {
1947 Unused
<< SetPersistentValue(nsGkAtoms::screenY
, sizeString
);
1952 if (aAttributes
.contains(PersistentAttribute::Size
)) {
1953 LayoutDeviceIntRect innerRect
=
1954 rect
- GetOuterToInnerSizeDifference(mWindow
);
1955 if (aPersistString
.Find(u
"width") >= 0) {
1956 sizeString
.Truncate();
1957 sizeString
.AppendInt(NSToIntRound(innerRect
.Width() / sizeScale
.scale
));
1958 aRootElement
.SetAttr(nsGkAtoms::width
, sizeString
, IgnoreErrors());
1959 if (aShouldPersist
) {
1960 Unused
<< SetPersistentValue(nsGkAtoms::width
, sizeString
);
1963 if (aPersistString
.Find(u
"height") >= 0) {
1964 sizeString
.Truncate();
1965 sizeString
.AppendInt(NSToIntRound(innerRect
.Height() / sizeScale
.scale
));
1966 aRootElement
.SetAttr(nsGkAtoms::height
, sizeString
, IgnoreErrors());
1967 if (aShouldPersist
) {
1968 Unused
<< SetPersistentValue(nsGkAtoms::height
, sizeString
);
1973 Unused
<< MaybeSaveEarlyWindowPersistentValues(rect
);
1976 void AppWindow::MaybeSavePersistentMiscAttributes(
1977 PersistentAttributes aAttributes
, Element
& aRootElement
,
1978 const nsAString
& aPersistString
, bool aShouldPersist
) {
1979 if (!aAttributes
.contains(PersistentAttribute::Misc
)) {
1983 nsSizeMode sizeMode
= mWindow
->SizeMode();
1984 nsAutoString sizeString
;
1985 if (sizeMode
!= nsSizeMode_Minimized
) {
1986 if (sizeMode
== nsSizeMode_Maximized
) {
1987 sizeString
.Assign(SIZEMODE_MAXIMIZED
);
1988 } else if (sizeMode
== nsSizeMode_Fullscreen
) {
1989 sizeString
.Assign(SIZEMODE_FULLSCREEN
);
1991 sizeString
.Assign(SIZEMODE_NORMAL
);
1993 aRootElement
.SetAttr(nsGkAtoms::sizemode
, sizeString
, IgnoreErrors());
1994 if (aShouldPersist
&& aPersistString
.Find(u
"sizemode") >= 0) {
1995 Unused
<< SetPersistentValue(nsGkAtoms::sizemode
, sizeString
);
1998 aRootElement
.SetAttribute(u
"gtktiledwindow"_ns
,
1999 mWindow
->IsTiled() ? u
"true"_ns
: u
"false"_ns
,
2003 void AppWindow::SavePersistentAttributes(
2004 const PersistentAttributes aAttributes
) {
2005 // can happen when the persistence timer fires at an inopportune time
2006 // during window shutdown
2011 nsCOMPtr
<dom::Element
> docShellElement
= GetWindowDOMElement();
2012 if (!docShellElement
) {
2016 nsAutoString persistString
;
2017 docShellElement
->GetAttr(nsGkAtoms::persist
, persistString
);
2018 if (persistString
.IsEmpty()) { // quick check which sometimes helps
2019 mPersistentAttributesDirty
.clear();
2023 bool shouldPersist
= mWindow
->SizeMode() != nsSizeMode_Fullscreen
;
2024 MaybeSavePersistentPositionAndSize(aAttributes
, *docShellElement
,
2025 persistString
, shouldPersist
);
2026 MaybeSavePersistentMiscAttributes(aAttributes
, *docShellElement
,
2027 persistString
, shouldPersist
);
2028 mPersistentAttributesDirty
-= aAttributes
;
2031 NS_IMETHODIMP
AppWindow::GetWindowDOMWindow(mozIDOMWindowProxy
** aDOMWindow
) {
2032 NS_ENSURE_STATE(mDocShell
);
2034 if (!mDOMWindow
) mDOMWindow
= mDocShell
->GetWindow();
2035 NS_ENSURE_TRUE(mDOMWindow
, NS_ERROR_FAILURE
);
2037 *aDOMWindow
= mDOMWindow
;
2038 NS_ADDREF(*aDOMWindow
);
2042 dom::Element
* AppWindow::GetWindowDOMElement() const {
2043 NS_ENSURE_TRUE(mDocShell
, nullptr);
2045 nsCOMPtr
<nsIDocumentViewer
> viewer
;
2046 mDocShell
->GetDocViewer(getter_AddRefs(viewer
));
2047 NS_ENSURE_TRUE(viewer
, nullptr);
2049 const dom::Document
* document
= viewer
->GetDocument();
2050 NS_ENSURE_TRUE(document
, nullptr);
2052 return document
->GetRootElement();
2055 nsresult
AppWindow::ContentShellAdded(nsIDocShellTreeItem
* aContentShell
,
2057 // Set the default content tree owner
2059 NS_ENSURE_SUCCESS(EnsurePrimaryContentTreeOwner(), NS_ERROR_FAILURE
);
2060 aContentShell
->SetTreeOwner(mPrimaryContentTreeOwner
);
2061 mPrimaryContentShell
= aContentShell
;
2062 mPrimaryBrowserParent
= nullptr;
2064 NS_ENSURE_SUCCESS(EnsureContentTreeOwner(), NS_ERROR_FAILURE
);
2065 aContentShell
->SetTreeOwner(mContentTreeOwner
);
2066 if (mPrimaryContentShell
== aContentShell
) mPrimaryContentShell
= nullptr;
2072 nsresult
AppWindow::ContentShellRemoved(nsIDocShellTreeItem
* aContentShell
) {
2073 if (mPrimaryContentShell
== aContentShell
) {
2074 mPrimaryContentShell
= nullptr;
2080 AppWindow::GetPrimaryContentSize(int32_t* aWidth
, int32_t* aHeight
) {
2081 if (mPrimaryBrowserParent
) {
2082 return GetPrimaryRemoteTabSize(aWidth
, aHeight
);
2084 if (mPrimaryContentShell
) {
2085 return GetPrimaryContentShellSize(aWidth
, aHeight
);
2087 return NS_ERROR_UNEXPECTED
;
2090 nsresult
AppWindow::GetPrimaryRemoteTabSize(int32_t* aWidth
, int32_t* aHeight
) {
2091 BrowserHost
* host
= BrowserHost::GetFrom(mPrimaryBrowserParent
.get());
2092 // Need strong ref, since Client* can run script.
2093 RefPtr
<dom::Element
> element
= host
->GetOwnerElement();
2094 NS_ENSURE_STATE(element
);
2096 CSSIntSize
size(element
->ClientWidth(), element
->ClientHeight());
2097 LayoutDeviceIntSize sizeDev
=
2098 RoundedToInt(size
* UnscaledDevicePixelsPerCSSPixel());
2100 *aWidth
= sizeDev
.width
;
2103 *aHeight
= sizeDev
.height
;
2108 nsresult
AppWindow::GetPrimaryContentShellSize(int32_t* aWidth
,
2110 NS_ENSURE_STATE(mPrimaryContentShell
);
2112 nsCOMPtr
<nsIBaseWindow
> shellWindow(do_QueryInterface(mPrimaryContentShell
));
2113 NS_ENSURE_STATE(shellWindow
);
2115 LayoutDeviceIntSize sizeDev
= shellWindow
->GetSize();
2117 *aWidth
= sizeDev
.width
;
2120 *aHeight
= sizeDev
.height
;
2126 AppWindow::SetPrimaryContentSize(int32_t aWidth
, int32_t aHeight
) {
2127 if (mPrimaryBrowserParent
) {
2128 return SetPrimaryRemoteTabSize(aWidth
, aHeight
);
2130 if (mPrimaryContentShell
) {
2131 return SizeShellTo(mPrimaryContentShell
, aWidth
, aHeight
);
2133 return NS_ERROR_UNEXPECTED
;
2136 nsresult
AppWindow::SetPrimaryRemoteTabSize(int32_t aWidth
, int32_t aHeight
) {
2137 int32_t shellWidth
, shellHeight
;
2138 GetPrimaryRemoteTabSize(&shellWidth
, &shellHeight
);
2139 SizeShellToWithLimit(aWidth
, aHeight
, shellWidth
, shellHeight
);
2143 nsresult
AppWindow::GetRootShellSize(int32_t* aWidth
, int32_t* aHeight
) {
2144 NS_ENSURE_TRUE(mDocShell
, NS_ERROR_FAILURE
);
2145 return mDocShell
->GetSize(aWidth
, aHeight
);
2148 nsresult
AppWindow::SetRootShellSize(int32_t aWidth
, int32_t aHeight
) {
2149 return SizeShellTo(mDocShell
, aWidth
, aHeight
);
2152 NS_IMETHODIMP
AppWindow::SizeShellTo(nsIDocShellTreeItem
* aShellItem
,
2153 int32_t aCX
, int32_t aCY
) {
2154 MOZ_ASSERT(aShellItem
== mDocShell
|| aShellItem
== mPrimaryContentShell
);
2155 if (aShellItem
== mDocShell
) {
2157 LayoutDeviceIntSize(aCX
, aCY
) + GetOuterToInnerSizeDifference(mWindow
);
2158 SetSize(newSize
.width
, newSize
.height
, /* aRepaint = */ true);
2159 mDominantClientSize
= true;
2163 // XXXTAB This is wrong, we should actually reflow based on the passed in
2164 // shell. For now we are hacking and doing delta sizing. This is bad
2165 // because it assumes all size we add will go to the shell which probably
2167 nsCOMPtr
<nsIBaseWindow
> shellAsWin(do_QueryInterface(aShellItem
));
2168 NS_ENSURE_TRUE(shellAsWin
, NS_ERROR_FAILURE
);
2172 shellAsWin
->GetSize(&width
, &height
);
2174 SizeShellToWithLimit(aCX
, aCY
, width
, height
);
2179 NS_IMETHODIMP
AppWindow::ExitModalLoop(nsresult aStatus
) {
2180 if (mContinueModalLoop
) EnableParent(true);
2181 mContinueModalLoop
= false;
2182 mModalStatus
= aStatus
;
2186 // top-level function to create a new window
2187 NS_IMETHODIMP
AppWindow::CreateNewWindow(int32_t aChromeFlags
,
2188 nsIOpenWindowInfo
* aOpenWindowInfo
,
2189 nsIAppWindow
** _retval
) {
2190 NS_ENSURE_ARG_POINTER(_retval
);
2192 if (aChromeFlags
& nsIWebBrowserChrome::CHROME_OPENAS_CHROME
) {
2195 "Unexpected nsOpenWindowInfo when creating a new chrome window");
2196 return CreateNewChromeWindow(aChromeFlags
, _retval
);
2199 return CreateNewContentWindow(aChromeFlags
, aOpenWindowInfo
, _retval
);
2202 NS_IMETHODIMP
AppWindow::CreateNewChromeWindow(int32_t aChromeFlags
,
2203 nsIAppWindow
** _retval
) {
2204 nsCOMPtr
<nsIAppShellService
> appShell(
2205 do_GetService(NS_APPSHELLSERVICE_CONTRACTID
));
2206 NS_ENSURE_TRUE(appShell
, NS_ERROR_FAILURE
);
2208 // Just do a normal create of a window and return.
2209 nsCOMPtr
<nsIAppWindow
> newWindow
;
2210 appShell
->CreateTopLevelWindow(
2211 this, nullptr, aChromeFlags
, nsIAppShellService::SIZE_TO_CONTENT
,
2212 nsIAppShellService::SIZE_TO_CONTENT
, getter_AddRefs(newWindow
));
2214 NS_ENSURE_TRUE(newWindow
, NS_ERROR_FAILURE
);
2216 newWindow
.forget(_retval
);
2221 NS_IMETHODIMP
AppWindow::CreateNewContentWindow(
2222 int32_t aChromeFlags
, nsIOpenWindowInfo
* aOpenWindowInfo
,
2223 nsIAppWindow
** _retval
) {
2224 nsCOMPtr
<nsIAppShellService
> appShell(
2225 do_GetService(NS_APPSHELLSERVICE_CONTRACTID
));
2226 NS_ENSURE_TRUE(appShell
, NS_ERROR_FAILURE
);
2228 // We need to create a new top level window and then enter a nested
2229 // loop. Eventually the new window will be told that it has loaded,
2230 // at which time we know it is safe to spin out of the nested loop
2231 // and allow the opening code to proceed.
2233 nsCOMPtr
<nsIURI
> uri
;
2234 nsAutoCString urlStr
;
2235 urlStr
.AssignLiteral(BROWSER_CHROME_URL_QUOTED
);
2237 nsCOMPtr
<nsIIOService
> service(do_GetService(NS_IOSERVICE_CONTRACTID
));
2239 service
->NewURI(urlStr
, nullptr, nullptr, getter_AddRefs(uri
));
2241 NS_ENSURE_TRUE(uri
, NS_ERROR_FAILURE
);
2243 // We need to create a chrome window to contain the content window we're about
2244 // to pass back. The subject principal needs to be system while we're creating
2245 // it to make things work right, so force a system caller. See bug 799348
2246 // comment 13 for a description of what happens when we don't.
2247 nsCOMPtr
<nsIAppWindow
> newWindow
;
2249 AutoNoJSAPI nojsapi
;
2250 appShell
->CreateTopLevelWindow(this, uri
, aChromeFlags
, 615, 480,
2251 getter_AddRefs(newWindow
));
2252 NS_ENSURE_TRUE(newWindow
, NS_ERROR_FAILURE
);
2256 static_cast<AppWindow
*>(static_cast<nsIAppWindow
*>(newWindow
));
2258 // Specify which flags should be used by browser.xhtml to create the initial
2259 // content browser window.
2260 appWin
->mInitialOpenWindowInfo
= aOpenWindowInfo
;
2262 // Specify that we want the window to remain locked until the chrome has
2264 appWin
->LockUntilChromeLoad();
2267 AutoNoJSAPI nojsapi
;
2268 SpinEventLoopUntil("AppWindow::CreateNewContentWindow"_ns
,
2269 [&]() { return !appWin
->IsLocked(); });
2272 NS_ENSURE_STATE(appWin
->mPrimaryContentShell
||
2273 appWin
->mPrimaryBrowserParent
);
2274 MOZ_ASSERT_IF(appWin
->mPrimaryContentShell
,
2275 !aOpenWindowInfo
->GetNextRemoteBrowser());
2277 newWindow
.forget(_retval
);
2282 NS_IMETHODIMP
AppWindow::GetHasPrimaryContent(bool* aResult
) {
2283 *aResult
= mPrimaryBrowserParent
|| mPrimaryContentShell
;
2287 void AppWindow::EnableParent(bool aEnable
) {
2288 nsCOMPtr
<nsIBaseWindow
> parentWindow
;
2289 nsCOMPtr
<nsIWidget
> parentWidget
;
2291 parentWindow
= do_QueryReferent(mParentWindow
);
2292 if (parentWindow
) parentWindow
->GetMainWidget(getter_AddRefs(parentWidget
));
2293 if (parentWidget
) parentWidget
->Enable(aEnable
);
2296 void AppWindow::SetContentScrollbarVisibility(bool aVisible
) {
2297 nsCOMPtr
<nsPIDOMWindowOuter
> contentWin(
2298 do_GetInterface(mPrimaryContentShell
));
2303 nsContentUtils::SetScrollbarsVisibility(contentWin
->GetDocShell(), aVisible
);
2306 void AppWindow::ApplyChromeFlags() {
2307 nsCOMPtr
<dom::Element
> window
= GetWindowDOMElement();
2312 if (mChromeLoaded
) {
2313 // The two calls in this block don't need to happen early because they
2314 // don't cause a global restyle on the document. Not only that, but the
2315 // scrollbar stuff needs a content area to toggle the scrollbars on anyway.
2316 // So just don't do these until mChromeLoaded is true.
2318 // Scrollbars have their own special treatment.
2319 SetContentScrollbarVisibility(mChromeFlags
&
2320 nsIWebBrowserChrome::CHROME_SCROLLBARS
);
2323 /* the other flags are handled together. we have style rules
2324 in navigator.css that trigger visibility based on
2325 the 'chromehidden' attribute of the <window> tag. */
2326 nsAutoString newvalue
;
2328 if (!(mChromeFlags
& nsIWebBrowserChrome::CHROME_MENUBAR
))
2329 newvalue
.AppendLiteral("menubar ");
2331 if (!(mChromeFlags
& nsIWebBrowserChrome::CHROME_TOOLBAR
))
2332 newvalue
.AppendLiteral("toolbar ");
2334 if (!(mChromeFlags
& nsIWebBrowserChrome::CHROME_LOCATIONBAR
))
2335 newvalue
.AppendLiteral("location ");
2337 if (!(mChromeFlags
& nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR
))
2338 newvalue
.AppendLiteral("directories ");
2340 if (!(mChromeFlags
& nsIWebBrowserChrome::CHROME_STATUSBAR
))
2341 newvalue
.AppendLiteral("status ");
2343 if (!(mChromeFlags
& nsIWebBrowserChrome::CHROME_EXTRA
))
2344 newvalue
.AppendLiteral("extrachrome ");
2346 // Note that if we're not actually changing the value this will be a no-op,
2347 // so no need to compare to the old value.
2348 IgnoredErrorResult rv
;
2349 window
->SetAttribute(u
"chromehidden"_ns
, newvalue
, rv
);
2353 AppWindow::BeforeStartLayout() {
2355 // Ordering here is important, loading width/height values in
2356 // LoadPersistentWindowState() depends on the customtitlebar attribute (since
2357 // we need to translate outer to inner sizes).
2358 SyncAttributesToWidget();
2359 LoadPersistentWindowState();
2367 AppWindow::LockAspectRatio(bool aShouldLock
) {
2368 mWindow
->LockAspectRatio(aShouldLock
);
2373 AppWindow::NeedFastSnaphot() {
2374 MOZ_ASSERT(mWindow
);
2376 return NS_ERROR_FAILURE
;
2378 mWindow
->SetNeedFastSnaphot();
2382 void AppWindow::LoadPersistentWindowState() {
2383 nsCOMPtr
<dom::Element
> docShellElement
= GetWindowDOMElement();
2384 if (!docShellElement
) {
2388 // Check if the window wants to persist anything.
2389 nsAutoString persist
;
2390 docShellElement
->GetAttr(nsGkAtoms::persist
, persist
);
2391 if (persist
.IsEmpty()) {
2395 auto loadValue
= [&](nsAtom
* aAttr
) {
2396 nsDependentAtomString
attrString(aAttr
);
2397 if (persist
.Find(attrString
) >= 0) {
2399 nsresult rv
= GetPersistentValue(aAttr
, value
);
2400 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
), "Failed to get persistent state.");
2401 if (NS_SUCCEEDED(rv
) && !value
.IsEmpty()) {
2402 docShellElement
->SetAttr(aAttr
, value
, IgnoreErrors());
2407 loadValue(nsGkAtoms::screenX
);
2408 loadValue(nsGkAtoms::screenY
);
2409 loadValue(nsGkAtoms::width
);
2410 loadValue(nsGkAtoms::height
);
2411 loadValue(nsGkAtoms::sizemode
);
2414 void AppWindow::IntrinsicallySizeShell(const CSSIntSize
& aWindowDiff
,
2415 int32_t& aSpecWidth
,
2416 int32_t& aSpecHeight
) {
2417 nsCOMPtr
<nsIDocumentViewer
> viewer
;
2418 mDocShell
->GetDocViewer(getter_AddRefs(viewer
));
2422 RefPtr
<nsDocShell
> docShell
= mDocShell
;
2424 CSSIntCoord maxWidth
= 0;
2425 CSSIntCoord maxHeight
= 0;
2426 CSSIntCoord prefWidth
= 0;
2427 if (RefPtr element
= GetWindowDOMElement()) {
2428 nsAutoString prefWidthAttr
;
2429 if (element
->GetAttr(nsGkAtoms::prefwidth
, prefWidthAttr
)) {
2430 // TODO: Make this more generic perhaps?
2431 if (prefWidthAttr
.EqualsLiteral("min-width")) {
2432 if (auto* f
= element
->GetPrimaryFrame(FlushType::Frames
)) {
2433 const auto& coord
= f
->StylePosition()->GetMinWidth();
2434 if (coord
.ConvertsToLength()) {
2435 prefWidth
= CSSPixel::FromAppUnitsRounded(coord
.ToLength());
2442 Maybe
<CSSIntSize
> size
=
2443 viewer
->GetContentSize(maxWidth
, maxHeight
, prefWidth
);
2447 nsPresContext
* pc
= viewer
->GetPresContext();
2448 MOZ_ASSERT(pc
, "Should have pres context");
2450 int32_t width
= pc
->CSSPixelsToDevPixels(size
->width
);
2451 int32_t height
= pc
->CSSPixelsToDevPixels(size
->height
);
2452 SizeShellTo(docShell
, width
, height
);
2454 // Update specified size for the final LoadPositionFromXUL call.
2455 aSpecWidth
= size
->width
+ aWindowDiff
.width
;
2456 aSpecHeight
= size
->height
+ aWindowDiff
.height
;
2459 void AppWindow::SizeShell() {
2460 AutoRestore
<bool> sizingShellFromXUL(mSizingShellFromXUL
);
2461 mSizingShellFromXUL
= true;
2463 int32_t specWidth
= -1, specHeight
= -1;
2464 bool gotSize
= false;
2466 nsAutoString windowType
;
2467 if (nsCOMPtr
<dom::Element
> windowElement
= GetWindowDOMElement()) {
2468 windowElement
->GetAttr(nsGkAtoms::windowtype
, windowType
);
2471 const CSSIntSize windowDiff
= GetOuterToInnerSizeDifferenceInCSSPixels(
2472 mWindow
, UnscaledDevicePixelsPerCSSPixel());
2474 // If we're using fingerprint resistance, we're going to resize the window
2475 // once we have primary content.
2476 if (nsContentUtils::ShouldResistFingerprinting(
2477 "if RFP is enabled we want to round the dimensions of the new"
2478 "new pop up window regardless of their origin",
2479 RFPTarget::RoundWindowSize
) &&
2480 windowType
.EqualsLiteral("navigator:browser")) {
2481 // Once we've got primary content, force dimensions.
2482 if (mPrimaryContentShell
|| mPrimaryBrowserParent
) {
2483 ForceRoundedDimensions();
2485 // Always avoid setting size/sizemode on this window.
2486 mIgnoreXULSize
= true;
2487 mIgnoreXULSizeMode
= true;
2488 } else if (!mIgnoreXULSize
) {
2489 gotSize
= LoadSizeFromXUL(specWidth
, specHeight
);
2490 specWidth
+= windowDiff
.width
;
2491 specHeight
+= windowDiff
.height
;
2494 bool positionSet
= !mIgnoreXULPosition
;
2495 nsCOMPtr
<nsIAppWindow
> parentWindow(do_QueryReferent(mParentWindow
));
2496 #if defined(XP_UNIX) && !defined(XP_MACOSX)
2497 // don't override WM placement on unix for independent, top-level windows
2498 // (however, we think the benefits of intelligent dependent window placement
2499 // trump that override.)
2500 if (!parentWindow
) positionSet
= false;
2503 // We have to do this before sizing the window, because sizing depends
2504 // on the resolution of the screen we're on. But positioning needs to
2505 // know the size so that it can constrain to screen bounds.... as an
2506 // initial guess here, we'll use the specified size (if any).
2507 positionSet
= LoadPositionFromXUL(specWidth
, specHeight
);
2511 SetSpecifiedSize(specWidth
, specHeight
);
2514 // If LoadSizeFromXUL set the size, mIntrinsicallySized will be false.
2515 if (mIntrinsicallySized
) {
2516 IntrinsicallySizeShell(windowDiff
, specWidth
, specHeight
);
2519 // Now that we have set the window's final size, we can re-do its
2520 // positioning so that it is properly constrained to the screen.
2522 LoadPositionFromXUL(specWidth
, specHeight
);
2525 UpdateWindowStateFromMiscXULAttributes();
2527 if (mChromeLoaded
&& mCenterAfterLoad
&& !positionSet
&&
2528 mWindow
->SizeMode() == nsSizeMode_Normal
) {
2529 Center(parentWindow
, parentWindow
? false : true, false);
2533 NS_IMETHODIMP
AppWindow::GetXULBrowserWindow(
2534 nsIXULBrowserWindow
** aXULBrowserWindow
) {
2535 NS_IF_ADDREF(*aXULBrowserWindow
= mXULBrowserWindow
);
2539 NS_IMETHODIMP
AppWindow::SetXULBrowserWindow(
2540 nsIXULBrowserWindow
* aXULBrowserWindow
) {
2541 mXULBrowserWindow
= aXULBrowserWindow
;
2545 // Given the dimensions of some content area held within this XUL window, and
2546 // assuming that that content area will change its dimensions in linear
2547 // proportion to the dimensions of this XUL window, changes the size of the XUL
2548 // window so that the content area reaches a particular size.
2549 void AppWindow::SizeShellToWithLimit(int32_t aDesiredWidth
,
2550 int32_t aDesiredHeight
,
2551 int32_t shellItemWidth
,
2552 int32_t shellItemHeight
) {
2553 int32_t widthDelta
= aDesiredWidth
- shellItemWidth
;
2554 int32_t heightDelta
= aDesiredHeight
- shellItemHeight
;
2556 int32_t winWidth
= 0;
2557 int32_t winHeight
= 0;
2559 GetSize(&winWidth
, &winHeight
);
2560 // There's no point in trying to make the window smaller than the
2561 // desired content area size --- that's not likely to work. This whole
2562 // function assumes that the outer docshell is adding some constant
2563 // "border" chrome to the content area.
2564 winWidth
= std::max(winWidth
+ widthDelta
, aDesiredWidth
);
2565 winHeight
= std::max(winHeight
+ heightDelta
, aDesiredHeight
);
2567 // Note: Because of the asynchronous resizing on Linux we have to call
2568 // SetSize even when the size doesn't appear to change. A previous call that
2569 // has yet to complete can still change the size. We want the latest call to
2570 // define the final size.
2571 SetSize(winWidth
, winHeight
, true);
2572 mDominantClientSize
= true;
2575 nsresult
AppWindow::GetTabCount(uint32_t* aResult
) {
2576 if (mXULBrowserWindow
) {
2577 return mXULBrowserWindow
->GetTabCount(aResult
);
2584 nsresult
AppWindow::GetInitialOpenWindowInfo(
2585 nsIOpenWindowInfo
** aOpenWindowInfo
) {
2586 NS_ENSURE_ARG_POINTER(aOpenWindowInfo
);
2587 *aOpenWindowInfo
= do_AddRef(mInitialOpenWindowInfo
).take();
2591 PresShell
* AppWindow::GetPresShell() {
2595 return mDocShell
->GetPresShell();
2598 bool AppWindow::WindowMoved(nsIWidget
* aWidget
, int32_t x
, int32_t y
) {
2599 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
2601 nsCOMPtr
<nsPIDOMWindowOuter
> window
=
2602 mDocShell
? mDocShell
->GetWindow() : nullptr;
2603 pm
->AdjustPopupsOnWindowChange(window
);
2606 // Notify all tabs that the widget moved.
2607 if (mDocShell
&& mDocShell
->GetWindow()) {
2608 nsCOMPtr
<EventTarget
> eventTarget
=
2609 mDocShell
->GetWindow()->GetTopWindowRoot();
2610 nsContentUtils::DispatchChromeEvent(
2611 mDocShell
->GetDocument(), eventTarget
, u
"MozUpdateWindowPos"_ns
,
2612 CanBubble::eNo
, Cancelable::eNo
, nullptr);
2615 // Persist position, but not immediately, in case this OS is firing
2616 // repeated move events as the user drags the window
2617 PersistentAttributesDirty(PersistentAttribute::Position
, Async
);
2621 bool AppWindow::WindowResized(nsIWidget
* aWidget
, int32_t aWidth
,
2623 mDominantClientSize
= false;
2625 mDocShell
->SetPositionAndSize(0, 0, aWidth
, aHeight
, 0);
2627 // Persist size, but not immediately, in case this OS is firing
2628 // repeated size events as the user drags the sizing handle
2630 PersistentAttributesDirty(AllPersistentAttributes(), Async
);
2632 // Check if we need to continue a fullscreen change.
2633 switch (mFullscreenChangeState
) {
2634 case FullscreenChangeState::WillChange
:
2635 mFullscreenChangeState
= FullscreenChangeState::WidgetResized
;
2637 case FullscreenChangeState::WidgetEnteredFullscreen
:
2638 FinishFullscreenChange(true);
2640 case FullscreenChangeState::WidgetExitedFullscreen
:
2641 FinishFullscreenChange(false);
2643 case FullscreenChangeState::WidgetResized
:
2644 case FullscreenChangeState::NotChanging
:
2650 bool AppWindow::RequestWindowClose(nsIWidget
* aWidget
) {
2651 // Maintain a reference to this as it is about to get destroyed.
2652 nsCOMPtr
<nsIAppWindow
> appWindow(this);
2654 nsCOMPtr
<nsPIDOMWindowOuter
> window(mDocShell
? mDocShell
->GetWindow()
2656 nsCOMPtr
<EventTarget
> eventTarget
= do_QueryInterface(window
);
2658 RefPtr
<PresShell
> presShell
= mDocShell
->GetPresShell();
2660 mozilla::DebugOnly
<bool> dying
;
2661 MOZ_ASSERT(NS_SUCCEEDED(mDocShell
->IsBeingDestroyed(&dying
)) && dying
,
2662 "No presShell, but window is not being destroyed");
2663 } else if (eventTarget
) {
2664 RefPtr
<nsPresContext
> presContext
= presShell
->GetPresContext();
2666 nsEventStatus status
= nsEventStatus_eIgnore
;
2667 WidgetMouseEvent
event(true, eClose
, nullptr, WidgetMouseEvent::eReal
);
2668 if (NS_SUCCEEDED(EventDispatcher::Dispatch(eventTarget
, presContext
, &event
,
2669 nullptr, &status
)) &&
2670 status
== nsEventStatus_eConsumeNoDefault
)
2678 void AppWindow::SizeModeChanged(nsSizeMode aSizeMode
) {
2679 const bool wasWidgetInFullscreen
= mIsWidgetInFullscreen
;
2680 // Fullscreen and minimized states are usually compatible, and the widget
2681 // typically returns to fullscreen after restoration. By not updating the
2682 // widget's fullscreen state while it is minimized, we can avoid unnecessary
2683 // fullscreen exits, such as those encountered in bug 1823284.
2684 if (aSizeMode
!= nsSizeMode_Minimized
) {
2685 mIsWidgetInFullscreen
= aSizeMode
== nsSizeMode_Fullscreen
;
2688 const bool fullscreenChanged
= wasWidgetInFullscreen
!= mIsWidgetInFullscreen
;
2689 if (fullscreenChanged
) {
2690 FullscreenWillChange(mIsWidgetInFullscreen
);
2693 RecomputeBrowsingContextVisibility();
2695 PersistentAttributesDirty(PersistentAttribute::Misc
, Sync
);
2696 nsCOMPtr
<nsPIDOMWindowOuter
> ourWindow
=
2697 mDocShell
? mDocShell
->GetWindow() : nullptr;
2699 // Always fire a user-defined sizemodechange event on the window
2700 ourWindow
->DispatchCustomEvent(u
"sizemodechange"_ns
);
2703 if (PresShell
* presShell
= GetPresShell()) {
2704 presShell
->GetPresContext()->SizeModeChanged(aSizeMode
);
2707 if (fullscreenChanged
) {
2708 FullscreenChanged(mIsWidgetInFullscreen
);
2711 // Note the current implementation of SetSizeMode just stores
2712 // the new state; it doesn't actually resize. So here we store
2713 // the state and pass the event on to the OS. The day is coming
2714 // when we'll handle the event here, and the return result will
2715 // then need to be different.
2718 void AppWindow::FullscreenWillChange(bool aInFullscreen
) {
2720 if (nsCOMPtr
<nsPIDOMWindowOuter
> ourWindow
= mDocShell
->GetWindow()) {
2721 ourWindow
->FullscreenWillChange(aInFullscreen
);
2724 MOZ_ASSERT(mFullscreenChangeState
== FullscreenChangeState::NotChanging
);
2726 CSSToLayoutDeviceScale scale
= UnscaledDevicePixelsPerCSSPixel();
2727 CSSIntSize windowSizeCSS
= RoundedToInt(GetSize() / scale
);
2729 CSSIntSize screenSizeCSS
;
2730 GetAvailScreenSize(&screenSizeCSS
.width
, &screenSizeCSS
.height
);
2732 // Check if the window is already at the expected dimensions. If it is, set
2733 // the fullscreen change state to WidgetResized to avoid waiting for a resize
2734 // event. On macOS, a fullscreen window could be slightly higher than
2735 // available screen size because of the OS menu bar isn't yet hidden.
2736 mFullscreenChangeState
=
2737 (aInFullscreen
== (windowSizeCSS
.width
== screenSizeCSS
.width
&&
2738 windowSizeCSS
.height
>= screenSizeCSS
.height
))
2739 ? FullscreenChangeState::WidgetResized
2740 : FullscreenChangeState::WillChange
;
2743 void AppWindow::FullscreenChanged(bool aInFullscreen
) {
2744 if (mFullscreenChangeState
== FullscreenChangeState::WidgetResized
) {
2745 FinishFullscreenChange(aInFullscreen
);
2747 NS_WARNING_ASSERTION(
2748 mFullscreenChangeState
== FullscreenChangeState::WillChange
,
2749 "Unexpected fullscreen change state");
2750 FullscreenChangeState newState
=
2751 aInFullscreen
? FullscreenChangeState::WidgetEnteredFullscreen
2752 : FullscreenChangeState::WidgetExitedFullscreen
;
2753 mFullscreenChangeState
= newState
;
2754 nsCOMPtr
<nsIAppWindow
> kungFuDeathGrip(this);
2755 // Wait for resize for a small amount of time.
2756 // 80ms is actually picked arbitrarily. But it shouldn't be too large
2757 // in case the widget resize is not going to happen at all, which can
2758 // be the case for some Linux window managers and possibly Android.
2759 NS_DelayedDispatchToCurrentThread(
2760 NS_NewRunnableFunction(
2761 "AppWindow::FullscreenChanged",
2762 [this, kungFuDeathGrip
, newState
, aInFullscreen
]() {
2763 if (mFullscreenChangeState
== newState
) {
2764 FinishFullscreenChange(aInFullscreen
);
2771 void AppWindow::FinishFullscreenChange(bool aInFullscreen
) {
2772 mFullscreenChangeState
= FullscreenChangeState::NotChanging
;
2773 if (nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance()) {
2777 if (nsCOMPtr
<nsPIDOMWindowOuter
> ourWindow
= mDocShell
->GetWindow()) {
2778 ourWindow
->FinishFullscreenChange(aInFullscreen
);
2783 void AppWindow::MacFullscreenMenubarOverlapChanged(
2784 mozilla::DesktopCoord aOverlapAmount
) {
2786 if (nsCOMPtr
<nsPIDOMWindowOuter
> ourWindow
= mDocShell
->GetWindow()) {
2787 ourWindow
->MacFullscreenMenubarOverlapChanged(aOverlapAmount
);
2792 void AppWindow::RecomputeBrowsingContextVisibility() {
2796 RefPtr bc
= mDocShell
->GetBrowsingContext();
2800 bc
->Canonical()->RecomputeAppWindowVisibility();
2803 void AppWindow::OcclusionStateChanged(bool aIsFullyOccluded
) {
2807 RecomputeBrowsingContextVisibility();
2808 if (RefPtr win
= mDocShell
->GetWindow()) {
2809 // And always fire a user-defined occlusionstatechange event on the window
2810 win
->DispatchCustomEvent(u
"occlusionstatechange"_ns
,
2811 ChromeOnlyDispatch::eYes
);
2815 void AppWindow::OSToolbarButtonPressed() {
2816 // Keep a reference as setting the chrome flags can fire events.
2817 nsCOMPtr
<nsIAppWindow
> appWindow(this);
2819 // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA"
2820 // due to components with multiple sidebar components
2821 // (such as Mail/News, Addressbook, etc)... and frankly,
2822 // Mac IE, OmniWeb, and other Mac OS X apps all work this way
2823 uint32_t chromeMask
= (nsIWebBrowserChrome::CHROME_TOOLBAR
|
2824 nsIWebBrowserChrome::CHROME_LOCATIONBAR
|
2825 nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR
);
2827 nsCOMPtr
<nsIWebBrowserChrome
> wbc(do_GetInterface(appWindow
));
2830 uint32_t chromeFlags
, newChromeFlags
= 0;
2831 wbc
->GetChromeFlags(&chromeFlags
);
2832 newChromeFlags
= chromeFlags
& chromeMask
;
2833 if (!newChromeFlags
)
2834 chromeFlags
|= chromeMask
;
2836 chromeFlags
&= (~newChromeFlags
);
2837 wbc
->SetChromeFlags(chromeFlags
);
2840 void AppWindow::WindowActivated() {
2841 nsCOMPtr
<nsIAppWindow
> appWindow(this);
2843 // focusing the window could cause it to close, so keep a reference to it
2845 if (nsCOMPtr
<nsPIDOMWindowOuter
> window
= mDocShell
->GetWindow()) {
2846 if (RefPtr
<nsFocusManager
> fm
= nsFocusManager::GetFocusManager()) {
2847 fm
->WindowRaised(window
, nsFocusManager::GenerateFocusActionId());
2852 if (mChromeLoaded
) {
2853 PersistentAttributesDirty(AllPersistentAttributes(), Sync
);
2857 void AppWindow::WindowDeactivated() {
2859 if (nsCOMPtr
<nsPIDOMWindowOuter
> window
= mDocShell
->GetWindow()) {
2860 if (RefPtr
<nsFocusManager
> fm
= nsFocusManager::GetFocusManager()) {
2861 if (!fm
->IsTestMode()) {
2862 fm
->WindowLowered(window
, nsFocusManager::GenerateFocusActionId());
2869 #ifdef USE_NATIVE_MENUS
2871 struct LoadNativeMenusListener
{
2872 LoadNativeMenusListener(Document
* aDoc
, nsIWidget
* aParentWindow
)
2873 : mDocument(aDoc
), mParentWindow(aParentWindow
) {}
2875 RefPtr
<Document
> mDocument
;
2876 nsCOMPtr
<nsIWidget
> mParentWindow
;
2879 // On macOS the hidden window is created eagerly, and we want to wait for it to
2880 // load the native menus.
2881 static bool sWaitingForHiddenWindowToLoadNativeMenus
=
2889 MOZ_RUNINIT
static nsTArray
<LoadNativeMenusListener
> sLoadNativeMenusListeners
;
2891 static void BeginLoadNativeMenus(Document
* aDoc
, nsIWidget
* aParentWindow
);
2893 static void LoadNativeMenus(Document
* aDoc
, nsIWidget
* aParentWindow
) {
2894 MOZ_ASSERT(!gfxPlatform::IsHeadless());
2896 // Find the menubar tag (if there is more than one, we ignore all but
2898 nsCOMPtr
<nsINodeList
> menubarElements
= aDoc
->GetElementsByTagNameNS(
2899 u
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"_ns
,
2902 RefPtr
<Element
> menubar
;
2903 if (menubarElements
) {
2904 menubar
= Element::FromNodeOrNull(menubarElements
->Item(0));
2907 widget::NativeMenuSupport::CreateNativeMenuBar(aParentWindow
, menubar
);
2909 if (sWaitingForHiddenWindowToLoadNativeMenus
) {
2910 sWaitingForHiddenWindowToLoadNativeMenus
= false;
2911 for (auto& listener
: sLoadNativeMenusListeners
) {
2912 BeginLoadNativeMenus(listener
.mDocument
, listener
.mParentWindow
);
2914 sLoadNativeMenusListeners
.Clear();
2918 class L10nReadyPromiseHandler final
: public dom::PromiseNativeHandler
{
2922 L10nReadyPromiseHandler(Document
* aDoc
, nsIWidget
* aParentWindow
)
2923 : mDocument(aDoc
), mWindow(aParentWindow
) {}
2925 void ResolvedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
2926 ErrorResult
& aRv
) override
{
2927 LoadNativeMenus(mDocument
, mWindow
);
2930 void RejectedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
2931 ErrorResult
& aRv
) override
{
2932 // Again, this shouldn't happen, but fallback to loading the menus as is.
2934 "L10nReadyPromiseHandler rejected - loading fallback native "
2936 LoadNativeMenus(mDocument
, mWindow
);
2940 ~L10nReadyPromiseHandler() = default;
2942 RefPtr
<Document
> mDocument
;
2943 nsCOMPtr
<nsIWidget
> mWindow
;
2946 NS_IMPL_ISUPPORTS0(L10nReadyPromiseHandler
)
2948 static void BeginLoadNativeMenus(Document
* aDoc
, nsIWidget
* aParentWindow
) {
2949 if (RefPtr
<DocumentL10n
> l10n
= aDoc
->GetL10n()) {
2950 // Wait for l10n to be ready so the menus are localized.
2951 RefPtr
<Promise
> promise
= l10n
->Ready();
2952 MOZ_ASSERT(promise
);
2953 RefPtr handler
= new L10nReadyPromiseHandler(aDoc
, aParentWindow
);
2954 promise
->AppendNativeHandler(handler
);
2956 // Something went wrong loading the doc and l10n wasn't created. This
2957 // shouldn't really happen, but if it does fallback to trying to load
2959 LoadNativeMenus(aDoc
, aParentWindow
);
2965 class AppWindowTimerCallback final
: public nsITimerCallback
, public nsINamed
{
2967 explicit AppWindowTimerCallback(AppWindow
* aWindow
) : mWindow(aWindow
) {}
2969 NS_DECL_THREADSAFE_ISUPPORTS
2971 NS_IMETHOD
Notify(nsITimer
* aTimer
) override
{
2972 // Although this object participates in a refcount cycle (this -> mWindow
2973 // -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this
2974 // after it fires. So we don't need to release mWindow here.
2976 mWindow
->FirePersistenceTimer();
2980 NS_IMETHOD
GetName(nsACString
& aName
) override
{
2981 aName
.AssignLiteral("AppWindowTimerCallback");
2986 ~AppWindowTimerCallback() {}
2988 RefPtr
<AppWindow
> mWindow
;
2991 NS_IMPL_ISUPPORTS(AppWindowTimerCallback
, nsITimerCallback
, nsINamed
)
2993 void AppWindow::PersistentAttributesDirty(PersistentAttributes aAttributes
,
2994 PersistentAttributeUpdate aUpdate
) {
2995 aAttributes
= aAttributes
& mPersistentAttributesMask
;
2996 if (aAttributes
.isEmpty()) {
3000 mPersistentAttributesDirty
+= aAttributes
;
3001 if (aUpdate
== Sync
) {
3002 // Only apply the attributes we've been requested to apply sync, not other
3003 // potentially dirty attributes that have been requested asynchronously.
3004 SavePersistentAttributes(aAttributes
);
3008 mSPTimer
= NS_NewTimer();
3010 NS_WARNING("Couldn't create timer instance?");
3015 RefPtr
<AppWindowTimerCallback
> callback
= new AppWindowTimerCallback(this);
3016 mSPTimer
->InitWithCallback(callback
, SIZE_PERSISTENCE_TIMEOUT
,
3017 nsITimer::TYPE_ONE_SHOT
);
3020 void AppWindow::FirePersistenceTimer() { SavePersistentAttributes(); }
3022 //----------------------------------------
3023 // nsIWebProgessListener implementation
3024 //----------------------------------------
3026 AppWindow::OnProgressChange(nsIWebProgress
* aProgress
, nsIRequest
* aRequest
,
3027 int32_t aCurSelfProgress
, int32_t aMaxSelfProgress
,
3028 int32_t aCurTotalProgress
,
3029 int32_t aMaxTotalProgress
) {
3030 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
3035 AppWindow::OnStateChange(nsIWebProgress
* aProgress
, nsIRequest
* aRequest
,
3036 uint32_t aStateFlags
, nsresult aStatus
) {
3037 // If the notification is not about a document finishing, then just
3039 if (!(aStateFlags
& nsIWebProgressListener::STATE_STOP
) ||
3040 !(aStateFlags
& nsIWebProgressListener::STATE_IS_NETWORK
)) {
3044 if (mChromeLoaded
) return NS_OK
;
3046 // If this document notification is for a frame then ignore it...
3047 nsCOMPtr
<mozIDOMWindowProxy
> eventWin
;
3048 aProgress
->GetDOMWindow(getter_AddRefs(eventWin
));
3049 auto* eventPWin
= nsPIDOMWindowOuter::From(eventWin
);
3051 nsPIDOMWindowOuter
* rootPWin
= eventPWin
->GetPrivateRoot();
3052 if (eventPWin
!= rootPWin
) return NS_OK
;
3055 mChromeLoaded
= true;
3056 mLockedUntilChromeLoad
= false;
3058 #ifdef USE_NATIVE_MENUS
3059 ///////////////////////////////
3060 // Find the Menubar DOM and Load the menus, hooking them up to the loaded
3062 ///////////////////////////////
3063 if (!gfxPlatform::IsHeadless()) {
3064 if (RefPtr
<Document
> menubarDoc
= mDocShell
->GetExtantDocument()) {
3065 if (mIsHiddenWindow
|| !sWaitingForHiddenWindowToLoadNativeMenus
) {
3066 BeginLoadNativeMenus(menubarDoc
, mWindow
);
3068 sLoadNativeMenusListeners
.EmplaceBack(menubarDoc
, mWindow
);
3072 #endif // USE_NATIVE_MENUS
3080 AppWindow::OnLocationChange(nsIWebProgress
* aProgress
, nsIRequest
* aRequest
,
3081 nsIURI
* aURI
, uint32_t aFlags
) {
3082 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
3087 AppWindow::OnStatusChange(nsIWebProgress
* aWebProgress
, nsIRequest
* aRequest
,
3088 nsresult aStatus
, const char16_t
* aMessage
) {
3089 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
3094 AppWindow::OnSecurityChange(nsIWebProgress
* aWebProgress
, nsIRequest
* aRequest
,
3096 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
3101 AppWindow::OnContentBlockingEvent(nsIWebProgress
* aWebProgress
,
3102 nsIRequest
* aRequest
, uint32_t aEvent
) {
3103 MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
3108 * ExecuteCloseHandler - Run the close handler, if any.
3109 * @return true iff we found a close handler to run.
3111 bool AppWindow::ExecuteCloseHandler() {
3112 /* If the event handler closes this window -- a likely scenario --
3113 things get deleted out of order without this death grip.
3114 (The problem may be the death grip in nsWindow::windowProc,
3115 which forces this window's widget to remain alive longer
3116 than it otherwise would.) */
3117 nsCOMPtr
<nsIAppWindow
> kungFuDeathGrip(this);
3119 nsCOMPtr
<EventTarget
> eventTarget
;
3121 eventTarget
= do_QueryInterface(mDocShell
->GetWindow());
3125 nsCOMPtr
<nsIDocumentViewer
> viewer
;
3126 mDocShell
->GetDocViewer(getter_AddRefs(viewer
));
3128 RefPtr
<nsPresContext
> presContext
= viewer
->GetPresContext();
3130 nsEventStatus status
= nsEventStatus_eIgnore
;
3131 WidgetMouseEvent
event(true, eClose
, nullptr, WidgetMouseEvent::eReal
);
3133 nsresult rv
= EventDispatcher::Dispatch(eventTarget
, presContext
, &event
,
3135 if (NS_SUCCEEDED(rv
) && status
== nsEventStatus_eConsumeNoDefault
)
3137 // else fall through and return false
3142 } // ExecuteCloseHandler
3144 void AppWindow::ConstrainToOpenerScreen(int32_t* aX
, int32_t* aY
) {
3145 if (mOpenerScreenRect
.IsEmpty()) {
3150 int32_t left
, top
, width
, height
;
3151 // Constrain initial positions to the same screen as opener
3152 nsCOMPtr
<nsIScreenManager
> screenmgr
=
3153 do_GetService("@mozilla.org/gfx/screenmanager;1");
3155 nsCOMPtr
<nsIScreen
> screen
= screenmgr
->ScreenForRect(mOpenerScreenRect
);
3157 screen
->GetAvailRectDisplayPix(&left
, &top
, &width
, &height
);
3158 if (*aX
< left
|| *aX
> left
+ width
) {
3161 if (*aY
< top
|| *aY
> top
+ height
) {
3168 nsIAppWindow
* AppWindow::WidgetListenerDelegate::GetAppWindow() {
3169 return mAppWindow
->GetAppWindow();
3172 PresShell
* AppWindow::WidgetListenerDelegate::GetPresShell() {
3173 return mAppWindow
->GetPresShell();
3176 bool AppWindow::WidgetListenerDelegate::WindowMoved(nsIWidget
* aWidget
,
3177 int32_t aX
, int32_t aY
,
3179 RefPtr
<AppWindow
> holder
= mAppWindow
;
3180 return holder
->WindowMoved(aWidget
, aX
, aY
);
3183 bool AppWindow::WidgetListenerDelegate::WindowResized(nsIWidget
* aWidget
,
3186 RefPtr
<AppWindow
> holder
= mAppWindow
;
3187 return holder
->WindowResized(aWidget
, aWidth
, aHeight
);
3190 bool AppWindow::WidgetListenerDelegate::RequestWindowClose(nsIWidget
* aWidget
) {
3191 RefPtr
<AppWindow
> holder
= mAppWindow
;
3192 return holder
->RequestWindowClose(aWidget
);
3195 void AppWindow::WidgetListenerDelegate::SizeModeChanged(nsSizeMode aSizeMode
) {
3196 RefPtr
<AppWindow
> holder
= mAppWindow
;
3197 holder
->SizeModeChanged(aSizeMode
);
3200 void AppWindow::WidgetListenerDelegate::MacFullscreenMenubarOverlapChanged(
3201 DesktopCoord aOverlapAmount
) {
3202 RefPtr
<AppWindow
> holder
= mAppWindow
;
3203 return holder
->MacFullscreenMenubarOverlapChanged(aOverlapAmount
);
3206 void AppWindow::WidgetListenerDelegate::OcclusionStateChanged(
3207 bool aIsFullyOccluded
) {
3208 RefPtr
<AppWindow
> holder
= mAppWindow
;
3209 holder
->OcclusionStateChanged(aIsFullyOccluded
);
3212 void AppWindow::WidgetListenerDelegate::OSToolbarButtonPressed() {
3213 RefPtr
<AppWindow
> holder
= mAppWindow
;
3214 holder
->OSToolbarButtonPressed();
3217 void AppWindow::WidgetListenerDelegate::WindowActivated() {
3218 RefPtr
<AppWindow
> holder
= mAppWindow
;
3219 holder
->WindowActivated();
3222 void AppWindow::WidgetListenerDelegate::WindowDeactivated() {
3223 RefPtr
<AppWindow
> holder
= mAppWindow
;
3224 holder
->WindowDeactivated();
3227 } // namespace mozilla