Bug 1470510 - Merge nsWebShellWindow into nsXULWindow r=smaug

nsWebShellWindow is the only class that extends nsXULWindow and only
nsWebShellWindows are ever instantiated.

Differential Revision: https://phabricator.services.mozilla.com/D51155

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Brendan Dahl 2019-11-04 23:11:32 +00:00
Родитель 96cc0b5247
Коммит ab6809f229
8 изменённых файлов: 855 добавлений и 969 удалений

Просмотреть файл

@ -1546,7 +1546,7 @@ void nsGlobalWindowOuter::SetInitialPrincipalToSubject(
// We should never create windows with an expanded principal.
// If we have a system principal, make sure we're not using it for a content
// docshell.
// NOTE: Please keep this logic in sync with nsWebShellWindow::Initialize().
// NOTE: Please keep this logic in sync with nsXULWindow::Initialize().
if (nsContentUtils::IsExpandedPrincipal(newWindowPrincipal) ||
(nsContentUtils::IsSystemPrincipal(newWindowPrincipal) &&
GetDocShell()->ItemType() != nsIDocShellTreeItem::typeChrome)) {

Просмотреть файл

@ -30,7 +30,6 @@ UNIFIED_SOURCES += [
'nsAppShellWindowEnumerator.cpp',
'nsChromeTreeOwner.cpp',
'nsContentTreeOwner.cpp',
'nsWebShellWindow.cpp',
'nsWindowMediator.cpp',
'nsXULWindow.cpp',
]

Просмотреть файл

@ -17,7 +17,7 @@
#include "nsIWindowWatcher.h"
#include "nsPIWindowWatcher.h"
#include "nsPIDOMWindow.h"
#include "nsWebShellWindow.h"
#include "nsXULWindow.h"
#include "nsWidgetInitData.h"
#include "nsWidgetsCID.h"
@ -133,7 +133,7 @@ nsAppShellService::CreateHiddenWindow() {
rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<nsWebShellWindow> newWindow;
RefPtr<nsXULWindow> newWindow;
rv =
JustCreateTopWindow(nullptr, url, chromeMask, initialWidth, initialHeight,
true, nullptr, nullptr, getter_AddRefs(newWindow));
@ -175,7 +175,7 @@ nsAppShellService::CreateTopLevelWindow(
StartupTimeline::RecordOnce(StartupTimeline::CREATE_TOP_LEVEL_WINDOW);
RefPtr<nsWebShellWindow> newWindow;
RefPtr<nsXULWindow> newWindow;
rv = JustCreateTopWindow(aParent, aUrl, aChromeMask, aInitialWidth,
aInitialHeight, false, aOpeningTab, aOpenerWindow,
getter_AddRefs(newWindow));
@ -558,14 +558,14 @@ nsresult nsAppShellService::JustCreateTopWindow(
nsIXULWindow* aParent, nsIURI* aUrl, uint32_t aChromeMask,
int32_t aInitialWidth, int32_t aInitialHeight, bool aIsHiddenWindow,
nsIRemoteTab* aOpeningTab, mozIDOMWindowProxy* aOpenerWindow,
nsWebShellWindow** aResult) {
nsXULWindow** aResult) {
*aResult = nullptr;
NS_ENSURE_STATE(!mXPCOMWillShutDown);
nsCOMPtr<nsIXULWindow> parent;
if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) parent = aParent;
RefPtr<nsWebShellWindow> window = new nsWebShellWindow(aChromeMask);
RefPtr<nsXULWindow> window = new nsXULWindow(aChromeMask);
#ifdef XP_WIN
// If the parent is currently fullscreen, tell the child to ignore persisted

Просмотреть файл

@ -10,7 +10,7 @@
#include "nsIObserver.h"
// Interfaces Needed
#include "nsWebShellWindow.h"
#include "nsXULWindow.h"
#include "nsStringFwd.h"
#include "nsAutoPtr.h"
#include "nsIRemoteTab.h"
@ -42,10 +42,10 @@ class nsAppShellService final : public nsIAppShellService, public nsIObserver {
int32_t aInitialHeight, bool aIsHiddenWindow,
nsIRemoteTab* aOpeningTab,
mozIDOMWindowProxy* aOpenerWindow,
nsWebShellWindow** aResult);
nsXULWindow** aResult);
uint32_t CalculateWindowZLevel(nsIXULWindow* aParent, uint32_t aChromeMask);
RefPtr<nsWebShellWindow> mHiddenWindow;
RefPtr<nsXULWindow> mHiddenWindow;
bool mXPCOMWillShutDown;
bool mXPCOMShuttingDown;
uint16_t mModalWindowCount;

Просмотреть файл

@ -1,818 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsWebShellWindow.h"
#include "nsLayoutCID.h"
#include "nsContentCID.h"
#include "nsContentList.h"
#include "nsIWeakReference.h"
#include "nsIContentViewer.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIURL.h"
#include "nsIIOService.h"
#include "nsIURL.h"
#include "nsNetCID.h"
#include "nsIStringBundle.h"
#include "nsReadableUtils.h"
#include "nsContentUtils.h"
#include "nsEscape.h"
#include "nsPIDOMWindow.h"
#include "nsIWebNavigation.h"
#include "nsIWindowWatcher.h"
#include "nsWidgetInitData.h"
#include "nsWidgetsCID.h"
#include "nsIWidget.h"
#include "nsIWidgetListener.h"
#include "nsINodeList.h"
#include "nsITimer.h"
#include "nsXULPopupManager.h"
#include "nsFocusManager.h"
#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"
#include "mozilla/dom/Document.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsIObserverService.h"
#include "nsIScreenManager.h"
#include "nsIScreen.h"
#include "nsIContent.h" // for menus
#include "nsIScriptSecurityManager.h"
// For calculating size
#include "nsPresContext.h"
#include "nsIBaseWindow.h"
#include "nsIDocShellTreeItem.h"
#include "nsDocShell.h"
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/PresShell.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/LoadURIOptionsBinding.h"
#include "nsPIWindowRoot.h"
#include "gfxPlatform.h"
#ifdef XP_MACOSX
# include "nsINativeMenuService.h"
# define USE_NATIVE_MENUS
#endif
using namespace mozilla;
using namespace mozilla::dom;
#define SIZE_PERSISTENCE_TIMEOUT 500 // msec
nsWebShellWindow::nsWebShellWindow(uint32_t aChromeFlags)
: nsXULWindow(aChromeFlags),
mSPTimerLock("nsWebShellWindow.mSPTimerLock"),
mWidgetListenerDelegate(this) {}
nsWebShellWindow::~nsWebShellWindow() {
MutexAutoLock lock(mSPTimerLock);
if (mSPTimer) mSPTimer->Cancel();
}
NS_IMPL_ADDREF_INHERITED(nsWebShellWindow, nsXULWindow)
NS_IMPL_RELEASE_INHERITED(nsWebShellWindow, nsXULWindow)
NS_INTERFACE_MAP_BEGIN(nsWebShellWindow)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_END_INHERITING(nsXULWindow)
nsresult nsWebShellWindow::Initialize(
nsIXULWindow* aParent, nsIXULWindow* aOpener, nsIURI* aUrl,
int32_t aInitialWidth, int32_t aInitialHeight, bool aIsHiddenWindow,
nsIRemoteTab* aOpeningTab, mozIDOMWindowProxy* aOpenerWindow,
nsWidgetInitData& widgetInitData) {
nsresult rv;
nsCOMPtr<nsIWidget> parentWidget;
mIsHiddenWindow = aIsHiddenWindow;
int32_t initialX = 0, initialY = 0;
nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(aOpener));
if (base) {
int32_t x, y, width, height;
rv = base->GetPositionAndSize(&x, &y, &width, &height);
if (NS_FAILED(rv)) {
mOpenerScreenRect.SetEmpty();
} else {
double scale;
if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) {
mOpenerScreenRect.SetRect(
NSToIntRound(x / scale), NSToIntRound(y / scale),
NSToIntRound(width / scale), NSToIntRound(height / scale));
} else {
mOpenerScreenRect.SetRect(x, y, width, height);
}
initialX = mOpenerScreenRect.X();
initialY = mOpenerScreenRect.Y();
ConstrainToOpenerScreen(&initialX, &initialY);
}
}
// XXX: need to get the default window size from prefs...
// Doesn't come from prefs... will come from CSS/XUL/RDF
DesktopIntRect deskRect(initialX, initialY, aInitialWidth, aInitialHeight);
// Create top level window
if (gfxPlatform::IsHeadless()) {
mWindow = nsIWidget::CreateHeadlessWidget();
} else {
mWindow = nsIWidget::CreateTopLevelWindow();
}
if (!mWindow) {
return NS_ERROR_FAILURE;
}
/* This next bit is troublesome. We carry two different versions of a pointer
to our parent window. One is the parent window's widget, which is passed
to our own widget. The other is a weak reference we keep here to our
parent WebShellWindow. The former is useful to the widget, and we can't
trust its treatment of the parent reference because they're platform-
specific. The latter is useful to this class.
A better implementation would be one in which the parent keeps strong
references to its children and closes them before it allows itself
to be closed. This would mimic the behaviour of OSes that support
top-level child windows in OSes that do not. Later.
*/
nsCOMPtr<nsIBaseWindow> parentAsWin(do_QueryInterface(aParent));
if (parentAsWin) {
parentAsWin->GetMainWidget(getter_AddRefs(parentWidget));
mParentWindow = do_GetWeakReference(aParent);
}
mWindow->SetWidgetListener(&mWidgetListenerDelegate);
rv = mWindow->Create((nsIWidget*)parentWidget, // Parent nsIWidget
nullptr, // Native parent widget
deskRect, // Widget dimensions
&widgetInitData); // Widget initialization data
NS_ENSURE_SUCCESS(rv, rv);
LayoutDeviceIntRect r = mWindow->GetClientBounds();
// Match the default background color of content. Important on windows
// since we no longer use content child widgets.
mWindow->SetBackgroundColor(NS_RGB(255, 255, 255));
// Create web shell
RefPtr<BrowsingContext> openerContext =
aOpenerWindow
? nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext()
: nullptr;
RefPtr<BrowsingContext> browsingContext =
BrowsingContext::Create(/* aParent */ nullptr, openerContext,
EmptyString(), BrowsingContext::Type::Chrome);
mDocShell = nsDocShell::Create(browsingContext);
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
// XXX(nika): This is used to handle propagating opener across remote tab
// creation. We should come up with a better system for doing this (probably
// based on BrowsingContext).
mDocShell->SetOpener(aOpeningTab);
// Make sure to set the item type on the docshell _before_ calling
// Create() so it knows what type it is.
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(mDocShell);
NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE);
docShellAsItem->SetTreeOwner(mChromeTreeOwner);
r.MoveTo(0, 0);
nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
NS_ENSURE_SUCCESS(docShellAsWin->InitWindow(nullptr, mWindow, r.X(), r.Y(),
r.Width(), r.Height()),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(docShellAsWin->Create(), NS_ERROR_FAILURE);
// Attach a WebProgress listener.during initialization...
nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
if (webProgress) {
webProgress->AddProgressListener(this,
nsIWebProgress::NOTIFY_STATE_NETWORK);
}
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
if (aOpenerWindow) {
BrowsingContext* bc = mDocShell->GetBrowsingContext();
BrowsingContext* openerBC =
nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext();
MOZ_DIAGNOSTIC_ASSERT(bc->GetOpenerId() == openerBC->Id());
MOZ_DIAGNOSTIC_ASSERT(bc->HadOriginalOpener());
}
#endif
// Eagerly create an about:blank content viewer with the right principal here,
// rather than letting it happening in the upcoming call to
// SetInitialPrincipalToSubject. This avoids creating the about:blank document
// and then blowing it away with a second one, which can cause problems for
// the top-level chrome window case. See bug 789773. Note that we don't accept
// expanded principals here, similar to SetInitialPrincipalToSubject.
if (nsContentUtils::IsInitialized()) { // Sometimes this happens really early
// See bug 793370.
MOZ_ASSERT(mDocShell->ItemType() == nsIDocShellTreeItem::typeChrome);
nsCOMPtr<nsIPrincipal> principal =
nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
if (nsContentUtils::IsExpandedPrincipal(principal)) {
principal = nullptr;
}
// Use the subject (or system) principal as the storage principal too until
// the new window finishes navigating and gets a real storage principal.
rv = mDocShell->CreateAboutBlankContentViewer(principal, principal,
/* aCsp = */ nullptr);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<Document> doc = mDocShell->GetDocument();
NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE);
doc->SetIsInitialDocument(true);
}
if (nullptr != aUrl) {
nsCString tmpStr;
rv = aUrl->GetSpec(tmpStr);
if (NS_FAILED(rv)) return rv;
NS_ConvertUTF8toUTF16 urlString(tmpStr);
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
LoadURIOptions loadURIOptions;
loadURIOptions.mTriggeringPrincipal = nsContentUtils::GetSystemPrincipal();
rv = webNav->LoadURI(urlString, loadURIOptions);
NS_ENSURE_SUCCESS(rv, rv);
}
return rv;
}
PresShell* nsWebShellWindow::GetPresShell() {
if (!mDocShell) {
return nullptr;
}
return mDocShell->GetPresShell();
}
bool nsWebShellWindow::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) {
nsCOMPtr<nsPIDOMWindowOuter> window =
mDocShell ? mDocShell->GetWindow() : nullptr;
pm->AdjustPopupsOnWindowChange(window);
}
// Notify all tabs that the widget moved.
if (mDocShell && mDocShell->GetWindow()) {
nsCOMPtr<EventTarget> eventTarget =
mDocShell->GetWindow()->GetTopWindowRoot();
nsContentUtils::DispatchChromeEvent(mDocShell->GetDocument(), eventTarget,
NS_LITERAL_STRING("MozUpdateWindowPos"),
CanBubble::eNo, Cancelable::eNo,
nullptr);
}
// Persist position, but not immediately, in case this OS is firing
// repeated move events as the user drags the window
SetPersistenceTimer(PAD_POSITION);
return false;
}
bool nsWebShellWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth,
int32_t aHeight) {
nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
if (shellAsWin) {
shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, 0);
}
// Persist size, but not immediately, in case this OS is firing
// repeated size events as the user drags the sizing handle
if (!IsLocked()) SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC);
return true;
}
bool nsWebShellWindow::RequestWindowClose(nsIWidget* aWidget) {
// Maintain a reference to this as it is about to get destroyed.
nsCOMPtr<nsIXULWindow> xulWindow(this);
nsCOMPtr<nsPIDOMWindowOuter> window(mDocShell ? mDocShell->GetWindow()
: nullptr);
nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window);
RefPtr<PresShell> presShell = mDocShell->GetPresShell();
if (!presShell) {
mozilla::DebugOnly<bool> dying;
MOZ_ASSERT(NS_SUCCEEDED(mDocShell->IsBeingDestroyed(&dying)) && dying,
"No presShell, but window is not being destroyed");
} else if (eventTarget) {
RefPtr<nsPresContext> presContext = presShell->GetPresContext();
nsEventStatus status = nsEventStatus_eIgnore;
WidgetMouseEvent event(true, eClose, nullptr, WidgetMouseEvent::eReal);
if (NS_SUCCEEDED(EventDispatcher::Dispatch(eventTarget, presContext, &event,
nullptr, &status)) &&
status == nsEventStatus_eConsumeNoDefault)
return false;
}
Destroy();
return false;
}
void nsWebShellWindow::SizeModeChanged(nsSizeMode sizeMode) {
// An alwaysRaised (or higher) window will hide any newly opened normal
// browser windows, so here we just drop a raised window to the normal
// zlevel if it's maximized. We make no provision for automatically
// re-raising it when restored.
if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) {
uint32_t zLevel;
GetZLevel(&zLevel);
if (zLevel > nsIXULWindow::normalZ) SetZLevel(nsIXULWindow::normalZ);
}
mWindow->SetSizeMode(sizeMode);
// Persist mode, but not immediately, because in many (all?)
// cases this will merge with the similar call in NS_SIZE and
// write the attribute values only once.
SetPersistenceTimer(PAD_MISC);
nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
mDocShell ? mDocShell->GetWindow() : nullptr;
if (ourWindow) {
// Ensure that the fullscreen state is synchronized between
// the widget and the outer window object.
if (sizeMode == nsSizeMode_Fullscreen) {
ourWindow->SetFullScreen(true);
} else if (sizeMode != nsSizeMode_Minimized) {
if (ourWindow->GetFullScreen()) {
// The first SetFullscreenInternal call below ensures that we do
// not trigger any fullscreen transition even if the window was
// put in fullscreen only for the Fullscreen API. The second
// SetFullScreen call ensures that the window really exit from
// fullscreen even if it entered fullscreen for both Fullscreen
// Mode and Fullscreen API.
ourWindow->SetFullscreenInternal(
FullscreenReason::ForForceExitFullscreen, false);
ourWindow->SetFullScreen(false);
}
}
// And always fire a user-defined sizemodechange event on the window
ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("sizemodechange"));
}
if (PresShell* presShell = GetPresShell()) {
presShell->GetPresContext()->SizeModeChanged(sizeMode);
}
// Note the current implementation of SetSizeMode just stores
// the new state; it doesn't actually resize. So here we store
// the state and pass the event on to the OS. The day is coming
// when we'll handle the event here, and the return result will
// then need to be different.
}
void nsWebShellWindow::UIResolutionChanged() {
nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
mDocShell ? mDocShell->GetWindow() : nullptr;
if (ourWindow) {
ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("resolutionchange"));
}
}
void nsWebShellWindow::FullscreenWillChange(bool aInFullscreen) {
if (mDocShell) {
if (nsCOMPtr<nsPIDOMWindowOuter> ourWindow = mDocShell->GetWindow()) {
ourWindow->FullscreenWillChange(aInFullscreen);
}
}
}
void nsWebShellWindow::FullscreenChanged(bool aInFullscreen) {
if (mDocShell) {
if (nsCOMPtr<nsPIDOMWindowOuter> ourWindow = mDocShell->GetWindow()) {
ourWindow->FinishFullscreenChange(aInFullscreen);
}
}
}
void nsWebShellWindow::OcclusionStateChanged(bool aIsFullyOccluded) {
nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
mDocShell ? mDocShell->GetWindow() : nullptr;
if (ourWindow) {
// And always fire a user-defined occlusionstatechange event on the window
ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("occlusionstatechange"));
}
}
void nsWebShellWindow::OSToolbarButtonPressed() {
// Keep a reference as setting the chrome flags can fire events.
nsCOMPtr<nsIXULWindow> xulWindow(this);
// rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA"
// due to components with multiple sidebar components
// (such as Mail/News, Addressbook, etc)... and frankly,
// Mac IE, OmniWeb, and other Mac OS X apps all work this way
uint32_t chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR |
nsIWebBrowserChrome::CHROME_LOCATIONBAR |
nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
nsCOMPtr<nsIWebBrowserChrome> wbc(do_GetInterface(xulWindow));
if (!wbc) return;
uint32_t chromeFlags, newChromeFlags = 0;
wbc->GetChromeFlags(&chromeFlags);
newChromeFlags = chromeFlags & chromeMask;
if (!newChromeFlags)
chromeFlags |= chromeMask;
else
chromeFlags &= (~newChromeFlags);
wbc->SetChromeFlags(chromeFlags);
}
bool nsWebShellWindow::ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow,
nsIWidget** aActualBelow) {
if (aActualBelow) *aActualBelow = nullptr;
return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow);
}
void nsWebShellWindow::WindowActivated() {
nsCOMPtr<nsIXULWindow> xulWindow(this);
// focusing the window could cause it to close, so keep a reference to it
nsCOMPtr<nsPIDOMWindowOuter> window =
mDocShell ? mDocShell->GetWindow() : nullptr;
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm && window) fm->WindowRaised(window);
if (mChromeLoaded) {
PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC);
SavePersistentAttributes();
}
}
void nsWebShellWindow::WindowDeactivated() {
nsCOMPtr<nsIXULWindow> xulWindow(this);
nsCOMPtr<nsPIDOMWindowOuter> window =
mDocShell ? mDocShell->GetWindow() : nullptr;
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm && window && !fm->IsTestMode()) fm->WindowLowered(window);
}
#ifdef USE_NATIVE_MENUS
static void LoadNativeMenus(Document* aDoc, nsIWidget* aParentWindow) {
if (gfxPlatform::IsHeadless()) {
return;
}
nsCOMPtr<nsINativeMenuService> nms =
do_GetService("@mozilla.org/widget/nativemenuservice;1");
if (!nms) {
return;
}
// Find the menubar tag (if there is more than one, we ignore all but
// the first).
nsCOMPtr<nsINodeList> menubarElements = aDoc->GetElementsByTagNameNS(
NS_LITERAL_STRING(
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"),
NS_LITERAL_STRING("menubar"));
nsCOMPtr<nsINode> menubarNode;
if (menubarElements) {
menubarNode = menubarElements->Item(0);
}
if (menubarNode) {
nsCOMPtr<Element> menubarContent(do_QueryInterface(menubarNode));
nms->CreateNativeMenuBar(aParentWindow, menubarContent);
} else {
nms->CreateNativeMenuBar(aParentWindow, nullptr);
}
}
#endif
namespace mozilla {
class WebShellWindowTimerCallback final : public nsITimerCallback,
public nsINamed {
public:
explicit WebShellWindowTimerCallback(nsWebShellWindow* aWindow)
: mWindow(aWindow) {}
NS_DECL_THREADSAFE_ISUPPORTS
NS_IMETHOD Notify(nsITimer* aTimer) override {
// Although this object participates in a refcount cycle (this -> mWindow
// -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this
// after it fires. So we don't need to release mWindow here.
mWindow->FirePersistenceTimer();
return NS_OK;
}
NS_IMETHOD GetName(nsACString& aName) override {
aName.AssignLiteral("WebShellWindowTimerCallback");
return NS_OK;
}
private:
~WebShellWindowTimerCallback() {}
RefPtr<nsWebShellWindow> mWindow;
};
NS_IMPL_ISUPPORTS(WebShellWindowTimerCallback, nsITimerCallback, nsINamed)
} // namespace mozilla
void nsWebShellWindow::SetPersistenceTimer(uint32_t aDirtyFlags) {
MutexAutoLock lock(mSPTimerLock);
if (!mSPTimer) {
mSPTimer = NS_NewTimer();
if (!mSPTimer) {
NS_WARNING("Couldn't create @mozilla.org/timer;1 instance?");
return;
}
}
RefPtr<WebShellWindowTimerCallback> callback =
new WebShellWindowTimerCallback(this);
mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT,
nsITimer::TYPE_ONE_SHOT);
PersistentAttributesDirty(aDirtyFlags);
}
void nsWebShellWindow::FirePersistenceTimer() {
MutexAutoLock lock(mSPTimerLock);
SavePersistentAttributes();
}
//----------------------------------------
// nsIWebProgessListener implementation
//----------------------------------------
NS_IMETHODIMP
nsWebShellWindow::OnProgressChange(nsIWebProgress* aProgress,
nsIRequest* aRequest,
int32_t aCurSelfProgress,
int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
int32_t aMaxTotalProgress) {
MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsWebShellWindow::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
uint32_t aStateFlags, nsresult aStatus) {
// If the notification is not about a document finishing, then just
// ignore it...
if (!(aStateFlags & nsIWebProgressListener::STATE_STOP) ||
!(aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)) {
return NS_OK;
}
if (mChromeLoaded) return NS_OK;
// If this document notification is for a frame then ignore it...
nsCOMPtr<mozIDOMWindowProxy> eventWin;
aProgress->GetDOMWindow(getter_AddRefs(eventWin));
auto* eventPWin = nsPIDOMWindowOuter::From(eventWin);
if (eventPWin) {
nsPIDOMWindowOuter* rootPWin = eventPWin->GetPrivateRoot();
if (eventPWin != rootPWin) return NS_OK;
}
mChromeLoaded = true;
mLockedUntilChromeLoad = false;
#ifdef USE_NATIVE_MENUS
///////////////////////////////
// Find the Menubar DOM and Load the menus, hooking them up to the loaded
// commands
///////////////////////////////
nsCOMPtr<nsIContentViewer> cv;
mDocShell->GetContentViewer(getter_AddRefs(cv));
if (cv) {
RefPtr<Document> menubarDoc = cv->GetDocument();
if (menubarDoc) LoadNativeMenus(menubarDoc, mWindow);
}
#endif // USE_NATIVE_MENUS
OnChromeLoaded();
return NS_OK;
}
NS_IMETHODIMP
nsWebShellWindow::OnLocationChange(nsIWebProgress* aProgress,
nsIRequest* aRequest, nsIURI* aURI,
uint32_t aFlags) {
MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsWebShellWindow::OnStatusChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, nsresult aStatus,
const char16_t* aMessage) {
MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsWebShellWindow::OnSecurityChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, uint32_t aState) {
MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsWebShellWindow::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aEvent) {
MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
return NS_OK;
}
/**
* ExecuteCloseHandler - Run the close handler, if any.
* @return true iff we found a close handler to run.
*/
bool nsWebShellWindow::ExecuteCloseHandler() {
/* If the event handler closes this window -- a likely scenario --
things get deleted out of order without this death grip.
(The problem may be the death grip in nsWindow::windowProc,
which forces this window's widget to remain alive longer
than it otherwise would.) */
nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
nsCOMPtr<EventTarget> eventTarget;
if (mDocShell) {
eventTarget = do_QueryInterface(mDocShell->GetWindow());
}
if (eventTarget) {
nsCOMPtr<nsIContentViewer> contentViewer;
mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
if (contentViewer) {
RefPtr<nsPresContext> presContext = contentViewer->GetPresContext();
nsEventStatus status = nsEventStatus_eIgnore;
WidgetMouseEvent event(true, eClose, nullptr, WidgetMouseEvent::eReal);
nsresult rv = EventDispatcher::Dispatch(eventTarget, presContext, &event,
nullptr, &status);
if (NS_SUCCEEDED(rv) && status == nsEventStatus_eConsumeNoDefault)
return true;
// else fall through and return false
}
}
return false;
} // ExecuteCloseHandler
void nsWebShellWindow::ConstrainToOpenerScreen(int32_t* aX, int32_t* aY) {
if (mOpenerScreenRect.IsEmpty()) {
*aX = *aY = 0;
return;
}
int32_t left, top, width, height;
// Constrain initial positions to the same screen as opener
nsCOMPtr<nsIScreenManager> screenmgr =
do_GetService("@mozilla.org/gfx/screenmanager;1");
if (screenmgr) {
nsCOMPtr<nsIScreen> screen;
screenmgr->ScreenForRect(
mOpenerScreenRect.X(), mOpenerScreenRect.Y(), mOpenerScreenRect.Width(),
mOpenerScreenRect.Height(), getter_AddRefs(screen));
if (screen) {
screen->GetAvailRectDisplayPix(&left, &top, &width, &height);
if (*aX < left || *aX > left + width) {
*aX = left;
}
if (*aY < top || *aY > top + height) {
*aY = top;
}
}
}
}
// nsIBaseWindow
NS_IMETHODIMP nsWebShellWindow::Destroy() {
nsresult rv;
nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
if (webProgress) {
webProgress->RemoveProgressListener(this);
}
nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
{
MutexAutoLock lock(mSPTimerLock);
if (mSPTimer) {
mSPTimer->Cancel();
SavePersistentAttributes();
mSPTimer = nullptr;
}
}
return nsXULWindow::Destroy();
}
nsIXULWindow* nsWebShellWindow::WidgetListenerDelegate::GetXULWindow() {
return mWebShellWindow->GetXULWindow();
}
PresShell* nsWebShellWindow::WidgetListenerDelegate::GetPresShell() {
return mWebShellWindow->GetPresShell();
}
bool nsWebShellWindow::WidgetListenerDelegate::WindowMoved(nsIWidget* aWidget,
int32_t aX,
int32_t aY) {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
return holder->WindowMoved(aWidget, aX, aY);
}
bool nsWebShellWindow::WidgetListenerDelegate::WindowResized(nsIWidget* aWidget,
int32_t aWidth,
int32_t aHeight) {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
return holder->WindowResized(aWidget, aWidth, aHeight);
}
bool nsWebShellWindow::WidgetListenerDelegate::RequestWindowClose(
nsIWidget* aWidget) {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
return holder->RequestWindowClose(aWidget);
}
void nsWebShellWindow::WidgetListenerDelegate::SizeModeChanged(
nsSizeMode aSizeMode) {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
holder->SizeModeChanged(aSizeMode);
}
void nsWebShellWindow::WidgetListenerDelegate::UIResolutionChanged() {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
holder->UIResolutionChanged();
}
void nsWebShellWindow::WidgetListenerDelegate::FullscreenWillChange(
bool aInFullscreen) {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
holder->FullscreenWillChange(aInFullscreen);
}
void nsWebShellWindow::WidgetListenerDelegate::FullscreenChanged(
bool aInFullscreen) {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
holder->FullscreenChanged(aInFullscreen);
}
void nsWebShellWindow::WidgetListenerDelegate::OcclusionStateChanged(
bool aIsFullyOccluded) {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
holder->OcclusionStateChanged(aIsFullyOccluded);
}
void nsWebShellWindow::WidgetListenerDelegate::OSToolbarButtonPressed() {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
holder->OSToolbarButtonPressed();
}
bool nsWebShellWindow::WidgetListenerDelegate::ZLevelChanged(
bool aImmediate, nsWindowZ* aPlacement, nsIWidget* aRequestBelow,
nsIWidget** aActualBelow) {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
return holder->ZLevelChanged(aImmediate, aPlacement, aRequestBelow,
aActualBelow);
}
void nsWebShellWindow::WidgetListenerDelegate::WindowActivated() {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
holder->WindowActivated();
}
void nsWebShellWindow::WidgetListenerDelegate::WindowDeactivated() {
RefPtr<nsWebShellWindow> holder = mWebShellWindow;
holder->WindowDeactivated();
}

