michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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: michael@0: #include "nsWebShellWindow.h" michael@0: michael@0: #include "nsLayoutCID.h" michael@0: #include "nsContentCID.h" michael@0: #include "nsIWeakReference.h" michael@0: #include "nsIContentViewer.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIURL.h" michael@0: #include "nsIIOService.h" michael@0: #include "nsIURL.h" michael@0: #include "nsNetCID.h" michael@0: #include "nsIStringBundle.h" michael@0: #include "nsReadableUtils.h" michael@0: michael@0: #include "nsEscape.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsIWebNavigation.h" michael@0: #include "nsIWindowWatcher.h" michael@0: michael@0: #include "nsIDOMXULElement.h" michael@0: michael@0: #include "nsWidgetInitData.h" michael@0: #include "nsWidgetsCID.h" michael@0: #include "nsIWidget.h" michael@0: #include "nsIWidgetListener.h" michael@0: michael@0: #include "nsIDOMCharacterData.h" michael@0: #include "nsIDOMNodeList.h" michael@0: michael@0: #include "nsITimer.h" michael@0: #include "nsXULPopupManager.h" michael@0: michael@0: michael@0: #include "nsIDOMXULDocument.h" michael@0: michael@0: #include "nsFocusManager.h" michael@0: michael@0: #include "nsIWebProgress.h" michael@0: #include "nsIWebProgressListener.h" michael@0: michael@0: #include "nsIDocument.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDOMNode.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIDocumentLoaderFactory.h" michael@0: #include "nsIObserverService.h" michael@0: #include "prprf.h" michael@0: michael@0: #include "nsIScreenManager.h" michael@0: #include "nsIScreen.h" michael@0: michael@0: #include "nsIContent.h" // for menus michael@0: #include "nsIScriptSecurityManager.h" michael@0: michael@0: // For calculating size michael@0: #include "nsIPresShell.h" michael@0: #include "nsPresContext.h" michael@0: michael@0: #include "nsIBaseWindow.h" michael@0: #include "nsIDocShellTreeItem.h" michael@0: michael@0: #include "nsIMarkupDocumentViewer.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/DebugOnly.h" michael@0: #include "mozilla/MouseEvents.h" michael@0: michael@0: #ifdef XP_MACOSX michael@0: #include "nsINativeMenuService.h" michael@0: #define USE_NATIVE_MENUS michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: /* Define Class IDs */ michael@0: static NS_DEFINE_CID(kWindowCID, NS_WINDOW_CID); michael@0: michael@0: #define SIZE_PERSISTENCE_TIMEOUT 500 // msec michael@0: michael@0: nsWebShellWindow::nsWebShellWindow(uint32_t aChromeFlags) michael@0: : nsXULWindow(aChromeFlags) michael@0: , mSPTimerLock("nsWebShellWindow.mSPTimerLock") michael@0: { michael@0: } michael@0: michael@0: nsWebShellWindow::~nsWebShellWindow() michael@0: { michael@0: MutexAutoLock lock(mSPTimerLock); michael@0: if (mSPTimer) michael@0: mSPTimer->Cancel(); michael@0: } michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(nsWebShellWindow, nsXULWindow) michael@0: NS_IMPL_RELEASE_INHERITED(nsWebShellWindow, nsXULWindow) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN(nsWebShellWindow) michael@0: NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) michael@0: NS_INTERFACE_MAP_END_INHERITING(nsXULWindow) michael@0: michael@0: nsresult nsWebShellWindow::Initialize(nsIXULWindow* aParent, michael@0: nsIXULWindow* aOpener, michael@0: nsIURI* aUrl, michael@0: int32_t aInitialWidth, michael@0: int32_t aInitialHeight, michael@0: bool aIsHiddenWindow, michael@0: nsWidgetInitData& widgetInitData) michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr parentWidget; michael@0: michael@0: mIsHiddenWindow = aIsHiddenWindow; michael@0: michael@0: int32_t initialX = 0, initialY = 0; michael@0: nsCOMPtr base(do_QueryInterface(aOpener)); michael@0: if (base) { michael@0: rv = base->GetPositionAndSize(&mOpenerScreenRect.x, michael@0: &mOpenerScreenRect.y, michael@0: &mOpenerScreenRect.width, michael@0: &mOpenerScreenRect.height); michael@0: if (NS_FAILED(rv)) { michael@0: mOpenerScreenRect.SetEmpty(); michael@0: } else { michael@0: double scale; michael@0: if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) { michael@0: mOpenerScreenRect.x = NSToIntRound(mOpenerScreenRect.x / scale); michael@0: mOpenerScreenRect.y = NSToIntRound(mOpenerScreenRect.y / scale); michael@0: mOpenerScreenRect.width = NSToIntRound(mOpenerScreenRect.width / scale); michael@0: mOpenerScreenRect.height = NSToIntRound(mOpenerScreenRect.height / scale); michael@0: } michael@0: initialX = mOpenerScreenRect.x; michael@0: initialY = mOpenerScreenRect.y; michael@0: ConstrainToOpenerScreen(&initialX, &initialY); michael@0: } michael@0: } michael@0: michael@0: // XXX: need to get the default window size from prefs... michael@0: // Doesn't come from prefs... will come from CSS/XUL/RDF michael@0: nsIntRect r(initialX, initialY, aInitialWidth, aInitialHeight); michael@0: michael@0: // Create top level window michael@0: mWindow = do_CreateInstance(kWindowCID, &rv); michael@0: if (NS_OK != rv) { michael@0: return rv; michael@0: } michael@0: michael@0: /* This next bit is troublesome. We carry two different versions of a pointer michael@0: to our parent window. One is the parent window's widget, which is passed michael@0: to our own widget. The other is a weak reference we keep here to our michael@0: parent WebShellWindow. The former is useful to the widget, and we can't michael@0: trust its treatment of the parent reference because they're platform- michael@0: specific. The latter is useful to this class. michael@0: A better implementation would be one in which the parent keeps strong michael@0: references to its children and closes them before it allows itself michael@0: to be closed. This would mimic the behaviour of OSes that support michael@0: top-level child windows in OSes that do not. Later. michael@0: */ michael@0: nsCOMPtr parentAsWin(do_QueryInterface(aParent)); michael@0: if (parentAsWin) { michael@0: parentAsWin->GetMainWidget(getter_AddRefs(parentWidget)); michael@0: mParentWindow = do_GetWeakReference(aParent); michael@0: } michael@0: michael@0: mWindow->SetWidgetListener(this); michael@0: mWindow->Create((nsIWidget *)parentWidget, // Parent nsIWidget michael@0: nullptr, // Native parent widget michael@0: r, // Widget dimensions michael@0: nullptr, // Device context michael@0: &widgetInitData); // Widget initialization data michael@0: mWindow->GetClientBounds(r); michael@0: // Match the default background color of content. Important on windows michael@0: // since we no longer use content child widgets. michael@0: mWindow->SetBackgroundColor(NS_RGB(255,255,255)); michael@0: michael@0: // Create web shell michael@0: mDocShell = do_CreateInstance("@mozilla.org/docshell;1"); michael@0: NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); michael@0: michael@0: // Make sure to set the item type on the docshell _before_ calling michael@0: // Create() so it knows what type it is. michael@0: nsCOMPtr docShellAsItem(do_QueryInterface(mDocShell)); michael@0: NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); michael@0: NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE); michael@0: michael@0: docShellAsItem->SetTreeOwner(mChromeTreeOwner); michael@0: docShellAsItem->SetItemType(nsIDocShellTreeItem::typeChrome); michael@0: michael@0: r.x = r.y = 0; michael@0: nsCOMPtr docShellAsWin(do_QueryInterface(mDocShell)); michael@0: NS_ENSURE_SUCCESS(docShellAsWin->InitWindow(nullptr, mWindow, michael@0: r.x, r.y, r.width, r.height), NS_ERROR_FAILURE); michael@0: NS_ENSURE_SUCCESS(docShellAsWin->Create(), NS_ERROR_FAILURE); michael@0: michael@0: // Attach a WebProgress listener.during initialization... michael@0: nsCOMPtr webProgress(do_GetInterface(mDocShell, &rv)); michael@0: if (webProgress) { michael@0: webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_NETWORK); michael@0: } michael@0: michael@0: // Eagerly create an about:blank content viewer with the right principal here, michael@0: // rather than letting it happening in the upcoming call to michael@0: // SetInitialPrincipalToSubject. This avoids creating the about:blank document michael@0: // and then blowing it away with a second one, which can cause problems for the michael@0: // top-level chrome window case. See bug 789773. michael@0: nsCOMPtr ssm = michael@0: do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); michael@0: if (ssm) { // Sometimes this happens really early See bug 793370. michael@0: nsCOMPtr principal; michael@0: ssm->GetSubjectPrincipal(getter_AddRefs(principal)); michael@0: if (!principal) { michael@0: ssm->GetSystemPrincipal(getter_AddRefs(principal)); michael@0: } michael@0: rv = mDocShell->CreateAboutBlankContentViewer(principal); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: nsCOMPtr doc = do_GetInterface(mDocShell); michael@0: NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE); michael@0: doc->SetIsInitialDocument(true); michael@0: } michael@0: michael@0: if (nullptr != aUrl) { michael@0: nsCString tmpStr; michael@0: michael@0: rv = aUrl->GetSpec(tmpStr); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: NS_ConvertUTF8toUTF16 urlString(tmpStr); michael@0: nsCOMPtr webNav(do_QueryInterface(mDocShell)); michael@0: NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); michael@0: rv = webNav->LoadURI(urlString.get(), michael@0: nsIWebNavigation::LOAD_FLAGS_NONE, michael@0: nullptr, michael@0: nullptr, michael@0: nullptr); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsIPresShell* michael@0: nsWebShellWindow::GetPresShell() michael@0: { michael@0: if (!mDocShell) michael@0: return nullptr; michael@0: michael@0: return mDocShell->GetPresShell(); michael@0: } michael@0: michael@0: bool michael@0: nsWebShellWindow::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) michael@0: { michael@0: nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); michael@0: if (pm) { michael@0: nsCOMPtr window = do_GetInterface(mDocShell); michael@0: pm->AdjustPopupsOnWindowChange(window); michael@0: } michael@0: michael@0: // Persist position, but not immediately, in case this OS is firing michael@0: // repeated move events as the user drags the window michael@0: SetPersistenceTimer(PAD_POSITION); michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: nsWebShellWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight) michael@0: { michael@0: nsCOMPtr shellAsWin(do_QueryInterface(mDocShell)); michael@0: if (shellAsWin) { michael@0: shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, false); michael@0: } michael@0: // Persist size, but not immediately, in case this OS is firing michael@0: // repeated size events as the user drags the sizing handle michael@0: if (!IsLocked()) michael@0: SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsWebShellWindow::RequestWindowClose(nsIWidget* aWidget) michael@0: { michael@0: // Maintain a reference to this as it is about to get destroyed. michael@0: nsCOMPtr xulWindow(this); michael@0: michael@0: nsCOMPtr window(do_GetInterface(mDocShell)); michael@0: nsCOMPtr eventTarget = do_QueryInterface(window); michael@0: michael@0: nsCOMPtr presShell = mDocShell->GetPresShell(); michael@0: michael@0: if (!presShell) { michael@0: mozilla::DebugOnly dying; michael@0: MOZ_ASSERT(NS_SUCCEEDED(mDocShell->IsBeingDestroyed(&dying)) && dying, michael@0: "No presShell, but window is not being destroyed"); michael@0: } else if (eventTarget) { michael@0: nsRefPtr presContext = presShell->GetPresContext(); michael@0: michael@0: nsEventStatus status = nsEventStatus_eIgnore; michael@0: WidgetMouseEvent event(true, NS_XUL_CLOSE, nullptr, michael@0: WidgetMouseEvent::eReal); michael@0: if (NS_SUCCEEDED(eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &status)) && michael@0: status == nsEventStatus_eConsumeNoDefault) michael@0: return false; michael@0: } michael@0: michael@0: Destroy(); michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsWebShellWindow::SizeModeChanged(nsSizeMode sizeMode) michael@0: { michael@0: // An alwaysRaised (or higher) window will hide any newly opened normal michael@0: // browser windows, so here we just drop a raised window to the normal michael@0: // zlevel if it's maximized. We make no provision for automatically michael@0: // re-raising it when restored. michael@0: if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) { michael@0: uint32_t zLevel; michael@0: GetZLevel(&zLevel); michael@0: if (zLevel > nsIXULWindow::normalZ) michael@0: SetZLevel(nsIXULWindow::normalZ); michael@0: } michael@0: mWindow->SetSizeMode(sizeMode); michael@0: michael@0: // Persist mode, but not immediately, because in many (all?) michael@0: // cases this will merge with the similar call in NS_SIZE and michael@0: // write the attribute values only once. michael@0: SetPersistenceTimer(PAD_MISC); michael@0: nsCOMPtr ourWindow = do_GetInterface(mDocShell); michael@0: if (ourWindow) { michael@0: // Let the application know if it's in fullscreen mode so it michael@0: // can update its UI. michael@0: if (sizeMode == nsSizeMode_Fullscreen) { michael@0: ourWindow->SetFullScreen(true); michael@0: } michael@0: else if (sizeMode != nsSizeMode_Minimized) { michael@0: ourWindow->SetFullScreen(false); michael@0: } michael@0: michael@0: // And always fire a user-defined sizemodechange event on the window michael@0: ourWindow->DispatchCustomEvent("sizemodechange"); michael@0: } michael@0: michael@0: // Note the current implementation of SetSizeMode just stores michael@0: // the new state; it doesn't actually resize. So here we store michael@0: // the state and pass the event on to the OS. The day is coming michael@0: // when we'll handle the event here, and the return result will michael@0: // then need to be different. michael@0: } michael@0: michael@0: void michael@0: nsWebShellWindow::OSToolbarButtonPressed() michael@0: { michael@0: // Keep a reference as setting the chrome flags can fire events. michael@0: nsCOMPtr xulWindow(this); michael@0: michael@0: // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA" michael@0: // due to components with multiple sidebar components michael@0: // (such as Mail/News, Addressbook, etc)... and frankly, michael@0: // Mac IE, OmniWeb, and other Mac OS X apps all work this way michael@0: uint32_t chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR | michael@0: nsIWebBrowserChrome::CHROME_LOCATIONBAR | michael@0: nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR); michael@0: michael@0: nsCOMPtr wbc(do_GetInterface(xulWindow)); michael@0: if (!wbc) michael@0: return; michael@0: michael@0: uint32_t chromeFlags, newChromeFlags = 0; michael@0: wbc->GetChromeFlags(&chromeFlags); michael@0: newChromeFlags = chromeFlags & chromeMask; michael@0: if (!newChromeFlags) chromeFlags |= chromeMask; michael@0: else chromeFlags &= (~newChromeFlags); michael@0: wbc->SetChromeFlags(chromeFlags); michael@0: } michael@0: michael@0: bool michael@0: nsWebShellWindow::ZLevelChanged(bool aImmediate, nsWindowZ *aPlacement, michael@0: nsIWidget* aRequestBelow, nsIWidget** aActualBelow) michael@0: { michael@0: if (aActualBelow) michael@0: *aActualBelow = nullptr; michael@0: michael@0: return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow); michael@0: } michael@0: michael@0: void michael@0: nsWebShellWindow::WindowActivated() michael@0: { michael@0: nsCOMPtr xulWindow(this); michael@0: michael@0: // focusing the window could cause it to close, so keep a reference to it michael@0: nsCOMPtr window = do_GetInterface(mDocShell); michael@0: nsCOMPtr fm = do_GetService(FOCUSMANAGER_CONTRACTID); michael@0: if (fm && window) michael@0: fm->WindowRaised(window); michael@0: michael@0: if (mChromeLoaded) { michael@0: PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC); michael@0: SavePersistentAttributes(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsWebShellWindow::WindowDeactivated() michael@0: { michael@0: nsCOMPtr xulWindow(this); michael@0: michael@0: nsCOMPtr window = do_GetInterface(mDocShell); michael@0: nsCOMPtr fm = do_GetService(FOCUSMANAGER_CONTRACTID); michael@0: if (fm && window) michael@0: fm->WindowLowered(window); michael@0: } michael@0: michael@0: #ifdef USE_NATIVE_MENUS michael@0: static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow) michael@0: { michael@0: // Find the menubar tag (if there is more than one, we ignore all but michael@0: // the first). michael@0: nsCOMPtr menubarElements; michael@0: aDOMDoc->GetElementsByTagNameNS(NS_LITERAL_STRING("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"), michael@0: NS_LITERAL_STRING("menubar"), michael@0: getter_AddRefs(menubarElements)); michael@0: michael@0: nsCOMPtr menubarNode; michael@0: if (menubarElements) michael@0: menubarElements->Item(0, getter_AddRefs(menubarNode)); michael@0: if (!menubarNode) michael@0: return; michael@0: michael@0: nsCOMPtr nms = do_GetService("@mozilla.org/widget/nativemenuservice;1"); michael@0: nsCOMPtr menubarContent(do_QueryInterface(menubarNode)); michael@0: if (nms && menubarContent) michael@0: nms->CreateNativeMenuBar(aParentWindow, menubarContent); michael@0: } michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: michael@0: class WebShellWindowTimerCallback MOZ_FINAL : public nsITimerCallback michael@0: { michael@0: public: michael@0: WebShellWindowTimerCallback(nsWebShellWindow* aWindow) michael@0: : mWindow(aWindow) michael@0: {} michael@0: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: NS_IMETHOD Notify(nsITimer* aTimer) michael@0: { michael@0: // Although this object participates in a refcount cycle (this -> mWindow michael@0: // -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this michael@0: // after it fires. So we don't need to release mWindow here. michael@0: michael@0: mWindow->FirePersistenceTimer(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: nsRefPtr mWindow; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(WebShellWindowTimerCallback, nsITimerCallback) michael@0: michael@0: } // namespace mozilla michael@0: michael@0: void michael@0: nsWebShellWindow::SetPersistenceTimer(uint32_t aDirtyFlags) michael@0: { michael@0: MutexAutoLock lock(mSPTimerLock); michael@0: if (!mSPTimer) { michael@0: mSPTimer = do_CreateInstance("@mozilla.org/timer;1"); michael@0: if (!mSPTimer) { michael@0: NS_WARNING("Couldn't create @mozilla.org/timer;1 instance?"); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: nsRefPtr callback = michael@0: new WebShellWindowTimerCallback(this); michael@0: mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT, michael@0: nsITimer::TYPE_ONE_SHOT); michael@0: michael@0: PersistentAttributesDirty(aDirtyFlags); michael@0: } michael@0: michael@0: void michael@0: nsWebShellWindow::FirePersistenceTimer() michael@0: { michael@0: MutexAutoLock lock(mSPTimerLock); michael@0: SavePersistentAttributes(); michael@0: } michael@0: michael@0: michael@0: //---------------------------------------- michael@0: // nsIWebProgessListener implementation michael@0: //---------------------------------------- michael@0: NS_IMETHODIMP michael@0: nsWebShellWindow::OnProgressChange(nsIWebProgress *aProgress, michael@0: nsIRequest *aRequest, michael@0: int32_t aCurSelfProgress, michael@0: int32_t aMaxSelfProgress, michael@0: int32_t aCurTotalProgress, michael@0: int32_t aMaxTotalProgress) michael@0: { michael@0: NS_NOTREACHED("notification excluded in AddProgressListener(...)"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWebShellWindow::OnStateChange(nsIWebProgress *aProgress, michael@0: nsIRequest *aRequest, michael@0: uint32_t aStateFlags, michael@0: nsresult aStatus) michael@0: { michael@0: // If the notification is not about a document finishing, then just michael@0: // ignore it... michael@0: if (!(aStateFlags & nsIWebProgressListener::STATE_STOP) || michael@0: !(aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (mChromeLoaded) michael@0: return NS_OK; michael@0: michael@0: // If this document notification is for a frame then ignore it... michael@0: nsCOMPtr eventWin; michael@0: aProgress->GetDOMWindow(getter_AddRefs(eventWin)); michael@0: nsCOMPtr eventPWin(do_QueryInterface(eventWin)); michael@0: if (eventPWin) { michael@0: nsPIDOMWindow *rootPWin = eventPWin->GetPrivateRoot(); michael@0: if (eventPWin != rootPWin) michael@0: return NS_OK; michael@0: } michael@0: michael@0: mChromeLoaded = true; michael@0: mLockedUntilChromeLoad = false; michael@0: michael@0: #ifdef USE_NATIVE_MENUS michael@0: /////////////////////////////// michael@0: // Find the Menubar DOM and Load the menus, hooking them up to the loaded commands michael@0: /////////////////////////////// michael@0: nsCOMPtr cv; michael@0: mDocShell->GetContentViewer(getter_AddRefs(cv)); michael@0: if (cv) { michael@0: nsCOMPtr menubarDOMDoc(do_QueryInterface(cv->GetDocument())); michael@0: if (menubarDOMDoc) michael@0: LoadNativeMenus(menubarDOMDoc, mWindow); michael@0: } michael@0: #endif // USE_NATIVE_MENUS michael@0: michael@0: OnChromeLoaded(); michael@0: LoadContentAreas(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWebShellWindow::OnLocationChange(nsIWebProgress *aProgress, michael@0: nsIRequest *aRequest, michael@0: nsIURI *aURI, michael@0: uint32_t aFlags) michael@0: { michael@0: NS_NOTREACHED("notification excluded in AddProgressListener(...)"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWebShellWindow::OnStatusChange(nsIWebProgress* aWebProgress, michael@0: nsIRequest* aRequest, michael@0: nsresult aStatus, michael@0: const char16_t* aMessage) michael@0: { michael@0: NS_NOTREACHED("notification excluded in AddProgressListener(...)"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWebShellWindow::OnSecurityChange(nsIWebProgress *aWebProgress, michael@0: nsIRequest *aRequest, michael@0: uint32_t state) michael@0: { michael@0: NS_NOTREACHED("notification excluded in AddProgressListener(...)"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: //---------------------------------------- michael@0: michael@0: // if the main document URL specified URLs for any content areas, start them loading michael@0: void nsWebShellWindow::LoadContentAreas() { michael@0: michael@0: nsAutoString searchSpec; michael@0: michael@0: // fetch the chrome document URL michael@0: nsCOMPtr contentViewer; michael@0: // yes, it's possible for the docshell to be null even this early michael@0: // see bug 57514. michael@0: if (mDocShell) michael@0: mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); michael@0: if (contentViewer) { michael@0: nsIDocument* doc = contentViewer->GetDocument(); michael@0: if (doc) { michael@0: nsIURI* mainURL = doc->GetDocumentURI(); michael@0: michael@0: nsCOMPtr url = do_QueryInterface(mainURL); michael@0: if (url) { michael@0: nsAutoCString search; michael@0: url->GetQuery(search); michael@0: michael@0: AppendUTF8toUTF16(search, searchSpec); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // content URLs are specified in the search part of the URL michael@0: // as =[;(repeat)] michael@0: if (!searchSpec.IsEmpty()) { michael@0: int32_t begPos, michael@0: eqPos, michael@0: endPos; michael@0: nsString contentAreaID, michael@0: contentURL; michael@0: char *urlChar; michael@0: nsresult rv; michael@0: for (endPos = 0; endPos < (int32_t)searchSpec.Length(); ) { michael@0: // extract contentAreaID and URL substrings michael@0: begPos = endPos; michael@0: eqPos = searchSpec.FindChar('=', begPos); michael@0: if (eqPos < 0) michael@0: break; michael@0: michael@0: endPos = searchSpec.FindChar(';', eqPos); michael@0: if (endPos < 0) michael@0: endPos = searchSpec.Length(); michael@0: searchSpec.Mid(contentAreaID, begPos, eqPos-begPos); michael@0: searchSpec.Mid(contentURL, eqPos+1, endPos-eqPos-1); michael@0: endPos++; michael@0: michael@0: // see if we have a docshell with a matching contentAreaID michael@0: nsCOMPtr content; michael@0: rv = GetContentShellById(contentAreaID.get(), getter_AddRefs(content)); michael@0: if (NS_SUCCEEDED(rv) && content) { michael@0: nsCOMPtr webNav(do_QueryInterface(content)); michael@0: if (webNav) { michael@0: urlChar = ToNewCString(contentURL); michael@0: if (urlChar) { michael@0: nsUnescape(urlChar); michael@0: contentURL.AssignWithConversion(urlChar); michael@0: webNav->LoadURI(contentURL.get(), michael@0: nsIWebNavigation::LOAD_FLAGS_NONE, michael@0: nullptr, michael@0: nullptr, michael@0: nullptr); michael@0: nsMemory::Free(urlChar); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * ExecuteCloseHandler - Run the close handler, if any. michael@0: * @return true iff we found a close handler to run. michael@0: */ michael@0: bool nsWebShellWindow::ExecuteCloseHandler() michael@0: { michael@0: /* If the event handler closes this window -- a likely scenario -- michael@0: things get deleted out of order without this death grip. michael@0: (The problem may be the death grip in nsWindow::windowProc, michael@0: which forces this window's widget to remain alive longer michael@0: than it otherwise would.) */ michael@0: nsCOMPtr kungFuDeathGrip(this); michael@0: michael@0: nsCOMPtr window(do_GetInterface(mDocShell)); michael@0: nsCOMPtr eventTarget = do_QueryInterface(window); michael@0: michael@0: if (eventTarget) { michael@0: nsCOMPtr contentViewer; michael@0: mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); michael@0: if (contentViewer) { michael@0: nsRefPtr presContext; michael@0: contentViewer->GetPresContext(getter_AddRefs(presContext)); michael@0: michael@0: nsEventStatus status = nsEventStatus_eIgnore; michael@0: WidgetMouseEvent event(true, NS_XUL_CLOSE, nullptr, michael@0: WidgetMouseEvent::eReal); michael@0: michael@0: nsresult rv = michael@0: eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &status); michael@0: if (NS_SUCCEEDED(rv) && status == nsEventStatus_eConsumeNoDefault) michael@0: return true; michael@0: // else fall through and return false michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } // ExecuteCloseHandler michael@0: michael@0: void nsWebShellWindow::ConstrainToOpenerScreen(int32_t* aX, int32_t* aY) michael@0: { michael@0: if (mOpenerScreenRect.IsEmpty()) { michael@0: *aX = *aY = 0; michael@0: return; michael@0: } michael@0: michael@0: int32_t left, top, width, height; michael@0: // Constrain initial positions to the same screen as opener michael@0: nsCOMPtr screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1"); michael@0: if (screenmgr) { michael@0: nsCOMPtr screen; michael@0: screenmgr->ScreenForRect(mOpenerScreenRect.x, mOpenerScreenRect.y, michael@0: mOpenerScreenRect.width, mOpenerScreenRect.height, michael@0: getter_AddRefs(screen)); michael@0: if (screen) { michael@0: screen->GetAvailRectDisplayPix(&left, &top, &width, &height); michael@0: if (*aX < left || *aX > left + width) { michael@0: *aX = left; michael@0: } michael@0: if (*aY < top || *aY > top + height) { michael@0: *aY = top; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // nsIBaseWindow michael@0: NS_IMETHODIMP nsWebShellWindow::Destroy() michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr webProgress(do_GetInterface(mDocShell, &rv)); michael@0: if (webProgress) { michael@0: webProgress->RemoveProgressListener(this); michael@0: } michael@0: michael@0: nsCOMPtr kungFuDeathGrip(this); michael@0: { michael@0: MutexAutoLock lock(mSPTimerLock); michael@0: if (mSPTimer) { michael@0: mSPTimer->Cancel(); michael@0: SavePersistentAttributes(); michael@0: mSPTimer = nullptr; michael@0: } michael@0: } michael@0: return nsXULWindow::Destroy(); michael@0: }