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

This commit is contained in:
pinkerton%netscape.com 2001-03-30 04:45:40 +00:00
Родитель 36c0c9ec6b
Коммит ffb57058a7
6 изменённых файлов: 702 добавлений и 301 удалений

Просмотреть файл

@ -83,8 +83,13 @@
#include "nsIFrameTraversal.h"
#include "nsLayoutCID.h"
#include "nsHTMLAtoms.h"
#include "nsXULAtoms.h"
#include "nsIDOMHTMLFormElement.h"
static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
//we will use key binding by default now. this wil lbreak viewer for now
#define NON_KEYBINDING 0
@ -141,6 +146,10 @@ nsEventStateManager::nsEventStateManager()
mBrowseWithCaret = PR_FALSE;
hHover = PR_FALSE;
NS_INIT_REFCNT();
#ifdef CLICK_HOLD_CONTEXT_MENUS
mEventDownWidget = nsnull;
#endif
++mInstanceCount;
}
@ -288,7 +297,7 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext,
switch (aEvent->message) {
case NS_MOUSE_LEFT_BUTTON_DOWN:
BeginTrackingDragGesture ( (nsGUIEvent*)aEvent, aTargetFrame );
BeginTrackingDragGesture ( aPresContext, (nsGUIEvent*)aEvent, aTargetFrame );
mLClickCount = ((nsMouseEvent*)aEvent)->clickCount;
SetClickCount(aPresContext, (nsMouseEvent*)aEvent, aStatus);
break;
@ -301,6 +310,9 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext,
SetClickCount(aPresContext, (nsMouseEvent*)aEvent, aStatus);
break;
case NS_MOUSE_LEFT_BUTTON_UP:
#ifdef CLICK_HOLD_CONTEXT_MENUS
KillClickHoldTimer();
#endif
StopTrackingDragGesture();
case NS_MOUSE_MIDDLE_BUTTON_UP:
case NS_MOUSE_RIGHT_BUTTON_UP:
@ -642,18 +654,188 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext,
}
#ifdef CLICK_HOLD_CONTEXT_MENUS
//
// CreateClickHoldTimer
//
// Fire off a timer for determining if the user wants click-hold. This timer
// is a one-shot that will be cancelled when the user moves enough to fire
// a drag.
//
void
nsEventStateManager :: CreateClickHoldTimer ( nsIPresContext* inPresContext, nsGUIEvent* inMouseDownEvent )
{
// just to be anal (er, safe)
if ( mClickHoldTimer ) {
mClickHoldTimer->Cancel();
mClickHoldTimer = nsnull;
}
mClickHoldTimer = do_CreateInstance("@mozilla.org/timer;1");
if ( mClickHoldTimer )
mClickHoldTimer->Init(sClickHoldCallback, this, kClickHoldDelay, NS_PRIORITY_HIGH);
mEventPoint = inMouseDownEvent->point;
mEventRefPoint = inMouseDownEvent->refPoint;
mEventDownWidget = inMouseDownEvent->widget;
mEventPresContext = inPresContext;
} // CreateClickHoldTimer
//
// KillClickHoldTimer
//
// Stop the timer that would show the context menu dead in its tracks
//
void
nsEventStateManager :: KillClickHoldTimer ( )
{
if ( mClickHoldTimer ) {
mClickHoldTimer->Cancel();
mClickHoldTimer = nsnull;
}
mEventDownWidget = nsnull;
mEventPresContext = nsnull;
} // KillTooltipTimer
//
// sClickHoldCallback
//
// This fires after the mouse has been down for a certain length of time.
//
void
nsEventStateManager :: sClickHoldCallback ( nsITimer *aTimer, void* aESM )
{
nsEventStateManager* self = NS_STATIC_CAST(nsEventStateManager*, aESM);
if ( self )
self->FireContextClick();
// NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
} // sAutoHideCallback
//
// FireContextClick
//
// If we're this far, our timer has fired, which means the mouse has been down
// for a certain period of time and has not moved enough to generate a dragGesture.
// We can be certain the user wants a context-click at this stage, so generate
// a dom event and fire it in.
//
// After the event fires, check if PreventDefault() has been set on the event which
// means that someone either ate the event or put up a context menu. This is our cue
// to stop tracking the drag gesture. If we always did this, draggable items w/out
// a context menu wouldn't be draggable after a certain length of time, which is
// _not_ what we want.
//
void
nsEventStateManager :: FireContextClick ( )
{
if ( !mEventDownWidget || !mEventPresContext )
return;
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event;
event.eventStructType = NS_MOUSE_EVENT;
event.message = NS_CONTEXTMENU;
event.widget = mEventDownWidget;
event.clickCount = 1;
event.point = mEventPoint;
event.refPoint = mEventRefPoint;
event.isShift = PR_FALSE;
event.isControl = PR_FALSE;
event.isAlt = PR_FALSE;
event.isMeta = PR_FALSE;
// Dispatch to the DOM. We have to fake out the ESM and tell it that the
// current target frame is actually where the mouseDown occurred, otherwise it
// will use the frame the mouse is currently over which may or may not be
// the same. (Note: saari and I have decided that we don't have to reset |mCurrentTarget|
// when we're through because no one else is doing anything more with this
// event and it will get reset on the very next event to the correct frame).
mCurrentTarget = mGestureDownFrame;
nsCOMPtr<nsIContent> lastContent;
if ( mGestureDownFrame ) {
mGestureDownFrame->GetContent(getter_AddRefs(lastContent));
if ( lastContent ) {
// before dispatching, check that we're not on something that doesn't get a context menu
PRBool allowedToDispatch = PR_TRUE;
nsCOMPtr<nsIAtom> tag;
lastContent->GetTag ( *getter_AddRefs(tag) );
nsCOMPtr<nsIFormControl> formElm ( do_QueryInterface(lastContent) );
if ( formElm ) {
// of all form elements, onlyt <input> and <textarea> are allowed to have context menus
if ( tag != nsHTMLAtoms::input && tag != nsHTMLAtoms::textarea )
allowedToDispatch = PR_FALSE;
}
if ( tag == nsXULAtoms::scrollbar || tag == nsXULAtoms::scrollbarbutton || tag == nsXULAtoms::button )
allowedToDispatch = PR_FALSE;
if ( allowedToDispatch ) {
// stop selection tracking, we're in control now
nsCOMPtr<nsIFrameSelection> frameSel;
GetSelection ( mGestureDownFrame, mEventPresContext, getter_AddRefs(frameSel) );
if ( frameSel ) {
PRBool mouseDownState = PR_TRUE;
frameSel->GetMouseDownState(&mouseDownState);
if (mouseDownState)
frameSel->SetMouseDownState(PR_FALSE);
}
// dispatch to DOM
lastContent->HandleDOMEvent(mEventPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
// dispatch to the frame
mGestureDownFrame->HandleEvent(mEventPresContext, &event, &status);
}
}
}
// now check if the event has been handled. If so, stop tracking a drag
if ( status == nsEventStatus_eConsumeNoDefault )
StopTrackingDragGesture();
KillClickHoldTimer();
} // FireContextClick
#endif
//
// BeginTrackingDragGesture
//
// Record that the mouse has gone down and that we should move to TRACKING state
// of d&d gesture tracker.
//
// We also use this to track click-hold context menus on mac. When the mouse goes down,
// fire off a short timer. If the timer goes off and we have yet to fire the
// drag gesture (ie, the mouse hasn't moved a certain distance), then we can
// assume the user wants a click-hold, so fire a context-click event. We only
// want to cancel the drag gesture if the context-click event is handled.
//
void
nsEventStateManager :: BeginTrackingDragGesture ( nsGUIEvent* inDownEvent, nsIFrame* inDownFrame )
nsEventStateManager :: BeginTrackingDragGesture ( nsIPresContext* aPresContext, nsGUIEvent* inDownEvent, nsIFrame* inDownFrame )
{
mIsTrackingDragGesture = PR_TRUE;
mGestureDownPoint = inDownEvent->point;
mGestureDownFrame = inDownFrame;
#ifdef CLICK_HOLD_CONTEXT_MENUS
// fire off a timer to track click-hold
CreateClickHoldTimer ( aPresContext, inDownEvent );
#endif
}
@ -672,6 +854,38 @@ nsEventStateManager :: StopTrackingDragGesture ( )
}
//
// GetSelection
//
// Helper routine to get an nsIFrameSelection from the given frame
//
void
nsEventStateManager :: GetSelection ( nsIFrame* inFrame, nsIPresContext* inPresContext, nsIFrameSelection** outSelection )
{
*outSelection = nsnull;
if (inFrame) {
nsCOMPtr<nsISelectionController> selCon;
nsresult rv = inFrame->GetSelectionController(inPresContext, getter_AddRefs(selCon));
if (NS_SUCCEEDED(rv) && selCon) {
nsCOMPtr<nsIFrameSelection> frameSel;
frameSel = do_QueryInterface(selCon);
if (! frameSel) {
nsCOMPtr<nsIPresShell> shell;
rv = inPresContext->GetShell(getter_AddRefs(shell));
if (NS_SUCCEEDED(rv) && shell)
rv = shell->GetFrameSelection(outSelection);
}
}
}
} // GetSelection
//
// GenerateDragGesture
//
@ -694,32 +908,14 @@ nsEventStateManager :: GenerateDragGesture ( nsIPresContext* aPresContext, nsGUI
// Check if selection is tracking drag gestures, if so
// don't interfere!
if (mGestureDownFrame) {
nsCOMPtr<nsISelectionController> selCon;
nsresult rv = mGestureDownFrame->GetSelectionController(aPresContext, getter_AddRefs(selCon));
if (NS_SUCCEEDED(rv) && selCon) {
nsCOMPtr<nsIFrameSelection> frameSel;
frameSel = do_QueryInterface(selCon);
if (! frameSel) {
nsCOMPtr<nsIPresShell> shell;
rv = aPresContext->GetShell(getter_AddRefs(shell));
if (NS_SUCCEEDED(rv) && shell)
rv = shell->GetFrameSelection(getter_AddRefs(frameSel));
}
if (NS_SUCCEEDED(rv) && frameSel) {
PRBool mouseDownState = PR_TRUE;
frameSel->GetMouseDownState(&mouseDownState);
if (mouseDownState) {
StopTrackingDragGesture();
return;
}
}
nsCOMPtr<nsIFrameSelection> frameSel;
GetSelection ( mGestureDownFrame, aPresContext, getter_AddRefs(frameSel) );
if ( frameSel ) {
PRBool mouseDownState = PR_TRUE;
frameSel->GetMouseDownState(&mouseDownState);
if (mouseDownState) {
StopTrackingDragGesture();
return;
}
}
@ -739,6 +935,12 @@ nsEventStateManager :: GenerateDragGesture ( nsIPresContext* aPresContext, nsGUI
// fire drag gesture if mouse has moved enough
if ( abs(aEvent->point.x - mGestureDownPoint.x) > twipDeltaToStartDrag ||
abs(aEvent->point.y - mGestureDownPoint.y) > twipDeltaToStartDrag ) {
#ifdef CLICK_HOLD_CONTEXT_MENUS
// stop the click-hold before we fire off the drag gesture, in case
// it takes a long time
KillClickHoldTimer();
#endif
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event;
event.eventStructType = NS_DRAGDROP_EVENT;
@ -1432,14 +1634,21 @@ nsEventStateManager::ClearFrameRefs(nsIFrame* aFrame)
mLastMouseOverFrame = nsnull;
if (aFrame == mLastDragOverFrame)
mLastDragOverFrame = nsnull;
if (aFrame == mGestureDownFrame)
if (aFrame == mGestureDownFrame) {
mGestureDownFrame = nsnull;
#if CLICK_HOLD_CONTEXT_MENUS
mEventDownWidget = nsnull;
mEventPresContext = nsnull;
#endif
}
if (aFrame == mCurrentTarget) {
if (aFrame) {
aFrame->GetContent(&mCurrentTargetContent);
}
mCurrentTarget = nsnull;
}
return NS_OK;
}

Просмотреть файл

@ -30,11 +30,19 @@
#include "nsIObserver.h"
#include "nsWeakReference.h"
#include "nsHashtable.h"
#include "nsITimer.h"
class nsIDocument;
class nsIScrollableView;
class nsIPresShell;
class nsITreeFrame;
class nsIFrameSelection;
// mac uses click-hold context menus, a holdover from 4.x
#ifdef XP_MAC
#define CLICK_HOLD_CONTEXT_MENUS 1
#endif
/*
* Event listener manager
@ -137,7 +145,7 @@ protected:
// end mousewheel functions
// routines for the d&d gesture tracking state machine
void BeginTrackingDragGesture ( nsGUIEvent* inDownEvent, nsIFrame* inDownFrame ) ;
void BeginTrackingDragGesture ( nsIPresContext* aPresContext, nsGUIEvent* inDownEvent, nsIFrame* inDownFrame ) ;
void StopTrackingDragGesture ( ) ;
void GenerateDragGesture ( nsIPresContext* aPresContext, nsGUIEvent *aEvent ) ;
PRBool IsTrackingDragGesture ( ) const { return mIsTrackingDragGesture; }
@ -150,6 +158,8 @@ protected:
nsresult MoveCaretToFocus();
nsresult EnsureCaretVisible(nsIPresShell* aPresShell, nsIContent *aContent);
void GetSelection ( nsIFrame* inFrame, nsIPresContext* inPresContext, nsIFrameSelection** outSelection ) ;
//Any frames here must be checked for validity in ClearFrameRefs
nsIFrame* mCurrentTarget;
nsIContent* mCurrentTargetContent;
@ -203,6 +213,24 @@ protected:
// So we don't have to keep checking accessibility.browsewithcaret pref
PRBool mBrowseWithCaret;
#ifdef CLICK_HOLD_CONTEXT_MENUS
enum { kClickHoldDelay = 500 } ; // 500ms == 1/2 second
void CreateClickHoldTimer ( nsIPresContext* aPresContext, nsGUIEvent* inMouseDownEvent ) ;
void KillClickHoldTimer ( ) ;
void FireContextClick ( ) ;
static void sClickHoldCallback ( nsITimer* aTimer, void* aESM ) ;
// stash a bunch of stuff because we're going through a timer and the event
// isn't guaranteed to be there later. We don't want to hold strong refs to
// things because we're alerted to when they are going away in ClearFrameRefs().
nsPoint mEventPoint, mEventRefPoint;
nsIWidget* mEventDownWidget;
nsIPresContext* mEventPresContext;
nsCOMPtr<nsITimer> mClickHoldTimer;
#endif
};
extern nsresult NS_NewEventStateManager(nsIEventStateManager** aInstancePtrResult);

Просмотреть файл

@ -67,6 +67,13 @@
#include "nsIPref.h"
// on win32 and os/2, context menus come up on mouse up. On other platforms,
// they appear on mouse down. Certain bits of code care about this difference.
#ifndef XP_PC
#define NS_CONTEXT_MENU_IS_MOUSEUP 1
#endif
////////////////////////////////////////////////////////////////////////
static NS_DEFINE_IID(kXULPopupListenerCID, NS_XULPOPUPLISTENER_CID);
@ -265,8 +272,8 @@ XULPopupListenerImpl::MouseUp(nsIDOMEvent* aMouseEvent)
nsresult
XULPopupListenerImpl::MouseDown(nsIDOMEvent* aMouseEvent)
{
// MacOS and Linux bring up context menus on mousedown, Windows on mouseup
#ifndef XP_PC
// Until we do the work, unix brings up context menus on mousedown, Windows/mac on ContextMenu
#ifdef XP_UNIX
return PreLaunchPopup(aMouseEvent);
#else
if(popupType != eXULPopupType_context)
@ -348,12 +355,15 @@ XULPopupListenerImpl::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
}
break;
case eXULPopupType_context:
// Check for right mouse button down
#ifdef XP_UNIX
// Check for right mouse button down (unix only for now)
mouseEvent->GetButton(&button);
#ifndef XP_PC
if (button == 2) {
#endif
// Time to launch a context menu
#ifndef NS_CONTEXT_MENU_IS_MOUSEUP
// If the context menu launches on mousedown,
// we have to fire focus on the content we clicked on
FireFocusOnTargetContent(targetNode);
@ -361,7 +371,7 @@ XULPopupListenerImpl::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
LaunchPopup(aMouseEvent);
aMouseEvent->PreventBubble();
aMouseEvent->PreventDefault();
#ifndef XP_PC
#ifdef XP_UNIX
}
#endif
break;

Просмотреть файл

@ -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

Просмотреть файл

@ -41,12 +41,14 @@
#include "nsWeakReference.h"
#include "nsIDOMKeyListener.h"
#include "nsIDOMMouseMotionListener.h"
#include "nsIDOMContextMenuListener.h"
#include "nsITimer.h"
#include "nsCommandHandler.h"
class nsWebBrowser;
class ChromeListener;
class ChromeTooltipListener;
class ChromeContextMenuListener;
// {6D10C180-6888-11d4-952B-0020183BF181}
#define NS_ICDOCSHELLTREEOWNER_IID \
@ -94,6 +96,7 @@ protected:
NS_IMETHOD SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome);
NS_IMETHOD AddChromeListeners();
NS_IMETHOD RemoveChromeListeners();
nsresult FindChildWithName(const PRUnichar *aName,
PRBool aRecurse, nsIDocShellTreeItem* aRequestor,
@ -115,37 +118,31 @@ protected:
nsIEmbeddingSiteWindow* mOwnerWin;
nsIInterfaceRequestor* mOwnerRequestor;
// the object that listens for chrome events like context menus and tooltips.
// It is a separate object to avoid circular references between |this|
// and the DOM. This is a strong, owning ref.
ChromeListener* mChromeListener;
// the objects that listen for chrome events like context menus and tooltips.
// They are separate objects to avoid circular references between |this|
// and the DOM. These are strong, owning refs.
ChromeTooltipListener* mChromeTooltipListener;
ChromeContextMenuListener* mChromeContextMenuListener;
};
//
// class ChromeListener
// class ChromeTooltipListener
//
// The class that listens to the chrome events and tells the embedding
// chrome to show things like context menus or tooltips, as appropriate.
// Handles registering itself with the DOM with AddChromeListeners()
// and removing itself with RemoveChromeListeners().
// chrome to show tooltips, as appropriate. Handles registering itself
// with the DOM with AddChromeListeners() and removing itself with
// RemoveChromeListeners().
//
// NOTE: Because of a leak/bug in the EventListenerManager having to do with
// a single listener with multiple IID's, we need to addref/release
// this class instead of just owning it and calling delete when we
// know we're done. This also forces us to make RemoveChromeListeners()
// public when it doesn't need to be. This is a reminder to fix when I
// fix the ELM bug. (pinkerton)
//
class ChromeListener : public nsIDOMMouseListener,
public nsIDOMKeyListener,
public nsIDOMMouseMotionListener
class ChromeTooltipListener : public nsIDOMMouseListener,
public nsIDOMKeyListener,
public nsIDOMMouseMotionListener
{
public:
NS_DECL_ISUPPORTS
ChromeListener ( nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) ;
virtual ~ChromeListener ( ) ;
ChromeTooltipListener ( nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) ;
virtual ~ChromeTooltipListener ( ) ;
// nsIDOMMouseListener
virtual nsresult HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }
@ -172,11 +169,22 @@ public:
private:
NS_IMETHOD AddContextMenuListener();
// various delays for tooltips
enum {
kTooltipAutoHideTime = 5000, // 5000ms = 5 seconds
kTooltipShowTime = 500 // 500ms = 0.5 seconds
};
NS_IMETHOD AddTooltipListener();
NS_IMETHOD RemoveContextMenuListener();
NS_IMETHOD RemoveTooltipListener();
NS_IMETHOD ShowTooltip ( PRInt32 inXCoords, PRInt32 inYCoords, const nsAReadableString & inTipText ) ;
NS_IMETHOD HideTooltip ( ) ;
// Determine if there is a TITLE attribute. Returns |PR_TRUE| if there is,
// and sets the text in |outText|.
PRBool FindTitleText ( nsIDOMNode* inNode, nsAWritableString & outText ) ;
nsWebBrowser* mWebBrowser;
nsCOMPtr<nsIDOMEventReceiver> mEventReceiver;
@ -186,24 +194,8 @@ private:
// to tell it, and no one would ever tell us of that fact.
nsCOMPtr<nsIWebBrowserChrome> mWebBrowserChrome;
PRPackedBool mContextMenuListenerInstalled;
PRPackedBool mTooltipListenerInstalled;
private:
// various delays for tooltips
enum {
kTooltipAutoHideTime = 5000, // 5000ms = 5 seconds
kTooltipShowTime = 500 // 500ms = 0.5 seconds
};
NS_IMETHOD ShowTooltip ( PRInt32 inXCoords, PRInt32 inYCoords, const nsAReadableString & inTipText ) ;
NS_IMETHOD HideTooltip ( ) ;
// Determine if there is a TITLE attribute. Returns |PR_TRUE| if there is,
// and sets the text in |outText|.
PRBool FindTitleText ( nsIDOMNode* inNode, nsAWritableString & outText ) ;
nsCOMPtr<nsITimer> mTooltipTimer;
static void sTooltipCallback ( nsITimer* aTimer, void* aListener ) ;
PRInt32 mMouseClientX, mMouseClientY; // mouse coordinates for tooltip event
@ -223,9 +215,47 @@ private:
// reference in each of those cases. So we don't leak.
nsCOMPtr<nsIDOMNode> mPossibleTooltipNode;
}; // ChromeListener
}; // ChromeTooltipListener
//
// class ChromeContextMenuListener
//
// The class that listens to the chrome events and tells the embedding
// chrome to show context menus, as appropriate. Handles registering itself
// with the DOM with AddChromeListeners() and removing itself with
// RemoveChromeListeners().
//
class ChromeContextMenuListener : public nsIDOMContextMenuListener
{
public:
NS_DECL_ISUPPORTS
ChromeContextMenuListener ( nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome ) ;
virtual ~ChromeContextMenuListener ( ) ;
// nsIDOMContextMenuListener
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }
NS_IMETHOD ContextMenu ( nsIDOMEvent* aEvent );
// Add/remove the relevant listeners, based on what interfaces
// the embedding chrome implements.
NS_IMETHOD AddChromeListeners();
NS_IMETHOD RemoveChromeListeners();
private:
NS_IMETHOD AddContextMenuListener();
NS_IMETHOD RemoveContextMenuListener();
PRPackedBool mContextMenuListenerInstalled;
nsWebBrowser* mWebBrowser;
nsCOMPtr<nsIDOMEventReceiver> mEventReceiver;
nsCOMPtr<nsIWebBrowserChrome> mWebBrowserChrome;
}; // class ChromeContextMenuListener
#endif /* nsDocShellTreeOwner_h__ */

Просмотреть файл

@ -40,10 +40,25 @@
#include <locale>
#endif
#define PINK_PROFILING_ACTIVATE 0
#if PINK_PROFILING_ACTIVATE
#include "profilerutils.h"
#endif
//#define DEBUG_TSM
extern nsIRollupListener * gRollupListener;
extern nsIWidget * gRollupWidget;
#if PINK_PROFILING_ACTIVATE
static Boolean KeyDown(const UInt8 theKey);
static Boolean KeyDown(const UInt8 theKey)
{
KeyMap map;
GetKeys(map);
return ((*((UInt8 *)map + (theKey >> 3)) >> (theKey & 7)) & 1) != 0;
}
#endif
// from MacHeaders.c
#ifndef topLeft
@ -1064,6 +1079,11 @@ PRBool nsMacEventHandler::HandleKeyEvent(EventRecord& aOSEvent)
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleActivateEvent(EventRecord& aOSEvent)
{
#if PINK_PROFILING_ACTIVATE
if (KeyDown(0x39)) // press [caps lock] to start the profile
ProfileStart();
#endif
OSErr err;
Boolean isActive;
@ -1138,6 +1158,11 @@ PRBool nsMacEventHandler::HandleActivateEvent(EventRecord& aOSEvent)
gEventDispatchHandler.SetDeactivated(mTopLevelWidget);
mTopLevelWidget->SetIsActive(PR_FALSE);
}
#if PINK_PROFILING_ACTIVATE
ProfileSuspend();
ProfileStop();
#endif
return PR_TRUE;
}
@ -1161,7 +1186,7 @@ PRBool nsMacEventHandler::HandleUpdateEvent(EventRecord& aOSEvent)
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMouseDownEvent(EventRecord& aOSEvent)
{
{
PRBool retVal = PR_FALSE;
WindowPtr whichWindow;
@ -1298,6 +1323,15 @@ PRBool nsMacEventHandler::HandleMouseDownEvent(EventRecord& aOSEvent)
// dispatch the event
retVal = widgetHit->DispatchMouseEvent(mouseEvent);
// if we're a control-click, send in an additional NS_CONTEXTMENU event
// after the mouse down.
if ( mouseButton == NS_MOUSE_RIGHT_BUTTON_DOWN ) {
nsMouseEvent contextMenuEvent;
ConvertOSEventToMouseEvent(aOSEvent, contextMenuEvent, NS_CONTEXTMENU);
contextMenuEvent.isControl = PR_FALSE;
widgetHit->DispatchMouseEvent(contextMenuEvent);
}
}
gEventDispatchHandler.SetWidgetHit(widgetHit);