Просмотреть файл

@ -1,133 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsWebShellWindow_h__
#define nsWebShellWindow_h__
#include "mozilla/Mutex.h"
#include "nsIWebProgressListener.h"
#include "nsITimer.h"
#include "nsCOMPtr.h"
#include "nsXULWindow.h"
#include "nsIWidgetListener.h"
#include "nsIRemoteTab.h"
/* Forward declarations.... */
class nsIURI;
struct nsWidgetInitData;
namespace mozilla {
class PresShell;
class WebShellWindowTimerCallback;
} // namespace mozilla
class nsWebShellWindow final : public nsXULWindow,
public nsIWebProgressListener {
public:
// The implementation of non-refcounted nsIWidgetListener, which would hold a
// strong reference on stack before calling nsWebShellWindow's
// MOZ_CAN_RUN_SCRIPT methods.
class WidgetListenerDelegate : public nsIWidgetListener {
public:
explicit WidgetListenerDelegate(nsWebShellWindow* aWebShellWindow)
: mWebShellWindow(aWebShellWindow) {}
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual nsIXULWindow* GetXULWindow() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual mozilla::PresShell* GetPresShell() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool WindowResized(nsIWidget* aWidget, int32_t aWidth,
int32_t aHeight) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool RequestWindowClose(nsIWidget* aWidget) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void SizeModeChanged(nsSizeMode sizeMode) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void UIResolutionChanged() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void FullscreenWillChange(bool aInFullscreen) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void FullscreenChanged(bool aInFullscreen) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void OcclusionStateChanged(bool aIsFullyOccluded) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void OSToolbarButtonPressed() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow,
nsIWidget** aActualBelow) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void WindowActivated() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void WindowDeactivated() override;
private:
// The lifetime of WidgetListenerDelegate is bound to nsWebShellWindow so
// we just use a raw pointer here.
nsWebShellWindow* mWebShellWindow;
};
explicit nsWebShellWindow(uint32_t aChromeFlags);
// nsISupports interface...
NS_DECL_ISUPPORTS_INHERITED
// nsWebShellWindow methods...
nsresult Initialize(nsIXULWindow* aParent, nsIXULWindow* aOpener,
nsIURI* aUrl, int32_t aInitialWidth,
int32_t aInitialHeight, bool aIsHiddenWindow,
nsIRemoteTab* aOpeningTab,
mozIDOMWindowProxy* aOpenerWIndow,
nsWidgetInitData& widgetInitData);
nsresult Toolbar();
// nsIWebProgressListener
NS_DECL_NSIWEBPROGRESSLISTENER
// nsIBaseWindow
NS_IMETHOD Destroy() override;
// nsIWidgetListener methods for WidgetListenerDelegate.
nsIXULWindow* GetXULWindow() { return this; }
mozilla::PresShell* GetPresShell();
MOZ_CAN_RUN_SCRIPT
bool WindowMoved(nsIWidget* aWidget, int32_t aX, int32_t aY);
MOZ_CAN_RUN_SCRIPT
bool WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight);
MOZ_CAN_RUN_SCRIPT bool RequestWindowClose(nsIWidget* aWidget);
MOZ_CAN_RUN_SCRIPT void SizeModeChanged(nsSizeMode aSizeMode);
MOZ_CAN_RUN_SCRIPT void UIResolutionChanged();
MOZ_CAN_RUN_SCRIPT void FullscreenWillChange(bool aInFullscreen);
MOZ_CAN_RUN_SCRIPT void FullscreenChanged(bool aInFullscreen);
MOZ_CAN_RUN_SCRIPT void OcclusionStateChanged(bool aIsFullyOccluded);
MOZ_CAN_RUN_SCRIPT void OSToolbarButtonPressed();
MOZ_CAN_RUN_SCRIPT
bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow, nsIWidget** aActualBelow);
MOZ_CAN_RUN_SCRIPT void WindowActivated();
MOZ_CAN_RUN_SCRIPT void WindowDeactivated();
protected:
friend class mozilla::WebShellWindowTimerCallback;
virtual ~nsWebShellWindow();
bool ExecuteCloseHandler();
void ConstrainToOpenerScreen(int32_t* aX, int32_t* aY);
nsCOMPtr<nsITimer> mSPTimer;
mozilla::Mutex mSPTimerLock;
WidgetListenerDelegate mWidgetListenerDelegate;
void SetPersistenceTimer(uint32_t aDirtyFlags);
void FirePersistenceTimer();
};
#endif /* nsWebShellWindow_h__ */

