Back to index

lightning-sunbird  0.9+nobinonly
nsDocShellTreeOwner.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Travis Bogard <travis@netscape.com>
00025  *   Adam Lock <adamlock@netscape.com>
00026  *   Mike Pinkerton <pinkerton@netscape.com>
00027  *   Dan Rosen <dr@netscape.com>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either the GNU General Public License Version 2 or later (the "GPL"), or
00031  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 // Local Includes
00044 #include "nsDocShellTreeOwner.h"
00045 #include "nsWebBrowser.h"
00046 
00047 // Helper Classes
00048 #include "nsIGenericFactory.h"
00049 #include "nsStyleCoord.h"
00050 #include "nsSize.h"
00051 #include "nsHTMLReflowState.h"
00052 #include "nsIServiceManager.h"
00053 #include "nsComponentManagerUtils.h"
00054 #include "nsXPIDLString.h"
00055 #include "nsIAtom.h"
00056 #include "nsReadableUtils.h"
00057 #include "nsUnicharUtils.h"
00058 #include "nsISimpleEnumerator.h"
00059 
00060 // Interfaces needed to be included
00061 #include "nsPresContext.h"
00062 #include "nsIContextMenuListener.h"
00063 #include "nsIContextMenuListener2.h"
00064 #include "nsITooltipListener.h"
00065 #include "nsIPrivateDOMEvent.h"
00066 #include "nsIDOMNode.h"
00067 #include "nsIDOMNodeList.h"
00068 #include "nsIDOMDocument.h"
00069 #include "nsIDOMDocumentType.h"
00070 #include "nsIDOMElement.h"
00071 #include "nsIDOMEvent.h"
00072 #include "nsIDOMMouseEvent.h"
00073 #include "nsIDOMNSUIEvent.h"
00074 #include "nsIDOMEventReceiver.h"
00075 #include "nsIDOMNamedNodeMap.h"
00076 #include "nsIDOMHTMLInputElement.h"
00077 #include "nsIWebNavigation.h"
00078 #include "nsIDOMHTMLElement.h"
00079 #include "nsIPresShell.h"
00080 #include "nsPIDOMWindow.h"
00081 #include "nsIDOMWindowCollection.h"
00082 #include "nsIFocusController.h"
00083 #include "nsIDOMWindowInternal.h"
00084 #include "nsIScriptGlobalObject.h"
00085 #include "nsIWindowWatcher.h"
00086 #include "nsPIWindowWatcher.h"
00087 #include "nsIPrompt.h"
00088 #include "nsRect.h"
00089 #include "nsIWebBrowserChromeFocus.h"
00090 #include "nsIContent.h"
00091 #include "imgIContainer.h"
00092 #include "nsContextMenuInfo.h"
00093 #include "nsPresContext.h"
00094 #include "nsIViewManager.h"
00095 #include "nsIView.h"
00096 
00097 //
00098 // GetEventReceiver
00099 //
00100 // A helper routine that navigates the tricky path from a |nsWebBrowser| to
00101 // a |nsIDOMEventReceiver| via the window root and chrome event handler.
00102 //
00103 static nsresult
00104 GetEventReceiver ( nsWebBrowser* inBrowser, nsIDOMEventReceiver** outEventRcvr )
00105 {
00106   nsCOMPtr<nsIDOMWindow> domWindow;
00107   inBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
00108   NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
00109 
00110   nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
00111   NS_ENSURE_TRUE(domWindowPrivate, NS_ERROR_FAILURE);
00112   nsPIDOMWindow *rootWindow = domWindowPrivate->GetPrivateRoot();
00113   NS_ENSURE_TRUE(rootWindow, NS_ERROR_FAILURE);
00114   nsIChromeEventHandler *chromeHandler = rootWindow->GetChromeEventHandler();
00115   NS_ENSURE_TRUE(chromeHandler, NS_ERROR_FAILURE);
00116 
00117   nsCOMPtr<nsIDOMEventReceiver> rcvr = do_QueryInterface(chromeHandler);
00118   *outEventRcvr = rcvr;
00119   NS_IF_ADDREF(*outEventRcvr);
00120   
00121   return NS_OK;
00122 }
00123 
00124 
00125 //*****************************************************************************
00126 //***    nsDocShellTreeOwner: Object Management
00127 //*****************************************************************************
00128 
00129 nsDocShellTreeOwner::nsDocShellTreeOwner() :
00130    mWebBrowser(nsnull), 
00131    mTreeOwner(nsnull),
00132    mPrimaryContentShell(nsnull),
00133    mWebBrowserChrome(nsnull),
00134    mOwnerWin(nsnull),
00135    mOwnerRequestor(nsnull),
00136    mChromeTooltipListener(nsnull),
00137    mChromeContextMenuListener(nsnull)
00138 {
00139 }
00140 
00141 nsDocShellTreeOwner::~nsDocShellTreeOwner()
00142 {
00143   RemoveChromeListeners();
00144 }
00145 
00146 //*****************************************************************************
00147 // nsDocShellTreeOwner::nsISupports
00148 //*****************************************************************************   
00149 
00150 NS_IMPL_ADDREF(nsDocShellTreeOwner)
00151 NS_IMPL_RELEASE(nsDocShellTreeOwner)
00152 
00153 NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner)
00154     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellTreeOwner)
00155     NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner)
00156     NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
00157     NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
00158     NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
00159     NS_INTERFACE_MAP_ENTRY(nsICDocShellTreeOwner)
00160     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00161 NS_INTERFACE_MAP_END
00162 
00163 //*****************************************************************************
00164 // nsDocShellTreeOwner::nsIInterfaceRequestor
00165 //*****************************************************************************   
00166 
00167 NS_IMETHODIMP
00168 nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink)
00169 {
00170   NS_ENSURE_ARG_POINTER(aSink);
00171 
00172   if(NS_SUCCEEDED(QueryInterface(aIID, aSink)))
00173     return NS_OK;
00174 
00175   if (aIID.Equals(NS_GET_IID(nsIWebBrowserChromeFocus))) {
00176     if (mWebBrowserChromeWeak != nsnull)
00177       return mWebBrowserChromeWeak->QueryReferent(aIID, aSink);
00178     return mOwnerWin->QueryInterface(aIID, aSink);
00179   }
00180 
00181   if (aIID.Equals(NS_GET_IID(nsIPrompt))) {
00182     nsIPrompt *prompt;
00183     EnsurePrompter();
00184     prompt = mPrompter;
00185     if (prompt) {
00186       NS_ADDREF(prompt);
00187       *aSink = prompt;
00188       return NS_OK;
00189     }
00190     return NS_NOINTERFACE;
00191   }
00192 
00193   if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
00194     nsIAuthPrompt *prompt;
00195     EnsureAuthPrompter();
00196     prompt = mAuthPrompter;
00197     if (prompt) {
00198       NS_ADDREF(prompt);
00199       *aSink = prompt;
00200       return NS_OK;
00201     }
00202     return NS_NOINTERFACE;
00203   }
00204 
00205   nsCOMPtr<nsIInterfaceRequestor> req = GetOwnerRequestor();
00206   if (req)
00207     return req->GetInterface(aIID, aSink);
00208 
00209   return NS_NOINTERFACE;
00210 }
00211 
00212 //*****************************************************************************
00213 // nsDocShellTreeOwner::nsIDocShellTreeOwner
00214 //*****************************************************************************   
00215 
00216 NS_IMETHODIMP
00217 nsDocShellTreeOwner::FindItemWithName(const PRUnichar* aName,
00218                                       nsIDocShellTreeItem* aRequestor,
00219                                       nsIDocShellTreeItem* aOriginalRequestor,
00220                                       nsIDocShellTreeItem** aFoundItem)
00221 {
00222   NS_ENSURE_ARG(aName);
00223   NS_ENSURE_ARG_POINTER(aFoundItem);
00224   *aFoundItem = nsnull; // if we don't find one, we return NS_OK and a null result 
00225   nsresult rv;
00226 
00227   nsAutoString name(aName);
00228 
00229   if (!mWebBrowser)
00230     return NS_OK; // stymied
00231 
00232   /* special cases */
00233   if(name.IsEmpty())
00234     return NS_OK;
00235   if(name.LowerCaseEqualsLiteral("_blank"))
00236     return NS_OK;
00237   // _main is an IE target which should be case-insensitive but isn't
00238   // see bug 217886 for details
00239   if(name.LowerCaseEqualsLiteral("_content") || name.EqualsLiteral("_main")) {
00240     *aFoundItem = mWebBrowser->mDocShellAsItem;
00241     NS_IF_ADDREF(*aFoundItem);
00242     return NS_OK;
00243   }
00244 
00245   // first, is it us?
00246   {
00247     nsCOMPtr<nsIDOMWindow> domWindow;
00248     mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
00249     if (domWindow) {
00250       nsAutoString ourName;
00251       domWindow->GetName(ourName);
00252       if (name.Equals(ourName, nsCaseInsensitiveStringComparator())) {
00253         *aFoundItem = mWebBrowser->mDocShellAsItem;
00254         NS_IF_ADDREF(*aFoundItem);
00255         return NS_OK;
00256       }
00257     }
00258   }
00259 
00260   // next, check our children
00261   rv = FindChildWithName(aName, PR_TRUE, aRequestor, aOriginalRequestor,
00262                          aFoundItem);
00263   if(NS_FAILED(rv) || *aFoundItem)
00264     return rv;
00265 
00266   // next, if we have a parent and it isn't the requestor, ask it
00267   nsCOMPtr<nsIDocShellTreeOwner> reqAsTreeOwner(do_QueryInterface(aRequestor));
00268 
00269   if(mTreeOwner) {
00270     if (mTreeOwner != reqAsTreeOwner)
00271       return mTreeOwner->FindItemWithName(aName, mWebBrowser->mDocShellAsItem,
00272                                           aOriginalRequestor, aFoundItem);
00273     return NS_OK;
00274   }
00275 
00276   // finally, failing everything else, search all windows
00277   return FindItemWithNameAcrossWindows(aName, aRequestor, aOriginalRequestor,
00278                                        aFoundItem);
00279 }
00280 
00281 nsresult
00282 nsDocShellTreeOwner::FindChildWithName(const PRUnichar *aName, PRBool aRecurse,
00283                                        nsIDocShellTreeItem* aRequestor,
00284                                        nsIDocShellTreeItem* aOriginalRequestor,
00285                                        nsIDocShellTreeItem **aFoundItem)
00286 {
00287   if (!mWebBrowser)
00288     return NS_OK;
00289 
00290   nsresult rv = NS_OK;
00291 
00292   nsCOMPtr<nsIDOMWindow> domWindow;
00293   mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
00294   if (!domWindow)
00295     return NS_OK;
00296 
00297   nsCOMPtr<nsIDOMWindowCollection> frames;
00298   domWindow->GetFrames(getter_AddRefs(frames));
00299   if (!frames)
00300     return NS_OK;
00301 
00302   PRUint32 ctr, count;
00303   frames->GetLength(&count);
00304   for (ctr = 0; ctr < count; ctr++) {
00305     nsCOMPtr<nsIDOMWindow> frame;
00306     frames->Item(ctr, getter_AddRefs(frame));
00307     if (frame) {
00308       nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(frame));
00309       if (sgo) {
00310         nsCOMPtr<nsIDocShellTreeItem> item =
00311           do_QueryInterface(sgo->GetDocShell());
00312         if (item && item != aRequestor) {
00313           rv = item->FindItemWithName(aName, mWebBrowser->mDocShellAsItem,
00314                                       aOriginalRequestor, aFoundItem);
00315           if (NS_FAILED(rv) || *aFoundItem)
00316             break;
00317         }
00318       }
00319     }
00320   }
00321   return rv;
00322 }
00323 
00324 nsresult
00325 nsDocShellTreeOwner::FindItemWithNameAcrossWindows(const PRUnichar* aName,
00326                                                    nsIDocShellTreeItem* aRequestor,
00327                                                    nsIDocShellTreeItem* aOriginalRequestor,
00328                                                    nsIDocShellTreeItem** aFoundItem)
00329 {
00330   // search for the item across the list of top-level windows
00331   nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00332   if (!wwatch)
00333     return NS_OK;
00334 
00335   return wwatch->FindItemWithName(aName, aRequestor, aOriginalRequestor,
00336                                   aFoundItem);
00337 }
00338 
00339 void
00340 nsDocShellTreeOwner::EnsurePrompter()
00341 {
00342   if (mPrompter)
00343     return;
00344 
00345   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00346   if (wwatch && mWebBrowser) {
00347     nsCOMPtr<nsIDOMWindow> domWindow;
00348     mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
00349     if (domWindow)
00350       wwatch->GetNewPrompter(domWindow, getter_AddRefs(mPrompter));
00351   }
00352 }
00353 
00354 void
00355 nsDocShellTreeOwner::EnsureAuthPrompter()
00356 {
00357   if (mAuthPrompter)
00358     return;
00359 
00360   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00361   if (wwatch && mWebBrowser) {
00362     nsCOMPtr<nsIDOMWindow> domWindow;
00363     mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
00364     if (domWindow)
00365       wwatch->GetNewAuthPrompter(domWindow, getter_AddRefs(mAuthPrompter));
00366   }
00367 }
00368 
00369 void
00370 nsDocShellTreeOwner::AddToWatcher()
00371 {
00372   if (mWebBrowser) {
00373     nsCOMPtr<nsIDOMWindow> domWindow;
00374     mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
00375     if (domWindow) {
00376       nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00377       if (wwatch) {
00378         nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
00379         if (webBrowserChrome)
00380           wwatch->AddWindow(domWindow, webBrowserChrome);
00381       }
00382     }
00383   }
00384 }
00385 
00386 void
00387 nsDocShellTreeOwner::RemoveFromWatcher()
00388 {
00389   if (mWebBrowser) {
00390     nsCOMPtr<nsIDOMWindow> domWindow;
00391     mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
00392     if (domWindow) {
00393       nsCOMPtr<nsPIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00394       if (wwatch)
00395         wwatch->RemoveWindow(domWindow);
00396     }
00397   }
00398 }
00399 
00400 
00401 NS_IMETHODIMP
00402 nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell,
00403                                        PRBool aPrimary, const PRUnichar* aID)
00404 {
00405    if(mTreeOwner)
00406       return mTreeOwner->ContentShellAdded(aContentShell, aPrimary, aID);
00407 
00408    if (aPrimary)
00409       mPrimaryContentShell = aContentShell;
00410    return NS_OK;
00411 }
00412 
00413 NS_IMETHODIMP
00414 nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem** aShell)
00415 {
00416    NS_ENSURE_ARG_POINTER(aShell);
00417 
00418    if(mTreeOwner)
00419        return mTreeOwner->GetPrimaryContentShell(aShell);
00420 
00421    *aShell = (mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShellAsItem.get());
00422    NS_IF_ADDREF(*aShell);
00423 
00424    return NS_OK;
00425 }
00426 
00427 NS_IMETHODIMP
00428 nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem,
00429                                  PRInt32 aCX, PRInt32 aCY)
00430 {
00431    nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
00432 
00433    NS_ENSURE_STATE(mTreeOwner || webBrowserChrome);
00434 
00435    if(mTreeOwner)
00436       return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY);
00437 
00438    if(aShellItem == mWebBrowser->mDocShellAsItem)
00439       return webBrowserChrome->SizeBrowserTo(aCX, aCY);
00440 
00441    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(aShellItem));
00442    NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
00443 
00444    nsCOMPtr<nsIDOMDocument> domDocument;
00445    webNav->GetDocument(getter_AddRefs(domDocument));
00446    NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE);
00447 
00448    nsCOMPtr<nsIDOMElement> domElement;
00449    domDocument->GetDocumentElement(getter_AddRefs(domElement));
00450    NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE);
00451 
00452    // Set the preferred Size
00453    //XXX
00454    NS_ERROR("Implement this");
00455    /*
00456    Set the preferred size on the aShellItem.
00457    */
00458 
00459    nsCOMPtr<nsPresContext> presContext;
00460    mWebBrowser->mDocShell->GetPresContext(getter_AddRefs(presContext));
00461    NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
00462 
00463    nsIPresShell *presShell = presContext->GetPresShell();
00464    NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
00465 
00466    NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE,
00467       NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE);
00468    
00469    nsRect shellArea = presContext->GetVisibleArea();
00470 
00471    float pixelScale;
00472    pixelScale = presContext->TwipsToPixels();
00473    PRInt32 browserCX = PRInt32((float)shellArea.width*pixelScale);
00474    PRInt32 browserCY = PRInt32((float)shellArea.height*pixelScale);
00475 
00476    return webBrowserChrome->SizeBrowserTo(browserCX, browserCY);
00477 }
00478 
00479 NS_IMETHODIMP
00480 nsDocShellTreeOwner::SetPersistence(PRBool aPersistPosition,
00481                                     PRBool aPersistSize,
00482                                     PRBool aPersistSizeMode)
00483 {
00484   return NS_ERROR_NOT_IMPLEMENTED;
00485 }
00486 
00487 NS_IMETHODIMP
00488 nsDocShellTreeOwner::GetPersistence(PRBool* aPersistPosition,
00489                                     PRBool* aPersistSize,
00490                                     PRBool* aPersistSizeMode)
00491 {
00492   return NS_ERROR_NOT_IMPLEMENTED;
00493 }
00494 
00495 //*****************************************************************************
00496 // nsDocShellTreeOwner::nsIBaseWindow
00497 //*****************************************************************************   
00498 
00499 
00500 NS_IMETHODIMP
00501 nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow,
00502                                 nsIWidget* aParentWidget, PRInt32 aX,
00503                                 PRInt32 aY, PRInt32 aCX, PRInt32 aCY)   
00504 {
00505   return NS_ERROR_NULL_POINTER;
00506 }
00507 
00508 NS_IMETHODIMP
00509 nsDocShellTreeOwner::Create()
00510 {
00511   return NS_ERROR_NULL_POINTER;
00512 }
00513 
00514 NS_IMETHODIMP
00515 nsDocShellTreeOwner::Destroy()
00516 {
00517   nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
00518   if (webBrowserChrome)
00519   {
00520     return webBrowserChrome->DestroyBrowserWindow();
00521   }
00522 
00523   return NS_ERROR_NULL_POINTER;
00524 }
00525 
00526 NS_IMETHODIMP
00527 nsDocShellTreeOwner::SetPosition(PRInt32 aX, PRInt32 aY)
00528 {
00529   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00530   if (ownerWin)
00531   {
00532     return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
00533                                    aX, aY, 0, 0);
00534   }
00535   return NS_ERROR_NULL_POINTER;
00536 }
00537 
00538 NS_IMETHODIMP
00539 nsDocShellTreeOwner::GetPosition(PRInt32* aX, PRInt32* aY)
00540 {
00541   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00542   if (ownerWin)
00543   {
00544     return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
00545                                    aX, aY, nsnull, nsnull);
00546   }
00547   return NS_ERROR_NULL_POINTER;
00548 }
00549 
00550 NS_IMETHODIMP
00551 nsDocShellTreeOwner::SetSize(PRInt32 aCX, PRInt32 aCY, PRBool aRepaint)
00552 {
00553   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00554   if (ownerWin)
00555   {
00556     return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
00557                                    0, 0, aCX, aCY);
00558   }
00559   return NS_ERROR_NULL_POINTER;
00560 }
00561 
00562 NS_IMETHODIMP
00563 nsDocShellTreeOwner::GetSize(PRInt32* aCX, PRInt32* aCY)
00564 {
00565   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00566   if (ownerWin)
00567   {
00568     return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
00569                                    nsnull, nsnull, aCX, aCY);
00570   }
00571   return NS_ERROR_NULL_POINTER;
00572 }
00573 
00574 NS_IMETHODIMP
00575 nsDocShellTreeOwner::SetPositionAndSize(PRInt32 aX, PRInt32 aY, PRInt32 aCX,
00576                                         PRInt32 aCY, PRBool aRepaint)
00577 {
00578   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00579   if (ownerWin)
00580   {
00581     return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
00582                                    nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
00583                                    aX, aY, aCX, aCY);
00584   }
00585   return NS_ERROR_NULL_POINTER;
00586 }
00587 
00588 NS_IMETHODIMP
00589 nsDocShellTreeOwner::GetPositionAndSize(PRInt32* aX, PRInt32* aY, PRInt32* aCX,
00590                                         PRInt32* aCY)
00591 {
00592   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00593   if (ownerWin)
00594   {
00595     return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
00596                                    nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
00597                                    aX, aY, aCX, aCY);
00598   }
00599   return NS_ERROR_NULL_POINTER;
00600 }
00601 
00602 NS_IMETHODIMP
00603 nsDocShellTreeOwner::Repaint(PRBool aForce)
00604 {
00605   return NS_ERROR_NULL_POINTER;
00606 }
00607 
00608 NS_IMETHODIMP
00609 nsDocShellTreeOwner::GetParentWidget(nsIWidget** aParentWidget)
00610 {
00611   return NS_ERROR_NULL_POINTER;
00612 }
00613 
00614 NS_IMETHODIMP
00615 nsDocShellTreeOwner::SetParentWidget(nsIWidget* aParentWidget)
00616 {
00617   return NS_ERROR_NULL_POINTER;
00618 }
00619 
00620 NS_IMETHODIMP
00621 nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
00622 {
00623   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00624   if (ownerWin)
00625   {
00626     return ownerWin->GetSiteWindow(aParentNativeWindow);
00627   }
00628   return NS_ERROR_NULL_POINTER;
00629 }
00630 
00631 NS_IMETHODIMP
00632 nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow)
00633 {
00634   return NS_ERROR_NULL_POINTER;
00635 }
00636 
00637 NS_IMETHODIMP
00638 nsDocShellTreeOwner::GetVisibility(PRBool* aVisibility)
00639 {
00640   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00641   if (ownerWin)
00642   {
00643     return ownerWin->GetVisibility(aVisibility);
00644   }
00645   return NS_ERROR_NULL_POINTER;
00646 }
00647 
00648 NS_IMETHODIMP
00649 nsDocShellTreeOwner::SetVisibility(PRBool aVisibility)
00650 {
00651   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00652   if (ownerWin)
00653   {
00654     return ownerWin->SetVisibility(aVisibility);
00655   }
00656   return NS_ERROR_NULL_POINTER;
00657 }
00658 
00659 NS_IMETHODIMP
00660 nsDocShellTreeOwner::GetEnabled(PRBool *aEnabled)
00661 {
00662   NS_ENSURE_ARG_POINTER(aEnabled);
00663   *aEnabled = PR_TRUE;
00664   return NS_ERROR_NOT_IMPLEMENTED;
00665 }
00666 
00667 NS_IMETHODIMP
00668 nsDocShellTreeOwner::SetEnabled(PRBool aEnabled)
00669 {
00670   return NS_ERROR_NOT_IMPLEMENTED;
00671 }
00672 
00673 NS_IMETHODIMP
00674 nsDocShellTreeOwner::GetBlurSuppression(PRBool *aBlurSuppression)
00675 {
00676   NS_ENSURE_ARG_POINTER(aBlurSuppression);
00677   *aBlurSuppression = PR_FALSE;
00678   return NS_ERROR_NOT_IMPLEMENTED;
00679 }
00680 
00681 NS_IMETHODIMP
00682 nsDocShellTreeOwner::SetBlurSuppression(PRBool aBlurSuppression)
00683 {
00684   return NS_ERROR_NOT_IMPLEMENTED;
00685 }
00686 
00687 NS_IMETHODIMP
00688 nsDocShellTreeOwner::GetMainWidget(nsIWidget** aMainWidget)
00689 {
00690     return NS_ERROR_NULL_POINTER;
00691 }
00692 
00693 NS_IMETHODIMP
00694 nsDocShellTreeOwner::SetFocus()
00695 {
00696   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00697   if (ownerWin)
00698   {
00699     return ownerWin->SetFocus();
00700   }
00701   return NS_ERROR_NULL_POINTER;
00702 }
00703 
00704 NS_IMETHODIMP
00705 nsDocShellTreeOwner::GetTitle(PRUnichar** aTitle)
00706 {
00707   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00708   if (ownerWin)
00709   {
00710     return ownerWin->GetTitle(aTitle);
00711   }
00712   return NS_ERROR_NULL_POINTER;
00713 }
00714 
00715 NS_IMETHODIMP
00716 nsDocShellTreeOwner::SetTitle(const PRUnichar* aTitle)
00717 {
00718   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
00719   if (ownerWin)
00720   {
00721     return ownerWin->SetTitle(aTitle);
00722   }
00723   return NS_ERROR_NULL_POINTER;
00724 }
00725 
00726 
00727 //*****************************************************************************
00728 // nsDocShellTreeOwner::nsIWebProgressListener
00729 //*****************************************************************************   
00730 
00731 
00732 NS_IMETHODIMP
00733 nsDocShellTreeOwner::OnProgressChange(nsIWebProgress* aProgress,
00734                                       nsIRequest* aRequest,
00735                                       PRInt32 aCurSelfProgress,
00736                                       PRInt32 aMaxSelfProgress, 
00737                                       PRInt32 aCurTotalProgress,
00738                                       PRInt32 aMaxTotalProgress)
00739 {
00740     // In the absence of DOM document creation event, this method is the
00741     // most convenient place to install the mouse listener on the
00742     // DOM document.
00743     return AddChromeListeners();
00744 }
00745 
00746 NS_IMETHODIMP
00747 nsDocShellTreeOwner::OnStateChange(nsIWebProgress* aProgress,
00748                                    nsIRequest* aRequest,
00749                                    PRUint32 aProgressStateFlags,
00750                                    nsresult aStatus)
00751 {
00752     return NS_OK;
00753 }
00754 
00755 NS_IMETHODIMP
00756 nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress,
00757                                       nsIRequest* aRequest,
00758                                       nsIURI* aURI)
00759 {
00760     return NS_OK;
00761 }
00762 
00763 NS_IMETHODIMP 
00764 nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress,
00765                                     nsIRequest* aRequest,
00766                                     nsresult aStatus,
00767                                     const PRUnichar* aMessage)
00768 {
00769     return NS_OK;
00770 }
00771 
00772 NS_IMETHODIMP 
00773 nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress, 
00774                                       nsIRequest *aRequest, 
00775                                       PRUint32 state)
00776 {
00777     return NS_OK;
00778 }
00779 
00780 
00781 //*****************************************************************************
00782 // nsDocShellTreeOwner: Helpers
00783 //*****************************************************************************   
00784 
00785 //*****************************************************************************
00786 // nsDocShellTreeOwner: Accessors
00787 //*****************************************************************************   
00788 
00789 void
00790 nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser)
00791 {
00792   if ( !aWebBrowser )
00793     RemoveChromeListeners();
00794   if (aWebBrowser != mWebBrowser) {
00795     mPrompter = 0;
00796     mAuthPrompter = 0;
00797   }
00798 
00799   mWebBrowser = aWebBrowser;
00800 }
00801 
00802 nsWebBrowser *
00803 nsDocShellTreeOwner::WebBrowser()
00804 {
00805    return mWebBrowser;
00806 }
00807 
00808 NS_IMETHODIMP
00809 nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
00810 { 
00811   if(aTreeOwner) {
00812     nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome(do_GetInterface(aTreeOwner));
00813     NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG);
00814     NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome), NS_ERROR_INVALID_ARG);
00815     mTreeOwner = aTreeOwner;
00816   }
00817   else {
00818     mTreeOwner = nsnull;
00819     nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
00820     if (!webBrowserChrome)
00821       NS_ENSURE_SUCCESS(SetWebBrowserChrome(nsnull), NS_ERROR_FAILURE);
00822   }
00823 
00824   return NS_OK;
00825 }
00826 
00827 NS_IMETHODIMP
00828 nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome)
00829 {
00830   if(!aWebBrowserChrome) {
00831     mWebBrowserChrome = nsnull;
00832     mOwnerWin = nsnull;
00833     mOwnerRequestor = nsnull;
00834     mWebBrowserChromeWeak = 0;
00835   } else {
00836     nsCOMPtr<nsISupportsWeakReference> supportsweak =
00837                                            do_QueryInterface(aWebBrowserChrome);
00838     if (supportsweak) {
00839       supportsweak->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak));
00840     } else {
00841       nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin(do_QueryInterface(aWebBrowserChrome));
00842       nsCOMPtr<nsIInterfaceRequestor> requestor(do_QueryInterface(aWebBrowserChrome));
00843 
00844       // it's ok for ownerWin or requestor to be null.
00845       mWebBrowserChrome = aWebBrowserChrome;
00846       mOwnerWin = ownerWin;
00847       mOwnerRequestor = requestor;
00848     }
00849   }
00850   return NS_OK;
00851 }
00852 
00853 
00854 //
00855 // AddChromeListeners
00856 //
00857 // Hook up things to the chrome like context menus and tooltips, if the chrome
00858 // has implemented the right interfaces.
00859 //
00860 NS_IMETHODIMP
00861 nsDocShellTreeOwner::AddChromeListeners()
00862 {
00863   nsresult rv = NS_OK;
00864 
00865   nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
00866   if (!webBrowserChrome)
00867     return NS_ERROR_FAILURE;
00868 
00869   // install tooltips
00870   if ( !mChromeTooltipListener ) { 
00871     nsCOMPtr<nsITooltipListener>
00872                            tooltipListener(do_QueryInterface(webBrowserChrome));
00873     if ( tooltipListener ) {
00874       mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser,
00875                                                          webBrowserChrome);
00876       if ( mChromeTooltipListener ) {
00877         NS_ADDREF(mChromeTooltipListener);
00878         rv = mChromeTooltipListener->AddChromeListeners();
00879       }
00880       else
00881         rv = NS_ERROR_OUT_OF_MEMORY;
00882     }
00883   }
00884   
00885   // install context menus
00886   if ( !mChromeContextMenuListener ) {
00887     nsCOMPtr<nsIContextMenuListener2>
00888                           contextListener2(do_QueryInterface(webBrowserChrome));
00889     nsCOMPtr<nsIContextMenuListener>
00890                            contextListener(do_QueryInterface(webBrowserChrome));
00891     if ( contextListener2 || contextListener ) {
00892       mChromeContextMenuListener =
00893                    new ChromeContextMenuListener(mWebBrowser, webBrowserChrome);
00894       if ( mChromeContextMenuListener ) {
00895         NS_ADDREF(mChromeContextMenuListener);
00896         rv = mChromeContextMenuListener->AddChromeListeners();
00897       }
00898       else
00899         rv = NS_ERROR_OUT_OF_MEMORY;
00900     }
00901   }
00902    
00903   // install the external dragDrop handler
00904   if ( !mChromeDragHandler ) {
00905     mChromeDragHandler = do_CreateInstance("@mozilla.org:/content/content-area-dragdrop;1", &rv);
00906     NS_ASSERTION(mChromeDragHandler, "Couldn't create the chrome drag handler");
00907     if ( mChromeDragHandler ) {
00908       nsCOMPtr<nsIDOMEventReceiver> rcvr;
00909       GetEventReceiver(mWebBrowser, getter_AddRefs(rcvr));
00910       nsCOMPtr<nsIDOMEventTarget> rcvrTarget(do_QueryInterface(rcvr));
00911       mChromeDragHandler->HookupTo(rcvrTarget, NS_STATIC_CAST(nsIWebNavigation*, mWebBrowser));
00912     }
00913   }
00914 
00915   return rv;
00916   
00917 } // AddChromeListeners
00918 
00919 
00920 NS_IMETHODIMP
00921 nsDocShellTreeOwner::RemoveChromeListeners()
00922 {
00923   if ( mChromeTooltipListener ) {
00924     mChromeTooltipListener->RemoveChromeListeners();
00925     NS_RELEASE(mChromeTooltipListener);
00926   }
00927   if ( mChromeContextMenuListener ) {
00928     mChromeContextMenuListener->RemoveChromeListeners();
00929     NS_RELEASE(mChromeContextMenuListener);
00930   }
00931   if ( mChromeDragHandler )
00932     mChromeDragHandler->Detach();
00933 
00934   return NS_OK;
00935 }
00936 
00937 already_AddRefed<nsIWebBrowserChrome>
00938 nsDocShellTreeOwner::GetWebBrowserChrome()
00939 {
00940   nsIWebBrowserChrome* chrome = nsnull;
00941   if (mWebBrowserChromeWeak != nsnull) {
00942     mWebBrowserChromeWeak->
00943                         QueryReferent(NS_GET_IID(nsIWebBrowserChrome),
00944                                       NS_REINTERPRET_CAST(void**, &chrome));
00945   } else if (mWebBrowserChrome) {
00946     chrome = mWebBrowserChrome;
00947     NS_ADDREF(mWebBrowserChrome);
00948   }
00949 
00950   return chrome;
00951 }
00952 
00953 already_AddRefed<nsIEmbeddingSiteWindow>
00954 nsDocShellTreeOwner::GetOwnerWin()
00955 {
00956   nsIEmbeddingSiteWindow* win = nsnull;
00957   if (mWebBrowserChromeWeak != nsnull) {
00958     mWebBrowserChromeWeak->
00959                         QueryReferent(NS_GET_IID(nsIEmbeddingSiteWindow),
00960                                       NS_REINTERPRET_CAST(void**, &win));
00961   } else if (mOwnerWin) {
00962     win = mOwnerWin;
00963     NS_ADDREF(mOwnerWin);
00964   }
00965 
00966   return win;
00967 }
00968 
00969 already_AddRefed<nsIInterfaceRequestor>
00970 nsDocShellTreeOwner::GetOwnerRequestor()
00971 {
00972   nsIInterfaceRequestor* req = nsnull;
00973   if (mWebBrowserChromeWeak != nsnull) {
00974     mWebBrowserChromeWeak->
00975                         QueryReferent(NS_GET_IID(nsIInterfaceRequestor),
00976                                       NS_REINTERPRET_CAST(void**, &req));
00977   } else if (mOwnerRequestor) {
00978     req = mOwnerRequestor;
00979     NS_ADDREF(mOwnerRequestor);
00980   }
00981 
00982   return req;
00983 }
00984 
00985 
00986 #ifdef XP_MAC
00987 #pragma mark -
00988 #endif
00989 
00990 
00992 // DefaultTooltipTextProvider
00993 
00994 class DefaultTooltipTextProvider : public nsITooltipTextProvider
00995 {
00996 public:
00997     DefaultTooltipTextProvider();
00998 
00999     NS_DECL_ISUPPORTS
01000     NS_DECL_NSITOOLTIPTEXTPROVIDER
01001     
01002 protected:
01003     nsCOMPtr<nsIAtom>   mTag_dialog;
01004     nsCOMPtr<nsIAtom>   mTag_dialogheader;
01005     nsCOMPtr<nsIAtom>   mTag_window;
01006 };
01007 
01008 NS_IMPL_THREADSAFE_ISUPPORTS1(DefaultTooltipTextProvider, nsITooltipTextProvider)
01009 
01010 DefaultTooltipTextProvider::DefaultTooltipTextProvider()
01011 {
01012     // There are certain element types which we don't want to use
01013     // as tool tip text. 
01014     mTag_dialog       = do_GetAtom("dialog");
01015     mTag_dialogheader = do_GetAtom("dialogheader");
01016     mTag_window       = do_GetAtom("window");   
01017 }
01018 
01019 /* void getNodeText (in nsIDOMNode aNode, out wstring aText); */
01020 NS_IMETHODIMP
01021 DefaultTooltipTextProvider::GetNodeText(nsIDOMNode *aNode, PRUnichar **aText,
01022                                         PRBool *_retval)
01023 {
01024   NS_ENSURE_ARG_POINTER(aNode);
01025   NS_ENSURE_ARG_POINTER(aText);
01026     
01027   nsString outText;
01028 
01029   PRBool found = PR_FALSE;
01030   nsCOMPtr<nsIDOMNode> current ( aNode );
01031   while ( !found && current ) {
01032     nsCOMPtr<nsIDOMElement> currElement ( do_QueryInterface(current) );
01033     if ( currElement ) {
01034       nsCOMPtr<nsIContent> content(do_QueryInterface(currElement));
01035       if (content) {
01036         nsIAtom *tagAtom = content->Tag();
01037         if (tagAtom != mTag_dialog &&
01038             tagAtom != mTag_dialogheader &&
01039             tagAtom != mTag_window) {
01040           // first try the normal title attribute...
01041           currElement->GetAttribute(NS_LITERAL_STRING("title"), outText);
01042           if ( outText.Length() )
01043             found = PR_TRUE;
01044           else {
01045             // ...ok, that didn't work, try it in the XLink namespace
01046             currElement->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"), NS_LITERAL_STRING("title"), outText);
01047             if ( outText.Length() )
01048               found = PR_TRUE;
01049           }
01050         }
01051       }
01052     }
01053     
01054     // not found here, walk up to the parent and keep trying
01055     if ( !found ) {
01056       nsCOMPtr<nsIDOMNode> temp ( current );
01057       temp->GetParentNode(getter_AddRefs(current));
01058     }
01059   } // while not found
01060 
01061   *_retval = found;
01062   *aText = (found) ? ToNewUnicode(outText) : nsnull;
01063 
01064   return NS_OK;
01065 }
01066 
01068 
01069 NS_IMPL_ADDREF(ChromeTooltipListener)
01070 NS_IMPL_RELEASE(ChromeTooltipListener)
01071 
01072 NS_INTERFACE_MAP_BEGIN(ChromeTooltipListener)
01073     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMouseListener)
01074     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMMouseListener)
01075     NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
01076     NS_INTERFACE_MAP_ENTRY(nsIDOMMouseMotionListener)
01077     NS_INTERFACE_MAP_ENTRY(nsIDOMKeyListener)
01078 NS_INTERFACE_MAP_END
01079 
01080 
01081 //
01082 // ChromeTooltipListener ctor
01083 //
01084 
01085 ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* inBrowser,
01086                                              nsIWebBrowserChrome* inChrome) 
01087   : mWebBrowser(inBrowser), mWebBrowserChrome(inChrome),
01088      mTooltipListenerInstalled(PR_FALSE),
01089      mMouseClientX(0), mMouseClientY(0),
01090      mShowingTooltip(PR_FALSE)
01091 {
01092   mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID);
01093   if (!mTooltipTextProvider) {
01094     nsISupports *pProvider = (nsISupports *) new DefaultTooltipTextProvider;
01095     mTooltipTextProvider = do_QueryInterface(pProvider);
01096   }
01097 } // ctor
01098 
01099 
01100 //
01101 // ChromeTooltipListener dtor
01102 //
01103 ChromeTooltipListener::~ChromeTooltipListener()
01104 {
01105 
01106 } // dtor
01107 
01108 
01109 //
01110 // AddChromeListeners
01111 //
01112 // Hook up things to the chrome like context menus and tooltips, if the chrome
01113 // has implemented the right interfaces.
01114 //
01115 NS_IMETHODIMP
01116 ChromeTooltipListener::AddChromeListeners()
01117 {  
01118   if ( !mEventReceiver )
01119     GetEventReceiver(mWebBrowser, getter_AddRefs(mEventReceiver));
01120   
01121   // Register the appropriate events for tooltips, but only if
01122   // the embedding chrome cares.
01123   nsresult rv = NS_OK;
01124   nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
01125   if ( tooltipListener && !mTooltipListenerInstalled ) {
01126     rv = AddTooltipListener();
01127     if ( NS_FAILED(rv) )
01128       return rv;
01129   }
01130   
01131   return rv;
01132   
01133 } // AddChromeListeners
01134 
01135 
01136 //
01137 // AddTooltipListener
01138 //
01139 // Subscribe to the events that will allow us to track tooltips. We need "mouse" for mouseExit,
01140 // "mouse motion" for mouseMove, and "key" for keyDown. As we add the listeners, keep track
01141 // of how many succeed so we can clean up correctly in Release().
01142 //
01143 NS_IMETHODIMP
01144 ChromeTooltipListener::AddTooltipListener()
01145 {
01146   if (mEventReceiver) {
01147     nsIDOMMouseListener *pListener = NS_STATIC_CAST(nsIDOMMouseListener *, this);
01148     nsresult rv = mEventReceiver->AddEventListenerByIID(pListener, NS_GET_IID(nsIDOMMouseListener));
01149     nsresult rv2 = mEventReceiver->AddEventListenerByIID(pListener, NS_GET_IID(nsIDOMMouseMotionListener));
01150     nsresult rv3 = mEventReceiver->AddEventListenerByIID(pListener, NS_GET_IID(nsIDOMKeyListener));
01151     
01152     // if all 3 succeed, we're a go!
01153     if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2) && NS_SUCCEEDED(rv3)) 
01154       mTooltipListenerInstalled = PR_TRUE;
01155   }
01156 
01157   return NS_OK;
01158 }
01159 
01160 
01161 //
01162 // RemoveChromeListeners
01163 //
01164 // Unsubscribe from the various things we've hooked up to the window root.
01165 //
01166 NS_IMETHODIMP
01167 ChromeTooltipListener::RemoveChromeListeners ( )
01168 {
01169   HideTooltip();
01170 
01171   if ( mTooltipListenerInstalled )
01172     RemoveTooltipListener();
01173   
01174   mEventReceiver = nsnull;
01175   
01176   // it really doesn't matter if these fail...
01177   return NS_OK;
01178   
01179 } // RemoveChromeTooltipListeners
01180 
01181 
01182 
01183 //
01184 // RemoveTooltipListener
01185 //
01186 // Unsubscribe from all the various tooltip events that we were listening to
01187 //
01188 NS_IMETHODIMP 
01189 ChromeTooltipListener::RemoveTooltipListener()
01190 {
01191   if (mEventReceiver) {
01192     nsIDOMMouseListener *pListener = NS_STATIC_CAST(nsIDOMMouseListener *, this);
01193     nsresult rv = mEventReceiver->RemoveEventListenerByIID(pListener, NS_GET_IID(nsIDOMMouseListener));
01194     nsresult rv2 = mEventReceiver->RemoveEventListenerByIID(pListener, NS_GET_IID(nsIDOMMouseMotionListener));
01195     nsresult rv3 = mEventReceiver->RemoveEventListenerByIID(pListener, NS_GET_IID(nsIDOMKeyListener));
01196     if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2) && NS_SUCCEEDED(rv3))
01197       mTooltipListenerInstalled = PR_FALSE;
01198   }
01199 
01200   return NS_OK;
01201 }
01202 
01203 
01204 //
01205 // KeyDown
01206 //
01207 // When the user starts typing, they generaly don't want to see any messy wax
01208 // builup. Hide the tooltip.
01209 //
01210 nsresult
01211 ChromeTooltipListener::KeyDown(nsIDOMEvent* aMouseEvent)
01212 {
01213   return HideTooltip();
01214 } // KeyDown
01215 
01216 
01217 //
01218 // KeyUp
01219 // KeyPress
01220 //
01221 // We can ignore these as they are already handled by KeyDown
01222 //
01223 nsresult
01224 ChromeTooltipListener::KeyUp(nsIDOMEvent* aMouseEvent)
01225 {
01226   return NS_OK;
01227     
01228 } // KeyUp
01229 
01230 nsresult
01231 ChromeTooltipListener::KeyPress(nsIDOMEvent* aMouseEvent)
01232 {
01233   return NS_OK;
01234     
01235 } // KeyPress
01236 
01237 
01238 //
01239 // MouseDown
01240 //
01241 // On a click, hide the tooltip
01242 //
01243 nsresult 
01244 ChromeTooltipListener::MouseDown(nsIDOMEvent* aMouseEvent)
01245 {
01246   return HideTooltip();
01247 
01248 } // MouseDown
01249 
01250 
01251 nsresult 
01252 ChromeTooltipListener::MouseUp(nsIDOMEvent* aMouseEvent)
01253 {
01254     return NS_OK; 
01255 }
01256 
01257 nsresult 
01258 ChromeTooltipListener::MouseClick(nsIDOMEvent* aMouseEvent)
01259 {
01260     return NS_OK; 
01261 }
01262 
01263 nsresult 
01264 ChromeTooltipListener::MouseDblClick(nsIDOMEvent* aMouseEvent)
01265 {
01266     return NS_OK; 
01267 }
01268 
01269 nsresult 
01270 ChromeTooltipListener::MouseOver(nsIDOMEvent* aMouseEvent)
01271 {
01272     return NS_OK; 
01273 }
01274 
01275 
01276 //
01277 // MouseOut
01278 //
01279 // If we're responding to tooltips, hide the tip whenever the mouse leaves
01280 // the area it was in.
01281 nsresult 
01282 ChromeTooltipListener::MouseOut(nsIDOMEvent* aMouseEvent)
01283 {
01284   return HideTooltip();
01285 }
01286 
01287 
01288 //
01289 // MouseMove
01290 //
01291 // If we're a tooltip, fire off a timer to see if a tooltip should be shown. If the
01292 // timer fires, we cache the node in |mPossibleTooltipNode|.
01293 //
01294 nsresult
01295 ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent)
01296 {
01297   nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
01298   if (!mouseEvent)
01299     return NS_OK;
01300 
01301   // stash the coordinates of the event so that we can still get back to it from within the 
01302   // timer callback. On win32, we'll get a MouseMove event even when a popup goes away --
01303   // even when the mouse doesn't change position! To get around this, we make sure the
01304   // mouse has really moved before proceeding.
01305   PRInt32 newMouseX, newMouseY;
01306   mouseEvent->GetClientX(&newMouseX);
01307   mouseEvent->GetClientY(&newMouseY);
01308   if ( mMouseClientX == newMouseX && mMouseClientY == newMouseY )
01309     return NS_OK;
01310   mMouseClientX = newMouseX; mMouseClientY = newMouseY;
01311   mouseEvent->GetScreenX(&mMouseScreenX);
01312   mouseEvent->GetScreenY(&mMouseScreenY);
01313 
01314   // We want to close the tip if it is being displayed and the mouse moves. Recall 
01315   // that |mShowingTooltip| is set when the popup is showing. Furthermore, as the mouse
01316   // moves, we want to make sure we reset the timer to show it, so that the delay
01317   // is from when the mouse stops moving, not when it enters the element.
01318   if ( mShowingTooltip )
01319     return HideTooltip();
01320   if ( mTooltipTimer )
01321     mTooltipTimer->Cancel();
01322 
01323   mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1");
01324   if ( mTooltipTimer ) {
01325     nsCOMPtr<nsIDOMEventTarget> eventTarget;
01326     aMouseEvent->GetTarget(getter_AddRefs(eventTarget));
01327     if ( eventTarget )
01328       mPossibleTooltipNode = do_QueryInterface(eventTarget);
01329     if ( mPossibleTooltipNode ) {
01330       nsresult rv = mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this, kTooltipShowTime, 
01331                                                         nsITimer::TYPE_ONE_SHOT);
01332       if (NS_FAILED(rv))
01333         mPossibleTooltipNode = nsnull;
01334     }
01335   }
01336   else
01337     NS_WARNING ( "Could not create a timer for tooltip tracking" );
01338     
01339   return NS_OK;
01340   
01341 } // MouseMove
01342 
01343 
01344 //
01345 // ShowTooltip
01346 //
01347 // Tell the registered chrome that they should show the tooltip
01348 //
01349 NS_IMETHODIMP
01350 ChromeTooltipListener::ShowTooltip(PRInt32 inXCoords, PRInt32 inYCoords,
01351                                    const nsAString & inTipText)
01352 {
01353   nsresult rv = NS_OK;
01354   
01355   // do the work to call the client
01356   nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
01357   if ( tooltipListener ) {
01358     rv = tooltipListener->OnShowTooltip ( inXCoords, inYCoords, PromiseFlatString(inTipText).get() ); 
01359     if ( NS_SUCCEEDED(rv) )
01360       mShowingTooltip = PR_TRUE;
01361   }
01362 
01363   return rv;
01364   
01365 } // ShowTooltip
01366 
01367 
01368 //
01369 // HideTooltip
01370 //
01371 // Tell the registered chrome that they should rollup the tooltip
01372 // NOTE: This routine is safe to call even if the popup is already closed.
01373 //
01374 NS_IMETHODIMP
01375 ChromeTooltipListener::HideTooltip()
01376 {
01377   nsresult rv = NS_OK;
01378   
01379   // shut down the relevant timers
01380   if ( mTooltipTimer ) {
01381     mTooltipTimer->Cancel();
01382     mTooltipTimer = nsnull;
01383     // release tooltip target
01384     mPossibleTooltipNode = nsnull;
01385   }
01386   if ( mAutoHideTimer ) {
01387     mAutoHideTimer->Cancel();
01388     mAutoHideTimer = nsnull;
01389   }
01390 
01391   // if we're showing the tip, tell the chrome to hide it
01392   if ( mShowingTooltip ) {
01393     nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
01394     if ( tooltipListener ) {
01395       rv = tooltipListener->OnHideTooltip ( );
01396       if ( NS_SUCCEEDED(rv) )
01397         mShowingTooltip = PR_FALSE;
01398     }
01399   }
01400 
01401   return rv;
01402   
01403 } // HideTooltip
01404 
01405 
01406 //
01407 // sTooltipCallback
01408 //
01409 // A timer callback, fired when the mouse has hovered inside of a frame for the 
01410 // appropriate amount of time. Getting to this point means that we should show the
01411 // tooltip, but only after we determine there is an appropriate TITLE element.
01412 //
01413 // This relies on certain things being cached into the |aChromeTooltipListener| object passed to
01414 // us by the timer:
01415 //   -- the x/y coordinates of the mouse      (mMouseClientY, mMouseClientX)
01416 //   -- the dom node the user hovered over    (mPossibleTooltipNode)
01417 //
01418 void
01419 ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer,
01420                                         void *aChromeTooltipListener)
01421 {
01422   ChromeTooltipListener* self = NS_STATIC_CAST(ChromeTooltipListener*,
01423                                                aChromeTooltipListener);
01424   if ( self && self->mPossibleTooltipNode ){
01425     // The actual coordinates we want to put the tooltip at are relative to the
01426     // toplevel docshell of our mWebBrowser.  We know what the screen
01427     // coordinates of the mouse event were, which means we just need the screen
01428     // coordinates of the docshell.  Unfortunately, there is no good way to
01429     // find those short of groveling for the presentation in that docshell and
01430     // finding the screen coords of its toplevel widget...
01431     nsCOMPtr<nsIDocShell> docShell =
01432       do_GetInterface(NS_STATIC_CAST(nsIWebBrowser*, self->mWebBrowser));
01433     nsCOMPtr<nsIPresShell> shell;
01434     if (docShell) {
01435       docShell->GetPresShell(getter_AddRefs(shell));
01436     }
01437 
01438     nsIWidget* widget = nsnull;
01439     if (shell) {
01440       nsIViewManager* vm = shell->GetViewManager();
01441       if (vm) {
01442         nsIView* view;
01443         vm->GetRootView(view);
01444         if (view) {
01445           nsPoint offset;
01446           widget = view->GetNearestWidget(&offset);
01447         }
01448       }
01449     }
01450 
01451     if (!widget) {
01452       // release tooltip target if there is one, NO MATTER WHAT
01453       self->mPossibleTooltipNode = nsnull;
01454       return;
01455     }
01456 
01457     // if there is text associated with the node, show the tip and fire
01458     // off a timer to auto-hide it.
01459 
01460     nsXPIDLString tooltipText;
01461     if (self->mTooltipTextProvider) {
01462       PRBool textFound = PR_FALSE;
01463 
01464       self->mTooltipTextProvider->GetNodeText(
01465           self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound);
01466       
01467       if (textFound) {
01468         nsString tipText(tooltipText);
01469         self->CreateAutoHideTimer();
01470         nsRect widgetDot(0, 0, 1, 1);
01471         nsRect screenDot;
01472         widget->WidgetToScreen(widgetDot, screenDot);
01473         self->ShowTooltip (self->mMouseScreenX - screenDot.x,
01474                            self->mMouseScreenY - screenDot.y,
01475                            tipText);
01476       }
01477     }
01478     
01479     // release tooltip target if there is one, NO MATTER WHAT
01480     self->mPossibleTooltipNode = nsnull;
01481   } // if "self" data valid
01482   
01483 } // sTooltipCallback
01484 
01485 
01486 //
01487 // CreateAutoHideTimer
01488 //
01489 // Create a new timer to see if we should auto-hide. It's ok if this fails.
01490 //
01491 void
01492 ChromeTooltipListener::CreateAutoHideTimer()
01493 {
01494   // just to be anal (er, safe)
01495   if ( mAutoHideTimer ) {
01496     mAutoHideTimer->Cancel();
01497     mAutoHideTimer = nsnull;
01498   }
01499   
01500   mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1");
01501   if ( mAutoHideTimer )
01502     mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime, 
01503                                          nsITimer::TYPE_ONE_SHOT);
01504 
01505 } // CreateAutoHideTimer
01506 
01507 
01508 //
01509 // sAutoHideCallback
01510 //
01511 // This fires after a tooltip has been open for a certain length of time. Just tell
01512 // the listener to close the popup. We don't have to worry, because HideTooltip() can
01513 // be called multiple times, even if the tip has already been closed.
01514 //
01515 void
01516 ChromeTooltipListener::sAutoHideCallback(nsITimer *aTimer, void* aListener)
01517 {
01518   ChromeTooltipListener* self = NS_STATIC_CAST(ChromeTooltipListener*, aListener);
01519   if ( self )
01520     self->HideTooltip();
01521 
01522   // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
01523   
01524 } // sAutoHideCallback
01525 
01526 
01527 
01528 #ifdef XP_MAC
01529 #pragma mark -
01530 #endif
01531 
01532 
01533 NS_IMPL_ADDREF(ChromeContextMenuListener)
01534 NS_IMPL_RELEASE(ChromeContextMenuListener)
01535 
01536 NS_INTERFACE_MAP_BEGIN(ChromeContextMenuListener)
01537     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMContextMenuListener)
01538     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMContextMenuListener)
01539     NS_INTERFACE_MAP_ENTRY(nsIDOMContextMenuListener)
01540 NS_INTERFACE_MAP_END
01541 
01542 
01543 //
01544 // ChromeTooltipListener ctor
01545 //
01546 ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) 
01547   : mContextMenuListenerInstalled(PR_FALSE),
01548     mWebBrowser(inBrowser),
01549     mWebBrowserChrome(inChrome)
01550 {
01551 } // ctor
01552 
01553 
01554 //
01555 // ChromeTooltipListener dtor
01556 //
01557 ChromeContextMenuListener::~ChromeContextMenuListener()
01558 {
01559 } // dtor
01560 
01561 
01562 //
01563 // AddContextMenuListener
01564 //
01565 // Subscribe to the events that will allow us to track context menus. Bascially, this
01566 // is just the context-menu DOM event.
01567 //
01568 NS_IMETHODIMP
01569 ChromeContextMenuListener::AddContextMenuListener()
01570 {
01571   if (mEventReceiver) {
01572     nsIDOMContextMenuListener *pListener = NS_STATIC_CAST(nsIDOMContextMenuListener *, this);
01573     nsresult rv = mEventReceiver->AddEventListenerByIID(pListener, NS_GET_IID(nsIDOMContextMenuListener));
01574     if (NS_SUCCEEDED(rv))
01575       mContextMenuListenerInstalled = PR_TRUE;
01576   }
01577 
01578   return NS_OK;
01579 }
01580 
01581 
01582 //
01583 // RemoveContextMenuListener
01584 //
01585 // Unsubscribe from all the various context menu events that we were listening to. 
01586 //
01587 NS_IMETHODIMP 
01588 ChromeContextMenuListener::RemoveContextMenuListener()
01589 {
01590   if (mEventReceiver) {
01591     nsIDOMContextMenuListener *pListener = NS_STATIC_CAST(nsIDOMContextMenuListener *, this);
01592     nsresult rv = mEventReceiver->RemoveEventListenerByIID(pListener, NS_GET_IID(nsIDOMContextMenuListener));
01593     if (NS_SUCCEEDED(rv))
01594       mContextMenuListenerInstalled = PR_FALSE;
01595   }
01596 
01597   return NS_OK;
01598 }
01599 
01600 
01601 //
01602 // AddChromeListeners
01603 //
01604 // Hook up things to the chrome like context menus and tooltips, if the chrome
01605 // has implemented the right interfaces.
01606 //
01607 NS_IMETHODIMP
01608 ChromeContextMenuListener::AddChromeListeners()
01609 {  
01610   if ( !mEventReceiver )
01611     GetEventReceiver(mWebBrowser, getter_AddRefs(mEventReceiver));
01612   
01613   // Register the appropriate events for context menus, but only if
01614   // the embedding chrome cares.
01615   nsresult rv = NS_OK;
01616 
01617   nsCOMPtr<nsIContextMenuListener2> contextListener2 ( do_QueryInterface(mWebBrowserChrome) );
01618   nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) );
01619   if ( (contextListener || contextListener2) && !mContextMenuListenerInstalled )
01620     rv = AddContextMenuListener();
01621 
01622   return rv;
01623   
01624 } // AddChromeListeners
01625 
01626 
01627 //
01628 // RemoveChromeListeners
01629 //
01630 // Unsubscribe from the various things we've hooked up to the window root.
01631 //
01632 NS_IMETHODIMP
01633 ChromeContextMenuListener::RemoveChromeListeners()
01634 {
01635   if ( mContextMenuListenerInstalled )
01636     RemoveContextMenuListener();
01637   
01638   mEventReceiver = nsnull;
01639   
01640   // it really doesn't matter if these fail...
01641   return NS_OK;
01642   
01643 } // RemoveChromeTooltipListeners
01644 
01645 
01646 
01647 //
01648 // ContextMenu
01649 //
01650 // We're on call to show the context menu. Dig around in the DOM to
01651 // find the type of object we're dealing with and notify the front
01652 // end chrome.
01653 //
01654 NS_IMETHODIMP
01655 ChromeContextMenuListener::ContextMenu(nsIDOMEvent* aMouseEvent)
01656 {     
01657   nsCOMPtr<nsIDOMNSUIEvent> uievent(do_QueryInterface(aMouseEvent));
01658 
01659   if (uievent) {
01660     PRBool isDefaultPrevented = PR_FALSE;
01661     uievent->GetPreventDefault(&isDefaultPrevented);
01662 
01663     if (isDefaultPrevented) {
01664       return NS_OK;
01665     }
01666   }
01667 
01668   nsCOMPtr<nsIDOMEventTarget> targetNode;
01669   nsresult res = aMouseEvent->GetTarget(getter_AddRefs(targetNode));
01670   if (NS_FAILED(res))
01671     return res;
01672   if (!targetNode)
01673     return NS_ERROR_NULL_POINTER;
01674 
01675   nsCOMPtr<nsIDOMNode> targetDOMnode;
01676   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(targetNode);
01677   if (!node)
01678     return NS_OK;
01679 
01680   // Stop the context menu event going to other windows (bug 78396)
01681   aMouseEvent->PreventDefault();
01682   
01683   // If the listener is a nsIContextMenuListener2, create the info object
01684   nsCOMPtr<nsIContextMenuListener2> menuListener2(do_QueryInterface(mWebBrowserChrome));
01685   nsContextMenuInfo *menuInfoImpl = nsnull;
01686   nsCOMPtr<nsIContextMenuInfo> menuInfo;
01687   if (menuListener2) {
01688     menuInfoImpl = new nsContextMenuInfo;
01689     if (!menuInfoImpl)
01690       return NS_ERROR_OUT_OF_MEMORY;
01691     menuInfo = menuInfoImpl; 
01692   }
01693 
01694   // Find the first node to be an element starting with this node and
01695   // working up through its parents.
01696 
01697   PRUint32 flags = nsIContextMenuListener::CONTEXT_NONE;
01698   PRUint32 flags2 = nsIContextMenuListener2::CONTEXT_NONE;
01699   nsCOMPtr<nsIContent> content;
01700   do {
01701     // XXX test for selected text
01702     content = do_QueryInterface(node);
01703     if (content && content->IsContentOfType(nsIContent::eHTML)) {
01704       const char *tagStr;
01705       content->Tag()->GetUTF8String(&tagStr);
01706 
01707       // Test what kind of element we're dealing with here
01708       if (strcmp(tagStr, "img") == 0)
01709       {
01710         flags |= nsIContextMenuListener::CONTEXT_IMAGE;
01711         flags2 |= nsIContextMenuListener2::CONTEXT_IMAGE;
01712         targetDOMnode = node;
01713         // if we see an image, keep searching for a possible anchor
01714       }
01715       else if (strcmp(tagStr, "input") == 0)
01716       {
01717         // INPUT element - button, combo, checkbox, text etc.
01718         flags |= nsIContextMenuListener::CONTEXT_INPUT;
01719         flags2 |= nsIContextMenuListener2::CONTEXT_INPUT;
01720         targetDOMnode = node;
01721         
01722         // See if the input type is an image
01723         if (menuListener2) {
01724           nsCOMPtr<nsIDOMHTMLInputElement> inputElement(do_QueryInterface(node));
01725           if (inputElement) {
01726             nsAutoString inputElemType;
01727             inputElement->GetType(inputElemType);
01728             if (inputElemType.LowerCaseEqualsLiteral("image"))
01729               flags2 |= nsIContextMenuListener2::CONTEXT_IMAGE;
01730           }
01731         }
01732         break; // exit do-while
01733       }
01734       else if (strcmp(tagStr, "textarea") == 0)
01735       {
01736         // text area
01737         flags |= nsIContextMenuListener::CONTEXT_TEXT;
01738         flags2 |= nsIContextMenuListener2::CONTEXT_TEXT;
01739         targetDOMnode = node;
01740         break; // exit do-while
01741       }
01742       else if (strcmp(tagStr, "html") == 0)
01743       {
01744         if (!flags && !flags2) { 
01745         // only care about this if no other context was found.
01746             flags |= nsIContextMenuListener::CONTEXT_DOCUMENT;
01747             flags2 |= nsIContextMenuListener2::CONTEXT_DOCUMENT;
01748             targetDOMnode = node;
01749         }
01750         if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE)) {
01751           // first check if this is a background image that the user was trying to click on
01752           // and if the listener is ready for that (only nsIContextMenuListener2 and up)
01753           if (menuInfoImpl && menuInfoImpl->HasBackgroundImage(node)) {
01754             flags2 |= nsIContextMenuListener2::CONTEXT_BACKGROUND_IMAGE;
01755           }
01756         }
01757         break; // exit do-while
01758       }
01759       else if (strcmp(tagStr, "object") == 0 ||  /* XXX what about images and documents? */
01760                strcmp(tagStr, "embed") == 0 ||
01761                strcmp(tagStr, "applet") == 0)
01762       {                // always consume events for plugins and Java 
01763         return NS_OK;  // who may throw their own context menus
01764       }
01765 
01766       // Test if the element has an associated link
01767       nsCOMPtr<nsIDOMElement> element(do_QueryInterface(node));
01768 
01769       PRBool hasAttr = PR_FALSE;
01770       res = element->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr);
01771 
01772       if (NS_SUCCEEDED(res) && hasAttr)
01773       {
01774         flags |= nsIContextMenuListener::CONTEXT_LINK;
01775         flags2 |= nsIContextMenuListener2::CONTEXT_LINK;
01776         if (!targetDOMnode)
01777           targetDOMnode = node;
01778         if (menuInfoImpl)
01779           menuInfoImpl->SetAssociatedLink(node);
01780         break; // exit do-while
01781       }
01782     }
01783 
01784     // walk-up-the-tree
01785     nsCOMPtr<nsIDOMNode> parentNode;
01786     node->GetParentNode(getter_AddRefs(parentNode));
01787     node = parentNode;
01788   } while (node);
01789 
01790   // we need to cache the event target into the focus controller's popupNode
01791   // so we can get at it later from command code, etc.:
01792 
01793   // get the dom window
01794   nsCOMPtr<nsIDOMWindow> win;
01795   res = mWebBrowser->GetContentDOMWindow(getter_AddRefs(win));
01796   NS_ENSURE_SUCCESS(res, res);
01797   NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
01798   // get the private dom window
01799   nsCOMPtr<nsPIDOMWindow> privateWin(do_QueryInterface(win, &res));
01800   NS_ENSURE_SUCCESS(res, res);
01801   NS_ENSURE_TRUE(privateWin, NS_ERROR_FAILURE);
01802   // get the focus controller
01803   nsIFocusController *focusController = privateWin->GetRootFocusController();
01804   NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
01805   // set the focus controller's popup node to the event target
01806   res = focusController->SetPopupNode(targetDOMnode);
01807   NS_ENSURE_SUCCESS(res, res);
01808 
01809   // Tell the listener all about the event
01810   if ( menuListener2 ) {
01811     menuInfoImpl->SetMouseEvent(aMouseEvent);
01812     menuInfoImpl->SetDOMNode(targetDOMnode);
01813     menuListener2->OnShowContextMenu(flags2, menuInfo);
01814   }
01815   else {
01816     nsCOMPtr<nsIContextMenuListener> menuListener(do_QueryInterface(mWebBrowserChrome));
01817     if ( menuListener )
01818       menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode);
01819   }
01820 
01821   return NS_OK;
01822 
01823 } // MouseDown