|
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 |
|
6 |
|
7 #include "nsWebShellWindow.h" |
|
8 |
|
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" |
|
21 |
|
22 #include "nsEscape.h" |
|
23 #include "nsPIDOMWindow.h" |
|
24 #include "nsIWebNavigation.h" |
|
25 #include "nsIWindowWatcher.h" |
|
26 |
|
27 #include "nsIDOMXULElement.h" |
|
28 |
|
29 #include "nsWidgetInitData.h" |
|
30 #include "nsWidgetsCID.h" |
|
31 #include "nsIWidget.h" |
|
32 #include "nsIWidgetListener.h" |
|
33 |
|
34 #include "nsIDOMCharacterData.h" |
|
35 #include "nsIDOMNodeList.h" |
|
36 |
|
37 #include "nsITimer.h" |
|
38 #include "nsXULPopupManager.h" |
|
39 |
|
40 |
|
41 #include "nsIDOMXULDocument.h" |
|
42 |
|
43 #include "nsFocusManager.h" |
|
44 |
|
45 #include "nsIWebProgress.h" |
|
46 #include "nsIWebProgressListener.h" |
|
47 |
|
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" |
|
55 |
|
56 #include "nsIScreenManager.h" |
|
57 #include "nsIScreen.h" |
|
58 |
|
59 #include "nsIContent.h" // for menus |
|
60 #include "nsIScriptSecurityManager.h" |
|
61 |
|
62 // For calculating size |
|
63 #include "nsIPresShell.h" |
|
64 #include "nsPresContext.h" |
|
65 |
|
66 #include "nsIBaseWindow.h" |
|
67 #include "nsIDocShellTreeItem.h" |
|
68 |
|
69 #include "nsIMarkupDocumentViewer.h" |
|
70 #include "mozilla/Attributes.h" |
|
71 #include "mozilla/DebugOnly.h" |
|
72 #include "mozilla/MouseEvents.h" |
|
73 |
|
74 #ifdef XP_MACOSX |
|
75 #include "nsINativeMenuService.h" |
|
76 #define USE_NATIVE_MENUS |
|
77 #endif |
|
78 |
|
79 using namespace mozilla; |
|
80 using namespace mozilla::dom; |
|
81 |
|
82 /* Define Class IDs */ |
|
83 static NS_DEFINE_CID(kWindowCID, NS_WINDOW_CID); |
|
84 |
|
85 #define SIZE_PERSISTENCE_TIMEOUT 500 // msec |
|
86 |
|
87 nsWebShellWindow::nsWebShellWindow(uint32_t aChromeFlags) |
|
88 : nsXULWindow(aChromeFlags) |
|
89 , mSPTimerLock("nsWebShellWindow.mSPTimerLock") |
|
90 { |
|
91 } |
|
92 |
|
93 nsWebShellWindow::~nsWebShellWindow() |
|
94 { |
|
95 MutexAutoLock lock(mSPTimerLock); |
|
96 if (mSPTimer) |
|
97 mSPTimer->Cancel(); |
|
98 } |
|
99 |
|
100 NS_IMPL_ADDREF_INHERITED(nsWebShellWindow, nsXULWindow) |
|
101 NS_IMPL_RELEASE_INHERITED(nsWebShellWindow, nsXULWindow) |
|
102 |
|
103 NS_INTERFACE_MAP_BEGIN(nsWebShellWindow) |
|
104 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) |
|
105 NS_INTERFACE_MAP_END_INHERITING(nsXULWindow) |
|
106 |
|
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; |
|
117 |
|
118 mIsHiddenWindow = aIsHiddenWindow; |
|
119 |
|
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 } |
|
142 |
|
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); |
|
146 |
|
147 // Create top level window |
|
148 mWindow = do_CreateInstance(kWindowCID, &rv); |
|
149 if (NS_OK != rv) { |
|
150 return rv; |
|
151 } |
|
152 |
|
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 } |
|
169 |
|
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)); |
|
180 |
|
181 // Create web shell |
|
182 mDocShell = do_CreateInstance("@mozilla.org/docshell;1"); |
|
183 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); |
|
184 |
|
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); |
|
190 |
|
191 docShellAsItem->SetTreeOwner(mChromeTreeOwner); |
|
192 docShellAsItem->SetItemType(nsIDocShellTreeItem::typeChrome); |
|
193 |
|
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); |
|
199 |
|
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 } |
|
205 |
|
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 } |
|
225 |
|
226 if (nullptr != aUrl) { |
|
227 nsCString tmpStr; |
|
228 |
|
229 rv = aUrl->GetSpec(tmpStr); |
|
230 if (NS_FAILED(rv)) return rv; |
|
231 |
|
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 } |
|
242 |
|
243 return rv; |
|
244 } |
|
245 |
|
246 nsIPresShell* |
|
247 nsWebShellWindow::GetPresShell() |
|
248 { |
|
249 if (!mDocShell) |
|
250 return nullptr; |
|
251 |
|
252 return mDocShell->GetPresShell(); |
|
253 } |
|
254 |
|
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 } |
|
263 |
|
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 } |
|
269 |
|
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 } |
|
283 |
|
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); |
|
289 |
|
290 nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell)); |
|
291 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window); |
|
292 |
|
293 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell(); |
|
294 |
|
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(); |
|
301 |
|
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 } |
|
309 |
|
310 Destroy(); |
|
311 return false; |
|
312 } |
|
313 |
|
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); |
|
328 |
|
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 } |
|
343 |
|
344 // And always fire a user-defined sizemodechange event on the window |
|
345 ourWindow->DispatchCustomEvent("sizemodechange"); |
|
346 } |
|
347 |
|
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 } |
|
354 |
|
355 void |
|
356 nsWebShellWindow::OSToolbarButtonPressed() |
|
357 { |
|
358 // Keep a reference as setting the chrome flags can fire events. |
|
359 nsCOMPtr<nsIXULWindow> xulWindow(this); |
|
360 |
|
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); |
|
368 |
|
369 nsCOMPtr<nsIWebBrowserChrome> wbc(do_GetInterface(xulWindow)); |
|
370 if (!wbc) |
|
371 return; |
|
372 |
|
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 } |
|
380 |
|
381 bool |
|
382 nsWebShellWindow::ZLevelChanged(bool aImmediate, nsWindowZ *aPlacement, |
|
383 nsIWidget* aRequestBelow, nsIWidget** aActualBelow) |
|
384 { |
|
385 if (aActualBelow) |
|
386 *aActualBelow = nullptr; |
|
387 |
|
388 return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow); |
|
389 } |
|
390 |
|
391 void |
|
392 nsWebShellWindow::WindowActivated() |
|
393 { |
|
394 nsCOMPtr<nsIXULWindow> xulWindow(this); |
|
395 |
|
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); |
|
401 |
|
402 if (mChromeLoaded) { |
|
403 PersistentAttributesDirty(PAD_POSITION | PAD_SIZE | PAD_MISC); |
|
404 SavePersistentAttributes(); |
|
405 } |
|
406 } |
|
407 |
|
408 void |
|
409 nsWebShellWindow::WindowDeactivated() |
|
410 { |
|
411 nsCOMPtr<nsIXULWindow> xulWindow(this); |
|
412 |
|
413 nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell); |
|
414 nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID); |
|
415 if (fm && window) |
|
416 fm->WindowLowered(window); |
|
417 } |
|
418 |
|
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)); |
|
428 |
|
429 nsCOMPtr<nsIDOMNode> menubarNode; |
|
430 if (menubarElements) |
|
431 menubarElements->Item(0, getter_AddRefs(menubarNode)); |
|
432 if (!menubarNode) |
|
433 return; |
|
434 |
|
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 |
|
441 |
|
442 namespace mozilla { |
|
443 |
|
444 class WebShellWindowTimerCallback MOZ_FINAL : public nsITimerCallback |
|
445 { |
|
446 public: |
|
447 WebShellWindowTimerCallback(nsWebShellWindow* aWindow) |
|
448 : mWindow(aWindow) |
|
449 {} |
|
450 |
|
451 NS_DECL_THREADSAFE_ISUPPORTS |
|
452 |
|
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. |
|
458 |
|
459 mWindow->FirePersistenceTimer(); |
|
460 return NS_OK; |
|
461 } |
|
462 |
|
463 private: |
|
464 nsRefPtr<nsWebShellWindow> mWindow; |
|
465 }; |
|
466 |
|
467 NS_IMPL_ISUPPORTS(WebShellWindowTimerCallback, nsITimerCallback) |
|
468 |
|
469 } // namespace mozilla |
|
470 |
|
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 } |
|
482 |
|
483 nsRefPtr<WebShellWindowTimerCallback> callback = |
|
484 new WebShellWindowTimerCallback(this); |
|
485 mSPTimer->InitWithCallback(callback, SIZE_PERSISTENCE_TIMEOUT, |
|
486 nsITimer::TYPE_ONE_SHOT); |
|
487 |
|
488 PersistentAttributesDirty(aDirtyFlags); |
|
489 } |
|
490 |
|
491 void |
|
492 nsWebShellWindow::FirePersistenceTimer() |
|
493 { |
|
494 MutexAutoLock lock(mSPTimerLock); |
|
495 SavePersistentAttributes(); |
|
496 } |
|
497 |
|
498 |
|
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 } |
|
513 |
|
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 } |
|
526 |
|
527 if (mChromeLoaded) |
|
528 return NS_OK; |
|
529 |
|
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 } |
|
539 |
|
540 mChromeLoaded = true; |
|
541 mLockedUntilChromeLoad = false; |
|
542 |
|
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 |
|
555 |
|
556 OnChromeLoaded(); |
|
557 LoadContentAreas(); |
|
558 |
|
559 return NS_OK; |
|
560 } |
|
561 |
|
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 } |
|
571 |
|
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 } |
|
581 |
|
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 } |
|
590 |
|
591 |
|
592 //---------------------------------------- |
|
593 |
|
594 // if the main document URL specified URLs for any content areas, start them loading |
|
595 void nsWebShellWindow::LoadContentAreas() { |
|
596 |
|
597 nsAutoString searchSpec; |
|
598 |
|
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(); |
|
609 |
|
610 nsCOMPtr<nsIURL> url = do_QueryInterface(mainURL); |
|
611 if (url) { |
|
612 nsAutoCString search; |
|
613 url->GetQuery(search); |
|
614 |
|
615 AppendUTF8toUTF16(search, searchSpec); |
|
616 } |
|
617 } |
|
618 } |
|
619 |
|
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; |
|
636 |
|
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++; |
|
643 |
|
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 } |
|
666 |
|
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); |
|
679 |
|
680 nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(mDocShell)); |
|
681 nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(window); |
|
682 |
|
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)); |
|
689 |
|
690 nsEventStatus status = nsEventStatus_eIgnore; |
|
691 WidgetMouseEvent event(true, NS_XUL_CLOSE, nullptr, |
|
692 WidgetMouseEvent::eReal); |
|
693 |
|
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 } |
|
701 |
|
702 return false; |
|
703 } // ExecuteCloseHandler |
|
704 |
|
705 void nsWebShellWindow::ConstrainToOpenerScreen(int32_t* aX, int32_t* aY) |
|
706 { |
|
707 if (mOpenerScreenRect.IsEmpty()) { |
|
708 *aX = *aY = 0; |
|
709 return; |
|
710 } |
|
711 |
|
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 } |
|
731 |
|
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 } |
|
740 |
|
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 } |