Просмотреть файл

@ -46,9 +46,11 @@
#include "nsStyleConsts.h"
#include "nsPresContext.h"
#include "nsContentUtils.h"
#include "nsWebShellWindow.h" // get rid of this one, too...
#include "nsGlobalWindow.h"
#include "nsXULTooltipListener.h"
#include "nsXULPopupManager.h"
#include "nsFocusManager.h"
#include "nsContentList.h"
#include "prenv.h"
#include "mozilla/AutoRestore.h"
@ -60,13 +62,25 @@
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/BrowserHost.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/LoadURIOptionsBinding.h"
#include "mozilla/EventDispatcher.h"
#ifdef MOZ_NEW_XULSTORE
# include "mozilla/XULStore.h"
#endif
#ifdef XP_MACOSX
# include "nsINativeMenuService.h"
# define USE_NATIVE_MENUS
#endif
using namespace mozilla;
using dom::AutoNoJSAPI;
using dom::BrowserHost;
using dom::BrowsingContext;
using dom::Document;
using dom::EventTarget;
using dom::LoadURIOptions;
#define SIZEMODE_NORMAL NS_LITERAL_STRING("normal")
#define SIZEMODE_MAXIMIZED NS_LITERAL_STRING("maximized")
@ -84,6 +98,8 @@ using dom::AutoNoJSAPI;
#define TILED_ATTRIBUTE NS_LITERAL_STRING("gtktiledwindow")
#define ZLEVEL_ATTRIBUTE NS_LITERAL_STRING("zlevel")
#define SIZE_PERSISTENCE_TIMEOUT 500 // msec
//*****************************************************************************
//*** nsXULWindow: Object Management
//*****************************************************************************
@ -111,9 +127,17 @@ nsXULWindow::nsXULWindow(uint32_t aChromeFlags)
mPersistentAttributesDirty(0),
mPersistentAttributesMask(0),
mChromeFlags(aChromeFlags),
mNextRemoteTabId(0) {}
mNextRemoteTabId(0),
mSPTimerLock("nsXULWindow.mSPTimerLock"),
mWidgetListenerDelegate(this) {}
nsXULWindow::~nsXULWindow() { Destroy(); }
nsXULWindow::~nsXULWindow() {
{
MutexAutoLock lock(mSPTimerLock);
if (mSPTimer) mSPTimer->Cancel();
}
Destroy();
}
//*****************************************************************************
// nsXULWindow::nsISupports
@ -128,9 +152,178 @@ NS_INTERFACE_MAP_BEGIN(nsXULWindow)
NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
NS_INTERFACE_MAP_ENTRY_CONCRETE(nsXULWindow)
NS_INTERFACE_MAP_END
nsresult nsXULWindow::Initialize(nsIXULWindow* aParent, nsIXULWindow* aOpener,
nsIURI* aUrl, int32_t aInitialWidth,
int32_t aInitialHeight, bool aIsHiddenWindow,
nsIRemoteTab* aOpeningTab,
mozIDOMWindowProxy* aOpenerWindow,
nsWidgetInitData& widgetInitData) {
nsresult rv;
nsCOMPtr<nsIWidget> parentWidget;
mIsHiddenWindow = aIsHiddenWindow;
int32_t initialX = 0, initialY = 0;
nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(aOpener));
if (base) {
int32_t x, y, width, height;
rv = base->GetPositionAndSize(&x, &y, &width, &height);
if (NS_FAILED(rv)) {
mOpenerScreenRect.SetEmpty();
} else {
double scale;
if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) {
mOpenerScreenRect.SetRect(
NSToIntRound(x / scale), NSToIntRound(y / scale),
NSToIntRound(width / scale), NSToIntRound(height / scale));
} else {
mOpenerScreenRect.SetRect(x, y, width, height);
}
initialX = mOpenerScreenRect.X();
initialY = mOpenerScreenRect.Y();
ConstrainToOpenerScreen(&initialX, &initialY);
}
}
// XXX: need to get the default window size from prefs...
// Doesn't come from prefs... will come from CSS/XUL/RDF
DesktopIntRect deskRect(initialX, initialY, aInitialWidth, aInitialHeight);
// Create top level window
if (gfxPlatform::IsHeadless()) {
mWindow = nsIWidget::CreateHeadlessWidget();
} else {
mWindow = nsIWidget::CreateTopLevelWindow();
}
if (!mWindow) {
return NS_ERROR_FAILURE;
}
/* This next bit is troublesome. We carry two different versions of a pointer
to our parent window. One is the parent window's widget, which is passed
to our own widget. The other is a weak reference we keep here to our
parent nsXULWindow. The former is useful to the widget, and we can't
trust its treatment of the parent reference because they're platform-
specific. The latter is useful to this class.
A better implementation would be one in which the parent keeps strong
references to its children and closes them before it allows itself
to be closed. This would mimic the behaviour of OSes that support
top-level child windows in OSes that do not. Later.
*/
nsCOMPtr<nsIBaseWindow> parentAsWin(do_QueryInterface(aParent));
if (parentAsWin) {
parentAsWin->GetMainWidget(getter_AddRefs(parentWidget));
mParentWindow = do_GetWeakReference(aParent);
}
mWindow->SetWidgetListener(&mWidgetListenerDelegate);
rv = mWindow->Create((nsIWidget*)parentWidget, // Parent nsIWidget
nullptr, // Native parent widget
deskRect, // Widget dimensions
&widgetInitData); // Widget initialization data
NS_ENSURE_SUCCESS(rv, rv);
LayoutDeviceIntRect r = mWindow->GetClientBounds();
// Match the default background color of content. Important on windows
// since we no longer use content child widgets.
mWindow->SetBackgroundColor(NS_RGB(255, 255, 255));
// Create web shell
RefPtr<BrowsingContext> openerContext =
aOpenerWindow
? nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext()
: nullptr;
RefPtr<BrowsingContext> browsingContext =
BrowsingContext::Create(/* aParent */ nullptr, openerContext,
EmptyString(), BrowsingContext::Type::Chrome);
mDocShell = nsDocShell::Create(browsingContext);
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
// XXX(nika): This is used to handle propagating opener across remote tab
// creation. We should come up with a better system for doing this (probably
// based on BrowsingContext).
mDocShell->SetOpener(aOpeningTab);
// Make sure to set the item type on the docshell _before_ calling
// Create() so it knows what type it is.
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(mDocShell);
NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE);
docShellAsItem->SetTreeOwner(mChromeTreeOwner);
r.MoveTo(0, 0);
nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
NS_ENSURE_SUCCESS(docShellAsWin->InitWindow(nullptr, mWindow, r.X(), r.Y(),
r.Width(), r.Height()),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(docShellAsWin->Create(), NS_ERROR_FAILURE);
// Attach a WebProgress listener.during initialization...
nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
if (webProgress) {
webProgress->AddProgressListener(this,
nsIWebProgress::NOTIFY_STATE_NETWORK);
}
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
if (aOpenerWindow) {
BrowsingContext* bc = mDocShell->GetBrowsingContext();
BrowsingContext* openerBC =
nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext();
MOZ_DIAGNOSTIC_ASSERT(bc->GetOpenerId() == openerBC->Id());
MOZ_DIAGNOSTIC_ASSERT(bc->HadOriginalOpener());
}
#endif
// Eagerly create an about:blank content viewer with the right principal here,
// rather than letting it happening in the upcoming call to
// SetInitialPrincipalToSubject. This avoids creating the about:blank document
// and then blowing it away with a second one, which can cause problems for
// the top-level chrome window case. See bug 789773. Note that we don't accept
// expanded principals here, similar to SetInitialPrincipalToSubject.
if (nsContentUtils::IsInitialized()) { // Sometimes this happens really early
// See bug 793370.
MOZ_ASSERT(mDocShell->ItemType() == nsIDocShellTreeItem::typeChrome);
nsCOMPtr<nsIPrincipal> principal =
nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
if (nsContentUtils::IsExpandedPrincipal(principal)) {
principal = nullptr;
}
// Use the subject (or system) principal as the storage principal too until
// the new window finishes navigating and gets a real storage principal.
rv = mDocShell->CreateAboutBlankContentViewer(principal, principal,
/* aCsp = */ nullptr);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<Document> doc = mDocShell->GetDocument();
NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE);
doc->SetIsInitialDocument(true);
}
if (nullptr != aUrl) {
nsCString tmpStr;
rv = aUrl->GetSpec(tmpStr);
if (NS_FAILED(rv)) return rv;
NS_ConvertUTF8toUTF16 urlString(tmpStr);
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
LoadURIOptions loadURIOptions;
loadURIOptions.mTriggeringPrincipal = nsContentUtils::GetSystemPrincipal();
rv = webNav->LoadURI(urlString, loadURIOptions);
NS_ENSURE_SUCCESS(rv, rv);
}
return rv;
}
//*****************************************************************************
// nsXULWindow::nsIIntefaceRequestor
//*****************************************************************************
@ -421,6 +614,22 @@ NS_IMETHODIMP nsXULWindow::Create() {
}
NS_IMETHODIMP nsXULWindow::Destroy() {
nsresult rv;
nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
if (webProgress) {
webProgress->RemoveProgressListener(this);
}
nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
{
MutexAutoLock lock(mSPTimerLock);
if (mSPTimer) {
mSPTimer->Cancel();
SavePersistentAttributes();
mSPTimer = nullptr;
}
}
if (!mWindow) return NS_OK;
// Ensure we don't reenter this code
@ -2496,3 +2705,530 @@ nsresult nsXULWindow::GetNextRemoteTabId(uint64_t* aNextRemoteTabId) {
*aNextRemoteTabId = mNextRemoteTabId;
return NS_OK;
}
PresShell* nsXULWindow::GetPresShell() {
if (!mDocShell) {
return nullptr;
}
return mDocShell->GetPresShell();
}
bool nsXULWindow::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) {
nsCOMPtr<nsPIDOMWindowOuter> window =
mDocShell ? mDocShell->GetWindow() : nullptr;
pm->AdjustPopupsOnWindowChange(window);
}
// Notify all tabs that the widget moved.
if (mDocShell && mDocShell->GetWindow()) {
nsCOMPtr<EventTarget> eventTarget =
mDocShell->GetWindow()->GetTopWindowRoot();
nsContentUtils::DispatchChromeEvent(mDocShell->GetDocument(), eventTarget,
NS_LITERAL_STRING("MozUpdateWindowPos"),
CanBubble::eNo, Cancelable::eNo,
nullptr);
}
// Persist position, but not immediately, in case this OS is firing
// repeated move events as the user drags the window
SetPersistenceTimer(PAD_POSITION);
return false;
}
bool nsXULWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth,
int32_t aHeight) {
nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
if (shellAsWin) {
shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, 0);
}
// Persist size, but not immediately, in case this OS is firing
// repeated size events as the user drags the sizing handle
if (!IsLocked()) SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC);
return true;
}
bool nsXULWindow::RequestWindowClose(nsIWidget* aWidget) {
// Maintain a reference to this as it is about to get destroyed.
nsCOMPtr<nsIXULWindow> xulWindow(this);
nsCOMPtr<nsPIDOMWindowOuter> window(mDocShell ? mDocShell->GetWindow()
: nullptr);
nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window);
RefPtr<PresShell> presShell = mDocShell->GetPresShell();
if (!presShell) {
mozilla::DebugOnly<bool> dying;
MOZ_ASSERT(NS_SUCCEEDED(mDocShell->IsBeingDestroyed(&dying)) && dying,
"No presShell, but window is not being destroyed");
} else if (eventTarget) {
RefPtr<nsPresContext> presContext = presShell->GetPresContext();
nsEventStatus status = nsEventStatus_eIgnore;
WidgetMouseEvent event(true, eClose, nullptr, WidgetMouseEvent::eReal);
if (NS_SUCCEEDED(EventDispatcher::Dispatch(eventTarget, presContext, &event,
nullptr, &status)) &&
status == nsEventStatus_eConsumeNoDefault)
return false;
}
Destroy();
return false;
}
void nsXULWindow::SizeModeChanged(nsSizeMode sizeMode) {
// An alwaysRaised (or higher) window will hide any newly opened normal
// browser windows, so here we just drop a raised window to the normal
// zlevel if it's maximized. We make no provision for automatically
// re-raising it when restored.
if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) {
uint32_t zLevel;
GetZLevel(&zLevel);
if (zLevel > nsIXULWindow::normalZ) SetZLevel(nsIXULWindow::normalZ);
}
mWindow->SetSizeMode(sizeMode);
// Persist mode, but not immediately, because in many (all?)
// cases this will merge with the similar call in NS_SIZE and
// write the attribute values only once.
SetPersistenceTimer(PAD_MISC);
nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
mDocShell ? mDocShell->GetWindow() : nullptr;
if (ourWindow) {
// Ensure that the fullscreen state is synchronized between
// the widget and the outer window object.
if (sizeMode == nsSizeMode_Fullscreen) {
ourWindow->SetFullScreen(true);
} else if (sizeMode != nsSizeMode_Minimized) {
if (ourWindow->GetFullScreen()) {
// The first SetFullscreenInternal call below ensures that we do
// not trigger any fullscreen transition even if the window was
// put in fullscreen only for the Fullscreen API. The second
// SetFullScreen call ensures that the window really exit from
// fullscreen even if it entered fullscreen for both Fullscreen
// Mode and Fullscreen API.
ourWindow->SetFullscreenInternal(
FullscreenReason::ForForceExitFullscreen, false);
ourWindow->SetFullScreen(false);
}
}
// And always fire a user-defined sizemodechange event on the window
ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("sizemodechange"));
}
if (PresShell* presShell = GetPresShell()) {
presShell->GetPresContext()->SizeModeChanged(sizeMode);
}
// Note the current implementation of SetSizeMode just stores
// the new state; it doesn't actually resize. So here we store
// the state and pass the event on to the OS. The day is coming
// when we'll handle the event here, and the return result will
// then need to be different.
}
void nsXULWindow::UIResolutionChanged() {
nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
mDocShell ? mDocShell->GetWindow() : nullptr;
if (ourWindow) {
ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("resolutionchange"));
}
}
void nsXULWindow::FullscreenWillChange(bool aInFullscreen) {
if (mDocShell) {
if (nsCOMPtr<nsPIDOMWindowOuter> ourWindow = mDocShell->GetWindow()) {
ourWindow->FullscreenWillChange(aInFullscreen);
}
}
}
void nsXULWindow::FullscreenChanged(bool aInFullscreen) {
if (mDocShell) {
if (nsCOMPtr<nsPIDOMWindowOuter> ourWindow = mDocShell->GetWindow()) {
ourWindow->FinishFullscreenChange(aInFullscreen);
}
}
}
void nsXULWindow::OcclusionStateChanged(bool aIsFullyOccluded) {
nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
mDocShell ? mDocShell->GetWindow() : nullptr;
if (ourWindow) {
// And always fire a user-defined occlusionstatechange event on the window
ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("occlusionstatechange"));
}
}
void nsXULWindow::OSToolbarButtonPressed() {
// Keep a reference as setting the chrome flags can fire events.
nsCOMPtr<nsIXULWindow> xulWindow(this);
// rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA"
// due to components with multiple sidebar components
// (such as Mail/News, Addressbook, etc)... and frankly,
// Mac IE, OmniWeb, and other Mac OS X apps all work this way
uint32_t chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR |
nsIWebBrowserChrome::CHROME_LOCATIONBAR |
nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
nsCOMPtr<nsIWebBrowserChrome> wbc(do_GetInterface(xulWindow));
if (!wbc) return;
uint32_t chromeFlags, newChromeFlags = 0;
wbc->GetChromeFlags(&chromeFlags);
newChromeFlags = chromeFlags & chromeMask;
if (!newChromeFlags)
chromeFlags |= chromeMask;
else
chromeFlags &= (~newChromeFlags);
wbc->SetChromeFlags(chromeFlags);
}
bool nsXULWindow::ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow,
nsIWidget** aActualBelow) {
if (aActualBelow) *aActualBelow = nullptr;
return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow);
}
void nsXULWindow::WindowActivated() {
nsCOMPtr<nsIXULWindow> xulWindow(this);
// focusing the window could cause it to close, so keep a reference to it
nsCOMPtr<nsPIDOMWindowOuter> window =
mDocShell ? mDocShell->GetWindow() : nullptr;
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm && window) fm->WindowRaised(window);
if (mChromeLoaded) {
PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC);
SavePersistentAttributes();
}
}
void nsXULWindow::WindowDeactivated() {
nsCOMPtr<nsIXULWindow> xulWindow(this);
nsCOMPtr<nsPIDOMWindowOuter> window =
mDocShell ? mDocShell->GetWindow() : nullptr;
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm && window && !fm->IsTestMode()) fm->WindowLowered(window);
}
#ifdef USE_NATIVE_MENUS
static void LoadNativeMenus(Document* aDoc, nsIWidget* aParentWindow) {
if (gfxPlatform::IsHeadless()) {
return;
}
nsCOMPtr<nsINativeMenuService> nms =
do_GetService("@mozilla.org/widget/nativemenuservice;1");
if (!nms) {
return;
}
// Find the menubar tag (if there is more than one, we ignore all but
// the first).
nsCOMPtr<nsINodeList> menubarElements = aDoc->GetElementsByTagNameNS(
NS_LITERAL_STRING(
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"),
NS_LITERAL_STRING("menubar"));
nsCOMPtr<nsINode> menubarNode;
if (menubarElements) {
menubarNode = menubarElements->Item(0);
}
if (menubarNode) {
nsCOMPtr<Element> menubarContent(do_QueryInterface(menubarNode));
nms->CreateNativeMenuBar(aParentWindow, menubarContent);
} else {
nms->CreateNativeMenuBar(aParentWindow, nullptr);
}
}
#endif
namespace mozilla {
class nsXULWindowTimerCallback final : public nsITimerCallback,
public nsINamed {
public:
explicit nsXULWindowTimerCallback(nsXULWindow* aWindow) : mWindow(aWindow) {}
NS_DECL_THREADSAFE_ISUPPORTS
NS_IMETHOD Notify(nsITimer* aTimer) override {
// Although this object participates in a refcount cycle (this -> mWindow
// -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this
// after it fires. So we don't need to release mWindow here.
mWindow->FirePersistenceTimer();
return NS_OK;
}
NS_IMETHOD GetName(nsACString& aName) override {
aName.AssignLiteral("nsXULWindowTimerCallback");
return NS_OK;
}
private:
~nsXULWindowTimerCallback() {}
RefPtr<nsXULWindow> mWindow;
};
NS_IMPL_ISUPPORTS(nsXULWindowTimerCallback, nsITimerCallback, nsINamed)
} // namespace mozilla
void nsXULWindow::SetPersistenceTimer(uint32_t aDirtyFlags) {
MutexAutoLock lock(mSPTimerLock);
if (!mSPTimer) {
mSPTimer = NS_NewTimer();
if (!mSPTimer) {
NS_WARNING("Couldn't create @mozilla.org/timer;1 instance?");
return;
}
}
RefPtr<nsXULWindowTimerCallback> callback =
new nsXULWindowTimerCallback(this);
mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT,
nsITimer::TYPE_ONE_SHOT);
PersistentAttributesDirty(aDirtyFlags);
}
void nsXULWindow::FirePersistenceTimer() {
MutexAutoLock lock(mSPTimerLock);
SavePersistentAttributes();
}
//----------------------------------------
// nsIWebProgessListener implementation
//----------------------------------------
NS_IMETHODIMP
nsXULWindow::OnProgressChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
int32_t aCurSelfProgress,
int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
int32_t aMaxTotalProgress) {
MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsXULWindow::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
uint32_t aStateFlags, nsresult aStatus) {
// If the notification is not about a document finishing, then just
// ignore it...
if (!(aStateFlags & nsIWebProgressListener::STATE_STOP) ||
!(aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)) {
return NS_OK;
}
if (mChromeLoaded) return NS_OK;
// If this document notification is for a frame then ignore it...
nsCOMPtr<mozIDOMWindowProxy> eventWin;
aProgress->GetDOMWindow(getter_AddRefs(eventWin));
auto* eventPWin = nsPIDOMWindowOuter::From(eventWin);
if (eventPWin) {
nsPIDOMWindowOuter* rootPWin = eventPWin->GetPrivateRoot();
if (eventPWin != rootPWin) return NS_OK;
}
mChromeLoaded = true;
mLockedUntilChromeLoad = false;
#ifdef USE_NATIVE_MENUS
///////////////////////////////
// Find the Menubar DOM and Load the menus, hooking them up to the loaded
// commands
///////////////////////////////
nsCOMPtr<nsIContentViewer> cv;
mDocShell->GetContentViewer(getter_AddRefs(cv));
if (cv) {
RefPtr<Document> menubarDoc = cv->GetDocument();
if (menubarDoc) LoadNativeMenus(menubarDoc, mWindow);
}
#endif // USE_NATIVE_MENUS
OnChromeLoaded();
return NS_OK;
}
NS_IMETHODIMP
nsXULWindow::OnLocationChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
nsIURI* aURI, uint32_t aFlags) {
MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsXULWindow::OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
nsresult aStatus, const char16_t* aMessage) {
MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsXULWindow::OnSecurityChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, uint32_t aState) {
MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsXULWindow::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, uint32_t aEvent) {
MOZ_ASSERT_UNREACHABLE("notification excluded in AddProgressListener(...)");
return NS_OK;
}
/**
* ExecuteCloseHandler - Run the close handler, if any.
* @return true iff we found a close handler to run.
*/
bool nsXULWindow::ExecuteCloseHandler() {
/* If the event handler closes this window -- a likely scenario --
things get deleted out of order without this death grip.
(The problem may be the death grip in nsWindow::windowProc,
which forces this window's widget to remain alive longer
than it otherwise would.) */
nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
nsCOMPtr<EventTarget> eventTarget;
if (mDocShell) {
eventTarget = do_QueryInterface(mDocShell->GetWindow());
}
if (eventTarget) {
nsCOMPtr<nsIContentViewer> contentViewer;
mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
if (contentViewer) {
RefPtr<nsPresContext> presContext = contentViewer->GetPresContext();
nsEventStatus status = nsEventStatus_eIgnore;
WidgetMouseEvent event(true, eClose, nullptr, WidgetMouseEvent::eReal);
nsresult rv = EventDispatcher::Dispatch(eventTarget, presContext, &event,
nullptr, &status);
if (NS_SUCCEEDED(rv) && status == nsEventStatus_eConsumeNoDefault)
return true;
// else fall through and return false
}
}
return false;
} // ExecuteCloseHandler
void nsXULWindow::ConstrainToOpenerScreen(int32_t* aX, int32_t* aY) {
if (mOpenerScreenRect.IsEmpty()) {
*aX = *aY = 0;
return;
}
int32_t left, top, width, height;
// Constrain initial positions to the same screen as opener
nsCOMPtr<nsIScreenManager> screenmgr =
do_GetService("@mozilla.org/gfx/screenmanager;1");
if (screenmgr) {
nsCOMPtr<nsIScreen> screen;
screenmgr->ScreenForRect(
mOpenerScreenRect.X(), mOpenerScreenRect.Y(), mOpenerScreenRect.Width(),
mOpenerScreenRect.Height(), getter_AddRefs(screen));
if (screen) {
screen->GetAvailRectDisplayPix(&left, &top, &width, &height);
if (*aX < left || *aX > left + width) {
*aX = left;
}
if (*aY < top || *aY > top + height) {
*aY = top;
}
}
}
}
nsIXULWindow* nsXULWindow::WidgetListenerDelegate::GetXULWindow() {
return mXULWindow->GetXULWindow();
}
PresShell* nsXULWindow::WidgetListenerDelegate::GetPresShell() {
return mXULWindow->GetPresShell();
}
bool nsXULWindow::WidgetListenerDelegate::WindowMoved(nsIWidget* aWidget,
int32_t aX, int32_t aY) {
RefPtr<nsXULWindow> holder = mXULWindow;
return holder->WindowMoved(aWidget, aX, aY);
}
bool nsXULWindow::WidgetListenerDelegate::WindowResized(nsIWidget* aWidget,
int32_t aWidth,
int32_t aHeight) {
RefPtr<nsXULWindow> holder = mXULWindow;
return holder->WindowResized(aWidget, aWidth, aHeight);
}
bool nsXULWindow::WidgetListenerDelegate::RequestWindowClose(
nsIWidget* aWidget) {
RefPtr<nsXULWindow> holder = mXULWindow;
return holder->RequestWindowClose(aWidget);
}
void nsXULWindow::WidgetListenerDelegate::SizeModeChanged(
nsSizeMode aSizeMode) {
RefPtr<nsXULWindow> holder = mXULWindow;
holder->SizeModeChanged(aSizeMode);
}
void nsXULWindow::WidgetListenerDelegate::UIResolutionChanged() {
RefPtr<nsXULWindow> holder = mXULWindow;
holder->UIResolutionChanged();
}
void nsXULWindow::WidgetListenerDelegate::FullscreenWillChange(
bool aInFullscreen) {
RefPtr<nsXULWindow> holder = mXULWindow;
holder->FullscreenWillChange(aInFullscreen);
}
void nsXULWindow::WidgetListenerDelegate::FullscreenChanged(
bool aInFullscreen) {
RefPtr<nsXULWindow> holder = mXULWindow;
holder->FullscreenChanged(aInFullscreen);
}
void nsXULWindow::WidgetListenerDelegate::OcclusionStateChanged(
bool aIsFullyOccluded) {
RefPtr<nsXULWindow> holder = mXULWindow;
holder->OcclusionStateChanged(aIsFullyOccluded);
}
void nsXULWindow::WidgetListenerDelegate::OSToolbarButtonPressed() {
RefPtr<nsXULWindow> holder = mXULWindow;
holder->OSToolbarButtonPressed();
}
bool nsXULWindow::WidgetListenerDelegate::ZLevelChanged(
bool aImmediate, nsWindowZ* aPlacement, nsIWidget* aRequestBelow,
nsIWidget** aActualBelow) {
RefPtr<nsXULWindow> holder = mXULWindow;
return holder->ZLevelChanged(aImmediate, aPlacement, aRequestBelow,
aActualBelow);
}
void nsXULWindow::WidgetListenerDelegate::WindowActivated() {
RefPtr<nsXULWindow> holder = mXULWindow;
holder->WindowActivated();
}
void nsXULWindow::WidgetListenerDelegate::WindowDeactivated() {
RefPtr<nsXULWindow> holder = mXULWindow;
holder->WindowDeactivated();
}

