Follow-on fix for bug 457825. Use sheet principal for agent and user sheets. r=dbaron...
[wine-gecko.git] / embedding / browser / webBrowser / nsDocShellTreeOwner.cpp
blob3312509304732908ead78b896e320179e4a8c6cc
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is the Mozilla browser.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications, Inc.
20 * Portions created by the Initial Developer are Copyright (C) 1999
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Travis Bogard <travis@netscape.com>
25 * Adam Lock <adamlock@netscape.com>
26 * Mike Pinkerton <pinkerton@netscape.com>
27 * Dan Rosen <dr@netscape.com>
29 * Alternatively, the contents of this file may be used under the terms of
30 * either the GNU General Public License Version 2 or later (the "GPL"), or
31 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
43 // Local Includes
44 #include "nsDocShellTreeOwner.h"
45 #include "nsWebBrowser.h"
47 // Helper Classes
48 #include "nsIGenericFactory.h"
49 #include "nsStyleCoord.h"
50 #include "nsSize.h"
51 #include "nsHTMLReflowState.h"
52 #include "nsIServiceManager.h"
53 #include "nsComponentManagerUtils.h"
54 #include "nsXPIDLString.h"
55 #include "nsIAtom.h"
56 #include "nsReadableUtils.h"
57 #include "nsUnicharUtils.h"
58 #include "nsISimpleEnumerator.h"
60 // Interfaces needed to be included
61 #include "nsPresContext.h"
62 #include "nsIContextMenuListener.h"
63 #include "nsIContextMenuListener2.h"
64 #include "nsITooltipListener.h"
65 #include "nsIPrivateDOMEvent.h"
66 #include "nsIDOMNode.h"
67 #include "nsIDOMNodeList.h"
68 #include "nsIDOMDocument.h"
69 #include "nsIDOMDocumentType.h"
70 #include "nsIDOMElement.h"
71 #include "nsIDOMEvent.h"
72 #include "nsIDOMMouseEvent.h"
73 #include "nsIDOMNSUIEvent.h"
74 #include "nsIDOMEventTarget.h"
75 #include "nsIDOMNamedNodeMap.h"
76 #include "nsIDOMHTMLInputElement.h"
77 #include "nsIDOMHTMLTextAreaElement.h"
78 #include "nsIDOMHTMLHtmlElement.h"
79 #include "nsIDOMHTMLAppletElement.h"
80 #include "nsIDOMHTMLObjectElement.h"
81 #include "nsIDOMHTMLEmbedElement.h"
82 #include "nsIDOMHTMLDocument.h"
83 #include "nsIImageLoadingContent.h"
84 #include "nsIWebNavigation.h"
85 #include "nsIDOMHTMLElement.h"
86 #include "nsIPresShell.h"
87 #include "nsPIDOMWindow.h"
88 #include "nsIDOMWindowCollection.h"
89 #include "nsIFocusController.h"
90 #include "nsIWindowWatcher.h"
91 #include "nsPIWindowWatcher.h"
92 #include "nsIPrompt.h"
93 #include "nsRect.h"
94 #include "nsIWebBrowserChromeFocus.h"
95 #include "nsIContent.h"
96 #include "imgIContainer.h"
97 #include "nsContextMenuInfo.h"
98 #include "nsPresContext.h"
99 #include "nsIViewManager.h"
100 #include "nsIView.h"
101 #include "nsPIDOMEventTarget.h"
104 // GetEventReceiver
106 // A helper routine that navigates the tricky path from a |nsWebBrowser| to
107 // a |nsPIDOMEventTarget| via the window root and chrome event handler.
109 static nsresult
110 GetPIDOMEventTarget( nsWebBrowser* inBrowser, nsPIDOMEventTarget** aTarget)
112 nsCOMPtr<nsIDOMWindow> domWindow;
113 inBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
114 NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
116 nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
117 NS_ENSURE_TRUE(domWindowPrivate, NS_ERROR_FAILURE);
118 nsPIDOMWindow *rootWindow = domWindowPrivate->GetPrivateRoot();
119 NS_ENSURE_TRUE(rootWindow, NS_ERROR_FAILURE);
120 nsCOMPtr<nsPIDOMEventTarget> piTarget =
121 do_QueryInterface(rootWindow->GetChromeEventHandler());
122 NS_ENSURE_TRUE(piTarget, NS_ERROR_FAILURE);
123 *aTarget = piTarget;
124 NS_IF_ADDREF(*aTarget);
126 return NS_OK;
130 //*****************************************************************************
131 //*** nsDocShellTreeOwner: Object Management
132 //*****************************************************************************
134 nsDocShellTreeOwner::nsDocShellTreeOwner() :
135 mWebBrowser(nsnull),
136 mTreeOwner(nsnull),
137 mPrimaryContentShell(nsnull),
138 mWebBrowserChrome(nsnull),
139 mOwnerWin(nsnull),
140 mOwnerRequestor(nsnull),
141 mChromeTooltipListener(nsnull),
142 mChromeContextMenuListener(nsnull)
146 nsDocShellTreeOwner::~nsDocShellTreeOwner()
148 RemoveChromeListeners();
151 //*****************************************************************************
152 // nsDocShellTreeOwner::nsISupports
153 //*****************************************************************************
155 NS_IMPL_ADDREF(nsDocShellTreeOwner)
156 NS_IMPL_RELEASE(nsDocShellTreeOwner)
158 NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner)
159 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellTreeOwner)
160 NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner)
161 NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
162 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
163 NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
164 NS_INTERFACE_MAP_ENTRY(nsICDocShellTreeOwner)
165 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
166 NS_INTERFACE_MAP_END
168 //*****************************************************************************
169 // nsDocShellTreeOwner::nsIInterfaceRequestor
170 //*****************************************************************************
172 NS_IMETHODIMP
173 nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
175 NS_ENSURE_ARG_POINTER(aSink);
177 if(NS_SUCCEEDED(QueryInterface(aIID, aSink)))
178 return NS_OK;
180 if (aIID.Equals(NS_GET_IID(nsIWebBrowserChromeFocus))) {
181 if (mWebBrowserChromeWeak != nsnull)
182 return mWebBrowserChromeWeak->QueryReferent(aIID, aSink);
183 return mOwnerWin->QueryInterface(aIID, aSink);
186 if (aIID.Equals(NS_GET_IID(nsIPrompt))) {
187 nsIPrompt *prompt;
188 EnsurePrompter();
189 prompt = mPrompter;
190 if (prompt) {
191 NS_ADDREF(prompt);
192 *aSink = prompt;
193 return NS_OK;
195 return NS_NOINTERFACE;
198 if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
199 nsIAuthPrompt *prompt;
200 EnsureAuthPrompter();
201 prompt = mAuthPrompter;
202 if (prompt) {
203 NS_ADDREF(prompt);
204 *aSink = prompt;
205 return NS_OK;
207 return NS_NOINTERFACE;
210 nsCOMPtr<nsIInterfaceRequestor> req = GetOwnerRequestor();
211 if (req)
212 return req->GetInterface(aIID, aSink);
214 return NS_NOINTERFACE;
217 //*****************************************************************************
218 // nsDocShellTreeOwner::nsIDocShellTreeOwner
219 //*****************************************************************************
221 NS_IMETHODIMP
222 nsDocShellTreeOwner::FindItemWithName(const PRUnichar* aName,
223 nsIDocShellTreeItem* aRequestor,
224 nsIDocShellTreeItem* aOriginalRequestor,
225 nsIDocShellTreeItem** aFoundItem)
227 NS_ENSURE_ARG(aName);
228 NS_ENSURE_ARG_POINTER(aFoundItem);
229 *aFoundItem = nsnull; // if we don't find one, we return NS_OK and a null result
230 nsresult rv;
232 nsAutoString name(aName);
234 if (!mWebBrowser)
235 return NS_OK; // stymied
237 /* special cases */
238 if(name.IsEmpty())
239 return NS_OK;
240 if(name.LowerCaseEqualsLiteral("_blank"))
241 return NS_OK;
242 // _main is an IE target which should be case-insensitive but isn't
243 // see bug 217886 for details
244 if(name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main")) {
245 *aFoundItem = mWebBrowser->mDocShellAsItem;
246 NS_IF_ADDREF(*aFoundItem);
247 return NS_OK;
250 // first, is it us?
252 nsCOMPtr<nsIDOMWindow> domWindow;
253 mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
254 if (domWindow) {
255 nsAutoString ourName;
256 domWindow->GetName(ourName);
257 if (name.Equals(ourName, nsCaseInsensitiveStringComparator())) {
258 *aFoundItem = mWebBrowser->mDocShellAsItem;
259 NS_IF_ADDREF(*aFoundItem);
260 return NS_OK;
265 // next, check our children
266 rv = FindChildWithName(aName, PR_TRUE, aRequestor, aOriginalRequestor,
267 aFoundItem);
268 if(NS_FAILED(rv) || *aFoundItem)
269 return rv;
271 // next, if we have a parent and it isn't the requestor, ask it
272 nsCOMPtr<nsIDocShellTreeOwner> reqAsTreeOwner(do_QueryInterface(aRequestor));
274 if(mTreeOwner) {
275 if (mTreeOwner != reqAsTreeOwner)
276 return mTreeOwner->FindItemWithName(aName, mWebBrowser->mDocShellAsItem,
277 aOriginalRequestor, aFoundItem);
278 return NS_OK;
281 // finally, failing everything else, search all windows
282 return FindItemWithNameAcrossWindows(aName, aRequestor, aOriginalRequestor,
283 aFoundItem);
286 nsresult
287 nsDocShellTreeOwner::FindChildWithName(const PRUnichar *aName, PRBool aRecurse,
288 nsIDocShellTreeItem* aRequestor,
289 nsIDocShellTreeItem* aOriginalRequestor,
290 nsIDocShellTreeItem **aFoundItem)
292 if (!mWebBrowser)
293 return NS_OK;
295 nsresult rv = NS_OK;
297 nsCOMPtr<nsIDOMWindow> domWindow;
298 mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
299 if (!domWindow)
300 return NS_OK;
302 nsCOMPtr<nsIDOMWindowCollection> frames;
303 domWindow->GetFrames(getter_AddRefs(frames));
304 if (!frames)
305 return NS_OK;
307 PRUint32 ctr, count;
308 frames->GetLength(&count);
309 for (ctr = 0; ctr < count; ctr++) {
310 nsCOMPtr<nsIDOMWindow> frame;
311 frames->Item(ctr, getter_AddRefs(frame));
312 nsCOMPtr<nsPIDOMWindow> w(do_QueryInterface(frame));
313 if (w) {
314 nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(w->GetDocShell());
315 if (item && item != aRequestor) {
316 rv = item->FindItemWithName(aName, mWebBrowser->mDocShellAsItem,
317 aOriginalRequestor, aFoundItem);
318 if (NS_FAILED(rv) || *aFoundItem)
319 break;
324 return rv;
327 nsresult
328 nsDocShellTreeOwner::FindItemWithNameAcrossWindows(const PRUnichar* aName,
329 nsIDocShellTreeItem* aRequestor,
330 nsIDocShellTreeItem* aOriginalRequestor,
331 nsIDocShellTreeItem** aFoundItem)
333 // search for the item across the list of top-level windows
334 nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
335 if (!wwatch)
336 return NS_OK;
338 return wwatch->FindItemWithName(aName, aRequestor, aOriginalRequestor,
339 aFoundItem);
342 void
343 nsDocShellTreeOwner::EnsurePrompter()
345 if (mPrompter)
346 return;
348 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
349 if (wwatch && mWebBrowser) {
350 nsCOMPtr<nsIDOMWindow> domWindow;
351 mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
352 if (domWindow)
353 wwatch->GetNewPrompter(domWindow, getter_AddRefs(mPrompter));
357 void
358 nsDocShellTreeOwner::EnsureAuthPrompter()
360 if (mAuthPrompter)
361 return;
363 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
364 if (wwatch && mWebBrowser) {
365 nsCOMPtr<nsIDOMWindow> domWindow;
366 mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
367 if (domWindow)
368 wwatch->GetNewAuthPrompter(domWindow, getter_AddRefs(mAuthPrompter));
372 void
373 nsDocShellTreeOwner::AddToWatcher()
375 if (mWebBrowser) {
376 nsCOMPtr<nsIDOMWindow> domWindow;
377 mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
378 if (domWindow) {
379 nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
380 if (wwatch) {
381 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
382 if (webBrowserChrome)
383 wwatch->AddWindow(domWindow, webBrowserChrome);
389 void
390 nsDocShellTreeOwner::RemoveFromWatcher()
392 if (mWebBrowser) {
393 nsCOMPtr<nsIDOMWindow> domWindow;
394 mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
395 if (domWindow) {
396 nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
397 if (wwatch)
398 wwatch->RemoveWindow(domWindow);
404 NS_IMETHODIMP
405 nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
406 PRBool aPrimary, PRBool aTargetable,
407 const nsAString& aID)
409 if(mTreeOwner)
410 return mTreeOwner->ContentShellAdded(aContentShell, aPrimary,
411 aTargetable, aID);
413 if (aPrimary)
414 mPrimaryContentShell = aContentShell;
415 return NS_OK;
418 NS_IMETHODIMP
419 nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem* aContentShell)
421 if(mTreeOwner)
422 return mTreeOwner->ContentShellRemoved(aContentShell);
424 if(mPrimaryContentShell == aContentShell)
425 mPrimaryContentShell = nsnull;
427 return NS_OK;
430 NS_IMETHODIMP
431 nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem** aShell)
433 NS_ENSURE_ARG_POINTER(aShell);
435 if(mTreeOwner)
436 return mTreeOwner->GetPrimaryContentShell(aShell);
438 *aShell = (mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShellAsItem.get());
439 NS_IF_ADDREF(*aShell);
441 return NS_OK;
444 NS_IMETHODIMP
445 nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem,
446 PRInt32 aCX, PRInt32 aCY)
448 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
450 NS_ENSURE_STATE(mTreeOwner || webBrowserChrome);
452 if(mTreeOwner)
453 return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY);
455 if(aShellItem == mWebBrowser->mDocShellAsItem)
456 return webBrowserChrome->SizeBrowserTo(aCX, aCY);
458 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(aShellItem));
459 NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
461 nsCOMPtr<nsIDOMDocument> domDocument;
462 webNav->GetDocument(getter_AddRefs(domDocument));
463 NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE);
465 nsCOMPtr<nsIDOMElement> domElement;
466 domDocument->GetDocumentElement(getter_AddRefs(domElement));
467 NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE);
469 // Set the preferred Size
470 //XXX
471 NS_ERROR("Implement this");
473 Set the preferred size on the aShellItem.
476 nsCOMPtr<nsPresContext> presContext;
477 mWebBrowser->mDocShell->GetPresContext(getter_AddRefs(presContext));
478 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
480 nsIPresShell *presShell = presContext->GetPresShell();
481 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
483 NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE,
484 NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE);
486 nsRect shellArea = presContext->GetVisibleArea();
488 PRInt32 browserCX = presContext->AppUnitsToDevPixels(shellArea.width);
489 PRInt32 browserCY = presContext->AppUnitsToDevPixels(shellArea.height);
491 return webBrowserChrome->SizeBrowserTo(browserCX, browserCY);
494 NS_IMETHODIMP
495 nsDocShellTreeOwner::SetPersistence(PRBool aPersistPosition,
496 PRBool aPersistSize,
497 PRBool aPersistSizeMode)
499 return NS_ERROR_NOT_IMPLEMENTED;
502 NS_IMETHODIMP
503 nsDocShellTreeOwner::GetPersistence(PRBool* aPersistPosition,
504 PRBool* aPersistSize,
505 PRBool* aPersistSizeMode)
507 return NS_ERROR_NOT_IMPLEMENTED;
510 //*****************************************************************************
511 // nsDocShellTreeOwner::nsIBaseWindow
512 //*****************************************************************************
515 NS_IMETHODIMP
516 nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow,
517 nsIWidget* aParentWidget, PRInt32 aX,
518 PRInt32 aY, PRInt32 aCX, PRInt32 aCY)
520 return NS_ERROR_NULL_POINTER;
523 NS_IMETHODIMP
524 nsDocShellTreeOwner::Create()
526 return NS_ERROR_NULL_POINTER;
529 NS_IMETHODIMP
530 nsDocShellTreeOwner::Destroy()
532 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
533 if (webBrowserChrome)
535 return webBrowserChrome->DestroyBrowserWindow();
538 return NS_ERROR_NULL_POINTER;
541 NS_IMETHODIMP
542 nsDocShellTreeOwner::SetPosition(PRInt32 aX, PRInt32 aY)
544 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
545 if (ownerWin)
547 return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
548 aX, aY, 0, 0);
550 return NS_ERROR_NULL_POINTER;
553 NS_IMETHODIMP
554 nsDocShellTreeOwner::GetPosition(PRInt32* aX, PRInt32* aY)
556 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
557 if (ownerWin)
559 return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
560 aX, aY, nsnull, nsnull);
562 return NS_ERROR_NULL_POINTER;
565 NS_IMETHODIMP
566 nsDocShellTreeOwner::SetSize(PRInt32 aCX, PRInt32 aCY, PRBool aRepaint)
568 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
569 if (ownerWin)
571 return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
572 0, 0, aCX, aCY);
574 return NS_ERROR_NULL_POINTER;
577 NS_IMETHODIMP
578 nsDocShellTreeOwner::GetSize(PRInt32* aCX, PRInt32* aCY)
580 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
581 if (ownerWin)
583 return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
584 nsnull, nsnull, aCX, aCY);
586 return NS_ERROR_NULL_POINTER;
589 NS_IMETHODIMP
590 nsDocShellTreeOwner::SetPositionAndSize(PRInt32 aX, PRInt32 aY, PRInt32 aCX,
591 PRInt32 aCY, PRBool aRepaint)
593 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
594 if (ownerWin)
596 return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
597 nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
598 aX, aY, aCX, aCY);
600 return NS_ERROR_NULL_POINTER;
603 NS_IMETHODIMP
604 nsDocShellTreeOwner::GetPositionAndSize(PRInt32* aX, PRInt32* aY, PRInt32* aCX,
605 PRInt32* aCY)
607 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
608 if (ownerWin)
610 return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
611 nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
612 aX, aY, aCX, aCY);
614 return NS_ERROR_NULL_POINTER;
617 NS_IMETHODIMP
618 nsDocShellTreeOwner::Repaint(PRBool aForce)
620 return NS_ERROR_NULL_POINTER;
623 NS_IMETHODIMP
624 nsDocShellTreeOwner::GetParentWidget(nsIWidget** aParentWidget)
626 return NS_ERROR_NULL_POINTER;
629 NS_IMETHODIMP
630 nsDocShellTreeOwner::SetParentWidget(nsIWidget* aParentWidget)
632 return NS_ERROR_NULL_POINTER;
635 NS_IMETHODIMP
636 nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
638 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
639 if (ownerWin)
641 return ownerWin->GetSiteWindow(aParentNativeWindow);
643 return NS_ERROR_NULL_POINTER;
646 NS_IMETHODIMP
647 nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow)
649 return NS_ERROR_NULL_POINTER;
652 NS_IMETHODIMP
653 nsDocShellTreeOwner::GetVisibility(PRBool* aVisibility)
655 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
656 if (ownerWin)
658 return ownerWin->GetVisibility(aVisibility);
660 return NS_ERROR_NULL_POINTER;
663 NS_IMETHODIMP
664 nsDocShellTreeOwner::SetVisibility(PRBool aVisibility)
666 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
667 if (ownerWin)
669 return ownerWin->SetVisibility(aVisibility);
671 return NS_ERROR_NULL_POINTER;
674 NS_IMETHODIMP
675 nsDocShellTreeOwner::GetEnabled(PRBool *aEnabled)
677 NS_ENSURE_ARG_POINTER(aEnabled);
678 *aEnabled = PR_TRUE;
679 return NS_ERROR_NOT_IMPLEMENTED;
682 NS_IMETHODIMP
683 nsDocShellTreeOwner::SetEnabled(PRBool aEnabled)
685 return NS_ERROR_NOT_IMPLEMENTED;
688 NS_IMETHODIMP
689 nsDocShellTreeOwner::GetBlurSuppression(PRBool *aBlurSuppression)
691 NS_ENSURE_ARG_POINTER(aBlurSuppression);
692 *aBlurSuppression = PR_FALSE;
693 return NS_ERROR_NOT_IMPLEMENTED;
696 NS_IMETHODIMP
697 nsDocShellTreeOwner::SetBlurSuppression(PRBool aBlurSuppression)
699 return NS_ERROR_NOT_IMPLEMENTED;
702 NS_IMETHODIMP
703 nsDocShellTreeOwner::GetMainWidget(nsIWidget** aMainWidget)
705 return NS_ERROR_NULL_POINTER;
708 NS_IMETHODIMP
709 nsDocShellTreeOwner::SetFocus()
711 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
712 if (ownerWin)
714 return ownerWin->SetFocus();
716 return NS_ERROR_NULL_POINTER;
719 NS_IMETHODIMP
720 nsDocShellTreeOwner::GetTitle(PRUnichar** aTitle)
722 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
723 if (ownerWin)
725 return ownerWin->GetTitle(aTitle);
727 return NS_ERROR_NULL_POINTER;
730 NS_IMETHODIMP
731 nsDocShellTreeOwner::SetTitle(const PRUnichar* aTitle)
733 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
734 if (ownerWin)
736 return ownerWin->SetTitle(aTitle);
738 return NS_ERROR_NULL_POINTER;
742 //*****************************************************************************
743 // nsDocShellTreeOwner::nsIWebProgressListener
744 //*****************************************************************************
747 NS_IMETHODIMP
748 nsDocShellTreeOwner::OnProgressChange(nsIWebProgress* aProgress,
749 nsIRequest* aRequest,
750 PRInt32 aCurSelfProgress,
751 PRInt32 aMaxSelfProgress,
752 PRInt32 aCurTotalProgress,
753 PRInt32 aMaxTotalProgress)
755 // In the absence of DOM document creation event, this method is the
756 // most convenient place to install the mouse listener on the
757 // DOM document.
758 return AddChromeListeners();
761 NS_IMETHODIMP
762 nsDocShellTreeOwner::OnStateChange(nsIWebProgress* aProgress,
763 nsIRequest* aRequest,
764 PRUint32 aProgressStateFlags,
765 nsresult aStatus)
767 return NS_OK;
770 NS_IMETHODIMP
771 nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress,
772 nsIRequest* aRequest,
773 nsIURI* aURI)
775 return NS_OK;
778 NS_IMETHODIMP
779 nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress,
780 nsIRequest* aRequest,
781 nsresult aStatus,
782 const PRUnichar* aMessage)
784 return NS_OK;
787 NS_IMETHODIMP
788 nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress,
789 nsIRequest *aRequest,
790 PRUint32 state)
792 return NS_OK;
796 //*****************************************************************************
797 // nsDocShellTreeOwner: Helpers
798 //*****************************************************************************
800 //*****************************************************************************
801 // nsDocShellTreeOwner: Accessors
802 //*****************************************************************************
804 void
805 nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser)
807 if ( !aWebBrowser )
808 RemoveChromeListeners();
809 if (aWebBrowser != mWebBrowser) {
810 mPrompter = 0;
811 mAuthPrompter = 0;
814 mWebBrowser = aWebBrowser;
817 nsWebBrowser *
818 nsDocShellTreeOwner::WebBrowser()
820 return mWebBrowser;
823 NS_IMETHODIMP
824 nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
826 if(aTreeOwner) {
827 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome(do_GetInterface(aTreeOwner));
828 NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG);
829 NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome), NS_ERROR_INVALID_ARG);
830 mTreeOwner = aTreeOwner;
832 else {
833 mTreeOwner = nsnull;
834 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
835 if (!webBrowserChrome)
836 NS_ENSURE_SUCCESS(SetWebBrowserChrome(nsnull), NS_ERROR_FAILURE);
839 return NS_OK;
842 NS_IMETHODIMP
843 nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome)
845 if(!aWebBrowserChrome) {
846 mWebBrowserChrome = nsnull;
847 mOwnerWin = nsnull;
848 mOwnerRequestor = nsnull;
849 mWebBrowserChromeWeak = 0;
850 } else {
851 nsCOMPtr<nsISupportsWeakReference> supportsweak =
852 do_QueryInterface(aWebBrowserChrome);
853 if (supportsweak) {
854 supportsweak->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak));
855 } else {
856 nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin(do_QueryInterface(aWebBrowserChrome));
857 nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryInterface(aWebBrowserChrome));
859 // it's ok for ownerWin or requestor to be null.
860 mWebBrowserChrome = aWebBrowserChrome;
861 mOwnerWin = ownerWin;
862 mOwnerRequestor = requestor;
865 return NS_OK;
870 // AddChromeListeners
872 // Hook up things to the chrome like context menus and tooltips, if the chrome
873 // has implemented the right interfaces.
875 NS_IMETHODIMP
876 nsDocShellTreeOwner::AddChromeListeners()
878 nsresult rv = NS_OK;
880 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
881 if (!webBrowserChrome)
882 return NS_ERROR_FAILURE;
884 // install tooltips
885 if ( !mChromeTooltipListener ) {
886 nsCOMPtr<nsITooltipListener>
887 tooltipListener(do_QueryInterface(webBrowserChrome));
888 if ( tooltipListener ) {
889 mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser,
890 webBrowserChrome);
891 if ( mChromeTooltipListener ) {
892 NS_ADDREF(mChromeTooltipListener);
893 rv = mChromeTooltipListener->AddChromeListeners();
895 else
896 rv = NS_ERROR_OUT_OF_MEMORY;
900 // install context menus
901 if ( !mChromeContextMenuListener ) {
902 nsCOMPtr<nsIContextMenuListener2>
903 contextListener2(do_QueryInterface(webBrowserChrome));
904 nsCOMPtr<nsIContextMenuListener>
905 contextListener(do_QueryInterface(webBrowserChrome));
906 if ( contextListener2 || contextListener ) {
907 mChromeContextMenuListener =
908 new ChromeContextMenuListener(mWebBrowser, webBrowserChrome);
909 if ( mChromeContextMenuListener ) {
910 NS_ADDREF(mChromeContextMenuListener);
911 rv = mChromeContextMenuListener->AddChromeListeners();
913 else
914 rv = NS_ERROR_OUT_OF_MEMORY;
918 // install the external dragDrop handler
919 if ( !mChromeDragHandler ) {
920 mChromeDragHandler = do_CreateInstance("@mozilla.org:/content/content-area-dragdrop;1", &rv);
921 NS_ASSERTION(mChromeDragHandler, "Couldn't create the chrome drag handler");
922 if ( mChromeDragHandler ) {
923 nsCOMPtr<nsPIDOMEventTarget> piTarget;
924 GetPIDOMEventTarget(mWebBrowser, getter_AddRefs(piTarget));
925 nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(piTarget));
926 mChromeDragHandler->HookupTo(target, static_cast<nsIWebNavigation*>(mWebBrowser));
930 return rv;
932 } // AddChromeListeners
935 NS_IMETHODIMP
936 nsDocShellTreeOwner::RemoveChromeListeners()
938 if ( mChromeTooltipListener ) {
939 mChromeTooltipListener->RemoveChromeListeners();
940 NS_RELEASE(mChromeTooltipListener);
942 if ( mChromeContextMenuListener ) {
943 mChromeContextMenuListener->RemoveChromeListeners();
944 NS_RELEASE(mChromeContextMenuListener);
946 if ( mChromeDragHandler )
947 mChromeDragHandler->Detach();
949 return NS_OK;
952 already_AddRefed<nsIWebBrowserChrome>
953 nsDocShellTreeOwner::GetWebBrowserChrome()
955 nsIWebBrowserChrome* chrome = nsnull;
956 if (mWebBrowserChromeWeak != nsnull) {
957 mWebBrowserChromeWeak->
958 QueryReferent(NS_GET_IID(nsIWebBrowserChrome),
959 reinterpret_cast<void**>(&chrome));
960 } else if (mWebBrowserChrome) {
961 chrome = mWebBrowserChrome;
962 NS_ADDREF(mWebBrowserChrome);
965 return chrome;
968 already_AddRefed<nsIEmbeddingSiteWindow>
969 nsDocShellTreeOwner::GetOwnerWin()
971 nsIEmbeddingSiteWindow* win = nsnull;
972 if (mWebBrowserChromeWeak != nsnull) {
973 mWebBrowserChromeWeak->
974 QueryReferent(NS_GET_IID(nsIEmbeddingSiteWindow),
975 reinterpret_cast<void**>(&win));
976 } else if (mOwnerWin) {
977 win = mOwnerWin;
978 NS_ADDREF(mOwnerWin);
981 return win;
984 already_AddRefed<nsIInterfaceRequestor>
985 nsDocShellTreeOwner::GetOwnerRequestor()
987 nsIInterfaceRequestor* req = nsnull;
988 if (mWebBrowserChromeWeak != nsnull) {
989 mWebBrowserChromeWeak->
990 QueryReferent(NS_GET_IID(nsIInterfaceRequestor),
991 reinterpret_cast<void**>(&req));
992 } else if (mOwnerRequestor) {
993 req = mOwnerRequestor;
994 NS_ADDREF(mOwnerRequestor);
997 return req;
1001 #ifdef XP_MAC
1002 #pragma mark -
1003 #endif
1006 ///////////////////////////////////////////////////////////////////////////////
1007 // DefaultTooltipTextProvider
1009 class DefaultTooltipTextProvider : public nsITooltipTextProvider
1011 public:
1012 DefaultTooltipTextProvider();
1014 NS_DECL_ISUPPORTS
1015 NS_DECL_NSITOOLTIPTEXTPROVIDER
1017 protected:
1018 nsCOMPtr<nsIAtom> mTag_dialog;
1019 nsCOMPtr<nsIAtom> mTag_dialogheader;
1020 nsCOMPtr<nsIAtom> mTag_window;
1023 NS_IMPL_THREADSAFE_ISUPPORTS1(DefaultTooltipTextProvider, nsITooltipTextProvider)
1025 DefaultTooltipTextProvider::DefaultTooltipTextProvider()
1027 // There are certain element types which we don't want to use
1028 // as tool tip text.
1029 mTag_dialog = do_GetAtom("dialog");
1030 mTag_dialogheader = do_GetAtom("dialogheader");
1031 mTag_window = do_GetAtom("window");
1034 /* void getNodeText (in nsIDOMNode aNode, out wstring aText); */
1035 NS_IMETHODIMP
1036 DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, PRUnichar **aText,
1037 PRBool *_retval)
1039 NS_ENSURE_ARG_POINTER(aNode);
1040 NS_ENSURE_ARG_POINTER(aText);
1042 nsString outText;
1044 PRBool found = PR_FALSE;
1045 nsCOMPtr<nsIDOMNode> current ( aNode );
1046 while ( !found && current ) {
1047 nsCOMPtr<nsIDOMElement> currElement ( do_QueryInterface(current) );
1048 if ( currElement ) {
1049 nsCOMPtr<nsIContent> content(do_QueryInterface(currElement));
1050 if (content) {
1051 nsIAtom *tagAtom = content->Tag();
1052 if (tagAtom != mTag_dialog &&
1053 tagAtom != mTag_dialogheader &&
1054 tagAtom != mTag_window) {
1055 // first try the normal title attribute...
1056 currElement->GetAttribute(NS_LITERAL_STRING("title"), outText);
1057 if ( outText.Length() )
1058 found = PR_TRUE;
1059 else {
1060 // ...ok, that didn't work, try it in the XLink namespace
1061 currElement->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"), NS_LITERAL_STRING("title"), outText);
1062 if ( outText.Length() )
1063 found = PR_TRUE;
1069 // not found here, walk up to the parent and keep trying
1070 if ( !found ) {
1071 nsCOMPtr<nsIDOMNode> temp ( current );
1072 temp->GetParentNode(getter_AddRefs(current));
1074 } // while not found
1076 *_retval = found;
1077 *aText = (found) ? ToNewUnicode(outText) : nsnull;
1079 return NS_OK;
1082 ///////////////////////////////////////////////////////////////////////////////
1084 NS_IMPL_ADDREF(ChromeTooltipListener)
1085 NS_IMPL_RELEASE(ChromeTooltipListener)
1087 NS_INTERFACE_MAP_BEGIN(ChromeTooltipListener)
1088 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMouseListener)
1089 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMMouseListener)
1090 NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
1091 NS_INTERFACE_MAP_ENTRY(nsIDOMMouseMotionListener)
1092 NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
1093 NS_INTERFACE_MAP_END
1097 // ChromeTooltipListener ctor
1100 ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* inBrowser,
1101 nsIWebBrowserChrome* inChrome)
1102 : mWebBrowser(inBrowser), mWebBrowserChrome(inChrome),
1103 mTooltipListenerInstalled(PR_FALSE),
1104 mMouseClientX(0), mMouseClientY(0),
1105 mShowingTooltip(PR_FALSE)
1107 mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID);
1108 if (!mTooltipTextProvider) {
1109 nsISupports *pProvider = (nsISupports *) new DefaultTooltipTextProvider;
1110 mTooltipTextProvider = do_QueryInterface(pProvider);
1112 } // ctor
1116 // ChromeTooltipListener dtor
1118 ChromeTooltipListener::~ChromeTooltipListener()
1121 } // dtor
1125 // AddChromeListeners
1127 // Hook up things to the chrome like context menus and tooltips, if the chrome
1128 // has implemented the right interfaces.
1130 NS_IMETHODIMP
1131 ChromeTooltipListener::AddChromeListeners()
1133 if (!mEventTarget)
1134 GetPIDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget));
1136 // Register the appropriate events for tooltips, but only if
1137 // the embedding chrome cares.
1138 nsresult rv = NS_OK;
1139 nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
1140 if ( tooltipListener && !mTooltipListenerInstalled ) {
1141 rv = AddTooltipListener();
1142 if ( NS_FAILED(rv) )
1143 return rv;
1146 return rv;
1148 } // AddChromeListeners
1152 // AddTooltipListener
1154 // Subscribe to the events that will allow us to track tooltips. We need "mouse" for mouseExit,
1155 // "mouse motion" for mouseMove, and "key" for keyDown. As we add the listeners, keep track
1156 // of how many succeed so we can clean up correctly in Release().
1158 NS_IMETHODIMP
1159 ChromeTooltipListener::AddTooltipListener()
1161 if (mEventTarget) {
1162 nsIDOMMouseListener *pListener = static_cast<nsIDOMMouseListener *>(this);
1163 nsresult rv = mEventTarget->AddEventListenerByIID(pListener, NS_GET_IID(nsIDOMMouseListener));
1164 nsresult rv2 = mEventTarget->AddEventListenerByIID(pListener, NS_GET_IID(nsIDOMMouseMotionListener));
1165 nsresult rv3 = mEventTarget->AddEventListenerByIID(pListener, NS_GET_IID(nsIDOMKeyListener));
1167 // if all 3 succeed, we're a go!
1168 if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2) && NS_SUCCEEDED(rv3))
1169 mTooltipListenerInstalled = PR_TRUE;
1172 return NS_OK;
1177 // RemoveChromeListeners
1179 // Unsubscribe from the various things we've hooked up to the window root.
1181 NS_IMETHODIMP
1182 ChromeTooltipListener::RemoveChromeListeners ( )
1184 HideTooltip();
1186 if ( mTooltipListenerInstalled )
1187 RemoveTooltipListener();
1189 mEventTarget = nsnull;
1191 // it really doesn't matter if these fail...
1192 return NS_OK;
1194 } // RemoveChromeTooltipListeners
1199 // RemoveTooltipListener
1201 // Unsubscribe from all the various tooltip events that we were listening to
1203 NS_IMETHODIMP
1204 ChromeTooltipListener::RemoveTooltipListener()
1206 if (mEventTarget) {
1207 nsIDOMMouseListener *pListener = static_cast<nsIDOMMouseListener *>(this);
1208 nsresult rv = mEventTarget->RemoveEventListenerByIID(pListener, NS_GET_IID(nsIDOMMouseListener));
1209 nsresult rv2 = mEventTarget->RemoveEventListenerByIID(pListener, NS_GET_IID(nsIDOMMouseMotionListener));
1210 nsresult rv3 = mEventTarget->RemoveEventListenerByIID(pListener, NS_GET_IID(nsIDOMKeyListener));
1211 if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2) && NS_SUCCEEDED(rv3))
1212 mTooltipListenerInstalled = PR_FALSE;
1215 return NS_OK;
1220 // KeyDown
1222 // When the user starts typing, they generaly don't want to see any messy wax
1223 // builup. Hide the tooltip.
1225 nsresult
1226 ChromeTooltipListener::KeyDown(nsIDOMEvent* aMouseEvent)
1228 return HideTooltip();
1229 } // KeyDown
1233 // KeyUp
1234 // KeyPress
1236 // We can ignore these as they are already handled by KeyDown
1238 nsresult
1239 ChromeTooltipListener::KeyUp(nsIDOMEvent* aMouseEvent)
1241 return NS_OK;
1243 } // KeyUp
1245 nsresult
1246 ChromeTooltipListener::KeyPress(nsIDOMEvent* aMouseEvent)
1248 return NS_OK;
1250 } // KeyPress
1254 // MouseDown
1256 // On a click, hide the tooltip
1258 nsresult
1259 ChromeTooltipListener::MouseDown(nsIDOMEvent* aMouseEvent)
1261 return HideTooltip();
1263 } // MouseDown
1266 nsresult
1267 ChromeTooltipListener::MouseUp(nsIDOMEvent* aMouseEvent)
1269 return NS_OK;
1272 nsresult
1273 ChromeTooltipListener::MouseClick(nsIDOMEvent* aMouseEvent)
1275 return NS_OK;
1278 nsresult
1279 ChromeTooltipListener::MouseDblClick(nsIDOMEvent* aMouseEvent)
1281 return NS_OK;
1284 nsresult
1285 ChromeTooltipListener::MouseOver(nsIDOMEvent* aMouseEvent)
1287 return NS_OK;
1292 // MouseOut
1294 // If we're responding to tooltips, hide the tip whenever the mouse leaves
1295 // the area it was in.
1296 nsresult
1297 ChromeTooltipListener::MouseOut(nsIDOMEvent* aMouseEvent)
1299 return HideTooltip();
1304 // MouseMove
1306 // If we're a tooltip, fire off a timer to see if a tooltip should be shown. If the
1307 // timer fires, we cache the node in |mPossibleTooltipNode|.
1309 nsresult
1310 ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent)
1312 nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
1313 if (!mouseEvent)
1314 return NS_OK;
1316 // stash the coordinates of the event so that we can still get back to it from within the
1317 // timer callback. On win32, we'll get a MouseMove event even when a popup goes away --
1318 // even when the mouse doesn't change position! To get around this, we make sure the
1319 // mouse has really moved before proceeding.
1320 PRInt32 newMouseX, newMouseY;
1321 mouseEvent->GetClientX(&newMouseX);
1322 mouseEvent->GetClientY(&newMouseY);
1323 if ( mMouseClientX == newMouseX && mMouseClientY == newMouseY )
1324 return NS_OK;
1325 mMouseClientX = newMouseX; mMouseClientY = newMouseY;
1326 mouseEvent->GetScreenX(&mMouseScreenX);
1327 mouseEvent->GetScreenY(&mMouseScreenY);
1329 // We want to close the tip if it is being displayed and the mouse moves. Recall
1330 // that |mShowingTooltip| is set when the popup is showing. Furthermore, as the mouse
1331 // moves, we want to make sure we reset the timer to show it, so that the delay
1332 // is from when the mouse stops moving, not when it enters the element.
1333 if ( mShowingTooltip )
1334 return HideTooltip();
1335 if ( mTooltipTimer )
1336 mTooltipTimer->Cancel();
1338 mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1");
1339 if ( mTooltipTimer ) {
1340 nsCOMPtr<nsIDOMEventTarget> eventTarget;
1341 aMouseEvent->GetTarget(getter_AddRefs(eventTarget));
1342 if ( eventTarget )
1343 mPossibleTooltipNode = do_QueryInterface(eventTarget);
1344 if ( mPossibleTooltipNode ) {
1345 nsresult rv = mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this, kTooltipShowTime,
1346 nsITimer::TYPE_ONE_SHOT);
1347 if (NS_FAILED(rv))
1348 mPossibleTooltipNode = nsnull;
1351 else
1352 NS_WARNING ( "Could not create a timer for tooltip tracking" );
1354 return NS_OK;
1356 } // MouseMove
1360 // ShowTooltip
1362 // Tell the registered chrome that they should show the tooltip
1364 NS_IMETHODIMP
1365 ChromeTooltipListener::ShowTooltip(PRInt32 inXCoords, PRInt32 inYCoords,
1366 const nsAString & inTipText)
1368 nsresult rv = NS_OK;
1370 // do the work to call the client
1371 nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
1372 if ( tooltipListener ) {
1373 rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() );
1374 if ( NS_SUCCEEDED(rv) )
1375 mShowingTooltip = PR_TRUE;
1378 return rv;
1380 } // ShowTooltip
1384 // HideTooltip
1386 // Tell the registered chrome that they should rollup the tooltip
1387 // NOTE: This routine is safe to call even if the popup is already closed.
1389 NS_IMETHODIMP
1390 ChromeTooltipListener::HideTooltip()
1392 nsresult rv = NS_OK;
1394 // shut down the relevant timers
1395 if ( mTooltipTimer ) {
1396 mTooltipTimer->Cancel();
1397 mTooltipTimer = nsnull;
1398 // release tooltip target
1399 mPossibleTooltipNode = nsnull;
1401 if ( mAutoHideTimer ) {
1402 mAutoHideTimer->Cancel();
1403 mAutoHideTimer = nsnull;
1406 // if we're showing the tip, tell the chrome to hide it
1407 if ( mShowingTooltip ) {
1408 nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
1409 if ( tooltipListener ) {
1410 rv = tooltipListener->OnHideTooltip ( );
1411 if ( NS_SUCCEEDED(rv) )
1412 mShowingTooltip = PR_FALSE;
1416 return rv;
1418 } // HideTooltip
1422 // sTooltipCallback
1424 // A timer callback, fired when the mouse has hovered inside of a frame for the
1425 // appropriate amount of time. Getting to this point means that we should show the
1426 // tooltip, but only after we determine there is an appropriate TITLE element.
1428 // This relies on certain things being cached into the |aChromeTooltipListener| object passed to
1429 // us by the timer:
1430 // -- the x/y coordinates of the mouse (mMouseClientY, mMouseClientX)
1431 // -- the dom node the user hovered over (mPossibleTooltipNode)
1433 void
1434 ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer,
1435 void *aChromeTooltipListener)
1437 ChromeTooltipListener* self = static_cast<ChromeTooltipListener*>
1438 (aChromeTooltipListener);
1439 if ( self && self->mPossibleTooltipNode ){
1440 // The actual coordinates we want to put the tooltip at are relative to the
1441 // toplevel docshell of our mWebBrowser. We know what the screen
1442 // coordinates of the mouse event were, which means we just need the screen
1443 // coordinates of the docshell. Unfortunately, there is no good way to
1444 // find those short of groveling for the presentation in that docshell and
1445 // finding the screen coords of its toplevel widget...
1446 nsCOMPtr<nsIDocShell> docShell =
1447 do_GetInterface(static_cast<nsIWebBrowser*>(self->mWebBrowser));
1448 nsCOMPtr<nsIPresShell> shell;
1449 if (docShell) {
1450 docShell->GetPresShell(getter_AddRefs(shell));
1453 nsIWidget* widget = nsnull;
1454 if (shell) {
1455 nsIViewManager* vm = shell->GetViewManager();
1456 if (vm) {
1457 nsIView* view;
1458 vm->GetRootView(view);
1459 if (view) {
1460 nsPoint offset;
1461 widget = view->GetNearestWidget(&offset);
1466 if (!widget) {
1467 // release tooltip target if there is one, NO MATTER WHAT
1468 self->mPossibleTooltipNode = nsnull;
1469 return;
1472 // if there is text associated with the node, show the tip and fire
1473 // off a timer to auto-hide it.
1475 nsXPIDLString tooltipText;
1476 if (self->mTooltipTextProvider) {
1477 PRBool textFound = PR_FALSE;
1479 self->mTooltipTextProvider->GetNodeText(
1480 self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound);
1482 if (textFound) {
1483 nsString tipText(tooltipText);
1484 self->CreateAutoHideTimer();
1485 nsRect widgetDot(0, 0, 1, 1);
1486 nsRect screenDot;
1487 widget->WidgetToScreen(widgetDot, screenDot);
1488 self->ShowTooltip (self->mMouseScreenX - screenDot.x,
1489 self->mMouseScreenY - screenDot.y,
1490 tipText);
1494 // release tooltip target if there is one, NO MATTER WHAT
1495 self->mPossibleTooltipNode = nsnull;
1496 } // if "self" data valid
1498 } // sTooltipCallback
1502 // CreateAutoHideTimer
1504 // Create a new timer to see if we should auto-hide. It's ok if this fails.
1506 void
1507 ChromeTooltipListener::CreateAutoHideTimer()
1509 // just to be anal (er, safe)
1510 if ( mAutoHideTimer ) {
1511 mAutoHideTimer->Cancel();
1512 mAutoHideTimer = nsnull;
1515 mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1");
1516 if ( mAutoHideTimer )
1517 mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime,
1518 nsITimer::TYPE_ONE_SHOT);
1520 } // CreateAutoHideTimer
1524 // sAutoHideCallback
1526 // This fires after a tooltip has been open for a certain length of time. Just tell
1527 // the listener to close the popup. We don't have to worry, because HideTooltip() can
1528 // be called multiple times, even if the tip has already been closed.
1530 void
1531 ChromeTooltipListener::sAutoHideCallback(nsITimer *aTimer, void* aListener)
1533 ChromeTooltipListener* self = static_cast<ChromeTooltipListener*>(aListener);
1534 if ( self )
1535 self->HideTooltip();
1537 // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
1539 } // sAutoHideCallback
1543 #ifdef XP_MAC
1544 #pragma mark -
1545 #endif
1548 NS_IMPL_ADDREF(ChromeContextMenuListener)
1549 NS_IMPL_RELEASE(ChromeContextMenuListener)
1551 NS_INTERFACE_MAP_BEGIN(ChromeContextMenuListener)
1552 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMContextMenuListener)
1553 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMContextMenuListener)
1554 NS_INTERFACE_MAP_ENTRY(nsIDOMContextMenuListener)
1555 NS_INTERFACE_MAP_END
1559 // ChromeTooltipListener ctor
1561 ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome )
1562 : mContextMenuListenerInstalled(PR_FALSE),
1563 mWebBrowser(inBrowser),
1564 mWebBrowserChrome(inChrome)
1566 } // ctor
1570 // ChromeTooltipListener dtor
1572 ChromeContextMenuListener::~ChromeContextMenuListener()
1574 } // dtor
1578 // AddContextMenuListener
1580 // Subscribe to the events that will allow us to track context menus. Bascially, this
1581 // is just the context-menu DOM event.
1583 NS_IMETHODIMP
1584 ChromeContextMenuListener::AddContextMenuListener()
1586 if (mEventTarget) {
1587 nsIDOMContextMenuListener *pListener = static_cast<nsIDOMContextMenuListener *>(this);
1588 nsresult rv = mEventTarget->AddEventListenerByIID(pListener, NS_GET_IID(nsIDOMContextMenuListener));
1589 if (NS_SUCCEEDED(rv))
1590 mContextMenuListenerInstalled = PR_TRUE;
1593 return NS_OK;
1598 // RemoveContextMenuListener
1600 // Unsubscribe from all the various context menu events that we were listening to.
1602 NS_IMETHODIMP
1603 ChromeContextMenuListener::RemoveContextMenuListener()
1605 if (mEventTarget) {
1606 nsIDOMContextMenuListener *pListener = static_cast<nsIDOMContextMenuListener *>(this);
1607 nsresult rv = mEventTarget->RemoveEventListenerByIID(pListener, NS_GET_IID(nsIDOMContextMenuListener));
1608 if (NS_SUCCEEDED(rv))
1609 mContextMenuListenerInstalled = PR_FALSE;
1612 return NS_OK;
1617 // AddChromeListeners
1619 // Hook up things to the chrome like context menus and tooltips, if the chrome
1620 // has implemented the right interfaces.
1622 NS_IMETHODIMP
1623 ChromeContextMenuListener::AddChromeListeners()
1625 if (!mEventTarget)
1626 GetPIDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget));
1628 // Register the appropriate events for context menus, but only if
1629 // the embedding chrome cares.
1630 nsresult rv = NS_OK;
1632 nsCOMPtr<nsIContextMenuListener2> contextListener2 ( do_QueryInterface(mWebBrowserChrome) );
1633 nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) );
1634 if ( (contextListener || contextListener2) && !mContextMenuListenerInstalled )
1635 rv = AddContextMenuListener();
1637 return rv;
1639 } // AddChromeListeners
1643 // RemoveChromeListeners
1645 // Unsubscribe from the various things we've hooked up to the window root.
1647 NS_IMETHODIMP
1648 ChromeContextMenuListener::RemoveChromeListeners()
1650 if ( mContextMenuListenerInstalled )
1651 RemoveContextMenuListener();
1653 mEventTarget = nsnull;
1655 // it really doesn't matter if these fail...
1656 return NS_OK;
1658 } // RemoveChromeTooltipListeners
1663 // ContextMenu
1665 // We're on call to show the context menu. Dig around in the DOM to
1666 // find the type of object we're dealing with and notify the front
1667 // end chrome.
1669 NS_IMETHODIMP
1670 ChromeContextMenuListener::ContextMenu(nsIDOMEvent* aMouseEvent)
1672 nsCOMPtr<nsIDOMNSUIEvent> uievent(do_QueryInterface(aMouseEvent));
1674 if (uievent) {
1675 PRBool isDefaultPrevented = PR_FALSE;
1676 uievent->GetPreventDefault(&isDefaultPrevented);
1678 if (isDefaultPrevented) {
1679 return NS_OK;
1683 nsCOMPtr<nsIDOMEventTarget> targetNode;
1684 nsresult res = aMouseEvent->GetTarget(getter_AddRefs(targetNode));
1685 if (NS_FAILED(res))
1686 return res;
1687 if (!targetNode)
1688 return NS_ERROR_NULL_POINTER;
1690 nsCOMPtr<nsIDOMNode> targetDOMnode;
1691 nsCOMPtr<nsIDOMNode> node = do_QueryInterface(targetNode);
1692 if (!node)
1693 return NS_OK;
1695 // Stop the context menu event going to other windows (bug 78396)
1696 aMouseEvent->PreventDefault();
1698 // If the listener is a nsIContextMenuListener2, create the info object
1699 nsCOMPtr<nsIContextMenuListener2> menuListener2(do_QueryInterface(mWebBrowserChrome));
1700 nsContextMenuInfo *menuInfoImpl = nsnull;
1701 nsCOMPtr<nsIContextMenuInfo> menuInfo;
1702 if (menuListener2) {
1703 menuInfoImpl = new nsContextMenuInfo;
1704 if (!menuInfoImpl)
1705 return NS_ERROR_OUT_OF_MEMORY;
1706 menuInfo = menuInfoImpl;
1709 PRUint32 flags = nsIContextMenuListener::CONTEXT_NONE;
1710 PRUint32 flags2 = nsIContextMenuListener2::CONTEXT_NONE;
1712 // XXX test for selected text
1714 PRUint16 nodeType;
1715 res = node->GetNodeType(&nodeType);
1716 NS_ENSURE_SUCCESS(res, res);
1718 // First, checks for nodes that never have children.
1719 if (nodeType == nsIDOMNode::ELEMENT_NODE) {
1720 nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(node));
1721 if (content) {
1722 nsCOMPtr<nsIURI> imgUri;
1723 content->GetCurrentURI(getter_AddRefs(imgUri));
1724 if (imgUri) {
1725 flags |= nsIContextMenuListener::CONTEXT_IMAGE;
1726 flags2 |= nsIContextMenuListener2::CONTEXT_IMAGE;
1727 targetDOMnode = node;
1731 nsCOMPtr<nsIDOMHTMLInputElement> inputElement(do_QueryInterface(node));
1732 if (inputElement) {
1733 flags |= nsIContextMenuListener::CONTEXT_INPUT;
1734 flags2 |= nsIContextMenuListener2::CONTEXT_INPUT;
1736 if (menuListener2) {
1737 nsAutoString inputElemType;
1738 inputElement->GetType(inputElemType);
1739 if (inputElemType.LowerCaseEqualsLiteral("text") ||
1740 inputElemType.LowerCaseEqualsLiteral("password"))
1741 flags2 |= nsIContextMenuListener2::CONTEXT_TEXT;
1744 targetDOMnode = node;
1747 nsCOMPtr<nsIDOMHTMLTextAreaElement> textElement(do_QueryInterface(node));
1748 if (textElement) {
1749 flags |= nsIContextMenuListener::CONTEXT_TEXT;
1750 flags2 |= nsIContextMenuListener2::CONTEXT_TEXT;
1751 targetDOMnode = node;
1754 // always consume events for plugins and Java who may throw their
1755 // own context menus but not for image objects. Document objects
1756 // will never be targets or ancestors of targets, so that's OK.
1757 nsCOMPtr<nsIDOMHTMLObjectElement> objectElement;
1758 if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE))
1759 objectElement = do_QueryInterface(node);
1760 nsCOMPtr<nsIDOMHTMLEmbedElement> embedElement(do_QueryInterface(node));
1761 nsCOMPtr<nsIDOMHTMLAppletElement> appletElement(do_QueryInterface(node));
1763 if (objectElement || embedElement || appletElement)
1764 return NS_OK;
1767 // Bubble out, looking for items of interest
1768 do {
1769 PRUint16 nodeType;
1770 res = node->GetNodeType(&nodeType);
1771 NS_ENSURE_SUCCESS(res, res);
1773 if (nodeType == nsIDOMNode::ELEMENT_NODE) {
1775 // Test if the element has an associated link
1776 nsCOMPtr<nsIDOMElement> element(do_QueryInterface(node));
1778 PRBool hasAttr = PR_FALSE;
1779 res = element->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr);
1781 if (NS_SUCCEEDED(res) && hasAttr)
1783 flags |= nsIContextMenuListener::CONTEXT_LINK;
1784 flags2 |= nsIContextMenuListener2::CONTEXT_LINK;
1785 if (!targetDOMnode)
1786 targetDOMnode = node;
1787 if (menuInfoImpl)
1788 menuInfoImpl->SetAssociatedLink(node);
1789 break; // exit do-while
1793 // walk-up-the-tree
1794 nsCOMPtr<nsIDOMNode> parentNode;
1795 node->GetParentNode(getter_AddRefs(parentNode));
1796 node = parentNode;
1797 } while (node);
1799 if (!flags && !flags2) {
1800 // We found nothing of interest so far, check if we
1801 // have at least an html document.
1802 nsCOMPtr<nsIDOMDocument> document;
1803 node = do_QueryInterface(targetNode);
1804 node->GetOwnerDocument(getter_AddRefs(document));
1805 nsCOMPtr<nsIDOMHTMLDocument> htmlDocument(do_QueryInterface(document));
1806 if (htmlDocument) {
1807 flags |= nsIContextMenuListener::CONTEXT_DOCUMENT;
1808 flags2 |= nsIContextMenuListener2::CONTEXT_DOCUMENT;
1809 targetDOMnode = node;
1810 if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE)) {
1811 // check if this is a background image that the user was trying to click on
1812 // and if the listener is ready for that (only nsIContextMenuListener2 and up)
1813 if (menuInfoImpl && menuInfoImpl->HasBackgroundImage(targetDOMnode)) {
1814 flags2 |= nsIContextMenuListener2::CONTEXT_BACKGROUND_IMAGE;
1815 // For the embedder to get the correct background image
1816 // targetDOMnode must point to the original node.
1817 targetDOMnode = do_QueryInterface(targetNode);
1823 // we need to cache the event target into the focus controller's popupNode
1824 // so we can get at it later from command code, etc.:
1826 // get the dom window
1827 nsCOMPtr<nsIDOMWindow> win;
1828 res = mWebBrowser->GetContentDOMWindow(getter_AddRefs(win));
1829 NS_ENSURE_SUCCESS(res, res);
1830 NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
1831 // get the private dom window
1832 nsCOMPtr<nsPIDOMWindow> privateWin(do_QueryInterface(win, &res));
1833 NS_ENSURE_SUCCESS(res, res);
1834 NS_ENSURE_TRUE(privateWin, NS_ERROR_FAILURE);
1835 // get the focus controller
1836 nsIFocusController *focusController = privateWin->GetRootFocusController();
1837 NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
1838 // set the focus controller's popup node to the event target
1839 res = focusController->SetPopupNode(targetDOMnode);
1840 NS_ENSURE_SUCCESS(res, res);
1842 // Tell the listener all about the event
1843 if ( menuListener2 ) {
1844 menuInfoImpl->SetMouseEvent(aMouseEvent);
1845 menuInfoImpl->SetDOMNode(targetDOMnode);
1846 menuListener2->OnShowContextMenu(flags2, menuInfo);
1848 else {
1849 nsCOMPtr<nsIContextMenuListener> menuListener(do_QueryInterface(mWebBrowserChrome));
1850 if ( menuListener )
1851 menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode);
1854 return NS_OK;
1856 } // MouseDown