Bug 563329 - Add a preference to enable/disable click hold context menus [r=smaug]

This commit is contained in:
Vivien Nicolas 2010-06-16 09:36:11 +02:00
parent f702826779
commit ae3e280802
5 changed files with 166 additions and 63 deletions

View File

@ -770,7 +770,8 @@ nsEventStateManager::nsEventStateManager()
mNormalLMouseEventInProcess(PR_FALSE),
m_haveShutdown(PR_FALSE),
mLastLineScrollConsumedX(PR_FALSE),
mLastLineScrollConsumedY(PR_FALSE)
mLastLineScrollConsumedY(PR_FALSE),
mClickHoldContextMenu(PR_FALSE)
{
if (sESMInstanceCount == 0) {
gUserInteractionTimerCallback = new nsUITimerCallback();
@ -804,7 +805,6 @@ nsEventStateManager::Init()
sLeftClickOnly =
nsContentUtils::GetBoolPref("nglayout.events.dispatchLeftClickOnly",
sLeftClickOnly);
sChromeAccessModifier =
GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeChrome);
sContentAccessModifier =
@ -815,6 +815,7 @@ nsEventStateManager::Init()
prefBranch->AddObserver("ui.key.generalAccessKey", this, PR_TRUE);
prefBranch->AddObserver("ui.key.chromeAccess", this, PR_TRUE);
prefBranch->AddObserver("ui.key.contentAccess", this, PR_TRUE);
prefBranch->AddObserver("ui.click_hold_context_menus", this, PR_TRUE);
#if 0
prefBranch->AddObserver("mousewheel.withaltkey.action", this, PR_TRUE);
prefBranch->AddObserver("mousewheel.withaltkey.numlines", this, PR_TRUE);
@ -833,14 +834,16 @@ nsEventStateManager::Init()
prefBranch->AddObserver("dom.popup_allowed_events", this, PR_TRUE);
}
mClickHoldContextMenu =
nsContentUtils::GetBoolPref("ui.click_hold_context_menus", PR_FALSE);
return NS_OK;
}
nsEventStateManager::~nsEventStateManager()
{
#if CLICK_HOLD_CONTEXT_MENUS
KillClickHoldTimer();
#endif
if (mClickHoldContextMenu)
KillClickHoldTimer();
--sESMInstanceCount;
if(sESMInstanceCount == 0) {
@ -882,6 +885,7 @@ nsEventStateManager::Shutdown()
prefBranch->RemoveObserver("ui.key.generalAccessKey", this);
prefBranch->RemoveObserver("ui.key.chromeAccess", this);
prefBranch->RemoveObserver("ui.key.contentAccess", this);
prefBranch->RemoveObserver("ui.click_hold_context_menus", this);
#if 0
prefBranch->RemoveObserver("mousewheel.withshiftkey.action", this);
prefBranch->RemoveObserver("mousewheel.withshiftkey.numlines", this);
@ -935,6 +939,9 @@ nsEventStateManager::Observe(nsISupports *aSubject,
} else if (data.EqualsLiteral("ui.key.contentAccess")) {
sContentAccessModifier =
GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeContent);
} else if (data.EqualsLiteral("ui.click_hold_context_menus")) {
mClickHoldContextMenu =
nsContentUtils::GetBoolPref("ui.click_hold_context_menus", PR_FALSE);
#if 0
} else if (data.EqualsLiteral("mousewheel.withaltkey.action")) {
} else if (data.EqualsLiteral("mousewheel.withaltkey.numlines")) {
@ -1063,7 +1070,7 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
switch (static_cast<nsMouseEvent*>(aEvent)->button) {
case nsMouseEvent::eLeftButton:
#ifndef XP_OS2
BeginTrackingDragGesture ( aPresContext, (nsMouseEvent*)aEvent, aTargetFrame );
BeginTrackingDragGesture(aPresContext, (nsMouseEvent*)aEvent, aTargetFrame);
#endif
mLClickCount = ((nsMouseEvent*)aEvent)->clickCount;
SetClickCount(aPresContext, (nsMouseEvent*)aEvent, aStatus);
@ -1075,7 +1082,7 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
break;
case nsMouseEvent::eRightButton:
#ifdef XP_OS2
BeginTrackingDragGesture ( aPresContext, (nsMouseEvent*)aEvent, aTargetFrame );
BeginTrackingDragGesture(aPresContext, (nsMouseEvent*)aEvent, aTargetFrame);
#endif
mRClickCount = ((nsMouseEvent*)aEvent)->clickCount;
SetClickCount(aPresContext, (nsMouseEvent*)aEvent, aStatus);
@ -1085,20 +1092,20 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
case NS_MOUSE_BUTTON_UP:
switch (static_cast<nsMouseEvent*>(aEvent)->button) {
case nsMouseEvent::eLeftButton:
#ifdef CLICK_HOLD_CONTEXT_MENUS
KillClickHoldTimer();
#endif
if (mClickHoldContextMenu) {
KillClickHoldTimer();
}
#ifndef XP_OS2
StopTrackingDragGesture();
StopTrackingDragGesture();
#endif
mNormalLMouseEventInProcess = PR_FALSE;
case nsMouseEvent::eRightButton:
mNormalLMouseEventInProcess = PR_FALSE;
case nsMouseEvent::eRightButton:
#ifdef XP_OS2
StopTrackingDragGesture();
StopTrackingDragGesture();
#endif
case nsMouseEvent::eMiddleButton:
SetClickCount(aPresContext, (nsMouseEvent*)aEvent, aStatus);
break;
case nsMouseEvent::eMiddleButton:
SetClickCount(aPresContext, (nsMouseEvent*)aEvent, aStatus);
break;
}
break;
case NS_MOUSE_EXIT:
@ -1132,13 +1139,13 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus);
GenerateMouseEnterExit((nsGUIEvent*)aEvent);
break;
#ifdef CLICK_HOLD_CONTEXT_MENUS
case NS_DRAGDROP_GESTURE:
// an external drag gesture event came in, not generated internally
// by Gecko. Make sure we get rid of the click-hold timer.
KillClickHoldTimer();
if (mClickHoldContextMenu) {
// an external drag gesture event came in, not generated internally
// by Gecko. Make sure we get rid of the click-hold timer.
KillClickHoldTimer();
}
break;
#endif
case NS_DRAGDROP_OVER:
// NS_DRAGDROP_DROP is fired before NS_DRAGDROP_DRAGDROP so send
// the enter/exit events before NS_DRAGDROP_DROP.
@ -1585,9 +1592,6 @@ nsEventStateManager::HandleAccessKey(nsPresContext* aPresContext,
}// end of HandleAccessKey
#ifdef CLICK_HOLD_CONTEXT_MENUS
//
// CreateClickHoldTimer
//
@ -1623,10 +1627,13 @@ nsEventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
}
mClickHoldTimer = do_CreateInstance("@mozilla.org/timer;1");
if ( mClickHoldTimer )
if (mClickHoldTimer) {
PRInt32 clickHoldDelay =
nsContentUtils::GetIntPref("ui.click_hold_context_menus.delay", 500);
mClickHoldTimer->InitWithFuncCallback(sClickHoldCallback, this,
kClickHoldDelay,
clickHoldDelay,
nsITimer::TYPE_ONE_SHOT);
}
} // CreateClickHoldTimer
@ -1654,7 +1661,7 @@ void
nsEventStateManager::sClickHoldCallback(nsITimer *aTimer, void* aESM)
{
nsEventStateManager* self = static_cast<nsEventStateManager*>(aESM);
if ( self )
if (self)
self->FireContextClick();
// NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
@ -1679,7 +1686,7 @@ nsEventStateManager::sClickHoldCallback(nsITimer *aTimer, void* aESM)
void
nsEventStateManager::FireContextClick()
{
if ( !mGestureDownContent )
if (!mGestureDownContent)
return;
#ifdef XP_MACOSX
@ -1786,7 +1793,7 @@ nsEventStateManager::FireContextClick()
}
// now check if the event has been handled. If so, stop tracking a drag
if ( status == nsEventStatus_eConsumeNoDefault ) {
if (status == nsEventStatus_eConsumeNoDefault) {
StopTrackingDragGesture();
}
@ -1794,8 +1801,6 @@ nsEventStateManager::FireContextClick()
} // FireContextClick
#endif
//
// BeginTrackingDragGesture
@ -1803,7 +1808,7 @@ nsEventStateManager::FireContextClick()
// 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,
// We also use this to track click-hold context menus. 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
@ -1814,9 +1819,12 @@ nsEventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
nsMouseEvent* inDownEvent,
nsIFrame* inDownFrame)
{
if (!inDownEvent->widget)
return;
// Note that |inDownEvent| could be either a mouse down event or a
// synthesized mouse move event.
mGestureDownPoint = inDownEvent->refPoint +
mGestureDownPoint = inDownEvent->refPoint +
inDownEvent->widget->WidgetToScreenOffset();
inDownFrame->GetContentForEvent(aPresContext, inDownEvent,
@ -1828,11 +1836,10 @@ nsEventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
mGestureDownAlt = inDownEvent->isAlt;
mGestureDownMeta = inDownEvent->isMeta;
#ifdef CLICK_HOLD_CONTEXT_MENUS
// fire off a timer to track click-hold
if (nsContentUtils::GetBoolPref("ui.click_hold_context_menus", PR_TRUE))
CreateClickHoldTimer ( aPresContext, inDownFrame, inDownEvent );
#endif
if (mClickHoldContextMenu) {
// fire off a timer to track click-hold
CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
}
}
@ -1885,7 +1892,7 @@ nsEventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
nsMouseEvent *aEvent)
{
NS_ASSERTION(aPresContext, "This shouldn't happen.");
if ( IsTrackingDragGesture() ) {
if (IsTrackingDragGesture()) {
mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
if (!mCurrentTarget) {
@ -1927,11 +1934,11 @@ nsEventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
nsIntPoint pt = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
if (PR_ABS(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
PR_ABS(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
#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
if (mClickHoldContextMenu) {
// stop the click-hold before we fire off the drag gesture, in case
// it takes a long time
KillClickHoldTimer();
}
nsRefPtr<nsDOMDataTransfer> dataTransfer = new nsDOMDataTransfer();
if (!dataTransfer)
@ -3663,7 +3670,7 @@ nsEventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
nsCOMPtr<nsIContent> targetContent;
mCurrentTarget->GetContentForEvent(aPresContext, aEvent, getter_AddRefs(targetContent));
if ( mLastDragOverFrame ) {
if (mLastDragOverFrame) {
//The frame has changed but the content may not have. Check before dispatching to content
mLastDragOverFrame->GetContentForEvent(aPresContext, aEvent, getter_AddRefs(lastContent));
@ -3684,7 +3691,7 @@ nsEventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
case NS_DRAGDROP_EXIT:
{
//This is actually the window mouse exit event.
if ( mLastDragOverFrame ) {
if (mLastDragOverFrame) {
nsCOMPtr<nsIContent> lastContent;
mLastDragOverFrame->GetContentForEvent(aPresContext, aEvent, getter_AddRefs(lastContent));

View File

@ -62,14 +62,6 @@ class nsIDocShellTreeItem;
class imgIContainer;
class nsDOMDataTransfer;
// mac uses click-hold context menus, a holdover from 4.x
// touch screens (like maemo) could use this also,
// perhaps we should move to NS_TOUCHSCREEN
#if defined(XP_MACOSX) || defined(MOZ_PLATFORM_MAEMO)
#define CLICK_HOLD_CONTEXT_MENUS 1
#endif
/*
* Event listener manager
*/
@ -399,19 +391,16 @@ protected:
PRPackedBool mLastLineScrollConsumedX;
PRPackedBool mLastLineScrollConsumedY;
#ifdef CLICK_HOLD_CONTEXT_MENUS
enum { kClickHoldDelay = 500 } ; // 500ms == 1/2 second
static PRInt32 sUserInputEventDepth;
// Functions used for click hold context menus
PRBool mClickHoldContextMenu;
nsCOMPtr<nsITimer> mClickHoldTimer;
void CreateClickHoldTimer ( nsPresContext* aPresContext, nsIFrame* inDownFrame,
nsGUIEvent* inMouseDownEvent ) ;
void KillClickHoldTimer ( ) ;
void FireContextClick ( ) ;
static void sClickHoldCallback ( nsITimer* aTimer, void* aESM ) ;
nsCOMPtr<nsITimer> mClickHoldTimer;
#endif
static PRInt32 sUserInputEventDepth;
};
/**

View File

@ -88,6 +88,7 @@ _TEST_FILES = \
test_bug547996-1.html \
test_bug547996-2.xhtml \
test_bug556493.html \
test_bug563329.html \
$(NULL)
_CHROME_FILES = \

View File

@ -0,0 +1,106 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=563329
-->
<head>
<title>Test for Bug 563329</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=563329">Mozilla Bug 563329</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
/** Test for Bug 563329 **/
/* ui.click_hold_context_menus preference */
var target = null;
var tests = getTests();
var currentTest = null;
function getTests() {
let tests = [
{ "func": function() { setTimeout(doCheckContextMenu, 100)}, "message": "Context menu should has fired"},
{ "func": function() { setTimeout(doCheckDuration, 100)}, "message": "Context menu should has fired with delay"},
{ "func": function() { setTimeout(finishTest, 100)}, "message": "" }
];
let i = 0;
while (i < tests.length)
yield tests[i++];
}
function doTest() {
// Enable context menus
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
prefs.setBoolPref("ui.click_hold_context_menus", true);
target = document.getElementById("testTarget");
document.documentElement.addEventListener("contextmenu", function() {
SimpleTest.ok(true, currentTest.message);
synthesizeMouse(target, 0, 0, {type: "mouseup"});
SimpleTest.executeSoon(function() {
currentTest = tests.next();
currentTest.func();
});
}, false);
SimpleTest.executeSoon(function() {
currentTest = tests.next();
currentTest.func();
});
}
function doCheckContextMenu() {
synthesizeMouse(target, 0, 0, {type: "mousedown"});
}
function doCheckDuration() {
var duration = 50;
// Change click hold delay
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
prefs.setIntPref("ui.click_hold_context_menus.delay", duration);
synthesizeMouse(target, 0, 0, {type: "mousedown"});
}
function finishTest() {
synthesizeKey("VK_ESCAPE", {}, window);
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
try {
prefs.clearUserPref("ui.click_hold_context_menus");
}
catch(e) {}
try {
prefs.clearUserPref("ui.click_hold_context_menus.delay");
}
catch(e) {}
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</pre>
<span id="testTarget" style="border: 1px solid black;">testTarget</span>
</body>
</html>

View File

@ -96,6 +96,7 @@ pref("browser.sessionhistory.max_total_viewers", -1);
pref("ui.use_native_colors", true);
pref("ui.use_native_popup_windows", false);
pref("ui.click_hold_context_menus", false);
pref("browser.display.use_document_fonts", 1); // 0 = never, 1 = quick, 2 = always
pref("browser.display.use_document_colors", true);
pref("browser.display.use_system_colors", false);
@ -1726,7 +1727,6 @@ pref("ui.trackpoint_hack.enabled", -1);
// Mac specific preference defaults
pref("browser.drag_out_of_frame_style", 1);
pref("ui.key.saveLink.shift", false); // true = shift, false = meta
pref("ui.click_hold_context_menus", false);
// default fonts (in UTF8 and using canonical names)
// to determine canonical font names, use a debug build and