зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
1081bbc846
Коммит
753219a03d
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче