xpfe/appshell/src/nsWebShellWindow.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6
michael@0 7 #include "nsWebShellWindow.h"
michael@0 8
michael@0 9 #include "nsLayoutCID.h"
michael@0 10 #include "nsContentCID.h"
michael@0 11 #include "nsIWeakReference.h"
michael@0 12 #include "nsIContentViewer.h"
michael@0 13 #include "nsIComponentManager.h"
michael@0 14 #include "nsIServiceManager.h"
michael@0 15 #include "nsIURL.h"
michael@0 16 #include "nsIIOService.h"
michael@0 17 #include "nsIURL.h"
michael@0 18 #include "nsNetCID.h"
michael@0 19 #include "nsIStringBundle.h"
michael@0 20 #include "nsReadableUtils.h"
michael@0 21
michael@0 22 #include "nsEscape.h"
michael@0 23 #include "nsPIDOMWindow.h"
michael@0 24 #include "nsIWebNavigation.h"
michael@0 25 #include "nsIWindowWatcher.h"
michael@0 26
michael@0 27 #include "nsIDOMXULElement.h"
michael@0 28
michael@0 29 #include "nsWidgetInitData.h"
michael@0 30 #include "nsWidgetsCID.h"
michael@0 31 #include "nsIWidget.h"
michael@0 32 #include "nsIWidgetListener.h"
michael@0 33
michael@0 34 #include "nsIDOMCharacterData.h"
michael@0 35 #include "nsIDOMNodeList.h"
michael@0 36
michael@0 37 #include "nsITimer.h"
michael@0 38 #include "nsXULPopupManager.h"
michael@0 39
michael@0 40
michael@0 41 #include "nsIDOMXULDocument.h"
michael@0 42
michael@0 43 #include "nsFocusManager.h"
michael@0 44
michael@0 45 #include "nsIWebProgress.h"
michael@0 46 #include "nsIWebProgressListener.h"
michael@0 47
michael@0 48 #include "nsIDocument.h"
michael@0 49 #include "nsIDOMDocument.h"
michael@0 50 #include "nsIDOMNode.h"
michael@0 51 #include "nsIDOMElement.h"
michael@0 52 #include "nsIDocumentLoaderFactory.h"
michael@0 53 #include "nsIObserverService.h"
michael@0 54 #include "prprf.h"
michael@0 55
michael@0 56 #include "nsIScreenManager.h"
michael@0 57 #include "nsIScreen.h"
michael@0 58
michael@0 59 #include "nsIContent.h" // for menus
michael@0 60 #include "nsIScriptSecurityManager.h"
michael@0 61
michael@0 62 // For calculating size
michael@0 63 #include "nsIPresShell.h"
michael@0 64 #include "nsPresContext.h"
michael@0 65
michael@0 66 #include "nsIBaseWindow.h"
michael@0 67 #include "nsIDocShellTreeItem.h"
michael@0 68
michael@0 69 #include "nsIMarkupDocumentViewer.h"
michael@0 70 #include "mozilla/Attributes.h"
michael@0 71 #include "mozilla/DebugOnly.h"
michael@0 72 #include "mozilla/MouseEvents.h"
michael@0 73
michael@0 74 #ifdef XP_MACOSX
michael@0 75 #include "nsINativeMenuService.h"
michael@0 76 #define USE_NATIVE_MENUS
michael@0 77 #endif
michael@0 78
michael@0 79 using namespace mozilla;
michael@0 80 using namespace mozilla::dom;
michael@0 81
michael@0 82 /* Define Class IDs */
michael@0 83 static NS_DEFINE_CID(kWindowCID, NS_WINDOW_CID);
michael@0 84
michael@0 85 #define SIZE_PERSISTENCE_TIMEOUT 500 // msec
michael@0 86
michael@0 87 nsWebShellWindow::nsWebShellWindow(uint32_t aChromeFlags)
michael@0 88 : nsXULWindow(aChromeFlags)
michael@0 89 , mSPTimerLock("nsWebShellWindow.mSPTimerLock")
michael@0 90 {
michael@0 91 }
michael@0 92
michael@0 93 nsWebShellWindow::~nsWebShellWindow()
michael@0 94 {
michael@0 95 MutexAutoLock lock(mSPTimerLock);
michael@0 96 if (mSPTimer)
michael@0 97 mSPTimer->Cancel();
michael@0 98 }
michael@0 99
michael@0 100 NS_IMPL_ADDREF_INHERITED(nsWebShellWindow, nsXULWindow)
michael@0 101 NS_IMPL_RELEASE_INHERITED(nsWebShellWindow, nsXULWindow)
michael@0 102
michael@0 103 NS_INTERFACE_MAP_BEGIN(nsWebShellWindow)
michael@0 104 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
michael@0 105 NS_INTERFACE_MAP_END_INHERITING(nsXULWindow)
michael@0 106
michael@0 107 nsresult nsWebShellWindow::Initialize(nsIXULWindow* aParent,
michael@0 108 nsIXULWindow* aOpener,
michael@0 109 nsIURI* aUrl,
michael@0 110 int32_t aInitialWidth,
michael@0 111 int32_t aInitialHeight,
michael@0 112 bool aIsHiddenWindow,
michael@0 113 nsWidgetInitData& widgetInitData)
michael@0 114 {
michael@0 115 nsresult rv;
michael@0 116 nsCOMPtr<nsIWidget> parentWidget;
michael@0 117
michael@0 118 mIsHiddenWindow = aIsHiddenWindow;
michael@0 119
michael@0 120 int32_t initialX = 0, initialY = 0;
michael@0 121 nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(aOpener));
michael@0 122 if (base) {
michael@0 123 rv = base->GetPositionAndSize(&mOpenerScreenRect.x,
michael@0 124 &mOpenerScreenRect.y,
michael@0 125 &mOpenerScreenRect.width,
michael@0 126 &mOpenerScreenRect.height);
michael@0 127 if (NS_FAILED(rv)) {
michael@0 128 mOpenerScreenRect.SetEmpty();
michael@0 129 } else {
michael@0 130 double scale;
michael@0 131 if (NS_SUCCEEDED(base->GetUnscaledDevicePixelsPerCSSPixel(&scale))) {
michael@0 132 mOpenerScreenRect.x = NSToIntRound(mOpenerScreenRect.x / scale);
michael@0 133 mOpenerScreenRect.y = NSToIntRound(mOpenerScreenRect.y / scale);
michael@0 134 mOpenerScreenRect.width = NSToIntRound(mOpenerScreenRect.width / scale);
michael@0 135 mOpenerScreenRect.height = NSToIntRound(mOpenerScreenRect.height / scale);
michael@0 136 }
michael@0 137 initialX = mOpenerScreenRect.x;
michael@0 138 initialY = mOpenerScreenRect.y;
michael@0 139 ConstrainToOpenerScreen(&initialX, &initialY);
michael@0 140 }
michael@0 141 }
michael@0 142
michael@0 143 // XXX: need to get the default window size from prefs...
michael@0 144 // Doesn't come from prefs... will come from CSS/XUL/RDF
michael@0 145 nsIntRect r(initialX, initialY, aInitialWidth, aInitialHeight);
michael@0 146
michael@0 147 // Create top level window
michael@0 148 mWindow = do_CreateInstance(kWindowCID, &rv);
michael@0 149 if (NS_OK != rv) {
michael@0 150 return rv;
michael@0 151 }
michael@0 152
michael@0 153 /* This next bit is troublesome. We carry two different versions of a pointer
michael@0 154 to our parent window. One is the parent window's widget, which is passed
michael@0 155 to our own widget. The other is a weak reference we keep here to our
michael@0 156 parent WebShellWindow. The former is useful to the widget, and we can't
michael@0 157 trust its treatment of the parent reference because they're platform-
michael@0 158 specific. The latter is useful to this class.
michael@0 159 A better implementation would be one in which the parent keeps strong
michael@0 160 references to its children and closes them before it allows itself
michael@0 161 to be closed. This would mimic the behaviour of OSes that support
michael@0 162 top-level child windows in OSes that do not. Later.
michael@0 163 */
michael@0 164 nsCOMPtr<nsIBaseWindow> parentAsWin(do_QueryInterface(aParent));
michael@0 165 if (parentAsWin) {
michael@0 166 parentAsWin->GetMainWidget(getter_AddRefs(parentWidget));
michael@0 167 mParentWindow = do_GetWeakReference(aParent);
michael@0 168 }
michael@0 169
michael@0 170 mWindow->SetWidgetListener(this);
michael@0 171 mWindow->Create((nsIWidget *)parentWidget, // Parent nsIWidget
michael@0 172 nullptr, // Native parent widget
michael@0 173 r, // Widget dimensions
michael@0 174 nullptr, // Device context
michael@0 175 &widgetInitData); // Widget initialization data
michael@0 176 mWindow->GetClientBounds(r);
michael@0 177 // Match the default background color of content. Important on windows
michael@0 178 // since we no longer use content child widgets.
michael@0 179 mWindow->SetBackgroundColor(NS_RGB(255,255,255));
michael@0 180
michael@0 181 // Create web shell
michael@0 182 mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
michael@0 183 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
michael@0 184
michael@0 185 // Make sure to set the item type on the docshell _before_ calling
michael@0 186 // Create() so it knows what type it is.
michael@0 187 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
michael@0 188 NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
michael@0 189 NS_ENSURE_SUCCESS(EnsureChromeTreeOwner(), NS_ERROR_FAILURE);
michael@0 190
michael@0 191 docShellAsItem->SetTreeOwner(mChromeTreeOwner);
michael@0 192 docShellAsItem->SetItemType(nsIDocShellTreeItem::typeChrome);
michael@0 193
michael@0 194 r.x = r.y = 0;
michael@0 195 nsCOMPtr<nsIBaseWindow> docShellAsWin(do_QueryInterface(mDocShell));
michael@0 196 NS_ENSURE_SUCCESS(docShellAsWin->InitWindow(nullptr, mWindow,
michael@0 197 r.x, r.y, r.width, r.height), NS_ERROR_FAILURE);
michael@0 198 NS_ENSURE_SUCCESS(docShellAsWin->Create(), NS_ERROR_FAILURE);
michael@0 199
michael@0 200 // Attach a WebProgress listener.during initialization...
michael@0 201 nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
michael@0 202 if (webProgress) {
michael@0 203 webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_NETWORK);
michael@0 204 }
michael@0 205
michael@0 206 // Eagerly create an about:blank content viewer with the right principal here,
michael@0 207 // rather than letting it happening in the upcoming call to
michael@0 208 // SetInitialPrincipalToSubject. This avoids creating the about:blank document
michael@0 209 // and then blowing it away with a second one, which can cause problems for the
michael@0 210 // top-level chrome window case. See bug 789773.
michael@0 211 nsCOMPtr<nsIScriptSecurityManager> ssm =
michael@0 212 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
michael@0 213 if (ssm) { // Sometimes this happens really early See bug 793370.
michael@0 214 nsCOMPtr<nsIPrincipal> principal;
michael@0 215 ssm->GetSubjectPrincipal(getter_AddRefs(principal));
michael@0 216 if (!principal) {
michael@0 217 ssm->GetSystemPrincipal(getter_AddRefs(principal));
michael@0 218 }
michael@0 219 rv = mDocShell->CreateAboutBlankContentViewer(principal);
michael@0 220 NS_ENSURE_SUCCESS(rv, rv);
michael@0 221 nsCOMPtr<nsIDocument> doc = do_GetInterface(mDocShell);
michael@0 222 NS_ENSURE_TRUE(!!doc, NS_ERROR_FAILURE);
michael@0 223 doc->SetIsInitialDocument(true);
michael@0 224 }
michael@0 225
michael@0 226 if (nullptr != aUrl) {
michael@0 227 nsCString tmpStr;
michael@0 228
michael@0 229 rv = aUrl->GetSpec(tmpStr);
michael@0 230 if (NS_FAILED(rv)) return rv;
michael@0 231
michael@0 232 NS_ConvertUTF8toUTF16 urlString(tmpStr);
michael@0 233 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
michael@0 234 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
michael@0 235 rv = webNav->LoadURI(urlString.get(),
michael@0 236 nsIWebNavigation::LOAD_FLAGS_NONE,
michael@0 237 nullptr,
michael@0 238 nullptr,
michael@0 239 nullptr);
michael@0 240 NS_ENSURE_SUCCESS(rv, rv);
michael@0 241 }
michael@0 242
michael@0 243 return rv;
michael@0 244 }
michael@0 245
michael@0 246 nsIPresShell*
michael@0 247 nsWebShellWindow::GetPresShell()
michael@0 248 {
michael@0 249 if (!mDocShell)
michael@0 250 return nullptr;
michael@0 251
michael@0 252 return mDocShell->GetPresShell();
michael@0 253 }
michael@0 254
michael@0 255 bool
michael@0 256 nsWebShellWindow::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y)
michael@0 257 {
michael@0 258 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
michael@0 259 if (pm) {
michael@0 260 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
michael@0 261 pm->AdjustPopupsOnWindowChange(window);
michael@0 262 }
michael@0 263
michael@0 264 // Persist position, but not immediately, in case this OS is firing
michael@0 265 // repeated move events as the user drags the window
michael@0 266 SetPersistenceTimer(PAD_POSITION);
michael@0 267 return false;
michael@0 268 }
michael@0 269
michael@0 270 bool
michael@0 271 nsWebShellWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight)
michael@0 272 {
michael@0 273 nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
michael@0 274 if (shellAsWin) {
michael@0 275 shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, false);
michael@0 276 }
michael@0 277 // Persist size, but not immediately, in case this OS is firing
michael@0 278 // repeated size events as the user drags the sizing handle
michael@0 279 if (!IsLocked())
michael@0 280 SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC);
michael@0 281 return true;
michael@0 282 }
michael@0 283
michael@0 284 bool
michael@0 285 nsWebShellWindow::RequestWindowClose(nsIWidget* aWidget)
michael@0 286 {
michael@0 287 // Maintain a reference to this as it is about to get destroyed.
michael@0 288 nsCOMPtr<nsIXULWindow> xulWindow(this);
michael@0 289
michael@0 290 nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell));
michael@0 291 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window);
michael@0 292
michael@0 293 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
michael@0 294
michael@0 295 if (!presShell) {
michael@0 296 mozilla::DebugOnly<bool> dying;
michael@0 297 MOZ_ASSERT(NS_SUCCEEDED(mDocShell->IsBeingDestroyed(&dying)) && dying,
michael@0 298 "No presShell, but window is not being destroyed");
michael@0 299 } else if (eventTarget) {
michael@0 300 nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
michael@0 301
michael@0 302 nsEventStatus status = nsEventStatus_eIgnore;
michael@0 303 WidgetMouseEvent event(true, NS_XUL_CLOSE, nullptr,
michael@0 304 WidgetMouseEvent::eReal);
michael@0 305 if (NS_SUCCEEDED(eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &status)) &&
michael@0 306 status == nsEventStatus_eConsumeNoDefault)
michael@0 307 return false;
michael@0 308 }
michael@0 309
michael@0 310 Destroy();
michael@0 311 return false;
michael@0 312 }
michael@0 313
michael@0 314 void
michael@0 315 nsWebShellWindow::SizeModeChanged(nsSizeMode sizeMode)
michael@0 316 {
michael@0 317 // An alwaysRaised (or higher) window will hide any newly opened normal
michael@0 318 // browser windows, so here we just drop a raised window to the normal
michael@0 319 // zlevel if it's maximized. We make no provision for automatically
michael@0 320 // re-raising it when restored.
michael@0 321 if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) {
michael@0 322 uint32_t zLevel;
michael@0 323 GetZLevel(&zLevel);
michael@0 324 if (zLevel > nsIXULWindow::normalZ)
michael@0 325 SetZLevel(nsIXULWindow::normalZ);
michael@0 326 }
michael@0 327 mWindow->SetSizeMode(sizeMode);
michael@0 328
michael@0 329 // Persist mode, but not immediately, because in many (all?)
michael@0 330 // cases this will merge with the similar call in NS_SIZE and
michael@0 331 // write the attribute values only once.
michael@0 332 SetPersistenceTimer(PAD_MISC);
michael@0 333 nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(mDocShell);
michael@0 334 if (ourWindow) {
michael@0 335 // Let the application know if it's in fullscreen mode so it
michael@0 336 // can update its UI.
michael@0 337 if (sizeMode == nsSizeMode_Fullscreen) {
michael@0 338 ourWindow->SetFullScreen(true);
michael@0 339 }
michael@0 340 else if (sizeMode != nsSizeMode_Minimized) {
michael@0 341 ourWindow->SetFullScreen(false);
michael@0 342 }
michael@0 343
michael@0 344 // And always fire a user-defined sizemodechange event on the window
michael@0 345 ourWindow->DispatchCustomEvent("sizemodechange");
michael@0 346 }
michael@0 347
michael@0 348 // Note the current implementation of SetSizeMode just stores
michael@0 349 // the new state; it doesn't actually resize. So here we store
michael@0 350 // the state and pass the event on to the OS. The day is coming
michael@0 351 // when we'll handle the event here, and the return result will
michael@0 352 // then need to be different.
michael@0 353 }
michael@0 354
michael@0 355 void
michael@0 356 nsWebShellWindow::OSToolbarButtonPressed()
michael@0 357 {
michael@0 358 // Keep a reference as setting the chrome flags can fire events.
michael@0 359 nsCOMPtr<nsIXULWindow> xulWindow(this);
michael@0 360
michael@0 361 // rjc: don't use "nsIWebBrowserChrome::CHROME_EXTRA"
michael@0 362 // due to components with multiple sidebar components
michael@0 363 // (such as Mail/News, Addressbook, etc)... and frankly,
michael@0 364 // Mac IE, OmniWeb, and other Mac OS X apps all work this way
michael@0 365 uint32_t chromeMask = (nsIWebBrowserChrome::CHROME_TOOLBAR |
michael@0 366 nsIWebBrowserChrome::CHROME_LOCATIONBAR |
michael@0 367 nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR);
michael@0 368
michael@0 369 nsCOMPtr<nsIWebBrowserChrome> wbc(do_GetInterface(xulWindow));
michael@0 370 if (!wbc)
michael@0 371 return;
michael@0 372
michael@0 373 uint32_t chromeFlags, newChromeFlags = 0;
michael@0 374 wbc->GetChromeFlags(&chromeFlags);
michael@0 375 newChromeFlags = chromeFlags & chromeMask;
michael@0 376 if (!newChromeFlags) chromeFlags |= chromeMask;
michael@0 377 else chromeFlags &= (~newChromeFlags);
michael@0 378 wbc->SetChromeFlags(chromeFlags);
michael@0 379 }
michael@0 380
michael@0 381 bool
michael@0 382 nsWebShellWindow::ZLevelChanged(bool aImmediate, nsWindowZ *aPlacement,
michael@0 383 nsIWidget* aRequestBelow, nsIWidget** aActualBelow)
michael@0 384 {
michael@0 385 if (aActualBelow)
michael@0 386 *aActualBelow = nullptr;
michael@0 387
michael@0 388 return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow);
michael@0 389 }
michael@0 390
michael@0 391 void
michael@0 392 nsWebShellWindow::WindowActivated()
michael@0 393 {
michael@0 394 nsCOMPtr<nsIXULWindow> xulWindow(this);
michael@0 395
michael@0 396 // focusing the window could cause it to close, so keep a reference to it
michael@0 397 nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mDocShell);
michael@0 398 nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
michael@0 399 if (fm && window)
michael@0 400 fm->WindowRaised(window);
michael@0 401
michael@0 402 if (mChromeLoaded) {
michael@0 403 PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC);
michael@0 404 SavePersistentAttributes();
michael@0 405 }
michael@0 406 }
michael@0 407
michael@0 408 void
michael@0 409 nsWebShellWindow::WindowDeactivated()
michael@0 410 {
michael@0 411 nsCOMPtr<nsIXULWindow> xulWindow(this);
michael@0 412
michael@0 413 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
michael@0 414 nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
michael@0 415 if (fm && window)
michael@0 416 fm->WindowLowered(window);
michael@0 417 }
michael@0 418
michael@0 419 #ifdef USE_NATIVE_MENUS
michael@0 420 static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow)
michael@0 421 {
michael@0 422 // Find the menubar tag (if there is more than one, we ignore all but
michael@0 423 // the first).
michael@0 424 nsCOMPtr<nsIDOMNodeList> menubarElements;
michael@0 425 aDOMDoc->GetElementsByTagNameNS(NS_LITERAL_STRING("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"),
michael@0 426 NS_LITERAL_STRING("menubar"),
michael@0 427 getter_AddRefs(menubarElements));
michael@0 428
michael@0 429 nsCOMPtr<nsIDOMNode> menubarNode;
michael@0 430 if (menubarElements)
michael@0 431 menubarElements->Item(0, getter_AddRefs(menubarNode));
michael@0 432 if (!menubarNode)
michael@0 433 return;
michael@0 434
michael@0 435 nsCOMPtr<nsINativeMenuService> nms = do_GetService("@mozilla.org/widget/nativemenuservice;1");
michael@0 436 nsCOMPtr<nsIContent> menubarContent(do_QueryInterface(menubarNode));
michael@0 437 if (nms && menubarContent)
michael@0 438 nms->CreateNativeMenuBar(aParentWindow, menubarContent);
michael@0 439 }
michael@0 440 #endif
michael@0 441
michael@0 442 namespace mozilla {
michael@0 443
michael@0 444 class WebShellWindowTimerCallback MOZ_FINAL : public nsITimerCallback
michael@0 445 {
michael@0 446 public:
michael@0 447 WebShellWindowTimerCallback(nsWebShellWindow* aWindow)
michael@0 448 : mWindow(aWindow)
michael@0 449 {}
michael@0 450
michael@0 451 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 452
michael@0 453 NS_IMETHOD Notify(nsITimer* aTimer)
michael@0 454 {
michael@0 455 // Although this object participates in a refcount cycle (this -> mWindow
michael@0 456 // -> mSPTimer -> this), mSPTimer is a one-shot timer and releases this
michael@0 457 // after it fires. So we don't need to release mWindow here.
michael@0 458
michael@0 459 mWindow->FirePersistenceTimer();
michael@0 460 return NS_OK;
michael@0 461 }
michael@0 462
michael@0 463 private:
michael@0 464 nsRefPtr<nsWebShellWindow> mWindow;
michael@0 465 };
michael@0 466
michael@0 467 NS_IMPL_ISUPPORTS(WebShellWindowTimerCallback, nsITimerCallback)
michael@0 468
michael@0 469 } // namespace mozilla
michael@0 470
michael@0 471 void
michael@0 472 nsWebShellWindow::SetPersistenceTimer(uint32_t aDirtyFlags)
michael@0 473 {
michael@0 474 MutexAutoLock lock(mSPTimerLock);
michael@0 475 if (!mSPTimer) {
michael@0 476 mSPTimer = do_CreateInstance("@mozilla.org/timer;1");
michael@0 477 if (!mSPTimer) {
michael@0 478 NS_WARNING("Couldn't create @mozilla.org/timer;1 instance?");
michael@0 479 return;
michael@0 480 }
michael@0 481 }
michael@0 482
michael@0 483 nsRefPtr<WebShellWindowTimerCallback> callback =
michael@0 484 new WebShellWindowTimerCallback(this);
michael@0 485 mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT,
michael@0 486 nsITimer::TYPE_ONE_SHOT);
michael@0 487
michael@0 488 PersistentAttributesDirty(aDirtyFlags);
michael@0 489 }
michael@0 490
michael@0 491 void
michael@0 492 nsWebShellWindow::FirePersistenceTimer()
michael@0 493 {
michael@0 494 MutexAutoLock lock(mSPTimerLock);
michael@0 495 SavePersistentAttributes();
michael@0 496 }
michael@0 497
michael@0 498
michael@0 499 //----------------------------------------
michael@0 500 // nsIWebProgessListener implementation
michael@0 501 //----------------------------------------
michael@0 502 NS_IMETHODIMP
michael@0 503 nsWebShellWindow::OnProgressChange(nsIWebProgress *aProgress,
michael@0 504 nsIRequest *aRequest,
michael@0 505 int32_t aCurSelfProgress,
michael@0 506 int32_t aMaxSelfProgress,
michael@0 507 int32_t aCurTotalProgress,
michael@0 508 int32_t aMaxTotalProgress)
michael@0 509 {
michael@0 510 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
michael@0 511 return NS_OK;
michael@0 512 }
michael@0 513
michael@0 514 NS_IMETHODIMP
michael@0 515 nsWebShellWindow::OnStateChange(nsIWebProgress *aProgress,
michael@0 516 nsIRequest *aRequest,
michael@0 517 uint32_t aStateFlags,
michael@0 518 nsresult aStatus)
michael@0 519 {
michael@0 520 // If the notification is not about a document finishing, then just
michael@0 521 // ignore it...
michael@0 522 if (!(aStateFlags & nsIWebProgressListener::STATE_STOP) ||
michael@0 523 !(aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)) {
michael@0 524 return NS_OK;
michael@0 525 }
michael@0 526
michael@0 527 if (mChromeLoaded)
michael@0 528 return NS_OK;
michael@0 529
michael@0 530 // If this document notification is for a frame then ignore it...
michael@0 531 nsCOMPtr<nsIDOMWindow> eventWin;
michael@0 532 aProgress->GetDOMWindow(getter_AddRefs(eventWin));
michael@0 533 nsCOMPtr<nsPIDOMWindow> eventPWin(do_QueryInterface(eventWin));
michael@0 534 if (eventPWin) {
michael@0 535 nsPIDOMWindow *rootPWin = eventPWin->GetPrivateRoot();
michael@0 536 if (eventPWin != rootPWin)
michael@0 537 return NS_OK;
michael@0 538 }
michael@0 539
michael@0 540 mChromeLoaded = true;
michael@0 541 mLockedUntilChromeLoad = false;
michael@0 542
michael@0 543 #ifdef USE_NATIVE_MENUS
michael@0 544 ///////////////////////////////
michael@0 545 // Find the Menubar DOM and Load the menus, hooking them up to the loaded commands
michael@0 546 ///////////////////////////////
michael@0 547 nsCOMPtr<nsIContentViewer> cv;
michael@0 548 mDocShell->GetContentViewer(getter_AddRefs(cv));
michael@0 549 if (cv) {
michael@0 550 nsCOMPtr<nsIDOMDocument> menubarDOMDoc(do_QueryInterface(cv->GetDocument()));
michael@0 551 if (menubarDOMDoc)
michael@0 552 LoadNativeMenus(menubarDOMDoc, mWindow);
michael@0 553 }
michael@0 554 #endif // USE_NATIVE_MENUS
michael@0 555
michael@0 556 OnChromeLoaded();
michael@0 557 LoadContentAreas();
michael@0 558
michael@0 559 return NS_OK;
michael@0 560 }
michael@0 561
michael@0 562 NS_IMETHODIMP
michael@0 563 nsWebShellWindow::OnLocationChange(nsIWebProgress *aProgress,
michael@0 564 nsIRequest *aRequest,
michael@0 565 nsIURI *aURI,
michael@0 566 uint32_t aFlags)
michael@0 567 {
michael@0 568 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
michael@0 569 return NS_OK;
michael@0 570 }
michael@0 571
michael@0 572 NS_IMETHODIMP
michael@0 573 nsWebShellWindow::OnStatusChange(nsIWebProgress* aWebProgress,
michael@0 574 nsIRequest* aRequest,
michael@0 575 nsresult aStatus,
michael@0 576 const char16_t* aMessage)
michael@0 577 {
michael@0 578 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
michael@0 579 return NS_OK;
michael@0 580 }
michael@0 581
michael@0 582 NS_IMETHODIMP
michael@0 583 nsWebShellWindow::OnSecurityChange(nsIWebProgress *aWebProgress,
michael@0 584 nsIRequest *aRequest,
michael@0 585 uint32_t state)
michael@0 586 {
michael@0 587 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
michael@0 588 return NS_OK;
michael@0 589 }
michael@0 590
michael@0 591
michael@0 592 //----------------------------------------
michael@0 593
michael@0 594 // if the main document URL specified URLs for any content areas, start them loading
michael@0 595 void nsWebShellWindow::LoadContentAreas() {
michael@0 596
michael@0 597 nsAutoString searchSpec;
michael@0 598
michael@0 599 // fetch the chrome document URL
michael@0 600 nsCOMPtr<nsIContentViewer> contentViewer;
michael@0 601 // yes, it's possible for the docshell to be null even this early
michael@0 602 // see bug 57514.
michael@0 603 if (mDocShell)
michael@0 604 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
michael@0 605 if (contentViewer) {
michael@0 606 nsIDocument* doc = contentViewer->GetDocument();
michael@0 607 if (doc) {
michael@0 608 nsIURI* mainURL = doc->GetDocumentURI();
michael@0 609
michael@0 610 nsCOMPtr<nsIURL> url = do_QueryInterface(mainURL);
michael@0 611 if (url) {
michael@0 612 nsAutoCString search;
michael@0 613 url->GetQuery(search);
michael@0 614
michael@0 615 AppendUTF8toUTF16(search, searchSpec);
michael@0 616 }
michael@0 617 }
michael@0 618 }
michael@0 619
michael@0 620 // content URLs are specified in the search part of the URL
michael@0 621 // as <contentareaID>=<escapedURL>[;(repeat)]
michael@0 622 if (!searchSpec.IsEmpty()) {
michael@0 623 int32_t begPos,
michael@0 624 eqPos,
michael@0 625 endPos;
michael@0 626 nsString contentAreaID,
michael@0 627 contentURL;
michael@0 628 char *urlChar;
michael@0 629 nsresult rv;
michael@0 630 for (endPos = 0; endPos < (int32_t)searchSpec.Length(); ) {
michael@0 631 // extract contentAreaID and URL substrings
michael@0 632 begPos = endPos;
michael@0 633 eqPos = searchSpec.FindChar('=', begPos);
michael@0 634 if (eqPos < 0)
michael@0 635 break;
michael@0 636
michael@0 637 endPos = searchSpec.FindChar(';', eqPos);
michael@0 638 if (endPos < 0)
michael@0 639 endPos = searchSpec.Length();
michael@0 640 searchSpec.Mid(contentAreaID, begPos, eqPos-begPos);
michael@0 641 searchSpec.Mid(contentURL, eqPos+1, endPos-eqPos-1);
michael@0 642 endPos++;
michael@0 643
michael@0 644 // see if we have a docshell with a matching contentAreaID
michael@0 645 nsCOMPtr<nsIDocShellTreeItem> content;
michael@0 646 rv = GetContentShellById(contentAreaID.get(), getter_AddRefs(content));
michael@0 647 if (NS_SUCCEEDED(rv) && content) {
michael@0 648 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(content));
michael@0 649 if (webNav) {
michael@0 650 urlChar = ToNewCString(contentURL);
michael@0 651 if (urlChar) {
michael@0 652 nsUnescape(urlChar);
michael@0 653 contentURL.AssignWithConversion(urlChar);
michael@0 654 webNav->LoadURI(contentURL.get(),
michael@0 655 nsIWebNavigation::LOAD_FLAGS_NONE,
michael@0 656 nullptr,
michael@0 657 nullptr,
michael@0 658 nullptr);
michael@0 659 nsMemory::Free(urlChar);
michael@0 660 }
michael@0 661 }
michael@0 662 }
michael@0 663 }
michael@0 664 }
michael@0 665 }
michael@0 666
michael@0 667 /**
michael@0 668 * ExecuteCloseHandler - Run the close handler, if any.
michael@0 669 * @return true iff we found a close handler to run.
michael@0 670 */
michael@0 671 bool nsWebShellWindow::ExecuteCloseHandler()
michael@0 672 {
michael@0 673 /* If the event handler closes this window -- a likely scenario --
michael@0 674 things get deleted out of order without this death grip.
michael@0 675 (The problem may be the death grip in nsWindow::windowProc,
michael@0 676 which forces this window's widget to remain alive longer
michael@0 677 than it otherwise would.) */
michael@0 678 nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
michael@0 679
michael@0 680 nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell));
michael@0 681 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window);
michael@0 682
michael@0 683 if (eventTarget) {
michael@0 684 nsCOMPtr<nsIContentViewer> contentViewer;
michael@0 685 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
michael@0 686 if (contentViewer) {
michael@0 687 nsRefPtr<nsPresContext> presContext;
michael@0 688 contentViewer->GetPresContext(getter_AddRefs(presContext));
michael@0 689
michael@0 690 nsEventStatus status = nsEventStatus_eIgnore;
michael@0 691 WidgetMouseEvent event(true, NS_XUL_CLOSE, nullptr,
michael@0 692 WidgetMouseEvent::eReal);
michael@0 693
michael@0 694 nsresult rv =
michael@0 695 eventTarget->DispatchDOMEvent(&event, nullptr, presContext, &status);
michael@0 696 if (NS_SUCCEEDED(rv) && status == nsEventStatus_eConsumeNoDefault)
michael@0 697 return true;
michael@0 698 // else fall through and return false
michael@0 699 }
michael@0 700 }
michael@0 701
michael@0 702 return false;
michael@0 703 } // ExecuteCloseHandler
michael@0 704
michael@0 705 void nsWebShellWindow::ConstrainToOpenerScreen(int32_t* aX, int32_t* aY)
michael@0 706 {
michael@0 707 if (mOpenerScreenRect.IsEmpty()) {
michael@0 708 *aX = *aY = 0;
michael@0 709 return;
michael@0 710 }
michael@0 711
michael@0 712 int32_t left, top, width, height;
michael@0 713 // Constrain initial positions to the same screen as opener
michael@0 714 nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
michael@0 715 if (screenmgr) {
michael@0 716 nsCOMPtr<nsIScreen> screen;
michael@0 717 screenmgr->ScreenForRect(mOpenerScreenRect.x, mOpenerScreenRect.y,
michael@0 718 mOpenerScreenRect.width, mOpenerScreenRect.height,
michael@0 719 getter_AddRefs(screen));
michael@0 720 if (screen) {
michael@0 721 screen->GetAvailRectDisplayPix(&left, &top, &width, &height);
michael@0 722 if (*aX < left || *aX > left + width) {
michael@0 723 *aX = left;
michael@0 724 }
michael@0 725 if (*aY < top || *aY > top + height) {
michael@0 726 *aY = top;
michael@0 727 }
michael@0 728 }
michael@0 729 }
michael@0 730 }
michael@0 731
michael@0 732 // nsIBaseWindow
michael@0 733 NS_IMETHODIMP nsWebShellWindow::Destroy()
michael@0 734 {
michael@0 735 nsresult rv;
michael@0 736 nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
michael@0 737 if (webProgress) {
michael@0 738 webProgress->RemoveProgressListener(this);
michael@0 739 }
michael@0 740
michael@0 741 nsCOMPtr<nsIXULWindow> kungFuDeathGrip(this);
michael@0 742 {
michael@0 743 MutexAutoLock lock(mSPTimerLock);
michael@0 744 if (mSPTimer) {
michael@0 745 mSPTimer->Cancel();
michael@0 746 SavePersistentAttributes();
michael@0 747 mSPTimer = nullptr;
michael@0 748 }
michael@0 749 }
michael@0 750 return nsXULWindow::Destroy();
michael@0 751 }

mercurial