summaryrefslogtreecommitdiffstats
path: root/xpfe/appshell/nsWebShellWindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpfe/appshell/nsWebShellWindow.cpp')
-rw-r--r--xpfe/appshell/nsWebShellWindow.cpp911
1 files changed, 911 insertions, 0 deletions
diff --git a/xpfe/appshell/nsWebShellWindow.cpp b/xpfe/appshell/nsWebShellWindow.cpp
new file mode 100644
index 000000000..288d94759
--- /dev/null
+++ b/xpfe/appshell/nsWebShellWindow.cpp
@@ -0,0 +1,911 @@
+/* -*- 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 "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 "nsIDOMXULElement.h"
+
+#include "nsWidgetInitData.h"
+#include "nsWidgetsCID.h"
+#include "nsIWidget.h"
+#include "nsIWidgetListener.h"
+
+#include "nsIDOMCharacterData.h"
+#include "nsIDOMNodeList.h"
+
+#include "nsITimer.h"
+#include "nsXULPopupManager.h"
+
+
+#include "nsIDOMXULDocument.h"
+
+#include "nsFocusManager.h"
+
+#include "nsIWebProgress.h"
+#include "nsIWebProgressListener.h"
+
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsIDOMNode.h"
+#include "nsIDOMElement.h"
+#include "nsIDocumentLoaderFactory.h"
+#include "nsIObserverService.h"
+#include "prprf.h"
+
+#include "nsIScreenManager.h"
+#include "nsIScreen.h"
+
+#include "nsIContent.h" // for menus
+#include "nsIScriptSecurityManager.h"
+
+// For calculating size
+#include "nsIPresShell.h"
+#include "nsPresContext.h"
+
+#include "nsIBaseWindow.h"
+#include "nsIDocShellTreeItem.h"
+
+#include "mozilla/Attributes.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/MouseEvents.h"
+
+#include "nsPIWindowRoot.h"
+
+#ifdef XP_MACOSX
+#include "nsINativeMenuService.h"
+#define USE_NATIVE_MENUS
+#endif
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+/* Define Class IDs */
+static NS_DEFINE_CID(kWindowCID, NS_WINDOW_CID);
+
+#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,
+ nsITabParent *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) {
+ rv = base->GetPositionAndSize(&mOpenerScreenRect.x,
+ &mOpenerScreenRect.y,
+ &mOpenerScreenRect.width,
+ &mOpenerScreenRect.height);
+ if (NS_FAILED(rv)) {
+ mOpenerScreenRect.SetEmpty();
+ } else {
+ double scale;
+ if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) {
+ mOpenerScreenRect.x = NSToIntRound(mOpenerScreenRect.x / scale);
+ mOpenerScreenRect.y = NSToIntRound(mOpenerScreenRect.y / scale);
+ mOpenerScreenRect.width = NSToIntRound(mOpenerScreenRect.width / scale);
+ mOpenerScreenRect.height = NSToIntRound(mOpenerScreenRect.height / scale);
+ }
+ 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
+ mWindow = do_CreateInstance(kWindowCID, &rv);
+ if (NS_OK != rv) {
+ return rv;
+ }
+
+ /* 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
+ mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
+ NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
+
+ 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(do_QueryInterface(mDocShell));
+ NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
+ NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE);
+
+ docShellAsItem->SetTreeOwner(mChromeTreeOwner);
+ docShellAsItem->SetItemType(nsIDocShellTreeItem::typeChrome);
+
+ r.x = r.y = 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);
+ }
+
+ if (aOpenerWindow) {
+ nsPIDOMWindowOuter* window = mDocShell->GetWindow();
+ MOZ_ASSERT(window);
+ window->SetOpenerWindow(nsPIDOMWindowOuter::From(aOpenerWindow), true);
+ }
+
+ // 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;
+ }
+ rv = mDocShell->CreateAboutBlankContentViewer(principal);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIDocument> 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);
+ rv = webNav->LoadURI(urlString.get(),
+ nsIWebNavigation::LOAD_FLAGS_NONE,
+ nullptr,
+ nullptr,
+ nullptr);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return rv;
+}
+
+nsIPresShell*
+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"),
+ false, false, 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);
+
+ nsCOMPtr<nsIPresShell> 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, eWindowClose, nullptr,
+ WidgetMouseEvent::eReal);
+ if (NS_SUCCEEDED(eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &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) {
+ MOZ_ASSERT(ourWindow->IsOuterWindow());
+
+ // 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"));
+ }
+
+ nsIPresShell* presShell;
+ if ((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) {
+ MOZ_ASSERT(ourWindow->IsOuterWindow());
+ ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("resolutionchange"));
+ }
+}
+
+void
+nsWebShellWindow::FullscreenChanged(bool aInFullscreen)
+{
+ if (mDocShell) {
+ if (nsCOMPtr<nsPIDOMWindowOuter> ourWindow = mDocShell->GetWindow()) {
+ ourWindow->FinishFullscreenChange(aInFullscreen);
+ }
+ }
+}
+
+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;
+ nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
+ 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;
+ nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
+ if (fm && window)
+ fm->WindowLowered(window);
+}
+
+#ifdef USE_NATIVE_MENUS
+static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow)
+{
+ 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<nsIDOMNodeList> menubarElements;
+ aDOMDoc->GetElementsByTagNameNS(NS_LITERAL_STRING("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"),
+ NS_LITERAL_STRING("menubar"),
+ getter_AddRefs(menubarElements));
+
+ nsCOMPtr<nsIDOMNode> menubarNode;
+ if (menubarElements)
+ menubarElements->Item(0, getter_AddRefs(menubarNode));
+
+ if (menubarNode) {
+ nsCOMPtr<nsIContent> menubarContent(do_QueryInterface(menubarNode));
+ nms->CreateNativeMenuBar(aParentWindow, menubarContent);
+ } else {
+ nms->CreateNativeMenuBar(aParentWindow, nullptr);
+ }
+}
+#endif
+
+namespace mozilla {
+
+class WebShellWindowTimerCallback final : public nsITimerCallback
+{
+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;
+ }
+
+private:
+ ~WebShellWindowTimerCallback() {}
+
+ RefPtr<nsWebShellWindow> mWindow;
+};
+
+NS_IMPL_ISUPPORTS(WebShellWindowTimerCallback, nsITimerCallback)
+
+} // namespace mozilla
+
+void
+nsWebShellWindow::SetPersistenceTimer(uint32_t aDirtyFlags)
+{
+ MutexAutoLock lock(mSPTimerLock);
+ if (!mSPTimer) {
+ mSPTimer = do_CreateInstance("@mozilla.org/timer;1");
+ 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)
+{
+ NS_NOTREACHED("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) {
+ nsCOMPtr<nsIDOMDocument> menubarDOMDoc(do_QueryInterface(cv->GetDocument()));
+ if (menubarDOMDoc)
+ LoadNativeMenus(menubarDOMDoc, mWindow);
+ }
+#endif // USE_NATIVE_MENUS
+
+ OnChromeLoaded();
+ LoadContentAreas();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebShellWindow::OnLocationChange(nsIWebProgress *aProgress,
+ nsIRequest *aRequest,
+ nsIURI *aURI,
+ uint32_t aFlags)
+{
+ NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebShellWindow::OnStatusChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest,
+ nsresult aStatus,
+ const char16_t* aMessage)
+{
+ NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebShellWindow::OnSecurityChange(nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ uint32_t state)
+{
+ NS_NOTREACHED("notification excluded in AddProgressListener(...)");
+ return NS_OK;
+}
+
+
+//----------------------------------------
+
+// if the main document URL specified URLs for any content areas, start them loading
+void nsWebShellWindow::LoadContentAreas() {
+
+ nsAutoString searchSpec;
+
+ // fetch the chrome document URL
+ nsCOMPtr<nsIContentViewer> contentViewer;
+ // yes, it's possible for the docshell to be null even this early
+ // see bug 57514.
+ if (mDocShell)
+ mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
+ if (contentViewer) {
+ nsIDocument* doc = contentViewer->GetDocument();
+ if (doc) {
+ nsIURI* mainURL = doc->GetDocumentURI();
+
+ nsCOMPtr<nsIURL> url = do_QueryInterface(mainURL);
+ if (url) {
+ nsAutoCString search;
+ url->GetQuery(search);
+
+ AppendUTF8toUTF16(search, searchSpec);
+ }
+ }
+ }
+
+ // content URLs are specified in the search part of the URL
+ // as <contentareaID>=<escapedURL>[;(repeat)]
+ if (!searchSpec.IsEmpty()) {
+ int32_t begPos,
+ eqPos,
+ endPos;
+ nsString contentAreaID,
+ contentURL;
+ char *urlChar;
+ nsresult rv;
+ for (endPos = 0; endPos < (int32_t)searchSpec.Length(); ) {
+ // extract contentAreaID and URL substrings
+ begPos = endPos;
+ eqPos = searchSpec.FindChar('=', begPos);
+ if (eqPos < 0)
+ break;
+
+ endPos = searchSpec.FindChar(';', eqPos);
+ if (endPos < 0)
+ endPos = searchSpec.Length();
+ searchSpec.Mid(contentAreaID, begPos, eqPos-begPos);
+ searchSpec.Mid(contentURL, eqPos+1, endPos-eqPos-1);
+ endPos++;
+
+ // see if we have a docshell with a matching contentAreaID
+ nsCOMPtr<nsIDocShellTreeItem> content;
+ rv = GetContentShellById(contentAreaID.get(), getter_AddRefs(content));
+ if (NS_SUCCEEDED(rv) && content) {
+ nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(content));
+ if (webNav) {
+ urlChar = ToNewCString(contentURL);
+ if (urlChar) {
+ nsUnescape(urlChar);
+ contentURL.AssignWithConversion(urlChar);
+ webNav->LoadURI(contentURL.get(),
+ nsIWebNavigation::LOAD_FLAGS_NONE,
+ nullptr,
+ nullptr,
+ nullptr);
+ free(urlChar);
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * 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(getter_AddRefs(presContext));
+
+ nsEventStatus status = nsEventStatus_eIgnore;
+ WidgetMouseEvent event(true, eWindowClose, nullptr,
+ WidgetMouseEvent::eReal);
+
+ nsresult rv =
+ eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &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();
+}
+
+nsIPresShell*
+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::FullscreenChanged(bool aInFullscreen)
+{
+ RefPtr<nsWebShellWindow> holder = mWebShellWindow;
+ holder->FullscreenChanged(aInFullscreen);
+}
+
+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();
+}