Bug 378028. Add an 'axis' field to DOMMouseScroll events so that we can distinguish horizontal from vertical scrolling, and use it in trees and listboxes. r=smaug,sr=sicking

This commit is contained in:
Robert O'Callahan 2008-07-25 16:07:43 +12:00
parent 9d6e86ec20
commit 52086cd743
21 changed files with 639 additions and 20 deletions

View File

@ -39,9 +39,6 @@
#endif
*/
// From nsMouseScrollEvent::kIsHorizontal
const MOUSE_SCROLL_IS_HORIZONTAL = 1 << 2;
// One of the possible values for the mousewheel.* preferences.
// From nsEventStateManager.cpp.
const MOUSE_SCROLL_ZOOM = 3;
@ -148,7 +145,7 @@ var FullZoom = {
// Construct the "mousewheel action" pref key corresponding to this event.
// Based on nsEventStateManager::GetBasePrefKeyForMouseWheel.
var pref = "mousewheel";
if (event.scrollFlags & MOUSE_SCROLL_IS_HORIZONTAL)
if (event.axis == event.HORIZONTAL_AXIS)
pref += ".horizscroll";
if (event.shiftKey)

View File

@ -81,6 +81,8 @@ NS_NewDOMUIEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext,
nsresult
NS_NewDOMMouseEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsInputEvent *aEvent);
nsresult
NS_NewDOMMouseScrollEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsInputEvent *aEvent);
nsresult
NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsKeyEvent *aEvent);
nsresult
NS_NewDOMMutationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsMutationEvent* aEvent);

View File

@ -75,6 +75,7 @@ CPPSRCS = \
nsDOMKeyboardEvent.cpp \
nsDOMTextEvent.cpp \
nsDOMMouseEvent.cpp \
nsDOMMouseScrollEvent.cpp \
nsDOMMutationEvent.cpp \
nsDOMPopupBlockedEvent.cpp \
nsDOMBeforeUnloadEvent.cpp \

View File

