1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpfe/appshell/src/nsWebShellWindow.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,751 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 + 1.10 +#include "nsWebShellWindow.h" 1.11 + 1.12 +#include "nsLayoutCID.h" 1.13 +#include "nsContentCID.h" 1.14 +#include "nsIWeakReference.h" 1.15 +#include "nsIContentViewer.h" 1.16 +#include "nsIComponentManager.h" 1.17 +#include "nsIServiceManager.h" 1.18 +#include "nsIURL.h" 1.19 +#include "nsIIOService.h" 1.20 +#include "nsIURL.h" 1.21 +#include "nsNetCID.h" 1.22 +#include "nsIStringBundle.h" 1.23 +#include "nsReadableUtils.h" 1.24 + 1.25 +#include "nsEscape.h" 1.26 +#include "nsPIDOMWindow.h" 1.27 +#include "nsIWebNavigation.h" 1.28 +#include "nsIWindowWatcher.h" 1.29 + 1.30 +#include "nsIDOMXULElement.h" 1.31 + 1.32 +#include "nsWidgetInitData.h" 1.33 +#include "nsWidgetsCID.h" 1.34 +#include "nsIWidget.h" 1.35 +#include "nsIWidgetListener.h" 1.36 + 1.37 +#include "nsIDOMCharacterData.h" 1.38 +#include "nsIDOMNodeList.h" 1.39 + 1.40 +#include "nsITimer.h" 1.41 +#include "nsXULPopupManager.h" 1.42 + 1.43 + 1.44 +#include "nsIDOMXULDocument.h" 1.45 + 1.46 +#include "nsFocusManager.h" 1.47 + 1.48 +#include "nsIWebProgress.h" 1.49 +#include "nsIWebProgressListener.h" 1.50 + 1.51 +#include "nsIDocument.h" 1.52 +#include "nsIDOMDocument.h" 1.53 +#include "nsIDOMNode.h" 1.54 +#include "nsIDOMElement.h" 1.55 +#include "nsIDocumentLoaderFactory.h" 1.56 +#include "nsIObserverService.h" 1.57 +#include "prprf.h" 1.58 + 1.59 +#include "nsIScreenManager.h" 1.60 +#include "nsIScreen.h" 1.61 + 1.62 +#include "nsIContent.h" // for menus 1.63 +#include "nsIScriptSecurityManager.h" 1.64 + 1.65 +// For calculating size 1.66 +#include "nsIPresShell.h" 1.67 +#include "nsPresContext.h" 1.68 + 1.69 +#include "nsIBaseWindow.h" 1.70 +#include "nsIDocShellTreeItem.h" 1.71 + 1.72 +#include "nsIMarkupDocumentViewer.h" 1.73 +#include "mozilla/Attributes.h" 1.74 +#include "mozilla/DebugOnly.h" 1.75 +#include "mozilla/MouseEvents.h" 1.76 + 1.77 +#ifdef XP_MACOSX 1.78 +#include "nsINativeMenuService.h" 1.79 +#define USE_NATIVE_MENUS 1.80 +#endif 1.81 + 1.82 +using namespace mozilla; 1.83 +using namespace mozilla::dom; 1.84 + 1.85 +/* Define Class IDs */ 1.86 +static NS_DEFINE_CID(kWindowCID, NS_WINDOW_CID); 1.87 + 1.88 +#define SIZE_PERSISTENCE_TIMEOUT 500 // msec 1.89 + 1.90 +nsWebShellWindow::nsWebShellWindow(uint32_t aChromeFlags) 1.91 + : nsXULWindow(aChromeFlags) 1.92 + , mSPTimerLock("nsWebShellWindow.mSPTimerLock") 1.93 +{ 1.94 +} 1.95 + 1.96 +nsWebShellWindow::~nsWebShellWindow() 1.97 +{ 1.98 + MutexAutoLock lock(mSPTimerLock); 1.99 + if (mSPTimer) 1.100 + mSPTimer->Cancel(); 1.101 +} 1.102 + 1.103 +NS_IMPL_ADDREF_INHERITED(nsWebShellWindow, nsXULWindow) 1.104 +NS_IMPL_RELEASE_INHERITED(nsWebShellWindow, nsXULWindow) 1.105 + 1.106 +NS_INTERFACE_MAP_BEGIN(nsWebShellWindow) 1.107 + NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) 1.108 +NS_INTERFACE_MAP_END_INHERITING(nsXULWindow) 1.109 + 1.110 +nsresult nsWebShellWindow::Initialize(nsIXULWindow* aParent, 1.111 + nsIXULWindow* aOpener, 1.112 + nsIURI* aUrl, 1.113 + int32_t aInitialWidth, 1.114 + int32_t aInitialHeight, 1.115 + bool aIsHiddenWindow, 1.116 + nsWidgetInitData& widgetInitData) 1.117 +{ 1.118 + nsresult rv; 1.119 + nsCOMPtr<nsIWidget> parentWidget; 1.120 + 1.121 + mIsHiddenWindow = aIsHiddenWindow; 1.122 + 1.123 + int32_t initialX = 0, initialY = 0; 1.124 + nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(aOpener)); 1.125 + if (base) { 1.126 + rv = base->GetPositionAndSize(&mOpenerScreenRect.x, 1.127 + &mOpenerScreenRect.y, 1.128 + &mOpenerScreenRect.width, 1.129 + &mOpenerScreenRect.height); 1.130 + if (NS_FAILED(rv)) { 1.131 + mOpenerScreenRect.SetEmpty(); 1.132 + } else { 1.133 + double scale; 1.134 + if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) { 1.135 + mOpenerScreenRect.x = NSToIntRound(mOpenerScreenRect.x / scale); 1.136 + mOpenerScreenRect.y = NSToIntRound(mOpenerScreenRect.y / scale); 1.137 + mOpenerScreenRect.width = NSToIntRound(mOpenerScreenRect.width / scale); 1.138 + mOpenerScreenRect.height = NSToIntRound(mOpenerScreenRect.height / scale); 1.139 + } 1.140 + initialX = mOpenerScreenRect.x; 1.141 + initialY = mOpenerScreenRect.y; 1.142 + ConstrainToOpenerScreen(&initialX, &initialY); 1.143 + } 1.144 + } 1.145 + 1.146 + // XXX: need to get the default window size from prefs... 1.147 + // Doesn't come from prefs... will come from CSS/XUL/RDF 1.148 + nsIntRect r(initialX, initialY, aInitialWidth, aInitialHeight); 1.149 + 1.150 + // Create top level window 1.151 + mWindow = do_CreateInstance(kWindowCID, &rv); 1.152 + if (NS_OK != rv) { 1.153 + return rv; 1.154 + } 1.155 + 1.156 + /* This next bit is troublesome. We carry two different versions of a pointer 1.157 + to our parent window. One is the parent window's widget, which is passed 1.158 + to our own widget. The other is a weak reference we keep here to our 1.159 + parent WebShellWindow. The former is useful to the widget, and we can't 1.160 + trust its treatment of the parent reference because they're platform- 1.161 + specific. The latter is useful to this class. 1.162 + A better implementation would be one in which the parent keeps strong 1.163 + references to its children and closes them before it allows itself 1.164 + to be closed. This would mimic the behaviour of OSes that support 1.165 + top-level child windows in OSes that do not. Later. 1.166 + */ 1.167 + nsCOMPtr<nsIBaseWindow> parentAsWin(do_QueryInterface(aParent)); 1.168 + if (parentAsWin) { 1.169 + parentAsWin->GetMainWidget(getter_AddRefs(parentWidget)); 1.170 + mParentWindow = do_GetWeakReference(aParent); 1.171 + } 1.172 + 1.173 + mWindow->SetWidgetListener(this); 1.174 + mWindow->Create((nsIWidget *)parentWidget, // Parent nsIWidget 1.175 + nullptr, // Native parent widget 1.176 + r, // Widget dimensions 1.177 + nullptr, // Device context 1.178 + &widgetInitData); // Widget initialization data 1.179 + mWindow->GetClientBounds(r); 1.180 + // Match the default background color of content. Important on windows 1.181 + // since we no longer use content child widgets. 1.182 + mWindow->SetBackgroundColor(NS_RGB(255,255,255)); 1.183 + 1.184 + // Create web shell 1.185 + mDocShell = do_CreateInstance("@mozilla.org/docshell;1"); 1.186 + NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); 1.187 + 1.188 + // Make sure to set the item type on the docshell _before_ calling 1.189 + // Create() so it knows what type it is. 1.190 + nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell)); 1.191 + NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); 1.192 + NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE); 1.193 + 1.194 + docShellAsItem->SetTreeOwner(mChromeTreeOwner); 1.195 + docShellAsItem->SetItemType(nsIDocShellTreeItem::typeChrome); 1.196 + 1.197 + r.x = r.y = 0; 1.198 + nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell)); 1.199 + NS_ENSURE_SUCCESS(docShellAsWin->InitWindow(nullptr, mWindow, 1.200 + r.x, r.y, r.width, r.height), NS_ERROR_FAILURE); 1.201 + NS_ENSURE_SUCCESS(docShellAsWin->Create(), NS_ERROR_FAILURE); 1.202 + 1.203 + // Attach a WebProgress listener.during initialization... 1.204 + nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv)); 1.205 + if (webProgress) { 1.206 + webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_NETWORK); 1.207 + } 1.208 + 1.209 + // Eagerly create an about:blank content viewer with the right principal here, 1.210 + // rather than letting it happening in the upcoming call to 1.211 + // SetInitialPrincipalToSubject. This avoids creating the about:blank document 1.212 + // and then blowing it away with a second one, which can cause problems for the 1.213 + // top-level chrome window case. See bug 789773. 1.214 + nsCOMPtr<nsIScriptSecurityManager> ssm = 1.215 + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); 1.216 + if (ssm) { // Sometimes this happens really early See bug 793370. 1.217 + nsCOMPtr<nsIPrincipal> principal; 1.218 + ssm->GetSubjectPrincipal(getter_AddRefs(principal)); 1.219 + if (!principal) { 1.220 + ssm->GetSystemPrincipal(getter_AddRefs(principal)); 1.221 + } 1.222 + rv = mDocShell->CreateAboutBlankContentViewer(principal); 1.223 + NS_ENSURE_SUCCESS(rv, rv); 1.224 + nsCOMPtr<nsIDocument> doc = do_GetInterface(mDocShell); 1.225 + NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE); 1.226 + doc->SetIsInitialDocument(true); 1.227 + } 1.228 + 1.229 + if (nullptr != aUrl) { 1.230 + nsCString tmpStr; 1.231 + 1.232 + rv = aUrl->GetSpec(tmpStr); 1.233 + if (NS_FAILED(rv)) return rv; 1.234 + 1.235 + NS_ConvertUTF8toUTF16 urlString(tmpStr); 1.236 + nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell)); 1.237 + NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); 1.238 + rv = webNav->LoadURI(urlString.get(), 1.239 + nsIWebNavigation::LOAD_FLAGS_NONE, 1.240 + nullptr, 1.241 + nullptr, 1.242 + nullptr); 1.243 + NS_ENSURE_SUCCESS(rv, rv); 1.244 + } 1.245 + 1.246 + return rv; 1.247 +} 1.248 + 1.249 +nsIPresShell* 1.250 +nsWebShellWindow::GetPresShell() 1.251 +{ 1.252 + if (!mDocShell) 1.253 + return nullptr; 1.254 + 1.255 + return mDocShell->GetPresShell(); 1.256 +} 1.257 + 1.258 +bool 1.259 +nsWebShellWindow::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y) 1.260 +{ 1.261 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.262 + if (pm) { 1.263 + nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell); 1.264 + pm->AdjustPopupsOnWindowChange(window); 1.265 + } 1.266 + 1.267 + // Persist position, but not immediately, in case this OS is firing 1.268 + // repeated move events as the user drags the window 1.269 + SetPersistenceTimer(PAD_POSITION); 1.270 + return false; 1.271 +} 1.272 + 1.273 +bool 1.274 +nsWebShellWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight) 1.275 +{ 1.276 + nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell)); 1.277 + if (shellAsWin) { 1.278 + shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, false); 1.279 + } 1.280 + // Persist size, but not immediately, in case this OS is firing 1.281 + // repeated size events as the user drags the sizing handle 1.282 + if (!IsLocked()) 1.283 + SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC); 1.284 + return true; 1.285 +} 1.286 + 1.287 +bool 1.288 +nsWebShellWindow::RequestWindowClose(nsIWidget* aWidget) 1.289 +{ 1.290 + // Maintain a reference to this as it is about to get destroyed. 1.291 + nsCOMPtr<nsIXULWindow> xulWindow(this); 1.292 + 1.293 + nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell)); 1.294 + nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window); 1.295 + 1.296 + nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell(); 1.297 + 1.298 + if (!presShell) { 1.299 + mozilla::DebugOnly<bool> dying; 1.300 + MOZ_ASSERT(NS_SUCCEEDED(mDocShell->IsBeingDestroyed(&dying)) && dying, 1.301 + "No presShell, but window is not being destroyed"); 1.302 + } else if (eventTarget) { 1.303 + nsRefPtr<nsPresContext> presContext = presShell->GetPresContext(); 1.304 + 1.305 + nsEventStatus status = nsEventStatus_eIgnore; 1.306 + WidgetMouseEvent event(true, NS_XUL_CLOSE, nullptr, 1.307 + WidgetMouseEvent::eReal); 1.308 + if (NS_SUCCEEDED(eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &status)) && 1.309 + status == nsEventStatus_eConsumeNoDefault) 1.310 + return false; 1.311 + } 1.312 + 1.313 + Destroy(); 1.314 + return false; 1.315 +} 1.316 + 1.317 +void 1.318 +nsWebShellWindow::SizeModeChanged(nsSizeMode sizeMode) 1.319 +{ 1.320 + // An alwaysRaised (or higher) window will hide any newly opened normal 1.321 + // browser windows, so here we just drop a raised window to the normal 1.322 + // zlevel if it's maximized. We make no provision for automatically 1.323 + // re-raising it when restored. 1.324 + if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) { 1.325 + uint32_t zLevel; 1.326 + GetZLevel(&zLevel); 1.327 + if (zLevel > nsIXULWindow::normalZ) 1.328 + SetZLevel(nsIXULWindow::normalZ); 1.329 + } 1.330 + mWindow->SetSizeMode(sizeMode); 1.331 + 1.332 + // Persist mode, but not immediately, because in many (all?) 1.333 + // cases this will merge with the similar call in NS_SIZE and 1.334 + // write the attribute values only once. 1.335 + SetPersistenceTimer(PAD_MISC); 1.336 + nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(mDocShell); 1.337 + if (ourWindow) { 1.338 + // Let the application know if it's in fullscreen mode so it 1.339 + // can update its UI. 1.340 + if (sizeMode == nsSizeMode_Fullscreen) { 1.341 + ourWindow->SetFullScreen(true); 1.342 + } 1.343 + else if (sizeMode != nsSizeMode_Minimized) { 1.344 + ourWindow->SetFullScreen(false); 1.345 + } 1.346 + 1.347 + // And always fire a user-defined sizemodechange event on the window 1.348 + ourWindow->DispatchCustomEvent("sizemodechange"); 1.349 + } 1.350 + 1.351 + // Note the current implementation of SetSizeMode just stores 1.352 + // the new state; it doesn't actually resize. So here we store 1.353 + // the state and pass the event on to the OS. The day is coming 1.354 + // when we'll handle the event here, and the return result will 1.355 + // then need to be different. 1.356 +} 1.357 + 1.358 +void 1.359 +nsWebShellWindow::OSToolbarButtonPressed() 1.360 +{ 1.361 + // Keep a reference as setting the chrome flags can fire events. 1.362 + nsCOMPtr<nsIXULWindow> xulWindow(this); 1.363 + 1.364 + // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA" 1.365 + // due to components with multiple sidebar components 1.366 + // (such as Mail/News, Addressbook, etc)... and frankly, 1.367 + // Mac IE, OmniWeb, and other Mac OS X apps all work this way 1.368 + uint32_t chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR | 1.369 + nsIWebBrowserChrome::CHROME_LOCATIONBAR | 1.370 + nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR); 1.371 + 1.372 + nsCOMPtr<nsIWebBrowserChrome> wbc(do_GetInterface(xulWindow)); 1.373 + if (!wbc) 1.374 + return; 1.375 + 1.376 + uint32_t chromeFlags, newChromeFlags = 0; 1.377 + wbc->GetChromeFlags(&chromeFlags); 1.378 + newChromeFlags = chromeFlags & chromeMask; 1.379 + if (!newChromeFlags) chromeFlags |= chromeMask; 1.380 + else chromeFlags &= (~newChromeFlags); 1.381 + wbc->SetChromeFlags(chromeFlags); 1.382 +} 1.383 + 1.384 +bool 1.385 +nsWebShellWindow::ZLevelChanged(bool aImmediate, nsWindowZ *aPlacement, 1.386 + nsIWidget* aRequestBelow, nsIWidget** aActualBelow) 1.387 +{ 1.388 + if (aActualBelow) 1.389 + *aActualBelow = nullptr; 1.390 + 1.391 + return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow); 1.392 +} 1.393 + 1.394 +void 1.395 +nsWebShellWindow::WindowActivated() 1.396 +{ 1.397 + nsCOMPtr<nsIXULWindow> xulWindow(this); 1.398 + 1.399 + // focusing the window could cause it to close, so keep a reference to it 1.400 + nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mDocShell); 1.401 + nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID); 1.402 + if (fm && window) 1.403 + fm->WindowRaised(window); 1.404 + 1.405 + if (mChromeLoaded) { 1.406 + PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC); 1.407 + SavePersistentAttributes(); 1.408 + } 1.409 +} 1.410 + 1.411 +void 1.412 +nsWebShellWindow::WindowDeactivated() 1.413 +{ 1.414 + nsCOMPtr<nsIXULWindow> xulWindow(this); 1.415 + 1.416 + nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell); 1.417 + nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID); 1.418 + if (fm && window) 1.419 + fm->WindowLowered(window); 1.420 +} 1.421 + 1.422 +#ifdef USE_NATIVE_MENUS 1.423 +static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow) 1.424 +{ 1.425 + // Find the menubar tag (if there is more than one, we ignore all but 1.426 + // the first). 1.427 + nsCOMPtr<nsIDOMNodeList> menubarElements; 1.428 + aDOMDoc->GetElementsByTagNameNS(NS_LITERAL_STRING("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"), 1.429 + NS_LITERAL_STRING("menubar"), 1.430 + getter_AddRefs(menubarElements)); 1.431 + 1.432 + nsCOMPtr<nsIDOMNode> menubarNode; 1.433 + if (menubarElements) 1.434 + menubarElements->Item(0, getter_AddRefs(menubarNode)); 1.435 + if (!menubarNode) 1.436 + return; 1.437 + 1.438 + nsCOMPtr<nsINativeMenuService> nms = do_GetService("@mozilla.org/widget/nativemenuservice;1"); 1.439 + nsCOMPtr<nsIContent> menubarContent(do_QueryInterface(menubarNode)); 1.440 + if (nms && menubarContent) 1.441 + nms->CreateNativeMenuBar(aParentWindow, menubarContent); 1.442 +} 1.443 +#endif 1.444 + 1.445 +namespace mozilla { 1.446 + 1.447 +class WebShellWindowTimerCallback MOZ_FINAL : public nsITimerCallback 1.448 +{ 1.449 +public: 1.450 + WebShellWindowTimerCallback(nsWebShellWindow* aWindow) 1.451 + : mWindow(aWindow) 1.452 + {} 1.453 + 1.454 + NS_DECL_THREADSAFE_ISUPPORTS 1.455 + 1.456 + NS_IMETHOD Notify(nsITimer* aTimer) 1.457 + { 1.458 + // Although this object participates in a refcount cycle (this -> mWindow 1.459 + // -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this 1.460 + // after it fires. So we don't need to release mWindow here. 1.461 + 1.462 + mWindow->FirePersistenceTimer(); 1.463 + return NS_OK; 1.464 + } 1.465 + 1.466 +private: 1.467 + nsRefPtr<nsWebShellWindow> mWindow; 1.468 +}; 1.469 + 1.470 +NS_IMPL_ISUPPORTS(WebShellWindowTimerCallback, nsITimerCallback) 1.471 + 1.472 +} // namespace mozilla 1.473 + 1.474 +void 1.475 +nsWebShellWindow::SetPersistenceTimer(uint32_t aDirtyFlags) 1.476 +{ 1.477 + MutexAutoLock lock(mSPTimerLock); 1.478 + if (!mSPTimer) { 1.479 + mSPTimer = do_CreateInstance("@mozilla.org/timer;1"); 1.480 + if (!mSPTimer) { 1.481 + NS_WARNING("Couldn't create @mozilla.org/timer;1 instance?"); 1.482 + return; 1.483 + } 1.484 + } 1.485 + 1.486 + nsRefPtr<WebShellWindowTimerCallback> callback = 1.487 + new WebShellWindowTimerCallback(this); 1.488 + mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT, 1.489 + nsITimer::TYPE_ONE_SHOT); 1.490 + 1.491 + PersistentAttributesDirty(aDirtyFlags); 1.492 +} 1.493 + 1.494 +void 1.495 +nsWebShellWindow::FirePersistenceTimer() 1.496 +{ 1.497 + MutexAutoLock lock(mSPTimerLock); 1.498 + SavePersistentAttributes(); 1.499 +} 1.500 + 1.501 + 1.502 +//---------------------------------------- 1.503 +// nsIWebProgessListener implementation 1.504 +//---------------------------------------- 1.505 +NS_IMETHODIMP 1.506 +nsWebShellWindow::OnProgressChange(nsIWebProgress *aProgress, 1.507 + nsIRequest *aRequest, 1.508 + int32_t aCurSelfProgress, 1.509 + int32_t aMaxSelfProgress, 1.510 + int32_t aCurTotalProgress, 1.511 + int32_t aMaxTotalProgress) 1.512 +{ 1.513 + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); 1.514 + return NS_OK; 1.515 +} 1.516 + 1.517 +NS_IMETHODIMP 1.518 +nsWebShellWindow::OnStateChange(nsIWebProgress *aProgress, 1.519 + nsIRequest *aRequest, 1.520 + uint32_t aStateFlags, 1.521 + nsresult aStatus) 1.522 +{ 1.523 + // If the notification is not about a document finishing, then just 1.524 + // ignore it... 1.525 + if (!(aStateFlags & nsIWebProgressListener::STATE_STOP) || 1.526 + !(aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)) { 1.527 + return NS_OK; 1.528 + } 1.529 + 1.530 + if (mChromeLoaded) 1.531 + return NS_OK; 1.532 + 1.533 + // If this document notification is for a frame then ignore it... 1.534 + nsCOMPtr<nsIDOMWindow> eventWin; 1.535 + aProgress->GetDOMWindow(getter_AddRefs(eventWin)); 1.536 + nsCOMPtr<nsPIDOMWindow> eventPWin(do_QueryInterface(eventWin)); 1.537 + if (eventPWin) { 1.538 + nsPIDOMWindow *rootPWin = eventPWin->GetPrivateRoot(); 1.539 + if (eventPWin != rootPWin) 1.540 + return NS_OK; 1.541 + } 1.542 + 1.543 + mChromeLoaded = true; 1.544 + mLockedUntilChromeLoad = false; 1.545 + 1.546 +#ifdef USE_NATIVE_MENUS 1.547 + /////////////////////////////// 1.548 + // Find the Menubar DOM and Load the menus, hooking them up to the loaded commands 1.549 + /////////////////////////////// 1.550 + nsCOMPtr<nsIContentViewer> cv; 1.551 + mDocShell->GetContentViewer(getter_AddRefs(cv)); 1.552 + if (cv) { 1.553 + nsCOMPtr<nsIDOMDocument> menubarDOMDoc(do_QueryInterface(cv->GetDocument())); 1.554 + if (menubarDOMDoc) 1.555 + LoadNativeMenus(menubarDOMDoc, mWindow); 1.556 + } 1.557 +#endif // USE_NATIVE_MENUS 1.558 + 1.559 + OnChromeLoaded(); 1.560 + LoadContentAreas(); 1.561 + 1.562 + return NS_OK; 1.563 +} 1.564 + 1.565 +NS_IMETHODIMP 1.566 +nsWebShellWindow::OnLocationChange(nsIWebProgress *aProgress, 1.567 + nsIRequest *aRequest, 1.568 + nsIURI *aURI, 1.569 + uint32_t aFlags) 1.570 +{ 1.571 + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); 1.572 + return NS_OK; 1.573 +} 1.574 + 1.575 +NS_IMETHODIMP 1.576 +nsWebShellWindow::OnStatusChange(nsIWebProgress* aWebProgress, 1.577 + nsIRequest* aRequest, 1.578 + nsresult aStatus, 1.579 + const char16_t* aMessage) 1.580 +{ 1.581 + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); 1.582 + return NS_OK; 1.583 +} 1.584 + 1.585 +NS_IMETHODIMP 1.586 +nsWebShellWindow::OnSecurityChange(nsIWebProgress *aWebProgress, 1.587 + nsIRequest *aRequest, 1.588 + uint32_t state) 1.589 +{ 1.590 + NS_NOTREACHED("notification excluded in AddProgressListener(...)"); 1.591 + return NS_OK; 1.592 +} 1.593 + 1.594 + 1.595 +//---------------------------------------- 1.596 + 1.597 +// if the main document URL specified URLs for any content areas, start them loading 1.598 +void nsWebShellWindow::LoadContentAreas() { 1.599 + 1.600 + nsAutoString searchSpec; 1.601 + 1.602 + // fetch the chrome document URL 1.603 + nsCOMPtr<nsIContentViewer> contentViewer; 1.604 + // yes, it's possible for the docshell to be null even this early 1.605 + // see bug 57514. 1.606 + if (mDocShell) 1.607 + mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); 1.608 + if (contentViewer) { 1.609 + nsIDocument* doc = contentViewer->GetDocument(); 1.610 + if (doc) { 1.611 + nsIURI* mainURL = doc->GetDocumentURI(); 1.612 + 1.613 + nsCOMPtr<nsIURL> url = do_QueryInterface(mainURL); 1.614 + if (url) { 1.615 + nsAutoCString search; 1.616 + url->GetQuery(search); 1.617 + 1.618 + AppendUTF8toUTF16(search, searchSpec); 1.619 + } 1.620 + } 1.621 + } 1.622 + 1.623 + // content URLs are specified in the search part of the URL 1.624 + // as <contentareaID>=<escapedURL>[;(repeat)] 1.625 + if (!searchSpec.IsEmpty()) { 1.626 + int32_t begPos, 1.627 + eqPos, 1.628 + endPos; 1.629 + nsString contentAreaID, 1.630 + contentURL; 1.631 + char *urlChar; 1.632 + nsresult rv; 1.633 + for (endPos = 0; endPos < (int32_t)searchSpec.Length(); ) { 1.634 + // extract contentAreaID and URL substrings 1.635 + begPos = endPos; 1.636 + eqPos = searchSpec.FindChar('=', begPos); 1.637 + if (eqPos < 0) 1.638 + break; 1.639 + 1.640 + endPos = searchSpec.FindChar(';', eqPos); 1.641 + if (endPos < 0) 1.642 + endPos = searchSpec.Length(); 1.643 + searchSpec.Mid(contentAreaID, begPos, eqPos-begPos); 1.644 + searchSpec.Mid(contentURL, eqPos+1, endPos-eqPos-1); 1.645 + endPos++; 1.646 + 1.647 + // see if we have a docshell with a matching contentAreaID 1.648 + nsCOMPtr<nsIDocShellTreeItem> content; 1.649 + rv = GetContentShellById(contentAreaID.get(), getter_AddRefs(content)); 1.650 + if (NS_SUCCEEDED(rv) && content) { 1.651 + nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(content)); 1.652 + if (webNav) { 1.653 + urlChar = ToNewCString(contentURL); 1.654 + if (urlChar) { 1.655 + nsUnescape(urlChar); 1.656 + contentURL.AssignWithConversion(urlChar); 1.657 + webNav->LoadURI(contentURL.get(), 1.658 + nsIWebNavigation::LOAD_FLAGS_NONE, 1.659 + nullptr, 1.660 + nullptr, 1.661 + nullptr); 1.662 + nsMemory::Free(urlChar); 1.663 + } 1.664 + } 1.665 + } 1.666 + } 1.667 + } 1.668 +} 1.669 + 1.670 +/** 1.671 + * ExecuteCloseHandler - Run the close handler, if any. 1.672 + * @return true iff we found a close handler to run. 1.673 + */ 1.674 +bool nsWebShellWindow::ExecuteCloseHandler() 1.675 +{ 1.676 + /* If the event handler closes this window -- a likely scenario -- 1.677 + things get deleted out of order without this death grip. 1.678 + (The problem may be the death grip in nsWindow::windowProc, 1.679 + which forces this window's widget to remain alive longer 1.680 + than it otherwise would.) */ 1.681 + nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this); 1.682 + 1.683 + nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell)); 1.684 + nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window); 1.685 + 1.686 + if (eventTarget) { 1.687 + nsCOMPtr<nsIContentViewer> contentViewer; 1.688 + mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); 1.689 + if (contentViewer) { 1.690 + nsRefPtr<nsPresContext> presContext; 1.691 + contentViewer->GetPresContext(getter_AddRefs(presContext)); 1.692 + 1.693 + nsEventStatus status = nsEventStatus_eIgnore; 1.694 + WidgetMouseEvent event(true, NS_XUL_CLOSE, nullptr, 1.695 + WidgetMouseEvent::eReal); 1.696 + 1.697 + nsresult rv = 1.698 + eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &status); 1.699 + if (NS_SUCCEEDED(rv) && status == nsEventStatus_eConsumeNoDefault) 1.700 + return true; 1.701 + // else fall through and return false 1.702 + } 1.703 + } 1.704 + 1.705 + return false; 1.706 +} // ExecuteCloseHandler 1.707 + 1.708 +void nsWebShellWindow::ConstrainToOpenerScreen(int32_t* aX, int32_t* aY) 1.709 +{ 1.710 + if (mOpenerScreenRect.IsEmpty()) { 1.711 + *aX = *aY = 0; 1.712 + return; 1.713 + } 1.714 + 1.715 + int32_t left, top, width, height; 1.716 + // Constrain initial positions to the same screen as opener 1.717 + nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1"); 1.718 + if (screenmgr) { 1.719 + nsCOMPtr<nsIScreen> screen; 1.720 + screenmgr->ScreenForRect(mOpenerScreenRect.x, mOpenerScreenRect.y, 1.721 + mOpenerScreenRect.width, mOpenerScreenRect.height, 1.722 + getter_AddRefs(screen)); 1.723 + if (screen) { 1.724 + screen->GetAvailRectDisplayPix(&left, &top, &width, &height); 1.725 + if (*aX < left || *aX > left + width) { 1.726 + *aX = left; 1.727 + } 1.728 + if (*aY < top || *aY > top + height) { 1.729 + *aY = top; 1.730 + } 1.731 + } 1.732 + } 1.733 +} 1.734 + 1.735 +// nsIBaseWindow 1.736 +NS_IMETHODIMP nsWebShellWindow::Destroy() 1.737 +{ 1.738 + nsresult rv; 1.739 + nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv)); 1.740 + if (webProgress) { 1.741 + webProgress->RemoveProgressListener(this); 1.742 + } 1.743 + 1.744 + nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this); 1.745 + { 1.746 + MutexAutoLock lock(mSPTimerLock); 1.747 + if (mSPTimer) { 1.748 + mSPTimer->Cancel(); 1.749 + SavePersistentAttributes(); 1.750 + mSPTimer = nullptr; 1.751 + } 1.752 + } 1.753 + return nsXULWindow::Destroy(); 1.754 +}