108757 - dispatch DOM events for mouse wheel scrolling, r=?, sr=?

This commit is contained in:
hewitt%netscape.com 2001-11-14 10:06:21 +00:00
parent c76d3a0afe
commit 76b5876544
17 changed files with 212 additions and 113 deletions

View File

@ -684,9 +684,13 @@ nsGenericDOMDataNode::HandleDOMEvent(nsIPresContext* aPresContext,
nsresult ret = NS_OK;
nsIDOMEvent* domEvent = nsnull;
PRBool externalDOMEvent = PR_FALSE;
if (NS_EVENT_FLAG_INIT & aFlags) {
if (!aDOMEvent) {
aDOMEvent = &domEvent;
} else {
externalDOMEvent = PR_TRUE;
}
aEvent->flags = aFlags;
aFlags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL);
@ -723,7 +727,7 @@ nsGenericDOMDataNode::HandleDOMEvent(nsIPresContext* aPresContext,
if (NS_EVENT_FLAG_INIT & aFlags) {
// We're leaving the DOM event loop so if we created a DOM event,
// release here.
if (nsnull != *aDOMEvent) {
if (!externalDOMEvent && nsnull != *aDOMEvent) {
if (0 != (*aDOMEvent)->Release()) {
// Okay, so someone in the DOM loop (a listener, JS object)
// still has a ref to the DOM Event but the internal data

View File

@ -1071,6 +1071,7 @@ nsGenericElement::InternalIsSupported(const nsAReadableString& aFeature,
feature.EqualsWithConversion("Events", PR_TRUE) ||
// feature.EqualsWithConversion("UIEvents", PR_TRUE) ||
feature.EqualsWithConversion("MouseEvents", PR_TRUE) ||
feature.EqualsWithConversion("MouseScrollEvents", PR_TRUE) ||
feature.EqualsWithConversion("HTMLEvents", PR_TRUE) ||
feature.EqualsWithConversion("Range", PR_TRUE)) {
if (!aVersion.Length() || aVersion.Equals(NS_LITERAL_STRING("2.0"))) {

View File

@ -166,6 +166,10 @@ nsDOMEvent::nsDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent,
mEvent = PR_NEWZAP(nsMouseEvent);
mEvent->eventStructType = NS_MOUSE_EVENT;
}
else if (eventType.EqualsIgnoreCase("MouseScrollEvents")) {
mEvent = PR_NEWZAP(nsMouseScrollEvent);
mEvent->eventStructType = NS_MOUSE_SCROLL_EVENT;
}
else if (eventType.EqualsIgnoreCase("KeyEvents")) {
mEvent = PR_NEWZAP(nsKeyEvent);
mEvent->eventStructType = NS_KEY_EVENT;
@ -506,6 +510,7 @@ nsDOMEvent::GetDetail(PRInt32* aDetail)
case NS_MOUSE_RIGHT_BUTTON_DOWN:
case NS_MOUSE_RIGHT_CLICK:
case NS_MOUSE_RIGHT_DOUBLECLICK:
case NS_USER_DEFINED_EVENT:
*aDetail = ((nsMouseEvent*)mEvent)->clickCount;
break;
default:
@ -514,6 +519,12 @@ nsDOMEvent::GetDetail(PRInt32* aDetail)
return NS_OK;
}
case NS_MOUSE_SCROLL_EVENT:
{
*aDetail = ((nsMouseScrollEvent*)mEvent)->delta;
break;
}
default:
*aDetail = 0;
return NS_OK;
@ -1212,7 +1223,7 @@ nsDOMEvent::InitUIEvent(const nsAReadableString& aTypeArg, PRBool aCanBubbleArg,
NS_IMETHODIMP
nsDOMEvent::InitMouseEvent(const nsAReadableString & aTypeArg, PRBool aCanBubbleArg, PRBool aCancelableArg,
nsIDOMAbstractView *aViewArg, PRUint16 aDetailArg, PRInt32 aScreenXArg,
nsIDOMAbstractView *aViewArg, PRInt32 aDetailArg, PRInt32 aScreenXArg,
PRInt32 aScreenYArg, PRInt32 aClientXArg, PRInt32 aClientYArg,
PRBool aCtrlKeyArg, PRBool aAltKeyArg, PRBool aShiftKeyArg,
PRBool aMetaKeyArg, PRUint16 aButtonArg, nsIDOMEventTarget *aRelatedTargetArg)
@ -1221,23 +1232,29 @@ nsDOMEvent::InitMouseEvent(const nsAReadableString & aTypeArg, PRBool aCanBubble
mEvent->flags |= aCanBubbleArg ? NS_EVENT_FLAG_NONE : NS_EVENT_FLAG_CANT_BUBBLE;
mEvent->flags |= aCancelableArg ? NS_EVENT_FLAG_NONE : NS_EVENT_FLAG_CANT_CANCEL;
if (mEvent->eventStructType == NS_MOUSE_EVENT) {
nsMouseEvent* mouseEvent = NS_STATIC_CAST(nsMouseEvent*, mEvent);
mouseEvent->isControl = aCtrlKeyArg;
mouseEvent->isAlt = aAltKeyArg;
mouseEvent->isShift = aShiftKeyArg;
mouseEvent->isMeta = aMetaKeyArg;
mouseEvent->point.x = aClientXArg;
mouseEvent->point.y = aClientYArg;
mouseEvent->refPoint.x = aScreenXArg;
mouseEvent->refPoint.y = aScreenYArg;
if (mEvent->eventStructType == NS_MOUSE_EVENT || mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
nsInputEvent* inputEvent = NS_STATIC_CAST(nsInputEvent*, mEvent);
inputEvent->isControl = aCtrlKeyArg;
inputEvent->isAlt = aAltKeyArg;
inputEvent->isShift = aShiftKeyArg;
inputEvent->isMeta = aMetaKeyArg;
inputEvent->point.x = aClientXArg;
inputEvent->point.y = aClientYArg;
inputEvent->refPoint.x = aScreenXArg;
inputEvent->refPoint.y = aScreenYArg;
mScreenPoint.x = aScreenXArg;
mScreenPoint.y = aScreenYArg;
mClientPoint.x = aClientXArg;
mClientPoint.y = aClientYArg;
mButton = aButtonArg;
if (mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
nsMouseScrollEvent* scrollEvent = NS_STATIC_CAST(nsMouseScrollEvent*, mEvent);
scrollEvent->delta = aDetailArg;
} else {
nsMouseEvent* mouseEvent = NS_STATIC_CAST(nsMouseEvent*, mEvent);
mouseEvent->clickCount = aDetailArg;
}
}
//include a way to set view once we have more than one
return NS_OK;

View File

@ -161,7 +161,7 @@ public:
NS_IMETHOD GetKeyCode(PRUint32* aKeyCode);
NS_IMETHOD InitMouseEvent(const nsAReadableString & aTypeArg,
PRBool aCanBubbleArg, PRBool aCancelableArg,
nsIDOMAbstractView *aViewArg, PRUint16 aDetailArg,
nsIDOMAbstractView *aViewArg, PRInt32 aDetailArg,
PRInt32 aScreenXArg, PRInt32 aDcreenYArg,
PRInt32 aClientXArg, PRInt32 aClientYArg,
PRBool aCtrlKeyArg, PRBool aAltKeyArg,

View File

@ -2342,7 +2342,7 @@ nsEventListenerManager::CreateEvent(nsIPresContext* aPresContext,
nsAutoString str(aEventType);
if (!aEvent && !str.EqualsIgnoreCase("MouseEvents") && !str.EqualsIgnoreCase("KeyEvents") &&
!str.EqualsIgnoreCase("HTMLEvents") && !str.EqualsIgnoreCase("MutationEvents") &&
!str.EqualsIgnoreCase("Events")) {
!str.EqualsIgnoreCase("MouseScrollEvents") && !str.EqualsIgnoreCase("Events")) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}

View File

@ -93,6 +93,12 @@
#include "nsIOutlinerBoxObject.h"
#include "nsIScrollableViewProvider.h"
#include "nsIDOMDocumentRange.h"
#include "nsIDOMDocumentEvent.h"
#include "nsIDOMMouseEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMDocumentView.h"
#include "nsIDOMAbstractView.h"
#include "nsIDOMNSUIEvent.h"
#include "nsIDOMRange.h"
#include "nsICaret.h"
@ -1200,63 +1206,6 @@ nsEventStateManager::ChangeTextSize(PRInt32 change)
//
// DoTreeScroll
//
// Trees know best how to deal with scrolling, so use the tree scroll api's instead
// of just blindly scrolling the view.
//
nsresult
nsEventStateManager::DoTreeScroll(nsIPresContext* inPresContext, PRInt32 inNumLines,
PRBool inScrollPage, nsITreeFrame* inTreeFrame)
{
PRInt32 scrollIndex, visibleRows;
inTreeFrame->GetIndexOfFirstVisibleRow(&scrollIndex);
inTreeFrame->GetNumberOfVisibleRows(&visibleRows);
if (inScrollPage)
scrollIndex += ((inNumLines > 0) ? visibleRows : -visibleRows);
else
scrollIndex += inNumLines;
if (scrollIndex < 0)
scrollIndex = 0;
else {
PRInt32 numRows;
inTreeFrame->GetRowCount(&numRows);
PRInt32 lastPageTopRow = numRows - visibleRows;
if (scrollIndex > lastPageTopRow)
scrollIndex = lastPageTopRow;
}
inTreeFrame->ScrollToIndex(scrollIndex);
// we have to do a sync update for mac because if we scroll too quickly
// w/out going back to the main event loop we can easily scroll the wrong
// bits and it looks like garbage (bug 63465).
nsIFrame* frame = nsnull;
if ( NS_SUCCEEDED(inTreeFrame->QueryInterface(NS_GET_IID(nsIFrame),
(void **)&frame)) ) {
nsIView* treeView = nsnull;
frame->GetView(inPresContext, &treeView);
if (!treeView) {
nsIFrame* frameWithView;
frame->GetParentWithView(inPresContext, &frameWithView);
if (frameWithView)
frameWithView->GetView(inPresContext, &treeView);
else
return NS_ERROR_FAILURE;
}
if (treeView)
ForceViewUpdate(treeView);
}
else
return NS_ERROR_FAILURE;
return NS_OK;
} // DoTreeScroll
nsresult
nsEventStateManager::DoWheelScroll(nsIPresContext* aPresContext,
nsIFrame* aTargetFrame,
@ -1264,27 +1213,50 @@ nsEventStateManager::DoWheelScroll(nsIPresContext* aPresContext,
PRInt32 numLines, PRBool scrollPage,
PRBool aUseTargetFrame)
{
nsCOMPtr<nsIContent> targetContent;
aTargetFrame->GetContent(getter_AddRefs(targetContent));
nsCOMPtr<nsIDocument> targetDoc;
targetContent->GetDocument(*getter_AddRefs(targetDoc));
if (!targetDoc) return NS_OK;
nsCOMPtr<nsIDOMDocumentEvent> targetDOMDoc(do_QueryInterface(targetDoc));
nsCOMPtr<nsIDOMEvent> event;
targetDOMDoc->CreateEvent(NS_LITERAL_STRING("MouseScrollEvents"), getter_AddRefs(event));
if (event) {
nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(event));
nsCOMPtr<nsIDOMDocumentView> docView = do_QueryInterface(targetDoc);
if (!docView) return nsnull;
nsCOMPtr<nsIDOMAbstractView> view;
docView->GetDefaultView(getter_AddRefs(view));
if (scrollPage)
numLines = numLines > 0 ? nsIDOMNSUIEvent::SCROLL_PAGE_DOWN : nsIDOMNSUIEvent::SCROLL_PAGE_UP;
mouseEvent->InitMouseEvent(NS_LITERAL_STRING("DOMMouseScroll"), PR_TRUE, PR_TRUE,
view, numLines,
msEvent->refPoint.x, msEvent->refPoint.y,
msEvent->point.x, msEvent->point.y,
msEvent->isControl, msEvent->isAlt, msEvent->isShift, msEvent->isMeta,
0, nsnull);
PRBool allowDefault;
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(targetContent));
if (target) {
target->DispatchEvent(event, &allowDefault);
if (!allowDefault)
return NS_OK;
}
}
targetDOMDoc->CreateEvent(NS_LITERAL_STRING("MouseScrollEvents"), getter_AddRefs(event));
if (event) {
nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(event));
}
nsIView* focusView = nsnull;
nsIScrollableView* sv = nsnull;
nsIFrame* focusFrame = nsnull;
// Special case for tree/list frames - they handle their own scrolling
nsITreeFrame* treeFrame = nsnull;
nsCOMPtr<nsIOutlinerBoxObject> outlinerBoxObject;
nsIFrame* curFrame = aTargetFrame;
while (curFrame) {
if (NS_OK == curFrame->QueryInterface(NS_GET_IID(nsITreeFrame),
(void**) &treeFrame))
break;
outlinerBoxObject = do_QueryInterface(curFrame);
if (outlinerBoxObject)
break;
curFrame->GetParent(&curFrame);
}
// Create a mouseout event that we fire to the content before
// scrolling, to allow tooltips to disappear, etc.
@ -1300,27 +1272,8 @@ nsEventStateManager::DoWheelScroll(nsIPresContext* aPresContext,
mouseOutEvent.isAlt = PR_FALSE;
mouseOutEvent.isMeta = PR_FALSE;
nsCOMPtr<nsIContent> targetContent;
aTargetFrame->GetContent(getter_AddRefs(targetContent));
nsEventStatus mouseoutStatus = nsEventStatus_eIgnore;
if (treeFrame) {
if (targetContent)
targetContent->HandleDOMEvent(aPresContext, &mouseOutEvent, nsnull,
NS_EVENT_FLAG_INIT, &mouseoutStatus);
return DoTreeScroll(aPresContext, numLines, scrollPage, treeFrame);
} else if (outlinerBoxObject) {
if (targetContent)
targetContent->HandleDOMEvent(aPresContext, &mouseOutEvent, nsnull,
NS_EVENT_FLAG_INIT, &mouseoutStatus);
if (scrollPage)
outlinerBoxObject->ScrollByPages((numLines > 0) ? 1 : -1);
else
outlinerBoxObject->ScrollByLines(numLines);
return NS_OK;
}
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));

View File

@ -174,8 +174,6 @@ protected:
nsIFrame* aTargetFrame,
nsMouseScrollEvent* msEvent, PRInt32 numLines,
PRBool scrollPage, PRBool aUseTargetFrame);
nsresult DoTreeScroll(nsIPresContext* inPresContext, PRInt32 inNumLines,
PRBool inScrollPage, nsITreeFrame* inTreeFrame);
void ForceViewUpdate(nsIView* aView);
nsresult getPrefService();
nsresult ChangeTextSize(PRInt32 change);

View File

@ -2388,9 +2388,17 @@ nsXULDocument::HandleDOMEvent(nsIPresContext* aPresContext,
{
nsresult ret = NS_OK;
nsIDOMEvent* domEvent = nsnull;
PRBool externalDOMEvent = PR_FALSE;
if (NS_EVENT_FLAG_INIT & aFlags) {
if (aDOMEvent) {
if (*aDOMEvent) {
externalDOMEvent = PR_TRUE;
}
}
else {
aDOMEvent = &domEvent;
}
aEvent->flags = aFlags;
aFlags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL);
}
@ -2414,7 +2422,7 @@ nsXULDocument::HandleDOMEvent(nsIPresContext* aPresContext,
if (NS_EVENT_FLAG_INIT & aFlags) {
// We're leaving the DOM event loop so if we created a DOM event, release here.
if (nsnull != *aDOMEvent) {
if (nsnull != *aDOMEvent && !externalDOMEvent) {
nsrefcnt rc;
NS_RELEASE2(*aDOMEvent, rc);
if (0 != rc) {

View File

@ -61,7 +61,7 @@ interface nsIDOMMouseEvent : nsIDOMUIEvent
in boolean canBubbleArg,
in boolean cancelableArg,
in nsIDOMAbstractView viewArg,
in unsigned short detailArg,
in long detailArg,
in long screenXArg,
in long screenYArg,
in long clientXArg,

View File

@ -43,6 +43,9 @@
[scriptable, uuid(a6cf90c4-15b3-11d2-932e-00805f8add32)]
interface nsIDOMNSUIEvent : nsISupports
{
const long SCROLL_PAGE_UP = -32768;
const long SCROLL_PAGE_DOWN = 32768;
boolean getPreventDefault();
readonly attribute long layerX;

View File

@ -46,6 +46,7 @@ interface nsITreeBoxObject : nsISupports
{
void ensureIndexIsVisible(in long rowIndex);
void scrollToIndex(in long rowIndex);
void scrollByLines(in long numLines);
nsIDOMElement getNextItem(in nsIDOMElement startItem, in long delta);
nsIDOMElement getPreviousItem(in nsIDOMElement startItem, in long delta);

View File

@ -57,6 +57,7 @@ public:
NS_IMETHOD GetNextItem(nsIDOMElement* aStartItem, PRInt32 aDelta, nsIDOMElement** aResult) = 0;
NS_IMETHOD GetPreviousItem(nsIDOMElement* aStartItem, PRInt32 aDelta, nsIDOMElement** aResult) = 0;
NS_IMETHOD ScrollToIndex(PRInt32 aRowIndex) = 0;
NS_IMETHOD ScrollByLines(nsIPresContext* aPresContext, PRInt32 aNumLines)=0;
NS_IMETHOD GetItemAtIndex(PRInt32 aIndex, nsIDOMElement** aResult) = 0;
NS_IMETHOD GetIndexOfItem(nsIPresContext* aPresContext, nsIDOMElement* aElement, PRInt32* aResult) = 0;
NS_IMETHOD GetNumberOfVisibleRows(PRInt32* aResult) = 0;

View File

@ -110,6 +110,19 @@ NS_IMETHODIMP nsTreeBoxObject::ScrollToIndex(PRInt32 aRowIndex)
return treeFrame->ScrollToIndex(aRowIndex);
}
NS_IMETHODIMP
nsTreeBoxObject::ScrollByLines(PRInt32 aNumLines)
{
nsIFrame* frame = GetFrame();
if (!frame)
return NS_OK;
nsCOMPtr<nsITreeFrame> treeFrame(do_QueryInterface(frame));
nsCOMPtr<nsIPresContext> presContext;
mPresShell->GetPresContext(getter_AddRefs(presContext));
return treeFrame->ScrollByLines(presContext, aNumLines);
}
/* nsIDOMElement getNextItem (in nsIDOMElement startItem, in long delta); */
NS_IMETHODIMP nsTreeBoxObject::GetNextItem(nsIDOMElement *aStartItem, PRInt32 aDelta, nsIDOMElement **aResult)
{

View File

@ -154,6 +154,58 @@ nsXULTreeFrame::ScrollToIndex(PRInt32 aRowIndex)
return NS_OK;
}
NS_IMETHODIMP
nsXULTreeFrame::ScrollByLines(nsIPresContext* aPresContext, PRInt32 aNumLines)
{
PRInt32 scrollIndex, visibleRows;
GetIndexOfFirstVisibleRow(&scrollIndex);
GetNumberOfVisibleRows(&visibleRows);
scrollIndex += aNumLines;
if (scrollIndex < 0)
scrollIndex = 0;
else {
PRInt32 numRows;
GetRowCount(&numRows);
PRInt32 lastPageTopRow = numRows - visibleRows;
if (scrollIndex > lastPageTopRow)
scrollIndex = lastPageTopRow;
}
ScrollToIndex(scrollIndex);
// we have to do a sync update for mac because if we scroll too quickly
// w/out going back to the main event loop we can easily scroll the wrong
// bits and it looks like garbage (bug 63465).
nsIFrame* frame = nsnull;
if ( NS_SUCCEEDED(QueryInterface(NS_GET_IID(nsIFrame), (void **)&frame)) ) {
nsIView* treeView = nsnull;
frame->GetView(aPresContext, &treeView);
if (!treeView) {
nsIFrame* frameWithView;
frame->GetParentWithView(aPresContext, &frameWithView);
if (frameWithView)
frameWithView->GetView(aPresContext, &treeView);
else
return NS_ERROR_FAILURE;
}
if (treeView) {
nsCOMPtr<nsIViewManager> vm;
if (treeView->GetViewManager(*getter_AddRefs(vm)) && nsnull != vm) {
// I'd use Composite here, but it doesn't always work.
// vm->Composite();
vm->ForceUpdate();
}
}
}
else
return NS_ERROR_FAILURE;
return NS_OK;
}
/* nsIDOMElement getNextItem (in nsIDOMElement startItem, in long delta); */
NS_IMETHODIMP
nsXULTreeFrame::GetNextItem(nsIDOMElement *aStartItem, PRInt32 aDelta, nsIDOMElement **aResult)

View File

@ -59,6 +59,7 @@ public:
NS_IMETHOD GetNextItem(nsIDOMElement* aStartItem, PRInt32 aDelta, nsIDOMElement** aResult);
NS_IMETHOD GetPreviousItem(nsIDOMElement* aStartItem, PRInt32 aDelta, nsIDOMElement** aResult);
NS_IMETHOD ScrollToIndex(PRInt32 aRowIndex);
NS_IMETHOD ScrollByLines(nsIPresContext* aPresContext, PRInt32 aNumLines);
NS_IMETHOD GetItemAtIndex(PRInt32 aIndex, nsIDOMElement** aResult);
NS_IMETHOD GetIndexOfItem(nsIPresContext* aPresContext, nsIDOMElement* aElement, PRInt32* aResult);
NS_IMETHOD GetNumberOfVisibleRows(PRInt32 *aResult);

View File

@ -23,6 +23,10 @@
</content>
<implementation>
<constructor>
this.addEventListener("DOMMouseScroll", this._handleMouseScroll, true);
</constructor>
<property name="outlinerBoxObject"
onget="return this.boxObject.QueryInterface(Components.interfaces.nsIOutlinerBoxObject);"
readonly="true"/>
@ -58,6 +62,24 @@
<field name="_columnsDirty">true</field>
<field name="_handleMouseScroll">
<![CDATA[
({
subject: this,
handleEvent: function(aEvent)
{
var rows = aEvent.detail;
if (rows == NSUIEvent.SCROLL_PAGE_UP)
this.subject.outlinerBoxObject.scrollByPages(-1);
else if (rows == NSUIEvent.SCROLL_PAGE_DOWN)
this.subject.outlinerBoxObject.scrollByPages(1);
else
this.subject.outlinerBoxObject.scrollByLines(aEvent.detail);
}
})
]]>
</field>
<method name="_ensureColumnOrder">
<body><![CDATA[
if (this._columnsDirty) {

View File

@ -284,6 +284,31 @@
<binding id="treerows"
extends="chrome://global/content/bindings/tree.xml#tree-base">
<content outer="true"/>
<implementation>
<constructor>
this.addEventListener("DOMMouseScroll", this._handleMouseScroll, true);
</constructor>
<field name="_handleMouseScroll">
<![CDATA[
({
subject: this,
handleEvent: function(aEvent)
{
var treeBox = this.subject.parentNode.treeBoxObject;
var rows = aEvent.detail;
if (rows == NSUIEvent.SCROLL_PAGE_UP)
rows = -1 * treeBox.getNumberOfVisibleRows();
else if (rows == NSUIEvent.SCROLL_PAGE_DOWN)
rows = treeBox.getNumberOfVisibleRows();
treeBox.scrollByLines(rows);
}
})
]]>
</field>
</implementation>
<handlers>
<!-- If there is no modifier key, we select on mousedown, not
click, so that drags work correctly. -->