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