nsWebShellWindow.cpp 28 KB

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