@ -67,9 +67,6 @@ nsDOMMouseEvent::nsDOMMouseEvent(nsPresContext* aPresContext,
case NS_MOUSE_EVENT:
mDetail = static_cast<nsMouseEvent*>(mEvent)->clickCount;
break;
case NS_MOUSE_SCROLL_EVENT:
mDetail = static_cast<nsMouseScrollEvent*>(mEvent)->delta;
break;
default:
break;
}
@ -77,15 +74,12 @@ nsDOMMouseEvent::nsDOMMouseEvent(nsPresContext* aPresContext,
nsDOMMouseEvent::~nsDOMMouseEvent()
{
if (mEventIsInternal) {
if (mEventIsInternal && mEvent) {
switch (mEvent->eventStructType)
{
case NS_MOUSE_EVENT:
delete static_cast<nsMouseEvent*>(mEvent);
break;
case NS_MOUSE_SCROLL_EVENT:
delete static_cast<nsMouseScrollEvent*>(mEvent);
break;
default:
delete mEvent;
break;
@ -129,10 +123,7 @@ nsDOMMouseEvent::InitMouseEvent(const nsAString & aType, PRBool aCanBubble, PRBo
inputEvent->refPoint.x = aScreenX;
inputEvent->refPoint.y = aScreenY;
if (mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
nsMouseScrollEvent* scrollEvent = static_cast<nsMouseScrollEvent*>(mEvent);
scrollEvent->delta = aDetail;
} else {
if (mEvent->eventStructType == NS_MOUSE_EVENT) {
nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(mEvent);
mouseEvent->clickCount = aDetail;
}

View File

@ -65,4 +65,8 @@ public:
NS_IMETHOD GetWhich(PRUint32 *aWhich);
};
#define NS_FORWARD_TO_NSDOMMOUSEEVENT \
NS_FORWARD_NSIDOMMOUSEEVENT(nsDOMMouseEvent::) \
NS_FORWARD_TO_NSDOMUIEVENT
#endif // nsDOMMouseEvent_h__

View File

@ -0,0 +1,127 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Markus Stange <mstange@themasta.com>
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMMouseScrollEvent.h"
#include "nsGUIEvent.h"
#include "nsIContent.h"
#include "nsIEventStateManager.h"
#include "nsContentUtils.h"
nsDOMMouseScrollEvent::nsDOMMouseScrollEvent(nsPresContext* aPresContext,
nsInputEvent* aEvent)
: nsDOMMouseEvent(aPresContext, aEvent ? aEvent :
new nsMouseScrollEvent(PR_FALSE, 0, nsnull))
{
if(mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
nsMouseScrollEvent* mouseEvent = static_cast<nsMouseScrollEvent*>(mEvent);
mDetail = mouseEvent->delta;
}
}
nsDOMMouseScrollEvent::~nsDOMMouseScrollEvent()
{
if (mEventIsInternal && mEvent) {
switch (mEvent->eventStructType)
{
case NS_MOUSE_SCROLL_EVENT:
delete static_cast<nsMouseScrollEvent*>(mEvent);
break;
default:
delete mEvent;
break;
}
mEvent = nsnull;
}
}
NS_IMPL_ADDREF_INHERITED(nsDOMMouseScrollEvent, nsDOMMouseEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMMouseScrollEvent, nsDOMMouseEvent)
NS_INTERFACE_MAP_BEGIN(nsDOMMouseScrollEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMMouseScrollEvent)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(MouseScrollEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMMouseEvent)
NS_IMETHODIMP
nsDOMMouseScrollEvent::InitMouseScrollEvent(const nsAString & aType, PRBool aCanBubble, PRBool aCancelable,
nsIDOMAbstractView *aView, PRInt32 aDetail, PRInt32 aScreenX,
PRInt32 aScreenY, PRInt32 aClientX, PRInt32 aClientY,
PRBool aCtrlKey, PRBool aAltKey, PRBool aShiftKey,
PRBool aMetaKey, PRUint16 aButton, nsIDOMEventTarget *aRelatedTarget,
PRInt32 aAxis)
{
nsresult rv = nsDOMMouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
aScreenX, aScreenY, aClientX, aClientY, aCtrlKey,
aAltKey, aShiftKey, aMetaKey, aButton, aRelatedTarget);
NS_ENSURE_SUCCESS(rv, rv);
if (mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
static_cast<nsMouseScrollEvent*>(mEvent)->scrollFlags =
(aAxis == HORIZONTAL_AXIS) ? nsMouseScrollEvent::kIsHorizontal
: nsMouseScrollEvent::kIsVertical;
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMMouseScrollEvent::GetAxis(PRInt32* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
if (mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
PRUint32 flags = static_cast<nsMouseScrollEvent*>(mEvent)->scrollFlags;
*aResult = (flags & nsMouseScrollEvent::kIsHorizontal)
? PRInt32(HORIZONTAL_AXIS) : PRInt32(VERTICAL_AXIS);
} else {
*aResult = 0;
}
return NS_OK;
}
nsresult NS_NewDOMMouseScrollEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsInputEvent *aEvent)
{
nsDOMMouseScrollEvent* it = new nsDOMMouseScrollEvent(aPresContext, aEvent);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
return CallQueryInterface(it, aInstancePtrResult);
}

View File

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Markus Stange <mstange@themasta.com>.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMMouseScrollEvent_h__
#define nsDOMMouseScrollEvent_h__
#include "nsIDOMMouseScrollEvent.h"
#include "nsDOMMouseEvent.h"
class nsDOMMouseScrollEvent : public nsIDOMMouseScrollEvent,
public nsDOMMouseEvent
{
public:
nsDOMMouseScrollEvent(nsPresContext* aPresContext, nsInputEvent* aEvent);
virtual ~nsDOMMouseScrollEvent();
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMMouseScrollEvent Interface
NS_DECL_NSIDOMMOUSESCROLLEVENT
// Forward to base class
NS_FORWARD_TO_NSDOMMOUSEEVENT
};
#endif // nsDOMMouseScrollEvent_h__

View File

@ -566,10 +566,12 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
return NS_NewDOMKeyboardEvent(aDOMEvent, aPresContext,
static_cast<nsKeyEvent*>(aEvent));
case NS_MOUSE_EVENT:
case NS_MOUSE_SCROLL_EVENT:
case NS_POPUP_EVENT:
return NS_NewDOMMouseEvent(aDOMEvent, aPresContext,
static_cast<nsInputEvent*>(aEvent));
case NS_MOUSE_SCROLL_EVENT:
return NS_NewDOMMouseScrollEvent(aDOMEvent, aPresContext,
static_cast<nsInputEvent*>(aEvent));
case NS_POPUPBLOCKED_EVENT:
return NS_NewDOMPopupBlockedEvent(aDOMEvent, aPresContext,
static_cast<nsPopupBlockedEvent*>
@ -612,9 +614,10 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
if (aEventType.LowerCaseEqualsLiteral("mouseevent") ||
aEventType.LowerCaseEqualsLiteral("mouseevents") ||
aEventType.LowerCaseEqualsLiteral("mousescrollevents") ||
aEventType.LowerCaseEqualsLiteral("popupevents"))
return NS_NewDOMMouseEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("mousescrollevents"))
return NS_NewDOMMouseScrollEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("keyboardevent") ||
aEventType.LowerCaseEqualsLiteral("keyevents"))
return NS_NewDOMKeyboardEvent(aDOMEvent, aPresContext, nsnull);

View File

@ -47,7 +47,7 @@
interface nsIDOMElement;
[scriptable, uuid(ef136142-9925-45f4-a3e4-6f0d275c6aa8)]
[scriptable, uuid(ee6500aa-fd51-4b89-801f-d4fbf2663beb)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -127,6 +127,33 @@ interface nsIDOMWindowUtils : nsISupports {
in long aClickCount,
in long aModifiers);
/** Synthesize a mouse scroll event for a window. The event types supported
* are:
* DOMMouseScroll
*
* Events are sent in coordinates offset by aX and aY from the window.
*
* Cannot be accessed from unprivileged context (not content-accessible)
* Will throw a DOM security error if called without UniversalXPConnect
* privileges.
*
* @param aType event type
* @param aX x offset
* @param aY y offset
* @param aButton button to synthesize
* @param aScrollFlags flag bits --- see nsMouseScrollFlags in nsGUIEvent.h
* @param aDelta the direction and amount to scroll (in lines or pixels,
* depending on whether kIsPixels is set in aScrollFlags)
* @param aModifiers modifiers pressed, using constants defined in nsIDOMNSEvent
*/
void sendMouseScrollEvent(in AString aType,
in long aX,
in long aY,
in long aButton,
in long aScrollFlags,
in long aDelta,
in long aModifiers);
/**
* Synthesize a key event to the window. The event types supported are:
* keydown, keyup, keypress

View File

@ -56,6 +56,7 @@ SDK_XPIDLSRCS = \
nsIDOMEventGroup.idl \
nsIDOMCustomEvent.idl \
nsIDOMMouseEvent.idl \
nsIDOMMouseScrollEvent.idl \
nsIDOMUIEvent.idl \
$(NULL)

View File

@ -0,0 +1,65 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Mozilla.org.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Robert O'Callahan <robert@ocallahan.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
[scriptable, uuid(f172af88-48c3-4989-b814-60449823fc7d)]
interface nsIDOMMouseScrollEvent : nsISupports
{
const long HORIZONTAL_AXIS = 1;
const long VERTICAL_AXIS = 2;
readonly attribute long axis;
void initMouseScrollEvent(in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancelableArg,
in nsIDOMAbstractView viewArg,
in long detailArg,
in long screenXArg,
in long screenYArg,
in long clientXArg,
in long clientYArg,
in boolean ctrlKeyArg,
in boolean altKeyArg,
in boolean shiftKeyArg,
in boolean metaKeyArg,
in unsigned short buttonArg,
in nsIDOMEventTarget relatedTargetArg,
in long axis);
};

View File

@ -83,6 +83,7 @@ enum nsDOMClassInfoID {
eDOMClassInfo_MutationEvent_id,
eDOMClassInfo_UIEvent_id,
eDOMClassInfo_MouseEvent_id,
eDOMClassInfo_MouseScrollEvent_id,
eDOMClassInfo_KeyboardEvent_id,
eDOMClassInfo_PopupBlockedEvent_id,

View File

@ -234,6 +234,7 @@
#include "nsIDOMDataContainerEvent.h"
#include "nsIDOMKeyEvent.h"
#include "nsIDOMMouseEvent.h"
#include "nsIDOMMouseScrollEvent.h"
#include "nsIDOMCommandEvent.h"
#include "nsIDOMPopupBlockedEvent.h"
#include "nsIDOMBeforeUnloadEvent.h"
@ -650,6 +651,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MouseEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MouseScrollEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(KeyboardEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(PopupBlockedEvent, nsDOMGenericSH,
@ -2105,6 +2108,11 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(MouseScrollEvent, nsIDOMMouseScrollEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMouseScrollEvent)
DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(HTMLDocument, nsIDOMHTMLDocument)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSHTMLDocument)

View File

@ -246,6 +246,49 @@ nsDOMWindowUtils::SendMouseEvent(const nsAString& aType,
return widget->DispatchEvent(&event, status);
}
NS_IMETHODIMP
nsDOMWindowUtils::SendMouseScrollEvent(const nsAString& aType,
PRInt32 aX,
PRInt32 aY,
PRInt32 aButton,
PRInt32 aScrollFlags,
PRInt32 aDelta,
PRInt32 aModifiers)
{
PRBool hasCap = PR_FALSE;
if (NS_FAILED(nsContentUtils::GetSecurityManager()->IsCapabilityEnabled("UniversalXPConnect", &hasCap))
|| !hasCap)
return NS_ERROR_DOM_SECURITY_ERR;
// get the widget to send the event to
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget)
return NS_ERROR_FAILURE;
PRInt32 msg;
if (aType.EqualsLiteral("DOMMouseScroll"))
msg = NS_MOUSE_SCROLL;
else
return NS_ERROR_FAILURE;
nsMouseScrollEvent event(PR_TRUE, msg, widget);
event.isShift = (aModifiers & nsIDOMNSEvent::SHIFT_MASK) ? PR_TRUE : PR_FALSE;
event.isControl = (aModifiers & nsIDOMNSEvent::CONTROL_MASK) ? PR_TRUE : PR_FALSE;
event.isAlt = (aModifiers & nsIDOMNSEvent::ALT_MASK) ? PR_TRUE : PR_FALSE;
event.isMeta = (aModifiers & nsIDOMNSEvent::META_MASK) ? PR_TRUE : PR_FALSE;
event.button = aButton;
event.widget = widget;
event.delta = aDelta;
event.scrollFlags = aScrollFlags;
event.time = PR_IntervalNow();
event.refPoint.x = aX;
event.refPoint.y = aY;
nsEventStatus status;
return widget->DispatchEvent(&event, status);
}
NS_IMETHODIMP
nsDOMWindowUtils::SendKeyEvent(const nsAString& aType,
PRInt32 aKeyCode,

View File

@ -187,7 +187,7 @@ function _parseModifiers(aEvent)
* aOffsetY. This allows mouse clicks to be simulated by calling this method.
*
* aEvent is an object which may contain the properties:
* shiftKey, ctrlKey, altKey, metaKey, accessKey, type
* shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type
*
* If the type is specified, an mouse event of that type is fired. Otherwise,
* a mousedown followed by a mouse up is performed.
@ -221,6 +221,59 @@ function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
}
}
/**
* Synthesize a mouse scroll event on a target. The actual client point is determined
* by taking the aTarget's client box and offseting it by aOffsetX and
* aOffsetY.
*
* aEvent is an object which may contain the properties:
* shiftKey, ctrlKey, altKey, metaKey, accessKey, button, type, axis, units, delta
*
* If the type is specified, an mouse scroll event of that type is fired. Otherwise,
* "DOMMouseScroll" is used.
*
* If the axis is specified, it must be one of "horizontal" or "vertical". If not specified,
* "vertical" is used.
*
* 'delta' is the amount to scroll by (can be positive or negative). It must
* be specified. 'units' is the units of 'delta', either "pixels" or "lines"; "lines"
* is the default if 'units' is ommitted.
*
* aWindow is optional, and defaults to the current window object.
*/
function synthesizeMouseScroll(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
{
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (!aWindow)
aWindow = window;
var utils = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
getInterface(Components.interfaces.nsIDOMWindowUtils);
if (utils) {
// See nsMouseScrollFlags in nsGUIEvent.h
const kIsVertical = 0x02;
const kIsHorizontal = 0x04;
const kIsPixels = 0x08;
var button = aEvent.button || 0;
var modifiers = _parseModifiers(aEvent);
var left = aTarget.boxObject.x;
var top = aTarget.boxObject.y;
var type = aEvent.type || "DOMMouseScroll";
var axis = aEvent.axis || "vertical";
var units = aEvent.units || "lines";
var scrollFlags = (axis == "horizontal") ? kIsHorizontal : kIsVertical;
if (units == "pixels") {
scrollFlags |= kIsPixels;
}
utils.sendMouseScrollEvent(type, left + aOffsetX, top + aOffsetY, button,
scrollFlags, aEvent.delta, modifiers);
}
}
/**
* Synthesize a key event. It is targeted at whatever would be targeted by an
* actual keypress by the user, typically the focused element.

View File

@ -101,6 +101,7 @@ _TEST_FILES = test_bug360220.xul \
test_menu_hide.xul \
test_focus.xul \
test_tabindex.xul \
test_mousescroll.xul \
test_scrollbar.xul \
test_sorttemplate.xul \
$(NULL)

View File

@ -0,0 +1,186 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=378028
-->
<window title="Mozilla Bug 378028"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="/MochiKit/packed.js" />
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=378028"
target="_blank">Mozilla Bug 378028</a>
</body>
<!-- richlistbox currently has no way of giving us a defined number of
rows, so we just choose an arbitrary height limit that should give
us plenty of vertical scrollability -->
<richlistbox id="richlistbox" style="height:50px;">
<richlistitem id="richlistbox_item1"><label value="Item 1"/></richlistitem>
<richlistitem id="richlistbox_item2"><label value="Item 2"/></richlistitem>
<richlistitem id="richlistbox_item3"><label value="Item 3"/></richlistitem>
<richlistitem id="richlistbox_item4"><label value="Item 4"/></richlistitem>
<richlistitem id="richlistbox_item5"><label value="Item 5"/></richlistitem>
<richlistitem id="richlistbox_item6"><label value="Item 6"/></richlistitem>
<richlistitem id="richlistbox_item7"><label value="Item 7"/></richlistitem>
<richlistitem id="richlistbox_item8"><label value="Item 8"/></richlistitem>
</richlistbox>
<listbox id="listbox" rows="2">
<listitem id="listbox_item1" label="Item 1"/>
<listitem id="listbox_item2" label="Item 2"/>
<listitem id="listbox_item3" label="Item 3"/>
<listitem id="listbox_item4" label="Item 4"/>
<listitem id="listbox_item5" label="Item 5"/>
<listitem id="listbox_item6" label="Item 6"/>
<listitem id="listbox_item7" label="Item 7"/>
<listitem id="listbox_item8" label="Item 8"/>
</listbox>
<box orient="horizontal">
<arrowscrollbox id="hscrollbox" clicktoscroll="true" orient="horizontal"
smoothscroll="false" style="max-width:80px;" flex="1">
<hbox style="width:40px; height:20px; background:white;"/>
<hbox style="width:40px; height:20px; background:black;"/>
<hbox style="width:40px; height:20px; background:white;"/>
<hbox style="width:40px; height:20px; background:black;"/>
<hbox style="width:40px; height:20px; background:white;"/>
<hbox style="width:40px; height:20px; background:black;"/>
<hbox style="width:40px; height:20px; background:white;"/>
<hbox style="width:40px; height:20px; background:black;"/>
</arrowscrollbox>
</box>
<arrowscrollbox id="vscrollbox" clicktoscroll="true" orient="vertical"
smoothscroll="false" style="max-height:80px;" flex="1">
<vbox style="width:100px; height:40px; background:white;"/>
<vbox style="width:100px; height:40px; background:black;"/>
<vbox style="width:100px; height:40px; background:white;"/>
<vbox style="width:100px; height:40px; background:black;"/>
<vbox style="width:100px; height:40px; background:white;"/>
<vbox style="width:100px; height:40px; background:black;"/>
<vbox style="width:100px; height:40px; background:white;"/>
<vbox style="width:100px; height:40px; background:black;"/>
<vbox style="width:100px; height:40px; background:white;"/>
<vbox style="width:100px; height:40px; background:black;"/>
</arrowscrollbox>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
/** Test for Bug 378028 **/
SimpleTest.waitForExplicitFinish();
function testListbox(id)
{
var listbox = document.getElementById(id);
function helper(aStart, aDelta)
{
listbox.scrollToIndex(aStart);
synthesizeMouseScroll(listbox, 10, 10,
{axis:"vertical", delta:aDelta});
is(listbox.getIndexOfFirstVisibleRow(), aStart + aDelta,
"mouse-scroll of '" + id + "' vertical starting " + aStart + " delta " + aDelta);
// Check that horizontal scrolling has no effect
listbox.scrollToIndex(aStart);
synthesizeMouseScroll(listbox, 10, 10,
{axis:"horizontal", delta:aDelta});
is(listbox.getIndexOfFirstVisibleRow(), aStart,
"mouse-scroll of '" + id + "' horizontal starting " + aStart + " delta " + aDelta);
}
helper(2, -1);
helper(2, 1);
helper(2, -2);
helper(2, 2);
}
function testRichListbox(id)
{
var listbox = document.getElementById(id);
function helper(aStart, aDelta, aExpected)
{
listbox.scrollToIndex(aStart);
synthesizeMouseScroll(listbox, 10, 10,
{axis:"vertical", delta:aDelta});
is(listbox.getIndexOfFirstVisibleRow(), aExpected,
"mouse-scroll of '" + id + "' vertical starting " + aStart + " delta " + aDelta);
// Check that horizontal scrolling has no effect
listbox.scrollToIndex(aStart);
synthesizeMouseScroll(listbox, 10, 10,
{axis:"horizontal", delta:aDelta});
is(listbox.getIndexOfFirstVisibleRow(), aStart,
"mouse-scroll of '" + id + "' horizontal starting " + aStart + " delta " + aDelta);
}
// richlistbox currently uses native XUL scrolling, so the "line"
// amounts don't necessarily correspond 1-to-1 with listbox items. So
// we just check that scrolling up/down a lot hits the first/last items
helper(2, -100, 0);
helper(2, 100, listbox.getRowCount() - listbox.getNumberOfVisibleRows());
}
function testArrowScrollbox(id)
{
var scrollbox = document.getElementById(id);
var scrollBoxObject = scrollbox.scrollBoxObject;
var orient = scrollbox.getAttribute("orient");
function helper(aStart, aDelta, aExpected)
{
var xpos = {};
var ypos = {};
var pos = orient == "horizontal" ? xpos : ypos;
scrollBoxObject.scrollTo(aStart, aStart);
synthesizeMouseScroll(scrollbox, 5, 5,
{axis:"vertical", delta:aDelta});
scrollBoxObject.getPosition(xpos, ypos);
// Note, vertical mouse scrolling is allowed to scroll horizontal
// arrowscrollboxes, because many users have no horizontal mouse scroll
// capability
is(pos.value, aExpected,
"mouse-scroll of '" + id + "' vertical starting " + aStart + " delta " + aDelta);
scrollBoxObject.scrollTo(aStart, aStart);
synthesizeMouseScroll(scrollbox, 5, 5,
{axis:"horizontal", delta:aDelta});
// horizontal mouse scrolling is never allowed to scroll vertical
// arrowscrollboxes
scrollBoxObject.getPosition(xpos, ypos);
var expected = orient == "horizontal" ? aExpected : aStart;
is(pos.value, expected,
"mouse-scroll of '" + id + "' horizontal starting " + aStart + " delta " + aDelta);
}
var scrolledWidth = {};
var scrolledHeight = {};
scrollBoxObject.getScrolledSize(scrolledWidth, scrolledHeight);
var scrollMaxX = scrolledWidth.value - scrollBoxObject.width;
var scrollMaxY = scrolledHeight.value - scrollBoxObject.height;
var scrollMax = orient == "horizontal" ? scrollMaxX : scrollMaxY;
helper(50, -100, 0);
helper(50, 100, scrollMax);
}
function runTests()
{
testRichListbox("richlistbox");
testListbox("listbox");
testArrowScrollbox("hscrollbox");
testArrowScrollbox("vscrollbox");
SimpleTest.finish();
}
window.onload = function() { setTimeout(runTests, 0); };
]]></script>
</window>

View File

@ -23,6 +23,13 @@ function testtag_tree(treeid, treerowinfoid, seltype, columnstype, testid)
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
// Stop keystrokes that aren't handled by the tree from leaking out and
// scrolling the main Mochitests window!
function preventDefault(event) {
event.preventDefault();
}
document.addEventListener("keypress", preventDefault, false);
var multiple = (seltype == "multiple");
var editable = false;
@ -93,6 +100,10 @@ function testtag_tree(treeid, treerowinfoid, seltype, columnstype, testid)
// do the sorting tests last as it will cause the rows to rearrange
testtag_tree_TreeView_rows_sort(tree, testid, rowInfo);
testtag_tree_mousescroll(tree);
document.removeEventListener("keypress", preventDefault, false);
SimpleTest.finish();
}
@ -1050,8 +1061,30 @@ function testtag_tree_column_reorder()
checkColumns(tree, reference, "drag to itself");
is(document.treecolDragging, null, "drag to itself completed");
// XXX roc should this be here???
SimpleTest.finish();
}
function testtag_tree_mousescroll(aTree)
{
function helper(aStart, aDelta)
{
aTree.treeBoxObject.scrollToRow(aStart);
synthesizeMouseScroll(aTree.body, 1, 1,
{type:"mousescroll", axis:"vertical", delta:aDelta});
is(aTree.treeBoxObject.getFirstVisibleRow(), aStart + aDelta, "mouse-scroll vertical starting " + aStart + " delta " + aDelta);
aTree.treeBoxObject.scrollToRow(aStart);
// Check that horizontal scrolling has no effect
synthesizeMouseScroll(aTree.body, 1, 1,
{type:"mousescroll", axis:"horizontal", delta:aDelta});
is(aTree.treeBoxObject.getFirstVisibleRow(), aStart, "mouse-scroll horizontal starting " + aStart + " delta " + aDelta);
}
helper(2, -1);
helper(2, 1);
helper(2, -2);
helper(2, 2);
}
function synthesizeColumnDrag(aTree, aMouseDownColumnNumber, aMouseUpColumnNumber, aAfter)

View File

@ -865,6 +865,9 @@
<handlers>
<handler event="DOMMouseScroll" phase="capturing">
<![CDATA[
if (event.axis == event.HORIZONTAL_AXIS)
return;
var listBox = this.parentNode.listBoxObject;
var rows = event.detail;
if (rows == NSUIEvent.SCROLL_PAGE_UP)

View File

@ -360,7 +360,18 @@
</implementation>
<handlers>
<handler event="DOMMouseScroll" action="this.scrollByIndex(event.detail); event.stopPropagation();"/>
<handler event="DOMMouseScroll"><![CDATA[
// prevent horizontal scrolling from scrolling a vertical scrollbox
if (event.axis == event.HORIZONTAL_AXIS &&
this.getAttribute("orient") != "horizontal")
return;
// We allow vertical scrolling to scroll a horizontal scrollbox
// because many users have a vertical scroll wheel but no
// horizontal support.
this.scrollByIndex(event.detail);
event.stopPropagation();
]]></handler>
<handler event="underflow"><![CDATA[
// filter underflow events which were dispatched on nested scrollboxes

View File

@ -633,6 +633,8 @@
<![CDATA[
if (this._editingColumn)
return;
if (event.axis == event.HORIZONTAL_AXIS)
return;
var rows = event.detail;
if (rows == NSUIEvent.SCROLL_PAGE_UP)