michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 ci et: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/MathAlgorithms.h" michael@0: michael@0: // Local includes michael@0: #include "nsXULWindow.h" michael@0: #include michael@0: michael@0: // Helper classes michael@0: #include "nsPrintfCString.h" michael@0: #include "nsString.h" michael@0: #include "nsWidgetsCID.h" michael@0: #include "prprf.h" michael@0: #include "nsCRT.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsNetCID.h" michael@0: michael@0: //Interfaces needed to be included michael@0: #include "nsIAppShell.h" michael@0: #include "nsIAppShellService.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIContentViewer.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDOMXULDocument.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIDOMXULElement.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsIDOMScreen.h" michael@0: #include "nsIEmbeddingSiteWindow.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIIOService.h" michael@0: #include "nsIMarkupDocumentViewer.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsIWindowMediator.h" michael@0: #include "nsIScreenManager.h" michael@0: #include "nsIScreen.h" michael@0: #include "nsIScrollable.h" michael@0: #include "nsIScriptSecurityManager.h" michael@0: #include "nsIWindowWatcher.h" michael@0: #include "nsIURI.h" michael@0: #include "nsIDOMCSSStyleDeclaration.h" michael@0: #include "nsAppShellCID.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsStyleConsts.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsWebShellWindow.h" // get rid of this one, too... michael@0: #include "nsGlobalWindow.h" michael@0: michael@0: #include "prenv.h" michael@0: #include "mozilla/AutoRestore.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/dom/BarProps.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "mozilla/dom/Event.h" michael@0: #include "mozilla/dom/ScriptSettings.h" michael@0: michael@0: using namespace mozilla; michael@0: using dom::AutoNoJSAPI; michael@0: michael@0: #define SIZEMODE_NORMAL NS_LITERAL_STRING("normal") michael@0: #define SIZEMODE_MAXIMIZED NS_LITERAL_STRING("maximized") michael@0: #define SIZEMODE_MINIMIZED NS_LITERAL_STRING("minimized") michael@0: #define SIZEMODE_FULLSCREEN NS_LITERAL_STRING("fullscreen") michael@0: michael@0: #define WINDOWTYPE_ATTRIBUTE NS_LITERAL_STRING("windowtype") michael@0: michael@0: #define PERSIST_ATTRIBUTE NS_LITERAL_STRING("persist") michael@0: #define SCREENX_ATTRIBUTE NS_LITERAL_STRING("screenX") michael@0: #define SCREENY_ATTRIBUTE NS_LITERAL_STRING("screenY") michael@0: #define WIDTH_ATTRIBUTE NS_LITERAL_STRING("width") michael@0: #define HEIGHT_ATTRIBUTE NS_LITERAL_STRING("height") michael@0: #define MODE_ATTRIBUTE NS_LITERAL_STRING("sizemode") michael@0: #define ZLEVEL_ATTRIBUTE NS_LITERAL_STRING("zlevel") michael@0: michael@0: michael@0: //***************************************************************************** michael@0: //*** nsXULWindow: Object Management michael@0: //***************************************************************************** michael@0: michael@0: nsXULWindow::nsXULWindow(uint32_t aChromeFlags) michael@0: : mChromeTreeOwner(nullptr), michael@0: mContentTreeOwner(nullptr), michael@0: mPrimaryContentTreeOwner(nullptr), michael@0: mModalStatus(NS_OK), michael@0: mContinueModalLoop(false), michael@0: mDebuting(false), michael@0: mChromeLoaded(false), michael@0: mShowAfterLoad(false), michael@0: mIntrinsicallySized(false), michael@0: mCenterAfterLoad(false), michael@0: mIsHiddenWindow(false), michael@0: mLockedUntilChromeLoad(false), michael@0: mIgnoreXULSize(false), michael@0: mIgnoreXULPosition(false), michael@0: mChromeFlagsFrozen(false), michael@0: mIgnoreXULSizeMode(false), michael@0: mDestroying(false), michael@0: mContextFlags(0), michael@0: mPersistentAttributesDirty(0), michael@0: mPersistentAttributesMask(0), michael@0: mChromeFlags(aChromeFlags) michael@0: { michael@0: } michael@0: michael@0: nsXULWindow::~nsXULWindow() michael@0: { michael@0: Destroy(); michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsXULWindow::nsISupports michael@0: //***************************************************************************** michael@0: michael@0: NS_IMPL_ADDREF(nsXULWindow) michael@0: NS_IMPL_RELEASE(nsXULWindow) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN(nsXULWindow) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULWindow) michael@0: NS_INTERFACE_MAP_ENTRY(nsIXULWindow) michael@0: NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) michael@0: NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) michael@0: NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) michael@0: if (aIID.Equals(NS_GET_IID(nsXULWindow))) michael@0: foundInterface = reinterpret_cast(this); michael@0: else michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: //***************************************************************************** michael@0: // nsXULWindow::nsIIntefaceRequestor michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetInterface(const nsIID& aIID, void** aSink) michael@0: { michael@0: nsresult rv; michael@0: michael@0: NS_ENSURE_ARG_POINTER(aSink); michael@0: michael@0: if (aIID.Equals(NS_GET_IID(nsIPrompt))) { michael@0: rv = EnsurePrompter(); michael@0: if (NS_FAILED(rv)) return rv; michael@0: return mPrompter->QueryInterface(aIID, aSink); michael@0: } michael@0: if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) { michael@0: rv = EnsureAuthPrompter(); michael@0: if (NS_FAILED(rv)) return rv; michael@0: return mAuthPrompter->QueryInterface(aIID, aSink); michael@0: } michael@0: if (aIID.Equals(NS_GET_IID(nsIDOMWindow))) { michael@0: return GetWindowDOMWindow(reinterpret_cast(aSink)); michael@0: } michael@0: if (aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) { michael@0: nsIDOMWindow* domWindow = nullptr; michael@0: rv = GetWindowDOMWindow(&domWindow); michael@0: nsIDOMWindowInternal* domWindowInternal = michael@0: static_cast(domWindow); michael@0: *aSink = domWindowInternal; michael@0: return rv; michael@0: } michael@0: if (aIID.Equals(NS_GET_IID(nsIWebBrowserChrome)) && michael@0: NS_SUCCEEDED(EnsureContentTreeOwner()) && michael@0: NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink))) michael@0: return NS_OK; michael@0: michael@0: if (aIID.Equals(NS_GET_IID(nsIEmbeddingSiteWindow)) && michael@0: NS_SUCCEEDED(EnsureContentTreeOwner()) && michael@0: NS_SUCCEEDED(mContentTreeOwner->QueryInterface(aIID, aSink))) michael@0: return NS_OK; michael@0: michael@0: return QueryInterface(aIID, aSink); michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsXULWindow::nsIXULWindow michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetDocShell(nsIDocShell** aDocShell) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDocShell); michael@0: michael@0: *aDocShell = mDocShell; michael@0: NS_IF_ADDREF(*aDocShell); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetZLevel(uint32_t *outLevel) michael@0: { michael@0: nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); michael@0: if (mediator) michael@0: mediator->GetZLevel(this, outLevel); michael@0: else michael@0: *outLevel = normalZ; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetZLevel(uint32_t aLevel) michael@0: { michael@0: nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); michael@0: if (!mediator) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: uint32_t zLevel; michael@0: mediator->GetZLevel(this, &zLevel); michael@0: if (zLevel == aLevel) michael@0: return NS_OK; michael@0: michael@0: /* refuse to raise a maximized window above the normal browser level, michael@0: for fear it could hide newly opened browser windows */ michael@0: if (aLevel > nsIXULWindow::normalZ && mWindow) { michael@0: int32_t sizeMode = mWindow->SizeMode(); michael@0: if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: // do it michael@0: mediator->SetZLevel(this, aLevel); michael@0: PersistentAttributesDirty(PAD_MISC); michael@0: SavePersistentAttributes(); michael@0: michael@0: nsCOMPtr cv; michael@0: mDocShell->GetContentViewer(getter_AddRefs(cv)); michael@0: if (cv) { michael@0: nsCOMPtr doc = cv->GetDocument(); michael@0: if (doc) { michael@0: ErrorResult rv; michael@0: nsRefPtr event = michael@0: doc->CreateEvent(NS_LITERAL_STRING("Events"),rv); michael@0: if (event) { michael@0: event->InitEvent(NS_LITERAL_STRING("windowZLevel"), true, false); michael@0: michael@0: event->SetTrusted(true); michael@0: michael@0: bool defaultActionEnabled; michael@0: doc->DispatchEvent(event, &defaultActionEnabled); michael@0: } michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetContextFlags(uint32_t *aContextFlags) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aContextFlags); michael@0: *aContextFlags = mContextFlags; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetContextFlags(uint32_t aContextFlags) michael@0: { michael@0: mContextFlags = aContextFlags; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetChromeFlags(uint32_t *aChromeFlags) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aChromeFlags); michael@0: *aChromeFlags = mChromeFlags; michael@0: /* mChromeFlags is kept up to date, except for scrollbar visibility. michael@0: That can be changed directly by the content DOM window, which michael@0: doesn't know to update the chrome window. So that we must check michael@0: separately. */ michael@0: michael@0: // however, it's pointless to ask if the window isn't set up yet michael@0: if (!mChromeLoaded) michael@0: return NS_OK; michael@0: michael@0: if (GetContentScrollbarVisibility()) michael@0: *aChromeFlags |= nsIWebBrowserChrome::CHROME_SCROLLBARS; michael@0: else michael@0: *aChromeFlags &= ~nsIWebBrowserChrome::CHROME_SCROLLBARS; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetChromeFlags(uint32_t aChromeFlags) michael@0: { michael@0: NS_ASSERTION(!mChromeFlagsFrozen, michael@0: "SetChromeFlags() after AssumeChromeFlagsAreFrozen()!"); michael@0: michael@0: mChromeFlags = aChromeFlags; michael@0: if (mChromeLoaded) michael@0: NS_ENSURE_SUCCESS(ApplyChromeFlags(), NS_ERROR_FAILURE); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::AssumeChromeFlagsAreFrozen() michael@0: { michael@0: mChromeFlagsFrozen = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetIntrinsicallySized(bool aIntrinsicallySized) michael@0: { michael@0: mIntrinsicallySized = aIntrinsicallySized; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetIntrinsicallySized(bool* aIntrinsicallySized) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aIntrinsicallySized); michael@0: michael@0: *aIntrinsicallySized = mIntrinsicallySized; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetPrimaryContentShell(nsIDocShellTreeItem** michael@0: aDocShellTreeItem) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDocShellTreeItem); michael@0: NS_IF_ADDREF(*aDocShellTreeItem = mPrimaryContentShell); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetContentShellById(const char16_t* aID, michael@0: nsIDocShellTreeItem** aDocShellTreeItem) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDocShellTreeItem); michael@0: *aDocShellTreeItem = nullptr; michael@0: michael@0: uint32_t count = mContentShells.Length(); michael@0: for (uint32_t i = 0; i < count; i++) { michael@0: nsContentShellInfo* shellInfo = mContentShells.ElementAt(i); michael@0: if (shellInfo->id.Equals(aID)) { michael@0: *aDocShellTreeItem = nullptr; michael@0: if (shellInfo->child) michael@0: CallQueryReferent(shellInfo->child.get(), aDocShellTreeItem); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::AddChildWindow(nsIXULWindow *aChild) michael@0: { michael@0: // we're not really keeping track of this right now michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::RemoveChildWindow(nsIXULWindow *aChild) michael@0: { michael@0: // we're not really keeping track of this right now michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::ShowModal() michael@0: { michael@0: // Store locally so it doesn't die on us michael@0: nsCOMPtr window = mWindow; michael@0: nsCOMPtr tempRef = this; michael@0: michael@0: window->SetModal(true); michael@0: mContinueModalLoop = true; michael@0: EnableParent(false); michael@0: michael@0: { michael@0: AutoNoJSAPI nojsapi; michael@0: nsIThread *thread = NS_GetCurrentThread(); michael@0: while (mContinueModalLoop) { michael@0: if (!NS_ProcessNextEvent(thread)) michael@0: break; michael@0: } michael@0: } michael@0: michael@0: mContinueModalLoop = false; michael@0: window->SetModal(false); michael@0: /* Note there's no EnableParent(true) here to match the false one michael@0: above. That's done in ExitModalLoop. It's important that the parent michael@0: be re-enabled before this window is made invisible; to do otherwise michael@0: causes bizarre z-ordering problems. At this point, the window is michael@0: already invisible. michael@0: No known current implementation of Enable would have a problem with michael@0: re-enabling the parent twice, so we could do it again here without michael@0: breaking any current implementation. But that's unnecessary if the michael@0: modal loop is always exited using ExitModalLoop (the other way would be michael@0: to change the protected member variable directly.) michael@0: */ michael@0: michael@0: return mModalStatus; michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: // nsXULWindow::nsIBaseWindow michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP nsXULWindow::InitWindow(nativeWindow aParentNativeWindow, michael@0: nsIWidget* parentWidget, int32_t x, int32_t y, int32_t cx, int32_t cy) michael@0: { michael@0: //XXX First Check In michael@0: NS_ASSERTION(false, "Not Yet Implemented"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::Create() michael@0: { michael@0: //XXX First Check In michael@0: NS_ASSERTION(false, "Not Yet Implemented"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::Destroy() michael@0: { michael@0: if (!mWindow) michael@0: return NS_OK; michael@0: michael@0: // Ensure we don't reenter this code michael@0: if (mDestroying) michael@0: return NS_OK; michael@0: michael@0: mozilla::AutoRestore guard(mDestroying); michael@0: mDestroying = true; michael@0: michael@0: nsCOMPtr appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); michael@0: NS_ASSERTION(appShell, "Couldn't get appShell... xpcom shutdown?"); michael@0: if (appShell) michael@0: appShell->UnregisterTopLevelWindow(static_cast(this)); michael@0: michael@0: nsCOMPtr parentWindow(do_QueryReferent(mParentWindow)); michael@0: if (parentWindow) michael@0: parentWindow->RemoveChildWindow(this); michael@0: michael@0: // let's make sure the window doesn't get deleted out from under us michael@0: // while we are trying to close....this can happen if the docshell michael@0: // we close ends up being the last owning reference to this xulwindow michael@0: michael@0: // XXXTAB This shouldn't be an issue anymore because the ownership model michael@0: // only goes in one direction. When webshell container is fully removed michael@0: // try removing this... michael@0: michael@0: nsCOMPtr placeHolder = this; michael@0: michael@0: // Remove modality (if any) and hide while destroying. More than michael@0: // a convenience, the hide prevents user interaction with the partially michael@0: // destroyed window. This is especially necessary when the eldest window michael@0: // in a stack of modal windows is destroyed first. It happens. michael@0: ExitModalLoop(NS_OK); michael@0: if (mWindow) michael@0: mWindow->Show(false); michael@0: michael@0: #if defined(XP_WIN) michael@0: // We need to explicitly set the focus on Windows, but michael@0: // only if the parent is visible. michael@0: nsCOMPtr parent(do_QueryReferent(mParentWindow)); michael@0: if (parent) { michael@0: nsCOMPtr parentWidget; michael@0: parent->GetMainWidget(getter_AddRefs(parentWidget)); michael@0: if (!parentWidget || parentWidget->IsVisible()) { michael@0: nsCOMPtr baseHiddenWindow; michael@0: if (appShell) { michael@0: nsCOMPtr hiddenWindow; michael@0: appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow)); michael@0: if (hiddenWindow) michael@0: baseHiddenWindow = do_GetInterface(hiddenWindow); michael@0: } michael@0: // somebody screwed up somewhere. hiddenwindow shouldn't be anybody's michael@0: // parent. still, when it happens, skip activating it. michael@0: if (baseHiddenWindow != parent) { michael@0: nsCOMPtr parentWidget; michael@0: parent->GetMainWidget(getter_AddRefs(parentWidget)); michael@0: if (parentWidget) michael@0: parentWidget->PlaceBehind(eZPlacementTop, 0, true); michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: mDOMWindow = nullptr; michael@0: if (mDocShell) { michael@0: nsCOMPtr shellAsWin(do_QueryInterface(mDocShell)); michael@0: shellAsWin->Destroy(); michael@0: mDocShell = nullptr; // this can cause reentrancy of this function michael@0: } michael@0: michael@0: // Remove our ref on the content shells michael@0: uint32_t count = mContentShells.Length(); michael@0: for (uint32_t i = 0; i < count; i++) { michael@0: nsContentShellInfo* shellInfo = mContentShells.ElementAt(i); michael@0: delete shellInfo; michael@0: } michael@0: mContentShells.Clear(); michael@0: mPrimaryContentShell = nullptr; michael@0: michael@0: if (mContentTreeOwner) { michael@0: mContentTreeOwner->XULWindow(nullptr); michael@0: NS_RELEASE(mContentTreeOwner); michael@0: } michael@0: if (mPrimaryContentTreeOwner) { michael@0: mPrimaryContentTreeOwner->XULWindow(nullptr); michael@0: NS_RELEASE(mPrimaryContentTreeOwner); michael@0: } michael@0: if (mChromeTreeOwner) { michael@0: mChromeTreeOwner->XULWindow(nullptr); michael@0: NS_RELEASE(mChromeTreeOwner); michael@0: } michael@0: if (mWindow) { michael@0: mWindow->SetWidgetListener(nullptr); // nsWebShellWindow hackery michael@0: mWindow->Destroy(); michael@0: mWindow = nullptr; michael@0: } michael@0: michael@0: if (!mIsHiddenWindow) { michael@0: /* Inform appstartup we've destroyed this window and it could michael@0: quit now if it wanted. This must happen at least after mDocShell michael@0: is destroyed, because onunload handlers fire then, and those being michael@0: script, anything could happen. A new window could open, even. michael@0: See bug 130719. */ michael@0: nsCOMPtr obssvc = michael@0: do_GetService("@mozilla.org/observer-service;1"); michael@0: NS_ASSERTION(obssvc, "Couldn't get observer service?"); michael@0: michael@0: if (obssvc) michael@0: obssvc->NotifyObservers(nullptr, "xul-window-destroyed", nullptr); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetUnscaledDevicePixelsPerCSSPixel(double *aScale) michael@0: { michael@0: *aScale = mWindow ? mWindow->GetDefaultScale().scale : 1.0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetPosition(int32_t aX, int32_t aY) michael@0: { michael@0: // Don't reset the window's size mode here - platforms that don't want to move michael@0: // maximized windows should reset it in their respective Move implementation. michael@0: CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); michael@0: double invScale = 1.0 / scale.scale; michael@0: nsresult rv = mWindow->Move(aX * invScale, aY * invScale); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: if (!mChromeLoaded) { michael@0: // If we're called before the chrome is loaded someone obviously wants this michael@0: // window at this position. We don't persist this one-time position. michael@0: mIgnoreXULPosition = true; michael@0: return NS_OK; michael@0: } michael@0: PersistentAttributesDirty(PAD_POSITION); michael@0: SavePersistentAttributes(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetPosition(int32_t* aX, int32_t* aY) michael@0: { michael@0: return GetPositionAndSize(aX, aY, nullptr, nullptr); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetSize(int32_t aCX, int32_t aCY, bool aRepaint) michael@0: { michael@0: /* any attempt to set the window's size or position overrides the window's michael@0: zoom state. this is important when these two states are competing while michael@0: the window is being opened. but it should probably just always be so. */ michael@0: mWindow->SetSizeMode(nsSizeMode_Normal); michael@0: michael@0: mIntrinsicallySized = false; michael@0: michael@0: CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); michael@0: double invScale = 1.0 / scale.scale; michael@0: nsresult rv = mWindow->Resize(aCX * invScale, aCY * invScale, aRepaint); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: if (!mChromeLoaded) { michael@0: // If we're called before the chrome is loaded someone obviously wants this michael@0: // window at this size & in the normal size mode (since it is the only mode michael@0: // in which setting dimensions makes sense). We don't persist this one-time michael@0: // size. michael@0: mIgnoreXULSize = true; michael@0: mIgnoreXULSizeMode = true; michael@0: return NS_OK; michael@0: } michael@0: PersistentAttributesDirty(PAD_SIZE); michael@0: SavePersistentAttributes(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetSize(int32_t* aCX, int32_t* aCY) michael@0: { michael@0: return GetPositionAndSize(nullptr, nullptr, aCX, aCY); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetPositionAndSize(int32_t aX, int32_t aY, michael@0: int32_t aCX, int32_t aCY, bool aRepaint) michael@0: { michael@0: /* any attempt to set the window's size or position overrides the window's michael@0: zoom state. this is important when these two states are competing while michael@0: the window is being opened. but it should probably just always be so. */ michael@0: mWindow->SetSizeMode(nsSizeMode_Normal); michael@0: michael@0: mIntrinsicallySized = false; michael@0: michael@0: CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); michael@0: double invScale = 1.0 / scale.scale; michael@0: nsresult rv = mWindow->Resize(aX * invScale, aY * invScale, michael@0: aCX * invScale, aCY * invScale, michael@0: aRepaint); michael@0: NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); michael@0: if (!mChromeLoaded) { michael@0: // If we're called before the chrome is loaded someone obviously wants this michael@0: // window at this size and position. We don't persist this one-time setting. michael@0: mIgnoreXULPosition = true; michael@0: mIgnoreXULSize = true; michael@0: mIgnoreXULSizeMode = true; michael@0: return NS_OK; michael@0: } michael@0: PersistentAttributesDirty(PAD_POSITION | PAD_SIZE); michael@0: SavePersistentAttributes(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetPositionAndSize(int32_t* x, int32_t* y, int32_t* cx, michael@0: int32_t* cy) michael@0: { michael@0: nsIntRect rect; michael@0: michael@0: if (!mWindow) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: mWindow->GetScreenBounds(rect); michael@0: michael@0: if (x) michael@0: *x = rect.x; michael@0: if (y) michael@0: *y = rect.y; michael@0: if (cx) michael@0: *cx = rect.width; michael@0: if (cy) michael@0: *cy = rect.height; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::Center(nsIXULWindow *aRelative, bool aScreen, bool aAlert) michael@0: { michael@0: int32_t left, top, width, height, michael@0: ourWidth, ourHeight; michael@0: bool screenCoordinates = false, michael@0: windowCoordinates = false; michael@0: nsresult result; michael@0: michael@0: if (!mChromeLoaded) { michael@0: // note we lose the parameters. at time of writing, this isn't a problem. michael@0: mCenterAfterLoad = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!aScreen && !aRelative) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: nsCOMPtr screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1", &result); michael@0: if (NS_FAILED(result)) michael@0: return result; michael@0: michael@0: nsCOMPtr screen; michael@0: michael@0: if (aRelative) { michael@0: nsCOMPtr base(do_QueryInterface(aRelative, &result)); michael@0: if (base) { michael@0: // get window rect michael@0: result = base->GetPositionAndSize(&left, &top, &width, &height); michael@0: if (NS_SUCCEEDED(result)) { michael@0: double scale; michael@0: if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) { michael@0: // convert device-pixel coordinates to global display pixels michael@0: left = NSToIntRound(left / scale); michael@0: top = NSToIntRound(top / scale); michael@0: width = NSToIntRound(width / scale); michael@0: height = NSToIntRound(height / scale); michael@0: } michael@0: // if centering on screen, convert that to the corresponding screen michael@0: if (aScreen) michael@0: screenmgr->ScreenForRect(left, top, width, height, getter_AddRefs(screen)); michael@0: else michael@0: windowCoordinates = true; michael@0: } else { michael@0: // something's wrong with the reference window. michael@0: // fall back to the primary screen michael@0: aRelative = 0; michael@0: aScreen = true; michael@0: } michael@0: } michael@0: } michael@0: if (!aRelative) { michael@0: if (!mOpenerScreenRect.IsEmpty()) { michael@0: // FIXME - check if these are device or display pixels michael@0: screenmgr->ScreenForRect(mOpenerScreenRect.x, mOpenerScreenRect.y, michael@0: mOpenerScreenRect.width, mOpenerScreenRect.height, michael@0: getter_AddRefs(screen)); michael@0: } else { michael@0: screenmgr->GetPrimaryScreen(getter_AddRefs(screen)); michael@0: } michael@0: } michael@0: michael@0: if (aScreen && screen) { michael@0: screen->GetAvailRectDisplayPix(&left, &top, &width, &height); michael@0: screenCoordinates = true; michael@0: } michael@0: michael@0: if (screenCoordinates || windowCoordinates) { michael@0: NS_ASSERTION(mWindow, "what, no window?"); michael@0: CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); michael@0: GetSize(&ourWidth, &ourHeight); michael@0: ourWidth = NSToIntRound(ourWidth / scale.scale); michael@0: ourHeight = NSToIntRound(ourHeight / scale.scale); michael@0: left += (width - ourWidth) / 2; michael@0: top += (height - ourHeight) / (aAlert ? 3 : 2); michael@0: if (windowCoordinates) { michael@0: mWindow->ConstrainPosition(false, &left, &top); michael@0: } michael@0: SetPosition(left * scale.scale, top * scale.scale); michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::Repaint(bool aForce) michael@0: { michael@0: //XXX First Check In michael@0: NS_ASSERTION(false, "Not Yet Implemented"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetParentWidget(nsIWidget** aParentWidget) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aParentWidget); michael@0: NS_ENSURE_STATE(mWindow); michael@0: michael@0: NS_IF_ADDREF(*aParentWidget = mWindow->GetParent()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetParentWidget(nsIWidget* aParentWidget) michael@0: { michael@0: //XXX First Check In michael@0: NS_ASSERTION(false, "Not Yet Implemented"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetParentNativeWindow(nativeWindow* aParentNativeWindow) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aParentNativeWindow); michael@0: michael@0: nsCOMPtr parentWidget; michael@0: NS_ENSURE_SUCCESS(GetParentWidget(getter_AddRefs(parentWidget)), NS_ERROR_FAILURE); michael@0: michael@0: if (parentWidget) { michael@0: *aParentNativeWindow = parentWidget->GetNativeData(NS_NATIVE_WIDGET); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetParentNativeWindow(nativeWindow aParentNativeWindow) michael@0: { michael@0: //XXX First Check In michael@0: NS_ASSERTION(false, "Not Yet Implemented"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetNativeHandle(nsAString& aNativeHandle) michael@0: { michael@0: nsCOMPtr mainWidget; michael@0: NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(mainWidget)), NS_ERROR_FAILURE); michael@0: michael@0: if (mainWidget) { michael@0: nativeWindow nativeWindowPtr = mainWidget->GetNativeData(NS_NATIVE_WINDOW); michael@0: /* the nativeWindow pointer is converted to and exposed as a string. This michael@0: is a more reliable way not to lose information (as opposed to JS michael@0: |Number| for instance) */ michael@0: aNativeHandle = NS_ConvertASCIItoUTF16(nsPrintfCString("0x%p", nativeWindowPtr)); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetVisibility(bool* aVisibility) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aVisibility); michael@0: michael@0: // Always claim to be visible for now. See bug michael@0: // https://bugzilla.mozilla.org/show_bug.cgi?id=306245. michael@0: michael@0: *aVisibility = true; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetVisibility(bool aVisibility) michael@0: { michael@0: if (!mChromeLoaded) { michael@0: mShowAfterLoad = aVisibility; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (mDebuting) { michael@0: return NS_OK; michael@0: } michael@0: mDebuting = true; // (Show / Focus is recursive) michael@0: michael@0: //XXXTAB Do we really need to show docshell and the window? Isn't michael@0: // the window good enough? michael@0: nsCOMPtr shellAsWin(do_QueryInterface(mDocShell)); michael@0: shellAsWin->SetVisibility(aVisibility); michael@0: // Store locally so it doesn't die on us. 'Show' can result in the window michael@0: // being closed with nsXULWindow::Destroy being called. That would set michael@0: // mWindow to null and posibly destroy the nsIWidget while its Show method michael@0: // is on the stack. We need to keep it alive until Show finishes. michael@0: nsCOMPtr window = mWindow; michael@0: window->Show(aVisibility); michael@0: michael@0: nsCOMPtr windowMediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); michael@0: if (windowMediator) michael@0: windowMediator->UpdateWindowTimeStamp(static_cast(this)); michael@0: michael@0: // notify observers so that we can hide the splash screen if possible michael@0: nsCOMPtr obssvc michael@0: (do_GetService("@mozilla.org/observer-service;1")); michael@0: NS_ASSERTION(obssvc, "Couldn't get observer service."); michael@0: if (obssvc) { michael@0: obssvc->NotifyObservers(nullptr, "xul-window-visible", nullptr); michael@0: } michael@0: michael@0: mDebuting = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetEnabled(bool *aEnabled) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aEnabled); michael@0: michael@0: if (mWindow) { michael@0: *aEnabled = mWindow->IsEnabled(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: *aEnabled = true; // better guess than most michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetEnabled(bool aEnable) michael@0: { michael@0: if (mWindow) { michael@0: mWindow->Enable(aEnable); michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetMainWidget(nsIWidget** aMainWidget) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aMainWidget); michael@0: michael@0: *aMainWidget = mWindow; michael@0: NS_IF_ADDREF(*aMainWidget); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetFocus() michael@0: { michael@0: //XXX First Check In michael@0: NS_ASSERTION(false, "Not Yet Implemented"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetTitle(char16_t** aTitle) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aTitle); michael@0: michael@0: *aTitle = ToNewUnicode(mTitle); michael@0: if (!*aTitle) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetTitle(const char16_t* aTitle) michael@0: { michael@0: NS_ENSURE_STATE(mWindow); michael@0: mTitle.Assign(aTitle); michael@0: mTitle.StripChars("\n\r"); michael@0: NS_ENSURE_SUCCESS(mWindow->SetTitle(mTitle), NS_ERROR_FAILURE); michael@0: michael@0: // Tell the window mediator that a title has changed michael@0: nsCOMPtr windowMediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); michael@0: if (!windowMediator) michael@0: return NS_OK; michael@0: michael@0: windowMediator->UpdateWindowTitle(static_cast(this), aTitle); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: //***************************************************************************** michael@0: // nsXULWindow: Helpers michael@0: //***************************************************************************** michael@0: michael@0: NS_IMETHODIMP nsXULWindow::EnsureChromeTreeOwner() michael@0: { michael@0: if (mChromeTreeOwner) michael@0: return NS_OK; michael@0: michael@0: mChromeTreeOwner = new nsChromeTreeOwner(); michael@0: NS_ENSURE_TRUE(mChromeTreeOwner, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: NS_ADDREF(mChromeTreeOwner); michael@0: mChromeTreeOwner->XULWindow(this); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::EnsureContentTreeOwner() michael@0: { michael@0: if (mContentTreeOwner) michael@0: return NS_OK; michael@0: michael@0: mContentTreeOwner = new nsContentTreeOwner(false); michael@0: NS_ENSURE_TRUE(mContentTreeOwner, NS_ERROR_FAILURE); michael@0: michael@0: NS_ADDREF(mContentTreeOwner); michael@0: mContentTreeOwner->XULWindow(this); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::EnsurePrimaryContentTreeOwner() michael@0: { michael@0: if (mPrimaryContentTreeOwner) michael@0: return NS_OK; michael@0: michael@0: mPrimaryContentTreeOwner = new nsContentTreeOwner(true); michael@0: NS_ENSURE_TRUE(mPrimaryContentTreeOwner, NS_ERROR_FAILURE); michael@0: michael@0: NS_ADDREF(mPrimaryContentTreeOwner); michael@0: mPrimaryContentTreeOwner->XULWindow(this); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::EnsurePrompter() michael@0: { michael@0: if (mPrompter) michael@0: return NS_OK; michael@0: michael@0: nsCOMPtr ourWindow; michael@0: nsresult rv = GetWindowDOMWindow(getter_AddRefs(ourWindow)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: nsCOMPtr wwatch = michael@0: do_GetService(NS_WINDOWWATCHER_CONTRACTID); michael@0: if (wwatch) michael@0: wwatch->GetNewPrompter(ourWindow, getter_AddRefs(mPrompter)); michael@0: } michael@0: return mPrompter ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::EnsureAuthPrompter() michael@0: { michael@0: if (mAuthPrompter) michael@0: return NS_OK; michael@0: michael@0: nsCOMPtr ourWindow; michael@0: nsresult rv = GetWindowDOMWindow(getter_AddRefs(ourWindow)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); michael@0: if (wwatch) michael@0: wwatch->GetNewAuthPrompter(ourWindow, getter_AddRefs(mAuthPrompter)); michael@0: } michael@0: return mAuthPrompter ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: void nsXULWindow::OnChromeLoaded() michael@0: { michael@0: nsresult rv = EnsureContentTreeOwner(); michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: mChromeLoaded = true; michael@0: ApplyChromeFlags(); michael@0: SyncAttributesToWidget(); michael@0: if (!mIgnoreXULSize) michael@0: LoadSizeFromXUL(); michael@0: if (mIntrinsicallySized) { michael@0: // (if LoadSizeFromXUL set the size, mIntrinsicallySized will be false) michael@0: nsCOMPtr cv; michael@0: mDocShell->GetContentViewer(getter_AddRefs(cv)); michael@0: nsCOMPtr markupViewer = do_QueryInterface(cv); michael@0: if (markupViewer) { michael@0: nsCOMPtr docShellAsItem = do_QueryInterface(mDocShell); michael@0: nsCOMPtr treeOwner; michael@0: docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner)); michael@0: if (treeOwner) { michael@0: int32_t width, height; michael@0: markupViewer->GetContentSize(&width, &height); michael@0: treeOwner->SizeShellTo(docShellAsItem, width, height); michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool positionSet = !mIgnoreXULPosition; michael@0: nsCOMPtr parentWindow(do_QueryReferent(mParentWindow)); michael@0: #if defined(XP_UNIX) && !defined(XP_MACOSX) michael@0: // don't override WM placement on unix for independent, top-level windows michael@0: // (however, we think the benefits of intelligent dependent window placement michael@0: // trump that override.) michael@0: if (!parentWindow) michael@0: positionSet = false; michael@0: #endif michael@0: if (positionSet) michael@0: positionSet = LoadPositionFromXUL(); michael@0: LoadMiscPersistentAttributesFromXUL(); michael@0: michael@0: if (mCenterAfterLoad && !positionSet) michael@0: Center(parentWindow, parentWindow ? false : true, false); michael@0: michael@0: if (mShowAfterLoad) { michael@0: SetVisibility(true); michael@0: // At this point the window may have been closed during Show(), so michael@0: // nsXULWindow::Destroy may already have been called. Take care! michael@0: } michael@0: } michael@0: mPersistentAttributesMask |= PAD_POSITION | PAD_SIZE | PAD_MISC; michael@0: } michael@0: michael@0: bool nsXULWindow::LoadPositionFromXUL() michael@0: { michael@0: bool gotPosition = false; michael@0: michael@0: // if we're the hidden window, don't try to validate our size/position. We're michael@0: // special. michael@0: if (mIsHiddenWindow) michael@0: return false; michael@0: michael@0: nsCOMPtr windowElement = GetWindowDOMElement(); michael@0: NS_ENSURE_TRUE(windowElement, false); michael@0: michael@0: int32_t currX = 0; michael@0: int32_t currY = 0; michael@0: int32_t currWidth = 0; michael@0: int32_t currHeight = 0; michael@0: nsresult errorCode; michael@0: int32_t temp; michael@0: michael@0: GetPositionAndSize(&currX, &currY, &currWidth, &currHeight); michael@0: michael@0: // Convert to global display pixels for consistent window management across michael@0: // screens with diverse resolutions michael@0: CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); michael@0: currX = NSToIntRound(currX / scale.scale); michael@0: currY = NSToIntRound(currY / scale.scale); michael@0: currWidth = NSToIntRound(currWidth / scale.scale); michael@0: currHeight = NSToIntRound(currHeight / scale.scale); michael@0: michael@0: // Obtain the position information from the element. michael@0: int32_t specX = currX; michael@0: int32_t specY = currY; michael@0: nsAutoString posString; michael@0: michael@0: windowElement->GetAttribute(SCREENX_ATTRIBUTE, posString); michael@0: temp = posString.ToInteger(&errorCode); michael@0: if (NS_SUCCEEDED(errorCode)) { michael@0: specX = temp; michael@0: gotPosition = true; michael@0: } michael@0: windowElement->GetAttribute(SCREENY_ATTRIBUTE, posString); michael@0: temp = posString.ToInteger(&errorCode); michael@0: if (NS_SUCCEEDED(errorCode)) { michael@0: specY = temp; michael@0: gotPosition = true; michael@0: } michael@0: michael@0: if (gotPosition) { michael@0: // our position will be relative to our parent, if any michael@0: nsCOMPtr parent(do_QueryReferent(mParentWindow)); michael@0: if (parent) { michael@0: int32_t parentX, parentY; michael@0: if (NS_SUCCEEDED(parent->GetPosition(&parentX, &parentY))) { michael@0: double scale; michael@0: if (NS_SUCCEEDED(parent->GetUnscaledDevicePixelsPerCSSPixel(&scale))) { michael@0: parentX = NSToIntRound(parentX / scale); michael@0: parentY = NSToIntRound(parentY / scale); michael@0: } michael@0: specX += parentX; michael@0: specY += parentY; michael@0: } michael@0: } michael@0: else { michael@0: StaggerPosition(specX, specY, currWidth, currHeight); michael@0: } michael@0: } michael@0: mWindow->ConstrainPosition(false, &specX, &specY); michael@0: if (specX != currX || specY != currY) { michael@0: CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); michael@0: SetPosition(specX * scale.scale, specY * scale.scale); michael@0: } michael@0: michael@0: return gotPosition; michael@0: } michael@0: michael@0: bool nsXULWindow::LoadSizeFromXUL() michael@0: { michael@0: bool gotSize = false; michael@0: michael@0: // if we're the hidden window, don't try to validate our size/position. We're michael@0: // special. michael@0: if (mIsHiddenWindow) michael@0: return false; michael@0: michael@0: nsCOMPtr windowElement = GetWindowDOMElement(); michael@0: NS_ENSURE_TRUE(windowElement, false); michael@0: michael@0: int32_t currWidth = 0; michael@0: int32_t currHeight = 0; michael@0: nsresult errorCode; michael@0: int32_t temp; michael@0: michael@0: NS_ASSERTION(mWindow, "we expected to have a window already"); michael@0: michael@0: CSSToLayoutDeviceScale scale = mWindow ? mWindow->GetDefaultScale() michael@0: : CSSToLayoutDeviceScale(1.0); michael@0: GetSize(&currWidth, &currHeight); michael@0: currWidth = NSToIntRound(currWidth / scale.scale); michael@0: currHeight = NSToIntRound(currHeight / scale.scale); michael@0: michael@0: // Obtain the position and sizing information from the element. michael@0: int32_t specWidth = currWidth; michael@0: int32_t specHeight = currHeight; michael@0: nsAutoString sizeString; michael@0: michael@0: windowElement->GetAttribute(WIDTH_ATTRIBUTE, sizeString); michael@0: temp = sizeString.ToInteger(&errorCode); michael@0: if (NS_SUCCEEDED(errorCode) && temp > 0) { michael@0: specWidth = std::max(temp, 100); michael@0: gotSize = true; michael@0: } michael@0: windowElement->GetAttribute(HEIGHT_ATTRIBUTE, sizeString); michael@0: temp = sizeString.ToInteger(&errorCode); michael@0: if (NS_SUCCEEDED(errorCode) && temp > 0) { michael@0: specHeight = std::max(temp, 100); michael@0: gotSize = true; michael@0: } michael@0: michael@0: if (gotSize) { michael@0: // constrain to screen size michael@0: nsCOMPtr domWindow; michael@0: GetWindowDOMWindow(getter_AddRefs(domWindow)); michael@0: if (domWindow) { michael@0: nsCOMPtr screen; michael@0: domWindow->GetScreen(getter_AddRefs(screen)); michael@0: if (screen) { michael@0: int32_t screenWidth; michael@0: int32_t screenHeight; michael@0: screen->GetAvailWidth(&screenWidth); michael@0: screen->GetAvailHeight(&screenHeight); michael@0: if (specWidth > screenWidth) michael@0: specWidth = screenWidth; michael@0: if (specHeight > screenHeight) michael@0: specHeight = screenHeight; michael@0: } michael@0: } michael@0: michael@0: mIntrinsicallySized = false; michael@0: if (specWidth != currWidth || specHeight != currHeight) { michael@0: CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); michael@0: SetSize(specWidth * scale.scale, specHeight * scale.scale, false); michael@0: } michael@0: } michael@0: michael@0: return gotSize; michael@0: } michael@0: michael@0: /* Miscellaneous persistent attributes are attributes named in the michael@0: |persist| attribute, other than size and position. Those are special michael@0: because it's important to load those before one of the misc michael@0: attributes (sizemode) and they require extra processing. */ michael@0: bool nsXULWindow::LoadMiscPersistentAttributesFromXUL() michael@0: { michael@0: bool gotState = false; michael@0: michael@0: /* There are no misc attributes of interest to the hidden window. michael@0: It's especially important not to try to validate that window's michael@0: size or position, because some platforms (Mac OS X) need to michael@0: make it visible and offscreen. */ michael@0: if (mIsHiddenWindow) michael@0: return false; michael@0: michael@0: nsCOMPtr windowElement = GetWindowDOMElement(); michael@0: NS_ENSURE_TRUE(windowElement, false); michael@0: michael@0: nsAutoString stateString; michael@0: michael@0: // sizemode michael@0: windowElement->GetAttribute(MODE_ATTRIBUTE, stateString); michael@0: int32_t sizeMode = nsSizeMode_Normal; michael@0: /* ignore request to minimize, to not confuse novices michael@0: if (stateString.Equals(SIZEMODE_MINIMIZED)) michael@0: sizeMode = nsSizeMode_Minimized; michael@0: */ michael@0: if (!mIgnoreXULSizeMode && michael@0: (stateString.Equals(SIZEMODE_MAXIMIZED) || stateString.Equals(SIZEMODE_FULLSCREEN))) { michael@0: /* Honor request to maximize only if the window is sizable. michael@0: An unsizable, unmaximizable, yet maximized window confuses michael@0: Windows OS and is something of a travesty, anyway. */ michael@0: if (mChromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) { michael@0: mIntrinsicallySized = false; michael@0: michael@0: if (stateString.Equals(SIZEMODE_MAXIMIZED)) michael@0: sizeMode = nsSizeMode_Maximized; michael@0: else michael@0: sizeMode = nsSizeMode_Fullscreen; michael@0: } michael@0: } michael@0: michael@0: // If we are told to ignore the size mode attribute update the michael@0: // document so the attribute and window are in sync. michael@0: if (mIgnoreXULSizeMode) { michael@0: nsAutoString sizeString; michael@0: if (sizeMode == nsSizeMode_Maximized) michael@0: sizeString.Assign(SIZEMODE_MAXIMIZED); michael@0: else if (sizeMode == nsSizeMode_Fullscreen) michael@0: sizeString.Assign(SIZEMODE_FULLSCREEN); michael@0: else if (sizeMode == nsSizeMode_Normal) michael@0: sizeString.Assign(SIZEMODE_NORMAL); michael@0: if (!sizeString.IsEmpty()) { michael@0: ErrorResult rv; michael@0: windowElement->SetAttribute(MODE_ATTRIBUTE, sizeString, rv); michael@0: } michael@0: } michael@0: michael@0: if (sizeMode == nsSizeMode_Fullscreen) { michael@0: nsCOMPtr ourWindow; michael@0: GetWindowDOMWindow(getter_AddRefs(ourWindow)); michael@0: ourWindow->SetFullScreen(true); michael@0: } else { michael@0: mWindow->SetSizeMode(sizeMode); michael@0: } michael@0: gotState = true; michael@0: michael@0: // zlevel michael@0: windowElement->GetAttribute(ZLEVEL_ATTRIBUTE, stateString); michael@0: if (!stateString.IsEmpty()) { michael@0: nsresult errorCode; michael@0: int32_t zLevel = stateString.ToInteger(&errorCode); michael@0: if (NS_SUCCEEDED(errorCode) && zLevel >= lowestZ && zLevel <= highestZ) michael@0: SetZLevel(zLevel); michael@0: } michael@0: michael@0: return gotState; michael@0: } michael@0: michael@0: /* Stagger windows of the same type so they don't appear on top of each other. michael@0: This code does have a scary double loop -- it'll keep passing through michael@0: the entire list of open windows until it finds a non-collision. Doesn't michael@0: seem to be a problem, but it deserves watching. michael@0: */ michael@0: void nsXULWindow::StaggerPosition(int32_t &aRequestedX, int32_t &aRequestedY, michael@0: int32_t aSpecWidth, int32_t aSpecHeight) michael@0: { michael@0: const int32_t kOffset = 22; michael@0: const uint32_t kSlop = 4; michael@0: michael@0: bool keepTrying; michael@0: int bouncedX = 0, // bounced off vertical edge of screen michael@0: bouncedY = 0; // bounced off horizontal edge michael@0: michael@0: // look for any other windows of this type michael@0: nsCOMPtr wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); michael@0: if (!wm) michael@0: return; michael@0: michael@0: nsCOMPtr windowElement = GetWindowDOMElement(); michael@0: if (!windowElement) michael@0: return; michael@0: michael@0: nsCOMPtr ourXULWindow(this); michael@0: michael@0: nsAutoString windowType; michael@0: windowElement->GetAttribute(WINDOWTYPE_ATTRIBUTE, windowType); michael@0: michael@0: int32_t screenTop = 0, // it's pointless to initialize these ... michael@0: screenRight = 0, // ... but to prevent oversalubrious and ... michael@0: screenBottom = 0, // ... underbright compilers from ... michael@0: screenLeft = 0; // ... issuing warnings. michael@0: bool gotScreen = false; michael@0: michael@0: { // fetch screen coordinates michael@0: nsCOMPtr screenMgr(do_GetService( michael@0: "@mozilla.org/gfx/screenmanager;1")); michael@0: if (screenMgr) { michael@0: nsCOMPtr ourScreen; michael@0: // the coordinates here are already display pixels michael@0: screenMgr->ScreenForRect(aRequestedX, aRequestedY, michael@0: aSpecWidth, aSpecHeight, michael@0: getter_AddRefs(ourScreen)); michael@0: if (ourScreen) { michael@0: int32_t screenWidth, screenHeight; michael@0: ourScreen->GetAvailRectDisplayPix(&screenLeft, &screenTop, michael@0: &screenWidth, &screenHeight); michael@0: screenBottom = screenTop + screenHeight; michael@0: screenRight = screenLeft + screenWidth; michael@0: gotScreen = true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // One full pass through all windows of this type, repeat until no collisions. michael@0: do { michael@0: keepTrying = false; michael@0: nsCOMPtr windowList; michael@0: wm->GetXULWindowEnumerator(windowType.get(), getter_AddRefs(windowList)); michael@0: michael@0: if (!windowList) michael@0: break; michael@0: michael@0: // One full pass through all windows of this type, offset and stop on collision. michael@0: do { michael@0: bool more; michael@0: windowList->HasMoreElements(&more); michael@0: if (!more) michael@0: break; michael@0: michael@0: nsCOMPtr supportsWindow; michael@0: windowList->GetNext(getter_AddRefs(supportsWindow)); michael@0: michael@0: nsCOMPtr listXULWindow(do_QueryInterface(supportsWindow)); michael@0: if (listXULWindow != ourXULWindow) { michael@0: int32_t listX, listY; michael@0: nsCOMPtr listBaseWindow(do_QueryInterface(supportsWindow)); michael@0: listBaseWindow->GetPosition(&listX, &listY); michael@0: double scale; michael@0: if (NS_SUCCEEDED(listBaseWindow->GetUnscaledDevicePixelsPerCSSPixel(&scale))) { michael@0: listX = NSToIntRound(listX / scale); michael@0: listY = NSToIntRound(listY / scale); michael@0: } michael@0: michael@0: if (Abs(listX - aRequestedX) <= kSlop && Abs(listY - aRequestedY) <= kSlop) { michael@0: // collision! offset and start over michael@0: if (bouncedX & 0x1) michael@0: aRequestedX -= kOffset; michael@0: else michael@0: aRequestedX += kOffset; michael@0: aRequestedY += kOffset; michael@0: michael@0: if (gotScreen) { michael@0: // if we're moving to the right and we need to bounce... michael@0: if (!(bouncedX & 0x1) && ((aRequestedX + aSpecWidth) > screenRight)) { michael@0: aRequestedX = screenRight - aSpecWidth; michael@0: ++bouncedX; michael@0: } michael@0: michael@0: // if we're moving to the left and we need to bounce... michael@0: if ((bouncedX & 0x1) && aRequestedX < screenLeft) { michael@0: aRequestedX = screenLeft; michael@0: ++bouncedX; michael@0: } michael@0: michael@0: // if we hit the bottom then bounce to the top michael@0: if (aRequestedY + aSpecHeight > screenBottom) { michael@0: aRequestedY = screenTop; michael@0: ++bouncedY; michael@0: } michael@0: } michael@0: michael@0: /* loop around again, michael@0: but it's time to give up once we've covered the screen. michael@0: there's a potential infinite loop with lots of windows. */ michael@0: keepTrying = bouncedX < 2 || bouncedY == 0; michael@0: break; michael@0: } michael@0: } michael@0: } while(1); michael@0: } while (keepTrying); michael@0: } michael@0: michael@0: void nsXULWindow::SyncAttributesToWidget() michael@0: { michael@0: nsCOMPtr windowElement = GetWindowDOMElement(); michael@0: if (!windowElement) michael@0: return; michael@0: michael@0: nsAutoString attr; michael@0: michael@0: // "hidechrome" attribute michael@0: if (windowElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidechrome, michael@0: nsGkAtoms::_true, eCaseMatters)) { michael@0: mWindow->HideWindowChrome(true); michael@0: } michael@0: michael@0: // "chromemargin" attribute michael@0: nsIntMargin margins; michael@0: windowElement->GetAttribute(NS_LITERAL_STRING("chromemargin"), attr); michael@0: if (nsContentUtils::ParseIntMarginValue(attr, margins)) { michael@0: mWindow->SetNonClientMargins(margins); michael@0: } michael@0: michael@0: // "accelerated" attribute michael@0: bool isAccelerated = windowElement->HasAttribute(NS_LITERAL_STRING("accelerated")); michael@0: mWindow->SetLayersAcceleration(isAccelerated); michael@0: michael@0: // "windowtype" attribute michael@0: windowElement->GetAttribute(WINDOWTYPE_ATTRIBUTE, attr); michael@0: if (!attr.IsEmpty()) { michael@0: mWindow->SetWindowClass(attr); michael@0: } michael@0: michael@0: // "id" attribute for icon michael@0: windowElement->GetAttribute(NS_LITERAL_STRING("id"), attr); michael@0: if (attr.IsEmpty()) { michael@0: attr.AssignLiteral("default"); michael@0: } michael@0: mWindow->SetIcon(attr); michael@0: michael@0: // "drawtitle" attribute michael@0: windowElement->GetAttribute(NS_LITERAL_STRING("drawtitle"), attr); michael@0: mWindow->SetDrawsTitle(attr.LowerCaseEqualsLiteral("true")); michael@0: michael@0: // "toggletoolbar" attribute michael@0: windowElement->GetAttribute(NS_LITERAL_STRING("toggletoolbar"), attr); michael@0: mWindow->SetShowsToolbarButton(attr.LowerCaseEqualsLiteral("true")); michael@0: michael@0: // "fullscreenbutton" attribute michael@0: windowElement->GetAttribute(NS_LITERAL_STRING("fullscreenbutton"), attr); michael@0: mWindow->SetShowsFullScreenButton(attr.LowerCaseEqualsLiteral("true")); michael@0: michael@0: // "macanimationtype" attribute michael@0: windowElement->GetAttribute(NS_LITERAL_STRING("macanimationtype"), attr); michael@0: if (attr.EqualsLiteral("document")) { michael@0: mWindow->SetWindowAnimationType(nsIWidget::eDocumentWindowAnimation); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SavePersistentAttributes() michael@0: { michael@0: // can happen when the persistence timer fires at an inopportune time michael@0: // during window shutdown michael@0: if (!mDocShell) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr docShellElement = GetWindowDOMElement(); michael@0: if (!docShellElement) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsAutoString persistString; michael@0: docShellElement->GetAttribute(PERSIST_ATTRIBUTE, persistString); michael@0: if (persistString.IsEmpty()) { // quick check which sometimes helps michael@0: mPersistentAttributesDirty = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // get our size, position and mode to persist michael@0: int32_t x, y, cx, cy; michael@0: NS_ENSURE_SUCCESS(GetPositionAndSize(&x, &y, &cx, &cy), NS_ERROR_FAILURE); michael@0: michael@0: int32_t sizeMode = mWindow->SizeMode(); michael@0: CSSToLayoutDeviceScale scale = mWindow->GetDefaultScale(); michael@0: michael@0: // make our position relative to our parent, if any michael@0: nsCOMPtr parent(do_QueryReferent(mParentWindow)); michael@0: if (parent) { michael@0: int32_t parentX, parentY; michael@0: if (NS_SUCCEEDED(parent->GetPosition(&parentX, &parentY))) { michael@0: x -= parentX; michael@0: y -= parentY; michael@0: } michael@0: } michael@0: michael@0: char sizeBuf[10]; michael@0: nsAutoString sizeString; michael@0: nsAutoString windowElementId; michael@0: nsCOMPtr ownerXULDoc; michael@0: michael@0: // fetch docShellElement's ID and XUL owner document michael@0: ownerXULDoc = do_QueryInterface(docShellElement->OwnerDoc()); michael@0: if (docShellElement->IsXUL()) { michael@0: docShellElement->GetId(windowElementId); michael@0: } michael@0: michael@0: ErrorResult rv; michael@0: // (only for size elements which are persisted) michael@0: if ((mPersistentAttributesDirty & PAD_POSITION) && michael@0: sizeMode == nsSizeMode_Normal) { michael@0: if (persistString.Find("screenX") >= 0) { michael@0: PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(x / scale.scale)); michael@0: sizeString.AssignWithConversion(sizeBuf); michael@0: docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString, rv); michael@0: if (ownerXULDoc) // force persistence in case the value didn't change michael@0: ownerXULDoc->Persist(windowElementId, SCREENX_ATTRIBUTE); michael@0: } michael@0: if (persistString.Find("screenY") >= 0) { michael@0: PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(y / scale.scale)); michael@0: sizeString.AssignWithConversion(sizeBuf); michael@0: docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString, rv); michael@0: if (ownerXULDoc) michael@0: ownerXULDoc->Persist(windowElementId, SCREENY_ATTRIBUTE); michael@0: } michael@0: } michael@0: michael@0: if ((mPersistentAttributesDirty & PAD_SIZE) && michael@0: sizeMode == nsSizeMode_Normal) { michael@0: if (persistString.Find("width") >= 0) { michael@0: PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(cx / scale.scale)); michael@0: sizeString.AssignWithConversion(sizeBuf); michael@0: docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv); michael@0: if (ownerXULDoc) michael@0: ownerXULDoc->Persist(windowElementId, WIDTH_ATTRIBUTE); michael@0: } michael@0: if (persistString.Find("height") >= 0) { michael@0: PR_snprintf(sizeBuf, sizeof(sizeBuf), "%d", NSToIntRound(cy / scale.scale)); michael@0: sizeString.AssignWithConversion(sizeBuf); michael@0: docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv); michael@0: if (ownerXULDoc) michael@0: ownerXULDoc->Persist(windowElementId, HEIGHT_ATTRIBUTE); michael@0: } michael@0: } michael@0: michael@0: if (mPersistentAttributesDirty & PAD_MISC) { michael@0: if (sizeMode != nsSizeMode_Minimized) { michael@0: if (sizeMode == nsSizeMode_Maximized) michael@0: sizeString.Assign(SIZEMODE_MAXIMIZED); michael@0: else if (sizeMode == nsSizeMode_Fullscreen) michael@0: sizeString.Assign(SIZEMODE_FULLSCREEN); michael@0: else michael@0: sizeString.Assign(SIZEMODE_NORMAL); michael@0: docShellElement->SetAttribute(MODE_ATTRIBUTE, sizeString, rv); michael@0: if (ownerXULDoc && persistString.Find("sizemode") >= 0) michael@0: ownerXULDoc->Persist(windowElementId, MODE_ATTRIBUTE); michael@0: } michael@0: if (persistString.Find("zlevel") >= 0) { michael@0: uint32_t zLevel; michael@0: nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); michael@0: if (mediator) { michael@0: mediator->GetZLevel(this, &zLevel); michael@0: PR_snprintf(sizeBuf, sizeof(sizeBuf), "%lu", (unsigned long)zLevel); michael@0: sizeString.AssignWithConversion(sizeBuf); michael@0: docShellElement->SetAttribute(ZLEVEL_ATTRIBUTE, sizeString, rv); michael@0: ownerXULDoc->Persist(windowElementId, ZLEVEL_ATTRIBUTE); michael@0: } michael@0: } michael@0: } michael@0: michael@0: mPersistentAttributesDirty = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetWindowDOMWindow(nsIDOMWindow** aDOMWindow) michael@0: { michael@0: NS_ENSURE_STATE(mDocShell); michael@0: michael@0: if (!mDOMWindow) michael@0: mDOMWindow = do_GetInterface(mDocShell); michael@0: NS_ENSURE_TRUE(mDOMWindow, NS_ERROR_FAILURE); michael@0: michael@0: *aDOMWindow = mDOMWindow; michael@0: NS_ADDREF(*aDOMWindow); michael@0: return NS_OK; michael@0: } michael@0: michael@0: dom::Element* michael@0: nsXULWindow::GetWindowDOMElement() const michael@0: { michael@0: NS_ENSURE_TRUE(mDocShell, nullptr); michael@0: michael@0: nsCOMPtr cv; michael@0: mDocShell->GetContentViewer(getter_AddRefs(cv)); michael@0: NS_ENSURE_TRUE(cv, nullptr); michael@0: michael@0: const nsIDocument* document = cv->GetDocument(); michael@0: NS_ENSURE_TRUE(document, nullptr); michael@0: michael@0: return document->GetRootElement(); michael@0: } michael@0: michael@0: nsresult nsXULWindow::ContentShellAdded(nsIDocShellTreeItem* aContentShell, michael@0: bool aPrimary, bool aTargetable, const nsAString& aID) michael@0: { michael@0: nsContentShellInfo* shellInfo = nullptr; michael@0: michael@0: uint32_t i, count = mContentShells.Length(); michael@0: nsWeakPtr contentShellWeak = do_GetWeakReference(aContentShell); michael@0: for (i = 0; i < count; i++) { michael@0: nsContentShellInfo* info = mContentShells.ElementAt(i); michael@0: if (info->id.Equals(aID)) { michael@0: // We already exist. Do a replace. michael@0: info->child = contentShellWeak; michael@0: shellInfo = info; michael@0: } michael@0: else if (info->child == contentShellWeak) michael@0: info->child = nullptr; michael@0: } michael@0: michael@0: if (!shellInfo) { michael@0: shellInfo = new nsContentShellInfo(aID, contentShellWeak); michael@0: mContentShells.AppendElement(shellInfo); michael@0: } michael@0: michael@0: // Set the default content tree owner michael@0: if (aPrimary) { michael@0: NS_ENSURE_SUCCESS(EnsurePrimaryContentTreeOwner(), NS_ERROR_FAILURE); michael@0: aContentShell->SetTreeOwner(mPrimaryContentTreeOwner); michael@0: mPrimaryContentShell = aContentShell; michael@0: } michael@0: else { michael@0: NS_ENSURE_SUCCESS(EnsureContentTreeOwner(), NS_ERROR_FAILURE); michael@0: aContentShell->SetTreeOwner(mContentTreeOwner); michael@0: if (mPrimaryContentShell == aContentShell) michael@0: mPrimaryContentShell = nullptr; michael@0: } michael@0: michael@0: if (aTargetable) { michael@0: #ifdef DEBUG michael@0: int32_t debugCount = mTargetableShells.Count(); michael@0: int32_t debugCounter; michael@0: for (debugCounter = debugCount - 1; debugCounter >= 0; --debugCounter) { michael@0: nsCOMPtr curItem = michael@0: do_QueryReferent(mTargetableShells[debugCounter]); michael@0: NS_ASSERTION(!SameCOMIdentity(curItem, aContentShell), michael@0: "Adding already existing item to mTargetableShells"); michael@0: } michael@0: #endif michael@0: michael@0: // put the new shell at the start of the targetable shells list if either michael@0: // it's the new primary shell or there is no existing primary shell (which michael@0: // means that chances are this one just stopped being primary). If we michael@0: // really cared, we could keep track of the "last no longer primary shell" michael@0: // explicitly, but it probably doesn't matter enough: the difference would michael@0: // only be felt in a situation where all shells were non-primary, which michael@0: // doesn't happen much. In a situation where there is one and only one michael@0: // primary shell, and in which shells get unmarked as primary before some michael@0: // other shell gets marked as primary, this effectively stores the list of michael@0: // targetable shells in "most recently primary first" order. michael@0: bool inserted; michael@0: if (aPrimary || !mPrimaryContentShell) { michael@0: inserted = mTargetableShells.InsertObjectAt(contentShellWeak, 0); michael@0: } else { michael@0: inserted = mTargetableShells.AppendObject(contentShellWeak); michael@0: } michael@0: NS_ENSURE_TRUE(inserted, NS_ERROR_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult nsXULWindow::ContentShellRemoved(nsIDocShellTreeItem* aContentShell) michael@0: { michael@0: if (mPrimaryContentShell == aContentShell) { michael@0: mPrimaryContentShell = nullptr; michael@0: } michael@0: michael@0: int32_t i, count = mContentShells.Length(); michael@0: for (i = count - 1; i >= 0; --i) { michael@0: nsContentShellInfo* info = mContentShells.ElementAt(i); michael@0: nsCOMPtr curItem = do_QueryReferent(info->child); michael@0: if (!curItem || SameCOMIdentity(curItem, aContentShell)) { michael@0: mContentShells.RemoveElementAt(i); michael@0: delete info; michael@0: } michael@0: } michael@0: michael@0: count = mTargetableShells.Count(); michael@0: for (i = count - 1; i >= 0; --i) { michael@0: nsCOMPtr curItem = michael@0: do_QueryReferent(mTargetableShells[i]); michael@0: if (!curItem || SameCOMIdentity(curItem, aContentShell)) { michael@0: mTargetableShells.RemoveObjectAt(i); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SizeShellTo(nsIDocShellTreeItem* aShellItem, michael@0: int32_t aCX, int32_t aCY) michael@0: { michael@0: // XXXTAB This is wrong, we should actually reflow based on the passed in michael@0: // shell. For now we are hacking and doing delta sizing. This is bad michael@0: // because it assumes all size we add will go to the shell which probably michael@0: // won't happen. michael@0: michael@0: nsCOMPtr shellAsWin(do_QueryInterface(aShellItem)); michael@0: NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE); michael@0: michael@0: int32_t width = 0; michael@0: int32_t height = 0; michael@0: shellAsWin->GetSize(&width, &height); michael@0: michael@0: int32_t widthDelta = aCX - width; michael@0: int32_t heightDelta = aCY - height; michael@0: michael@0: if (widthDelta || heightDelta) { michael@0: int32_t winCX = 0; michael@0: int32_t winCY = 0; michael@0: michael@0: GetSize(&winCX, &winCY); michael@0: // There's no point in trying to make the window smaller than the michael@0: // desired docshell size --- that's not likely to work. This whole michael@0: // function assumes that the outer docshell is adding some constant michael@0: // "border" chrome to aShellItem. michael@0: winCX = std::max(winCX + widthDelta, aCX); michael@0: winCY = std::max(winCY + heightDelta, aCY); michael@0: SetSize(winCX, winCY, true); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::ExitModalLoop(nsresult aStatus) michael@0: { michael@0: if (mContinueModalLoop) michael@0: EnableParent(true); michael@0: mContinueModalLoop = false; michael@0: mModalStatus = aStatus; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // top-level function to create a new window michael@0: NS_IMETHODIMP nsXULWindow::CreateNewWindow(int32_t aChromeFlags, michael@0: nsIXULWindow **_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: michael@0: if (aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME) michael@0: return CreateNewChromeWindow(aChromeFlags, _retval); michael@0: return CreateNewContentWindow(aChromeFlags, _retval); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::CreateNewChromeWindow(int32_t aChromeFlags, michael@0: nsIXULWindow **_retval) michael@0: { michael@0: nsCOMPtr appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); michael@0: NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE); michael@0: michael@0: // Just do a normal create of a window and return. michael@0: michael@0: nsCOMPtr newWindow; michael@0: appShell->CreateTopLevelWindow(this, nullptr, aChromeFlags, michael@0: nsIAppShellService::SIZE_TO_CONTENT, michael@0: nsIAppShellService::SIZE_TO_CONTENT, michael@0: getter_AddRefs(newWindow)); michael@0: michael@0: NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE); michael@0: michael@0: *_retval = newWindow; michael@0: NS_ADDREF(*_retval); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::CreateNewContentWindow(int32_t aChromeFlags, michael@0: nsIXULWindow **_retval) michael@0: { michael@0: nsCOMPtr appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); michael@0: NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE); michael@0: michael@0: // We need to create a new top level window and then enter a nested michael@0: // loop. Eventually the new window will be told that it has loaded, michael@0: // at which time we know it is safe to spin out of the nested loop michael@0: // and allow the opening code to proceed. michael@0: michael@0: nsCOMPtr uri; michael@0: michael@0: nsAdoptingCString urlStr = Preferences::GetCString("browser.chromeURL"); michael@0: if (urlStr.IsEmpty()) { michael@0: urlStr.AssignLiteral("chrome://navigator/content/navigator.xul"); michael@0: } michael@0: michael@0: nsCOMPtr service(do_GetService(NS_IOSERVICE_CONTRACTID)); michael@0: if (service) { michael@0: service->NewURI(urlStr, nullptr, nullptr, getter_AddRefs(uri)); michael@0: } michael@0: NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); michael@0: michael@0: // We need to create a chrome window to contain the content window we're about michael@0: // to pass back. The subject principal needs to be system while we're creating michael@0: // it to make things work right, so force a system caller. See bug 799348 michael@0: // comment 13 for a description of what happens when we don't. michael@0: nsCOMPtr newWindow; michael@0: { michael@0: AutoNoJSAPI nojsapi; michael@0: appShell->CreateTopLevelWindow(this, uri, michael@0: aChromeFlags, 615, 480, michael@0: getter_AddRefs(newWindow)); michael@0: NS_ENSURE_TRUE(newWindow, NS_ERROR_FAILURE); michael@0: } michael@0: michael@0: // Specify that we want the window to remain locked until the chrome has loaded. michael@0: nsXULWindow *xulWin = static_cast michael@0: (static_cast michael@0: (newWindow)); michael@0: michael@0: xulWin->LockUntilChromeLoad(); michael@0: michael@0: { michael@0: AutoNoJSAPI nojsapi; michael@0: nsIThread *thread = NS_GetCurrentThread(); michael@0: while (xulWin->IsLocked()) { michael@0: if (!NS_ProcessNextEvent(thread)) michael@0: break; michael@0: } michael@0: } michael@0: michael@0: NS_ENSURE_STATE(xulWin->mPrimaryContentShell); michael@0: michael@0: *_retval = newWindow; michael@0: NS_ADDREF(*_retval); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void nsXULWindow::EnableParent(bool aEnable) michael@0: { michael@0: nsCOMPtr parentWindow; michael@0: nsCOMPtr parentWidget; michael@0: michael@0: parentWindow = do_QueryReferent(mParentWindow); michael@0: if (parentWindow) michael@0: parentWindow->GetMainWidget(getter_AddRefs(parentWidget)); michael@0: if (parentWidget) michael@0: parentWidget->Enable(aEnable); michael@0: } michael@0: michael@0: // Constrain the window to its proper z-level michael@0: bool nsXULWindow::ConstrainToZLevel(bool aImmediate, michael@0: nsWindowZ *aPlacement, michael@0: nsIWidget *aReqBelow, michael@0: nsIWidget **aActualBelow) michael@0: { michael@0: #if 0 michael@0: /* Do we have a parent window? This means our z-order is already constrained, michael@0: since we're a dependent window. Our window list isn't hierarchical, michael@0: so we can't properly calculate placement for such a window. michael@0: Should we just abort? */ michael@0: nsCOMPtr parentWindow = do_QueryReferent(mParentWindow); michael@0: if (parentWindow) michael@0: return false; michael@0: #endif michael@0: michael@0: nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); michael@0: if (!mediator) michael@0: return false; michael@0: michael@0: bool altered; michael@0: uint32_t position, michael@0: newPosition, michael@0: zLevel; michael@0: nsIXULWindow *us = this; michael@0: michael@0: altered = false; michael@0: mediator->GetZLevel(this, &zLevel); michael@0: michael@0: // translate from WidgetGUIEvent to nsIWindowMediator constants michael@0: position = nsIWindowMediator::zLevelTop; michael@0: if (*aPlacement == nsWindowZBottom || zLevel == nsIXULWindow::lowestZ) michael@0: position = nsIWindowMediator::zLevelBottom; michael@0: else if (*aPlacement == nsWindowZRelative) michael@0: position = nsIWindowMediator::zLevelBelow; michael@0: michael@0: if (NS_SUCCEEDED(mediator->CalculateZPosition(us, position, aReqBelow, michael@0: &newPosition, aActualBelow, &altered))) { michael@0: /* If we were asked to move to the top but constrained to remain michael@0: below one of our other windows, first move all windows in that michael@0: window's layer and above to the top. This allows the user to michael@0: click a window which can't be topmost and still bring mozilla michael@0: to the foreground. */ michael@0: if (altered && michael@0: (position == nsIWindowMediator::zLevelTop || michael@0: (position == nsIWindowMediator::zLevelBelow && aReqBelow == 0))) michael@0: PlaceWindowLayersBehind(zLevel + 1, nsIXULWindow::highestZ, 0); michael@0: michael@0: if (*aPlacement != nsWindowZBottom && michael@0: position == nsIWindowMediator::zLevelBottom) michael@0: altered = true; michael@0: if (altered || aImmediate) { michael@0: if (newPosition == nsIWindowMediator::zLevelTop) michael@0: *aPlacement = nsWindowZTop; michael@0: else if (newPosition == nsIWindowMediator::zLevelBottom) michael@0: *aPlacement = nsWindowZBottom; michael@0: else michael@0: *aPlacement = nsWindowZRelative; michael@0: michael@0: if (aImmediate) { michael@0: nsCOMPtr ourBase = do_QueryObject(this); michael@0: if (ourBase) { michael@0: nsCOMPtr ourWidget; michael@0: ourBase->GetMainWidget(getter_AddRefs(ourWidget)); michael@0: ourWidget->PlaceBehind(*aPlacement == nsWindowZBottom ? michael@0: eZPlacementBottom : eZPlacementBelow, michael@0: *aActualBelow, false); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* CalculateZPosition can tell us to be below nothing, because it tries michael@0: not to change something it doesn't recognize. A request to verify michael@0: being below an unrecognized window, then, is treated as a request michael@0: to come to the top (below null) */ michael@0: nsCOMPtr windowAbove; michael@0: if (newPosition == nsIWindowMediator::zLevelBelow && *aActualBelow) { michael@0: windowAbove = (*aActualBelow)->GetWidgetListener()->GetXULWindow(); michael@0: } michael@0: michael@0: mediator->SetZPosition(us, newPosition, windowAbove); michael@0: } michael@0: michael@0: return altered; michael@0: } michael@0: michael@0: /* Re-z-position all windows in the layers from aLowLevel to aHighLevel, michael@0: inclusive, to be behind aBehind. aBehind of null means on top. michael@0: Note this method actually does nothing to our relative window positions. michael@0: (And therefore there's no need to inform WindowMediator we're moving michael@0: things, because we aren't.) This method is useful for, say, moving michael@0: a range of layers of our own windows relative to windows belonging to michael@0: external applications. michael@0: */ michael@0: void nsXULWindow::PlaceWindowLayersBehind(uint32_t aLowLevel, michael@0: uint32_t aHighLevel, michael@0: nsIXULWindow *aBehind) michael@0: { michael@0: // step through windows in z-order from top to bottommost window michael@0: michael@0: nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID)); michael@0: if (!mediator) michael@0: return; michael@0: michael@0: nsCOMPtr windowEnumerator; michael@0: mediator->GetZOrderXULWindowEnumerator(0, true, michael@0: getter_AddRefs(windowEnumerator)); michael@0: if (!windowEnumerator) michael@0: return; michael@0: michael@0: // each window will be moved behind previousHighWidget, itself michael@0: // a moving target. initialize it. michael@0: nsCOMPtr previousHighWidget; michael@0: if (aBehind) { michael@0: nsCOMPtr highBase(do_QueryInterface(aBehind)); michael@0: if (highBase) michael@0: highBase->GetMainWidget(getter_AddRefs(previousHighWidget)); michael@0: } michael@0: michael@0: // get next lower window michael@0: bool more; michael@0: while (windowEnumerator->HasMoreElements(&more), more) { michael@0: uint32_t nextZ; // z-level of nextWindow michael@0: nsCOMPtr nextWindow; michael@0: windowEnumerator->GetNext(getter_AddRefs(nextWindow)); michael@0: nsCOMPtr nextXULWindow(do_QueryInterface(nextWindow)); michael@0: nextXULWindow->GetZLevel(&nextZ); michael@0: if (nextZ < aLowLevel) michael@0: break; // we've processed all windows through aLowLevel michael@0: michael@0: // move it just below its next higher window michael@0: nsCOMPtr nextBase(do_QueryInterface(nextXULWindow)); michael@0: if (nextBase) { michael@0: nsCOMPtr nextWidget; michael@0: nextBase->GetMainWidget(getter_AddRefs(nextWidget)); michael@0: if (nextZ <= aHighLevel) michael@0: nextWidget->PlaceBehind(eZPlacementBelow, previousHighWidget, false); michael@0: previousHighWidget = nextWidget; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void nsXULWindow::SetContentScrollbarVisibility(bool aVisible) michael@0: { michael@0: nsCOMPtr contentWin(do_GetInterface(mPrimaryContentShell)); michael@0: if (contentWin) { michael@0: mozilla::ErrorResult rv; michael@0: nsRefPtr window = static_cast(contentWin.get()); michael@0: nsRefPtr scrollbars = window->GetScrollbars(rv); michael@0: if (scrollbars) { michael@0: scrollbars->SetVisible(aVisible, rv); michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool nsXULWindow::GetContentScrollbarVisibility() michael@0: { michael@0: // This code already exists in dom/src/base/nsBarProp.cpp, but we michael@0: // can't safely get to that from here as this function is called michael@0: // while the DOM window is being set up, and we need the DOM window michael@0: // to get to that code. michael@0: nsCOMPtr scroller(do_QueryInterface(mPrimaryContentShell)); michael@0: michael@0: if (scroller) { michael@0: int32_t prefValue; michael@0: scroller->GetDefaultScrollbarPreferences( michael@0: nsIScrollable::ScrollOrientation_Y, &prefValue); michael@0: if (prefValue == nsIScrollable::Scrollbar_Never) // try the other way michael@0: scroller->GetDefaultScrollbarPreferences( michael@0: nsIScrollable::ScrollOrientation_X, &prefValue); michael@0: michael@0: if (prefValue == nsIScrollable::Scrollbar_Never) michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // during spinup, attributes that haven't been loaded yet can't be dirty michael@0: void nsXULWindow::PersistentAttributesDirty(uint32_t aDirtyFlags) michael@0: { michael@0: mPersistentAttributesDirty |= aDirtyFlags & mPersistentAttributesMask; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::ApplyChromeFlags() michael@0: { michael@0: nsCOMPtr window = GetWindowDOMElement(); michael@0: NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); michael@0: michael@0: if (mChromeLoaded) { michael@0: // The two calls in this block don't need to happen early because they michael@0: // don't cause a global restyle on the document. Not only that, but the michael@0: // scrollbar stuff needs a content area to toggle the scrollbars on anyway. michael@0: // So just don't do these until mChromeLoaded is true. michael@0: michael@0: // Scrollbars have their own special treatment. michael@0: SetContentScrollbarVisibility(mChromeFlags & michael@0: nsIWebBrowserChrome::CHROME_SCROLLBARS ? michael@0: true : false); michael@0: } michael@0: michael@0: /* the other flags are handled together. we have style rules michael@0: in navigator.css that trigger visibility based on michael@0: the 'chromehidden' attribute of the tag. */ michael@0: nsAutoString newvalue; michael@0: michael@0: if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_MENUBAR)) michael@0: newvalue.AppendLiteral("menubar "); michael@0: michael@0: if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_TOOLBAR)) michael@0: newvalue.AppendLiteral("toolbar "); michael@0: michael@0: if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_LOCATIONBAR)) michael@0: newvalue.AppendLiteral("location "); michael@0: michael@0: if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR)) michael@0: newvalue.AppendLiteral("directories "); michael@0: michael@0: if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_STATUSBAR)) michael@0: newvalue.AppendLiteral("status "); michael@0: michael@0: if (! (mChromeFlags & nsIWebBrowserChrome::CHROME_EXTRA)) michael@0: newvalue.AppendLiteral("extrachrome "); michael@0: michael@0: // Note that if we're not actually changing the value this will be a no-op, michael@0: // so no need to compare to the old value. michael@0: ErrorResult rv; michael@0: window->SetAttribute(NS_LITERAL_STRING("chromehidden"), newvalue, rv); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::GetXULBrowserWindow(nsIXULBrowserWindow * *aXULBrowserWindow) michael@0: { michael@0: NS_IF_ADDREF(*aXULBrowserWindow = mXULBrowserWindow); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsXULWindow::SetXULBrowserWindow(nsIXULBrowserWindow * aXULBrowserWindow) michael@0: { michael@0: mXULBrowserWindow = aXULBrowserWindow; michael@0: return NS_OK; michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: //*** nsContentShellInfo: Object Management michael@0: //***************************************************************************** michael@0: michael@0: nsContentShellInfo::nsContentShellInfo(const nsAString& aID, michael@0: nsIWeakReference* aContentShell) michael@0: : id(aID), michael@0: child(aContentShell) michael@0: { michael@0: MOZ_COUNT_CTOR(nsContentShellInfo); michael@0: } michael@0: michael@0: nsContentShellInfo::~nsContentShellInfo() michael@0: { michael@0: MOZ_COUNT_DTOR(nsContentShellInfo); michael@0: //XXX Set Tree Owner to null if the tree owner is nsXULWindow->mContentTreeOwner michael@0: }