Просмотреть файл

@ -19,6 +19,7 @@
#include "nsCOMArray.h"
#include "nsRect.h"
#include "Units.h"
#include "mozilla/Mutex.h"
// Interfaces needed
#include "nsIBaseWindow.h"
@ -32,6 +33,8 @@
#include "nsIXULBrowserWindow.h"
#include "nsIWidgetListener.h"
#include "nsIRemoteTab.h"
#include "nsIWebProgressListener.h"
#include "nsITimer.h"
#ifndef MOZ_NEW_XULSTORE
# include "nsIXULStore.h"
@ -45,6 +48,12 @@ class Element;
class nsAtom;
class nsXULTooltipListener;
struct nsWidgetInitData;
namespace mozilla {
class PresShell;
class nsXULWindowTimerCallback;
} // namespace mozilla
// nsXULWindow
@ -57,14 +66,61 @@ class nsXULTooltipListener;
class nsContentShellInfo;
class nsXULWindow : public nsIBaseWindow,
public nsIInterfaceRequestor,
public nsIXULWindow,
public nsSupportsWeakReference {
class nsXULWindow final : public nsIBaseWindow,
public nsIInterfaceRequestor,
public nsIXULWindow,
public nsSupportsWeakReference,
public nsIWebProgressListener {
friend class nsChromeTreeOwner;
friend class nsContentTreeOwner;
public:
// The implementation of non-refcounted nsIWidgetListener, which would hold a
// strong reference on stack before calling nsXULWindow's
// MOZ_CAN_RUN_SCRIPT methods.
class WidgetListenerDelegate : public nsIWidgetListener {
public:
explicit WidgetListenerDelegate(nsXULWindow* aXULWindow)
: mXULWindow(aXULWindow) {}
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual nsIXULWindow* GetXULWindow() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual mozilla::PresShell* GetPresShell() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool WindowResized(nsIWidget* aWidget, int32_t aWidth,
int32_t aHeight) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool RequestWindowClose(nsIWidget* aWidget) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void SizeModeChanged(nsSizeMode sizeMode) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void UIResolutionChanged() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void FullscreenWillChange(bool aInFullscreen) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void FullscreenChanged(bool aInFullscreen) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void OcclusionStateChanged(bool aIsFullyOccluded) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void OSToolbarButtonPressed() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow,
nsIWidget** aActualBelow) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void WindowActivated() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void WindowDeactivated() override;
private:
// The lifetime of WidgetListenerDelegate is bound to nsXULWindow so
// we just use a raw pointer here.
nsXULWindow* mXULWindow;
};
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINTERFACEREQUESTOR
@ -78,6 +134,41 @@ class nsXULWindow : public nsIBaseWindow,
void IgnoreXULSizeMode(bool aEnable) { mIgnoreXULSizeMode = aEnable; }
void WasRegistered() { mRegistered = true; }
// nsXULWindow methods...
nsresult Initialize(nsIXULWindow* aParent, nsIXULWindow* aOpener,
nsIURI* aUrl, int32_t aInitialWidth,
int32_t aInitialHeight, bool aIsHiddenWindow,
nsIRemoteTab* aOpeningTab,
mozIDOMWindowProxy* aOpenerWIndow,
nsWidgetInitData& widgetInitData);
nsresult Toolbar();
// nsIWebProgressListener
NS_DECL_NSIWEBPROGRESSLISTENER
// nsIWidgetListener methods for WidgetListenerDelegate.
nsIXULWindow* GetXULWindow() { return this; }
mozilla::PresShell* GetPresShell();
MOZ_CAN_RUN_SCRIPT
bool WindowMoved(nsIWidget* aWidget, int32_t aX, int32_t aY);
MOZ_CAN_RUN_SCRIPT
bool WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight);
MOZ_CAN_RUN_SCRIPT bool RequestWindowClose(nsIWidget* aWidget);
MOZ_CAN_RUN_SCRIPT void SizeModeChanged(nsSizeMode aSizeMode);
MOZ_CAN_RUN_SCRIPT void UIResolutionChanged();
MOZ_CAN_RUN_SCRIPT void FullscreenWillChange(bool aInFullscreen);
MOZ_CAN_RUN_SCRIPT void FullscreenChanged(bool aInFullscreen);
MOZ_CAN_RUN_SCRIPT void OcclusionStateChanged(bool aIsFullyOccluded);
MOZ_CAN_RUN_SCRIPT void OSToolbarButtonPressed();
MOZ_CAN_RUN_SCRIPT
bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow, nsIWidget** aActualBelow);
MOZ_CAN_RUN_SCRIPT void WindowActivated();
MOZ_CAN_RUN_SCRIPT void WindowDeactivated();
explicit nsXULWindow(uint32_t aChromeFlags);
protected:
enum persistentAttributes {
PAD_MISC = 0x1,
@ -85,9 +176,16 @@ class nsXULWindow : public nsIBaseWindow,
PAD_SIZE = 0x4
};
explicit nsXULWindow(uint32_t aChromeFlags);
virtual ~nsXULWindow();
friend class mozilla::nsXULWindowTimerCallback;
bool ExecuteCloseHandler();
void ConstrainToOpenerScreen(int32_t* aX, int32_t* aY);
void SetPersistenceTimer(uint32_t aDirtyFlags);
void FirePersistenceTimer();
NS_IMETHOD EnsureChromeTreeOwner();
NS_IMETHOD EnsureContentTreeOwner();
NS_IMETHOD EnsurePrimaryContentTreeOwner();
@ -189,6 +287,10 @@ class nsXULWindow : public nsIBaseWindow,
nsCOMPtr<nsIRemoteTab> mPrimaryBrowserParent;
nsCOMPtr<nsITimer> mSPTimer;
mozilla::Mutex mSPTimerLock;
WidgetListenerDelegate mWidgetListenerDelegate;
private:
// GetPrimaryBrowserParentSize is called from xpidl methods and we don't have
// a good way to annotate those with MOZ_CAN_RUN_SCRIPT yet. It takes no