Bug 1061147, embedding/content process tooltips shouldn't autohide, r=neil
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -1130,17 +1130,17 @@ NS_IMPL_ISUPPORTS(ChromeTooltipListener,
// ChromeTooltipListener ctor
//
ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* inBrowser,
nsIWebBrowserChrome* inChrome)
: mWebBrowser(inBrowser), mWebBrowserChrome(inChrome),
mTooltipListenerInstalled(false),
mMouseClientX(0), mMouseClientY(0),
- mShowingTooltip(false)
+ mShowingTooltip(false), mTooltipShownOnce(false)
{
mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID);
if (!mTooltipTextProvider) {
nsISupports *pProvider = (nsISupports *) new DefaultTooltipTextProvider;
mTooltipTextProvider = do_QueryInterface(pProvider);
}
} // ctor
@@ -1265,21 +1265,27 @@ ChromeTooltipListener::RemoveTooltipList
NS_IMETHODIMP
ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent)
{
nsAutoString eventType;
aEvent->GetType(eventType);
if (eventType.EqualsLiteral("keydown") ||
- eventType.EqualsLiteral("mousedown") ||
- eventType.EqualsLiteral("mouseout"))
+ eventType.EqualsLiteral("mousedown")) {
return HideTooltip();
- if (eventType.EqualsLiteral("mousemove"))
+ }
+ else if (eventType.EqualsLiteral("mouseout")) {
+ // Reset flag so that tooltip will display on the next MouseMove
+ mTooltipShownOnce = false;
+ return HideTooltip();
+ }
+ else if (eventType.EqualsLiteral("mousemove")) {
return MouseMove(aEvent);
+ }
NS_ERROR("Unexpected event type");
return NS_OK;
}
//
// MouseMove
//
@@ -1297,45 +1303,53 @@ ChromeTooltipListener::MouseMove(nsIDOME
// timer callback. On win32, we'll get a MouseMove event even when a popup goes away --
// even when the mouse doesn't change position! To get around this, we make sure the
// mouse has really moved before proceeding.
int32_t newMouseX, newMouseY;
mouseEvent->GetClientX(&newMouseX);
mouseEvent->GetClientY(&newMouseY);
if ( mMouseClientX == newMouseX && mMouseClientY == newMouseY )
return NS_OK;
+
+ // Filter out minor mouse movements.
+ if (mShowingTooltip &&
+ (abs(mMouseClientX - newMouseX) <= kTooltipMouseMoveTolerance) &&
+ (abs(mMouseClientY - newMouseY) <= kTooltipMouseMoveTolerance))
+ return NS_OK;
+
mMouseClientX = newMouseX; mMouseClientY = newMouseY;
mouseEvent->GetScreenX(&mMouseScreenX);
mouseEvent->GetScreenY(&mMouseScreenY);
- // We want to close the tip if it is being displayed and the mouse moves. Recall
- // that |mShowingTooltip| is set when the popup is showing. Furthermore, as the mouse
- // moves, we want to make sure we reset the timer to show it, so that the delay
- // is from when the mouse stops moving, not when it enters the element.
- if ( mShowingTooltip )
- return HideTooltip();
- if ( mTooltipTimer )
+ if ( mTooltipTimer ) {
mTooltipTimer->Cancel();
+ }
- mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1");
- if ( mTooltipTimer ) {
- nsCOMPtr<EventTarget> eventTarget = aMouseEvent->InternalDOMEvent()->GetTarget();
- if ( eventTarget )
- mPossibleTooltipNode = do_QueryInterface(eventTarget);
- if ( mPossibleTooltipNode ) {
- nsresult rv =
- mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this,
- LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500),
- nsITimer::TYPE_ONE_SHOT);
- if (NS_FAILED(rv))
- mPossibleTooltipNode = nullptr;
+ if (!mShowingTooltip && !mTooltipShownOnce) {
+ mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1");
+ if ( mTooltipTimer ) {
+ nsCOMPtr<EventTarget> eventTarget = aMouseEvent->InternalDOMEvent()->GetTarget();
+ if ( eventTarget )
+ mPossibleTooltipNode = do_QueryInterface(eventTarget);
+ if ( mPossibleTooltipNode ) {
+ nsresult rv =
+ mTooltipTimer->InitWithFuncCallback(sTooltipCallback, this,
+ LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500),
+ nsITimer::TYPE_ONE_SHOT);
+ if (NS_FAILED(rv))
+ mPossibleTooltipNode = nullptr;
+ }
}
+ else
+ NS_WARNING ( "Could not create a timer for tooltip tracking" );
}
- else
- NS_WARNING ( "Could not create a timer for tooltip tracking" );
+ else {
+ mTooltipShownOnce = true;
+ return HideTooltip();
+ }
return NS_OK;
} // MouseMove
//
// ShowTooltip
@@ -1374,20 +1388,16 @@ ChromeTooltipListener::HideTooltip()
// shut down the relevant timers
if ( mTooltipTimer ) {
mTooltipTimer->Cancel();
mTooltipTimer = nullptr;
// release tooltip target
mPossibleTooltipNode = nullptr;
}
- if ( mAutoHideTimer ) {
- mAutoHideTimer->Cancel();
- mAutoHideTimer = nullptr;
- }
// if we're showing the tip, tell the chrome to hide it
if ( mShowingTooltip ) {
nsCOMPtr<nsITooltipListener> tooltipListener ( do_QueryInterface(mWebBrowserChrome) );
if ( tooltipListener ) {
rv = tooltipListener->OnHideTooltip ( );
if ( NS_SUCCEEDED(rv) )
mShowingTooltip = false;
@@ -1456,72 +1466,30 @@ ChromeTooltipListener::sTooltipCallback(
if (self->mTooltipTextProvider) {
bool textFound = false;
self->mTooltipTextProvider->GetNodeText(
self->mPossibleTooltipNode, getter_Copies(tooltipText), &textFound);
if (textFound) {
nsString tipText(tooltipText);
- self->CreateAutoHideTimer();
nsIntPoint screenDot = widget->WidgetToScreenOffset();
self->ShowTooltip (self->mMouseScreenX - screenDot.x,
self->mMouseScreenY - screenDot.y,
tipText);
}
}
// release tooltip target if there is one, NO MATTER WHAT
self->mPossibleTooltipNode = nullptr;
} // if "self" data valid
} // sTooltipCallback
-//
-// CreateAutoHideTimer
-//
-// Create a new timer to see if we should auto-hide. It's ok if this fails.
-//
-void
-ChromeTooltipListener::CreateAutoHideTimer()
-{
- // just to be anal (er, safe)
- if ( mAutoHideTimer ) {
- mAutoHideTimer->Cancel();
- mAutoHideTimer = nullptr;
- }
-
- mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1");
- if ( mAutoHideTimer )
- mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime,
- nsITimer::TYPE_ONE_SHOT);
-
-} // CreateAutoHideTimer
-
-
-//
-// sAutoHideCallback
-//
-// This fires after a tooltip has been open for a certain length of time. Just tell
-// the listener to close the popup. We don't have to worry, because HideTooltip() can
-// be called multiple times, even if the tip has already been closed.
-//
-void
-ChromeTooltipListener::sAutoHideCallback(nsITimer *aTimer, void* aListener)
-{
- ChromeTooltipListener* self = static_cast<ChromeTooltipListener*>(aListener);
- if ( self )
- self->HideTooltip();
-
- // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
-
-} // sAutoHideCallback
-
-
NS_IMPL_ISUPPORTS(ChromeContextMenuListener, nsIDOMEventListener)
//
// ChromeTooltipListener ctor
//
ChromeContextMenuListener::ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome )
: mContextMenuListenerInstalled(false),
--- a/embedding/browser/nsDocShellTreeOwner.h
+++ b/embedding/browser/nsDocShellTreeOwner.h
@@ -161,17 +161,18 @@ public:
// the embedding chrome implements.
NS_IMETHOD AddChromeListeners();
NS_IMETHOD RemoveChromeListeners();
private:
// various delays for tooltips
enum {
- kTooltipAutoHideTime = 5000 // 5000ms = 5 seconds
+ kTooltipAutoHideTime = 5000, // 5000ms = 5 seconds
+ kTooltipMouseMoveTolerance = 7 // 7 pixel tolerance for mousemove event
};
NS_IMETHOD AddTooltipListener();
NS_IMETHOD RemoveTooltipListener();
NS_IMETHOD ShowTooltip ( int32_t inXCoords, int32_t inYCoords, const nsAString & inTipText ) ;
NS_IMETHOD HideTooltip ( ) ;
@@ -187,21 +188,17 @@ private:
bool mTooltipListenerInstalled;
nsCOMPtr<nsITimer> mTooltipTimer;
static void sTooltipCallback ( nsITimer* aTimer, void* aListener ) ;
int32_t mMouseClientX, mMouseClientY; // mouse coordinates for last mousemove event we saw
int32_t mMouseScreenX, mMouseScreenY; // mouse coordinates for tooltip event
bool mShowingTooltip;
-
- // a timer for auto-hiding the tooltip after a certain delay
- nsCOMPtr<nsITimer> mAutoHideTimer;
- static void sAutoHideCallback ( nsITimer* aTimer, void* aListener ) ;
- void CreateAutoHideTimer ( ) ;
+ bool mTooltipShownOnce;
// The node hovered over that fired the timer. This may turn into the node that
// triggered the tooltip, but only if the timer ever gets around to firing.
// This is a strong reference, because the tooltip content can be destroyed while we're
// waiting for the tooltip to pup up, and we need to detect that.
// It's set only when the tooltip timer is created and launched. The timer must
// either fire or be cancelled (or possibly released?), and we release this
// reference in each of those cases. So we don't leak.