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