switching mac to use NS_CONTEXTMENU event, click-hold context menus, switching embedding to use NS_CONTEXTMENU event. r=saari/sr=hyatt. bug# 36665, 18726

git-svn-id: svn://10.0.0.236/trunk@90828 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
pinkerton%netscape.com
2001-03-30 04:45:40 +00:00
parent 33374aacdf
commit ccfecb4d51
6 changed files with 702 additions and 301 deletions

View File

@@ -69,17 +69,15 @@ nsDocShellTreeOwner::nsDocShellTreeOwner() :
mWebBrowserChrome(nsnull),
mOwnerWin(nsnull),
mOwnerRequestor(nsnull),
mChromeListener(nsnull)
mChromeTooltipListener(nsnull),
mChromeContextMenuListener(nsnull)
{
NS_INIT_REFCNT();
}
nsDocShellTreeOwner::~nsDocShellTreeOwner()
{
if ( mChromeListener ) {
mChromeListener->RemoveChromeListeners();
NS_RELEASE(mChromeListener);
}
RemoveChromeListeners();
}
//*****************************************************************************
@@ -651,12 +649,9 @@ nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress *aWebProgress,
void nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser)
{
if ( !aWebBrowser ) {
if ( mChromeListener ) {
mChromeListener->RemoveChromeListeners();
NS_RELEASE(mChromeListener);
}
}
if ( !aWebBrowser )
RemoveChromeListeners();
mWebBrowser = aWebBrowser;
}
@@ -715,14 +710,28 @@ nsDocShellTreeOwner :: AddChromeListeners ( )
{
nsresult rv = NS_OK;
if ( !mChromeListener ) {
nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) );
// install tooltips
if ( !mChromeTooltipListener ) {
nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
if ( contextListener || tooltipListener ) {
mChromeListener = new ChromeListener ( mWebBrowser, mWebBrowserChrome );
if ( mChromeListener ) {
NS_ADDREF(mChromeListener);
rv = mChromeListener->AddChromeListeners();
if ( tooltipListener ) {
mChromeTooltipListener = new ChromeTooltipListener ( mWebBrowser, mWebBrowserChrome );
if ( mChromeTooltipListener ) {
NS_ADDREF(mChromeTooltipListener);
rv = mChromeTooltipListener->AddChromeListeners();
}
else
rv = NS_ERROR_OUT_OF_MEMORY;
}
}
// install context menus
if ( !mChromeContextMenuListener ) {
nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) );
if ( contextListener ) {
mChromeContextMenuListener = new ChromeContextMenuListener ( mWebBrowser, mWebBrowserChrome );
if ( mChromeContextMenuListener ) {
NS_ADDREF(mChromeContextMenuListener);
rv = mChromeContextMenuListener->AddChromeListeners();
}
else
rv = NS_ERROR_OUT_OF_MEMORY;
@@ -734,15 +743,31 @@ nsDocShellTreeOwner :: AddChromeListeners ( )
} // AddChromeListeners
NS_IMETHODIMP
nsDocShellTreeOwner :: RemoveChromeListeners ( )
{
if ( mChromeTooltipListener ) {
mChromeTooltipListener->RemoveChromeListeners();
NS_RELEASE(mChromeTooltipListener);
}
if ( mChromeContextMenuListener ) {
mChromeContextMenuListener->RemoveChromeListeners();
NS_RELEASE(mChromeContextMenuListener);
}
return NS_OK;
}
#ifdef XP_MAC
#pragma mark -
#endif
NS_IMPL_ADDREF(ChromeListener)
NS_IMPL_RELEASE(ChromeListener)
NS_IMPL_ADDREF(ChromeTooltipListener)
NS_IMPL_RELEASE(ChromeTooltipListener)
NS_INTERFACE_MAP_BEGIN(ChromeListener)
NS_INTERFACE_MAP_BEGIN(ChromeTooltipListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMouseListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMMouseListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
@@ -752,23 +777,23 @@ NS_INTERFACE_MAP_END
//
// ChromeListener ctor
// ChromeTooltipListener ctor
//
ChromeListener :: ChromeListener ( nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome )
ChromeTooltipListener :: ChromeTooltipListener ( nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome )
: mWebBrowser(inBrowser), mWebBrowserChrome(inChrome),
mContextMenuListenerInstalled(PR_FALSE), mTooltipListenerInstalled(PR_FALSE),
mTooltipListenerInstalled(PR_FALSE),
mShowingTooltip(PR_FALSE), mMouseClientX(0), mMouseClientY(0)
{
NS_INIT_REFCNT();
NS_INIT_REFCNT();
} // ctor
//
// ChromeListener dtor
// ChromeTooltipListener dtor
//
ChromeListener :: ~ChromeListener ( )
ChromeTooltipListener :: ~ChromeTooltipListener ( )
{
} // dtor
@@ -779,7 +804,7 @@ ChromeListener :: ~ChromeListener ( )
// has implemented the right interfaces.
//
NS_IMETHODIMP
ChromeListener :: AddChromeListeners ( )
ChromeTooltipListener :: AddChromeListeners ( )
{
if ( !mEventReceiver ) {
nsCOMPtr<nsIDOMWindow> domWindow;
@@ -799,18 +824,9 @@ ChromeListener :: AddChromeListeners ( )
mEventReceiver = do_QueryInterface(chromeHandler);
}
// Register the appropriate events for context menus, but only if
// the embedding chrome cares.
nsresult rv = NS_OK;
nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) );
if ( contextListener && !mContextMenuListenerInstalled ) {
rv = AddContextMenuListener();
if ( NS_FAILED(rv) )
return rv;
}
// Register the appropriate events for tooltips, but only if
// the embedding chrome cares.
nsresult rv = NS_OK;
nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
if ( tooltipListener && !mTooltipListenerInstalled ) {
rv = AddTooltipListener();
@@ -823,26 +839,6 @@ ChromeListener :: AddChromeListeners ( )
} // AddChromeListeners
//
// AddContextMenuListener
//
// Subscribe to the events that will allow us to track context menus. Bascially, this
// is just the mouseDown event.
//
NS_IMETHODIMP
ChromeListener :: AddContextMenuListener()
{
if (mEventReceiver) {
nsIDOMMouseListener *pListener = NS_STATIC_CAST(nsIDOMMouseListener *, this);
nsresult rv = mEventReceiver->AddEventListenerByIID(pListener, NS_GET_IID(nsIDOMMouseListener));
if (NS_SUCCEEDED(rv))
mContextMenuListenerInstalled = PR_TRUE;
}
return NS_OK;
}
//
// AddTooltipListener
//
@@ -851,7 +847,7 @@ ChromeListener :: AddContextMenuListener()
// of how many succeed so we can clean up correctly in Release().
//
NS_IMETHODIMP
ChromeListener :: AddTooltipListener()
ChromeTooltipListener :: AddTooltipListener()
{
if (mEventReceiver) {
nsIDOMMouseListener *pListener = NS_STATIC_CAST(nsIDOMMouseListener *, this);
@@ -871,17 +867,13 @@ ChromeListener :: AddTooltipListener()
//
// RemoveChromeListeners
//
// Unsubscribe from the various things we've hooked up to the window root, including
// context menus and tooltips for starters.
// Unsubscribe from the various things we've hooked up to the window root.
//
NS_IMETHODIMP
ChromeListener :: RemoveChromeListeners ( )
ChromeTooltipListener :: RemoveChromeListeners ( )
{
HideTooltip();
if ( mContextMenuListenerInstalled )
RemoveContextMenuListener();
if ( mTooltipListenerInstalled )
RemoveTooltipListener();
@@ -890,28 +882,9 @@ ChromeListener :: RemoveChromeListeners ( )
// it really doesn't matter if these fail...
return NS_OK;
} // RemoveChromeListeners
} // RemoveChromeTooltipListeners
//
// RemoveContextMenuListener
//
// Unsubscribe from all the various context menu events that we were listening to.
// Bascially, this is just the mouseDown event.
//
NS_IMETHODIMP
ChromeListener :: RemoveContextMenuListener()
{
if (mEventReceiver) {
nsIDOMMouseListener *pListener = NS_STATIC_CAST(nsIDOMMouseListener *, this);
nsresult rv = mEventReceiver->RemoveEventListenerByIID(pListener, NS_GET_IID(nsIDOMMouseListener));
if (NS_SUCCEEDED(rv))
mContextMenuListenerInstalled = PR_FALSE;
}
return NS_OK;
}
//
// RemoveTooltipListener
@@ -919,7 +892,7 @@ ChromeListener :: RemoveContextMenuListener()
// Unsubscribe from all the various tooltip events that we were listening to
//
NS_IMETHODIMP
ChromeListener :: RemoveTooltipListener()
ChromeTooltipListener :: RemoveTooltipListener()
{
if (mEventReceiver) {
nsIDOMMouseListener *pListener = NS_STATIC_CAST(nsIDOMMouseListener *, this);
@@ -941,12 +914,8 @@ ChromeListener :: RemoveTooltipListener()
// builup. Hide the tooltip.
//
nsresult
ChromeListener::KeyDown(nsIDOMEvent* aMouseEvent)
ChromeTooltipListener::KeyDown(nsIDOMEvent* aMouseEvent)
{
// make sure we're a tooltip. if not, bail. Just to be safe.
if ( ! mTooltipListenerInstalled )
return NS_OK;
return HideTooltip();
} // KeyDown
@@ -959,14 +928,14 @@ ChromeListener::KeyDown(nsIDOMEvent* aMouseEvent)
// We can ignore these as they are already handled by KeyDown
//
nsresult
ChromeListener::KeyUp(nsIDOMEvent* aMouseEvent)
ChromeTooltipListener::KeyUp(nsIDOMEvent* aMouseEvent)
{
return NS_OK;
} // KeyUp
nsresult
ChromeListener::KeyPress(nsIDOMEvent* aMouseEvent)
ChromeTooltipListener::KeyPress(nsIDOMEvent* aMouseEvent)
{
return NS_OK;
@@ -976,141 +945,36 @@ ChromeListener::KeyPress(nsIDOMEvent* aMouseEvent)
//
// MouseDown
//
// Do the processing for context menus, if this is a right-mouse click
// On a click, hide the tooltip
//
nsresult
ChromeListener::MouseDown(nsIDOMEvent* aMouseEvent)
ChromeTooltipListener::MouseDown(nsIDOMEvent* aMouseEvent)
{
nsCOMPtr<nsIDOMMouseEvent> mouseEvent (do_QueryInterface(aMouseEvent));
if (!mouseEvent)
return NS_OK;
// if the mouse goes down for any reason when a tooltip is showing,
// we want to hide it, but continue processing the event.
if ( mShowingTooltip )
HideTooltip();
// Test for right mouse button click
PRUint16 buttonNumber;
nsresult res = mouseEvent->GetButton(&buttonNumber);
if (NS_FAILED(res))
return res;
if (buttonNumber != 2) // 2 is the magic number
return NS_OK;
nsCOMPtr<nsIDOMEventTarget> targetNode;
res = aMouseEvent->GetTarget(getter_AddRefs(targetNode));
if (NS_FAILED(res))
return res;
if (!targetNode)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> targetDOMnode;
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(targetNode);
if (!node)
return NS_OK;
// Find the first node to be an element starting with this node and
// working up through its parents.
PRUint32 flags = nsIContextMenuListener::CONTEXT_NONE;
nsCOMPtr<nsIDOMHTMLElement> element;
do {
//PRUint16 type;
//node->GetNodeType(&type);
// XXX test for selected text
element = do_QueryInterface(node);
if (element)
{
nsAutoString tag;
element->GetTagName(tag);
// Test what kind of element we're dealing with here
if (tag.EqualsWithConversion("img", PR_TRUE))
{
flags |= nsIContextMenuListener::CONTEXT_IMAGE;
targetDOMnode = node;
// if we see an image, keep searching for a possible anchor
}
else if (tag.EqualsWithConversion("input", PR_TRUE))
{
// INPUT element - button, combo, checkbox, text etc.
flags |= nsIContextMenuListener::CONTEXT_INPUT;
targetDOMnode = node;
break; // exit do-while
}
else if (tag.EqualsWithConversion("textarea", PR_TRUE))
{
// text area
flags |= nsIContextMenuListener::CONTEXT_TEXT;
targetDOMnode = node;
break; // exit do-while
}
else if (tag.EqualsWithConversion("html", PR_TRUE))
{
// only care about this if no other context was found.
if (!flags) {
flags |= nsIContextMenuListener::CONTEXT_DOCUMENT;
targetDOMnode = node;
}
break; // exit do-while
}
// Test if the element has an associated link
nsCOMPtr<nsIDOMNamedNodeMap> attributes;
node->GetAttributes(getter_AddRefs(attributes));
if (attributes)
{
nsCOMPtr<nsIDOMNode> hrefNode;
nsAutoString href; href.AssignWithConversion("href");
attributes->GetNamedItem(href, getter_AddRefs(hrefNode));
if (hrefNode)
{
flags |= nsIContextMenuListener::CONTEXT_LINK;
if (!targetDOMnode)
targetDOMnode = node;
break; // exit do-while
}
}
}
// walk-up-the-tree
nsCOMPtr<nsIDOMNode> parentNode;
node->GetParentNode(getter_AddRefs(parentNode));
node = parentNode;
} while (node);
// Tell the listener all about the event
nsCOMPtr<nsIContextMenuListener> menuListener(do_QueryInterface(mWebBrowserChrome));
if ( menuListener )
menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode);
return NS_OK;
return HideTooltip();
} // MouseDown
nsresult
ChromeListener::MouseUp(nsIDOMEvent* aMouseEvent)
ChromeTooltipListener::MouseUp(nsIDOMEvent* aMouseEvent)
{
return NS_OK;
}
nsresult
ChromeListener::MouseClick(nsIDOMEvent* aMouseEvent)
ChromeTooltipListener::MouseClick(nsIDOMEvent* aMouseEvent)
{
return NS_OK;
}
nsresult
ChromeListener::MouseDblClick(nsIDOMEvent* aMouseEvent)
ChromeTooltipListener::MouseDblClick(nsIDOMEvent* aMouseEvent)
{
return NS_OK;
}
nsresult
ChromeListener::MouseOver(nsIDOMEvent* aMouseEvent)
ChromeTooltipListener::MouseOver(nsIDOMEvent* aMouseEvent)
{
return NS_OK;
}
@@ -1122,12 +986,8 @@ ChromeListener::MouseOver(nsIDOMEvent* aMouseEvent)
// If we're responding to tooltips, hide the tip whenever the mouse leaves
// the area it was in.
nsresult
ChromeListener::MouseOut(nsIDOMEvent* aMouseEvent)
ChromeTooltipListener::MouseOut(nsIDOMEvent* aMouseEvent)
{
// make sure we're a tooltip. if not, bail. Just to be safe.
if ( ! mTooltipListenerInstalled )
return NS_OK;
return HideTooltip();
}
@@ -1139,12 +999,8 @@ ChromeListener::MouseOut(nsIDOMEvent* aMouseEvent)
// timer fires, we cache the node in |mPossibleTooltipNode|.
//
nsresult
ChromeListener::MouseMove(nsIDOMEvent* aMouseEvent)
ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent)
{
// make sure we're a tooltip. if not, bail. Just to be safe.
if ( ! mTooltipListenerInstalled )
return NS_OK;
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
if (!mouseEvent)
return NS_OK;
@@ -1195,7 +1051,7 @@ ChromeListener::MouseMove(nsIDOMEvent* aMouseEvent)
// Tell the registered chrome that they should show the tooltip
//
NS_IMETHODIMP
ChromeListener :: ShowTooltip ( PRInt32 inXCoords, PRInt32 inYCoords, const nsAReadableString & inTipText )
ChromeTooltipListener :: ShowTooltip ( PRInt32 inXCoords, PRInt32 inYCoords, const nsAReadableString & inTipText )
{
nsresult rv = NS_OK;
@@ -1219,7 +1075,7 @@ ChromeListener :: ShowTooltip ( PRInt32 inXCoords, PRInt32 inYCoords, const nsAR
// NOTE: This routine is safe to call even if the popup is already closed.
//
NS_IMETHODIMP
ChromeListener :: HideTooltip ( )
ChromeTooltipListener :: HideTooltip ( )
{
nsresult rv = NS_OK;
@@ -1257,7 +1113,7 @@ ChromeListener :: HideTooltip ( )
// namespace. Returns |PR_TRUE| if there is, and sets the text in |outText|.
//
PRBool
ChromeListener :: FindTitleText ( nsIDOMNode* inNode, nsAWritableString & outText )
ChromeTooltipListener :: FindTitleText ( nsIDOMNode* inNode, nsAWritableString & outText )
{
PRBool found = PR_FALSE;
@@ -1296,15 +1152,15 @@ ChromeListener :: FindTitleText ( nsIDOMNode* inNode, nsAWritableString & outTex
// appropriate amount of time. Getting to this point means that we should show the
// tooltip, but only after we determine there is an appropriate TITLE element.
//
// This relies on certain things being cached into the |aChromeListener| object passed to
// This relies on certain things being cached into the |aChromeTooltipListener| object passed to
// us by the timer:
// -- the x/y coordinates of the mouse (mMouseClientY, mMouseClientX)
// -- the dom node the user hovered over (mPossibleTooltipNode)
//
void
ChromeListener :: sTooltipCallback (nsITimer *aTimer, void *aChromeListener)
ChromeTooltipListener :: sTooltipCallback (nsITimer *aTimer, void *aChromeTooltipListener)
{
ChromeListener* self = NS_STATIC_CAST(ChromeListener*, aChromeListener);
ChromeTooltipListener* self = NS_STATIC_CAST(ChromeTooltipListener*, aChromeTooltipListener);
if ( self && self->mPossibleTooltipNode ) {
// if there is a TITLE tag, show the tip and fire off a timer to auto-hide it
nsAutoString tooltipText;
@@ -1326,7 +1182,7 @@ ChromeListener :: sTooltipCallback (nsITimer *aTimer, void *aChromeListener)
// Create a new timer to see if we should auto-hide. It's ok if this fails.
//
void
ChromeListener :: CreateAutoHideTimer ( )
ChromeTooltipListener :: CreateAutoHideTimer ( )
{
// just to be anal (er, safe)
if ( mAutoHideTimer ) {
@@ -1349,9 +1205,9 @@ ChromeListener :: CreateAutoHideTimer ( )
// be called multiple times, even if the tip has already been closed.
//
void
ChromeListener :: sAutoHideCallback ( nsITimer *aTimer, void* aListener )
ChromeTooltipListener :: sAutoHideCallback ( nsITimer *aTimer, void* aListener )
{
ChromeListener* self = NS_STATIC_CAST(ChromeListener*, aListener);
ChromeTooltipListener* self = NS_STATIC_CAST(ChromeTooltipListener*, aListener);
if ( self )
self->HideTooltip();
@@ -1360,3 +1216,237 @@ ChromeListener :: sAutoHideCallback ( nsITimer *aTimer, void* aListener )
} // sAutoHideCallback
#ifdef XP_MAC
#pragma mark -
#endif
NS_IMPL_ADDREF(ChromeContextMenuListener)
NS_IMPL_RELEASE(ChromeContextMenuListener)
NS_INTERFACE_MAP_BEGIN(ChromeContextMenuListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMContextMenuListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMContextMenuListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMContextMenuListener)
NS_INTERFACE_MAP_END
//
// ChromeTooltipListener ctor
//
ChromeContextMenuListener :: ChromeContextMenuListener ( nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome )
: mWebBrowser(inBrowser), mWebBrowserChrome(inChrome), mContextMenuListenerInstalled(PR_FALSE)
{
NS_INIT_REFCNT();
} // ctor
//
// ChromeTooltipListener dtor
//
ChromeContextMenuListener :: ~ChromeContextMenuListener ( )
{
} // dtor
//
// AddContextMenuListener
//
// Subscribe to the events that will allow us to track context menus. Bascially, this
// is just the context-menu DOM event.
//
NS_IMETHODIMP
ChromeContextMenuListener :: AddContextMenuListener()
{
if (mEventReceiver) {
nsIDOMContextMenuListener *pListener = NS_STATIC_CAST(nsIDOMContextMenuListener *, this);
nsresult rv = mEventReceiver->AddEventListenerByIID(pListener, NS_GET_IID(nsIDOMContextMenuListener));
if (NS_SUCCEEDED(rv))
mContextMenuListenerInstalled = PR_TRUE;
}
return NS_OK;
}
//
// RemoveContextMenuListener
//
// Unsubscribe from all the various context menu events that we were listening to.
//
NS_IMETHODIMP
ChromeContextMenuListener :: RemoveContextMenuListener()
{
if (mEventReceiver) {
nsIDOMContextMenuListener *pListener = NS_STATIC_CAST(nsIDOMContextMenuListener *, this);
nsresult rv = mEventReceiver->RemoveEventListenerByIID(pListener, NS_GET_IID(nsIDOMContextMenuListener));
if (NS_SUCCEEDED(rv))
mContextMenuListenerInstalled = PR_FALSE;
}
return NS_OK;
}
//
// AddChromeListeners
//
// Hook up things to the chrome like context menus and tooltips, if the chrome
// has implemented the right interfaces.
//
NS_IMETHODIMP
ChromeContextMenuListener :: AddChromeListeners ( )
{
if ( !mEventReceiver ) {
nsCOMPtr<nsIDOMWindow> domWindow;
mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
nsCOMPtr<nsPIDOMWindow> domWindowPrivate = do_QueryInterface(domWindow);
NS_ENSURE_TRUE(domWindowPrivate, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMWindowInternal> rootWindow;
domWindowPrivate->GetPrivateRoot(getter_AddRefs(rootWindow));
NS_ENSURE_TRUE(rootWindow, NS_ERROR_FAILURE);
nsCOMPtr<nsIChromeEventHandler> chromeHandler;
nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(rootWindow));
piWin->GetChromeEventHandler(getter_AddRefs(chromeHandler));
NS_ENSURE_TRUE(chromeHandler, NS_ERROR_FAILURE);
mEventReceiver = do_QueryInterface(chromeHandler);
}
// Register the appropriate events for context menus, but only if
// the embedding chrome cares.
nsresult rv = NS_OK;
nsCOMPtr<nsIContextMenuListener> contextListener ( do_QueryInterface(mWebBrowserChrome) );
if ( contextListener && !mContextMenuListenerInstalled ) {
rv = AddContextMenuListener();
if ( NS_FAILED(rv) )
return rv;
}
return rv;
} // AddChromeListeners
//
// RemoveChromeListeners
//
// Unsubscribe from the various things we've hooked up to the window root.
//
NS_IMETHODIMP
ChromeContextMenuListener :: RemoveChromeListeners ( )
{
if ( mContextMenuListenerInstalled )
RemoveContextMenuListener();
mEventReceiver = nsnull;
// it really doesn't matter if these fail...
return NS_OK;
} // RemoveChromeTooltipListeners
//
// ContextMenu
//
// We're on call to show the context menu. Dig around in the DOM to
// find the type of object we're dealing with and notify the front
// end chrome.
//
nsresult
ChromeContextMenuListener :: ContextMenu ( nsIDOMEvent* aMouseEvent )
{
nsCOMPtr<nsIDOMEventTarget> targetNode;
nsresult res = aMouseEvent->GetTarget(getter_AddRefs(targetNode));
if (NS_FAILED(res))
return res;
if (!targetNode)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> targetDOMnode;
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(targetNode);
if (!node)
return NS_OK;
// Find the first node to be an element starting with this node and
// working up through its parents.
PRUint32 flags = nsIContextMenuListener::CONTEXT_NONE;
nsCOMPtr<nsIDOMHTMLElement> element;
do {
// XXX test for selected text
element = do_QueryInterface(node);
if (element)
{
nsAutoString tag;
element->GetTagName(tag);
// Test what kind of element we're dealing with here
if (tag.EqualsWithConversion("img", PR_TRUE))
{
flags |= nsIContextMenuListener::CONTEXT_IMAGE;
targetDOMnode = node;
// if we see an image, keep searching for a possible anchor
}
else if (tag.EqualsWithConversion("input", PR_TRUE))
{
// INPUT element - button, combo, checkbox, text etc.
flags |= nsIContextMenuListener::CONTEXT_INPUT;
targetDOMnode = node;
break; // exit do-while
}
else if (tag.EqualsWithConversion("textarea", PR_TRUE))
{
// text area
flags |= nsIContextMenuListener::CONTEXT_TEXT;
targetDOMnode = node;
break; // exit do-while
}
else if (tag.EqualsWithConversion("html", PR_TRUE))
{
// only care about this if no other context was found.
if (!flags) {
flags |= nsIContextMenuListener::CONTEXT_DOCUMENT;
targetDOMnode = node;
}
break; // exit do-while
}
// Test if the element has an associated link
nsCOMPtr<nsIDOMNamedNodeMap> attributes;
node->GetAttributes(getter_AddRefs(attributes));
if (attributes)
{
nsCOMPtr<nsIDOMNode> hrefNode;
nsAutoString href; href.AssignWithConversion("href");
attributes->GetNamedItem(href, getter_AddRefs(hrefNode));
if (hrefNode)
{
flags |= nsIContextMenuListener::CONTEXT_LINK;
if (!targetDOMnode)
targetDOMnode = node;
break; // exit do-while
}
}
}
// walk-up-the-tree
nsCOMPtr<nsIDOMNode> parentNode;
node->GetParentNode(getter_AddRefs(parentNode));
node = parentNode;
} while (node);
// Tell the listener all about the event
nsCOMPtr<nsIContextMenuListener> menuListener(do_QueryInterface(mWebBrowserChrome));
if ( menuListener )
menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode);
return NS_OK;
} // MouseDown