зеркало из https://github.com/mozilla/gecko-dev.git
Bug 503541 - Fine grained control of gesture registration on widgets (Win7). r=smaug+roc, sr=smaug
This commit is contained in:
Родитель
7322fb49a2
Коммит
b0e97d0c8b
|
@ -61,6 +61,7 @@
|
|||
#include "nsIEditorDocShell.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsIComboboxControlFrame.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "nsIDOMNSHTMLElement.h"
|
||||
#include "nsIDOMHTMLAnchorElement.h"
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
|
@ -2492,6 +2493,115 @@ nsEventStateManager::DoScrollText(nsPresContext* aPresContext,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsEventStateManager::DecideGestureEvent(nsGestureNotifyEvent* aEvent,
|
||||
nsIFrame* targetFrame)
|
||||
{
|
||||
|
||||
NS_ASSERTION(aEvent->message == NS_GESTURENOTIFY_EVENT_START,
|
||||
"DecideGestureEvent called with a non-gesture event");
|
||||
|
||||
/* Check the ancestor tree to decide if any frame is willing* to receive
|
||||
* a MozPixelScroll event. If that's the case, the current touch gesture
|
||||
* will be used as a pan gesture; otherwise it will be a regular
|
||||
* mousedown/mousemove/click event.
|
||||
*
|
||||
* *willing: determine if it makes sense to pan the element using scroll events:
|
||||
* - For web content: if there are any visible scrollbars on the touch point
|
||||
* - For XUL: if it's an scrollable element that can currently scroll in some
|
||||
* direction.
|
||||
*
|
||||
* Note: we'll have to one-off various cases to ensure a good usable behavior
|
||||
*/
|
||||
nsGestureNotifyEvent::ePanDirection panDirection = nsGestureNotifyEvent::ePanNone;
|
||||
PRBool displayPanFeedback = PR_FALSE;
|
||||
for (nsIFrame* current = targetFrame; current;
|
||||
current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
|
||||
|
||||
nsIAtom* currentFrameType = current->GetType();
|
||||
|
||||
// Scrollbars should always be draggable
|
||||
if (currentFrameType == nsGkAtoms::scrollbarFrame) {
|
||||
panDirection = nsGestureNotifyEvent::ePanNone;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
// Special check for trees
|
||||
nsTreeBodyFrame* treeFrame = do_QueryFrame(current);
|
||||
if (treeFrame) {
|
||||
if (treeFrame->GetHorizontalOverflow()) {
|
||||
panDirection = nsGestureNotifyEvent::ePanHorizontal;
|
||||
}
|
||||
if (treeFrame->GetVerticalOverflow()) {
|
||||
panDirection = nsGestureNotifyEvent::ePanVertical;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIScrollableFrame* scrollableFrame = do_QueryFrame(current);
|
||||
if (scrollableFrame) {
|
||||
if (current->IsFrameOfType(nsIFrame::eXULBox)) {
|
||||
|
||||
nsIScrollableView* scrollableView = scrollableFrame->GetScrollableView();
|
||||
if (scrollableView) {
|
||||
|
||||
displayPanFeedback = PR_TRUE;
|
||||
|
||||
PRBool canScrollUp, canScrollDown, canScrollLeft, canScrollRight;
|
||||
scrollableView->CanScroll(PR_FALSE, PR_TRUE, canScrollDown);
|
||||
scrollableView->CanScroll(PR_FALSE, PR_FALSE, canScrollUp);
|
||||
scrollableView->CanScroll(PR_TRUE, PR_TRUE, canScrollRight);
|
||||
scrollableView->CanScroll(PR_TRUE, PR_FALSE, canScrollLeft);
|
||||
|
||||
if (targetFrame->GetType() == nsGkAtoms::menuFrame) {
|
||||
// menu frames report horizontal scroll when they have submenus
|
||||
// and we don't want that
|
||||
canScrollRight = PR_FALSE;
|
||||
canScrollLeft = PR_FALSE;
|
||||
displayPanFeedback = PR_FALSE;
|
||||
}
|
||||
|
||||
//Vertical panning has priority over horizontal panning, so
|
||||
//when a vertical movement is detected we can just finish the loop.
|
||||
if (canScrollUp || canScrollDown) {
|
||||
panDirection = nsGestureNotifyEvent::ePanVertical;
|
||||
break;
|
||||
}
|
||||
|
||||
if (canScrollLeft || canScrollRight) {
|
||||
panDirection = nsGestureNotifyEvent::ePanHorizontal;
|
||||
displayPanFeedback = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
} else { //Not a XUL box
|
||||
|
||||
nsMargin scrollbarSizes = scrollableFrame->GetActualScrollbarSizes();
|
||||
|
||||
//Check if we have visible scrollbars
|
||||
if (scrollbarSizes.LeftRight()) {
|
||||
panDirection = nsGestureNotifyEvent::ePanVertical;
|
||||
displayPanFeedback = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (scrollbarSizes.TopBottom()) {
|
||||
panDirection = nsGestureNotifyEvent::ePanHorizontal;
|
||||
displayPanFeedback = PR_TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} //scrollableFrame
|
||||
} //ancestor chain
|
||||
|
||||
aEvent->displayPanFeedback = displayPanFeedback;
|
||||
aEvent->panDirection = panDirection;
|
||||
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEventStateManager::GetParentScrollingView(nsInputEvent *aEvent,
|
||||
nsPresContext* aPresContext,
|
||||
|
@ -2798,6 +2908,13 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
|||
}
|
||||
break;
|
||||
|
||||
case NS_GESTURENOTIFY_EVENT_START:
|
||||
{
|
||||
if (nsEventStatus_eConsumeNoDefault != *aStatus)
|
||||
DecideGestureEvent(static_cast<nsGestureNotifyEvent*>(aEvent), mCurrentTarget);
|
||||
}
|
||||
break;
|
||||
|
||||
case NS_DRAGDROP_ENTER:
|
||||
case NS_DRAGDROP_OVER:
|
||||
{
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
#include "nsIEventStateManager.h"
|
||||
#include "nsEvent.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
@ -278,6 +279,16 @@ protected:
|
|||
nsresult ChangeFullZoom(PRInt32 change);
|
||||
// end mousewheel functions
|
||||
|
||||
/*
|
||||
* When a touch gesture is about to start, this function determines what
|
||||
* kind of gesture interaction we will want to use, based on what is
|
||||
* underneath the initial touch point.
|
||||
* Currently it decides between panning (finger scrolling) or dragging
|
||||
* the target element, as well as the orientation to trigger panning and
|
||||
* display visual boundary feedback. The decision is stored back in aEvent.
|
||||
*/
|
||||
void DecideGestureEvent(nsGestureNotifyEvent* aEvent, nsIFrame* targetFrame);
|
||||
|
||||
// routines for the d&d gesture tracking state machine
|
||||
void BeginTrackingDragGesture ( nsPresContext* aPresContext, nsMouseEvent* inDownEvent,
|
||||
nsIFrame* inDownFrame ) ;
|
||||
|
|
|
@ -648,6 +648,7 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aF
|
|||
aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
|
||||
aEvent->eventStructType != NS_DRAG_EVENT &&
|
||||
aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT &&
|
||||
aEvent->eventStructType != NS_GESTURENOTIFY_EVENT &&
|
||||
aEvent->eventStructType != NS_QUERY_CONTENT_EVENT))
|
||||
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
|
||||
|
|
|
@ -186,6 +186,9 @@ public:
|
|||
|
||||
nsITreeBoxObject* GetTreeBoxObject() const { return mTreeBoxObject; }
|
||||
|
||||
PRBool GetVerticalOverflow() const { return mVerticalOverflow; }
|
||||
PRBool GetHorizontalOverflow() const {return mHorizontalOverflow; }
|
||||
|
||||
protected:
|
||||
friend class nsOverflowChecker;
|
||||
|
||||
|
|
|
@ -105,6 +105,7 @@ class nsHashKey;
|
|||
#define NS_SIMPLE_GESTURE_EVENT 37
|
||||
#define NS_SELECTION_EVENT 38
|
||||
#define NS_CONTENT_COMMAND_EVENT 39
|
||||
#define NS_GESTURENOTIFY_EVENT 40
|
||||
|
||||
// These flags are sort of a mess. They're sort of shared between event
|
||||
// listener flags and event flags, but only some of them. You've been
|
||||
|
@ -429,6 +430,9 @@ class nsHashKey;
|
|||
#define NS_CONTENT_COMMAND_UNDO (NS_CONTENT_COMMAND_EVENT_START+4)
|
||||
#define NS_CONTENT_COMMAND_REDO (NS_CONTENT_COMMAND_EVENT_START+5)
|
||||
|
||||
// Event to gesture notification
|
||||
#define NS_GESTURENOTIFY_EVENT_START 3900
|
||||
|
||||
/**
|
||||
* Return status for event processors, nsEventStatus, is defined in
|
||||
* nsEvent.h.
|
||||
|
@ -1074,6 +1078,38 @@ public:
|
|||
PRInt32 scrollOverflow;
|
||||
};
|
||||
|
||||
/*
|
||||
* Gesture Notify Event:
|
||||
*
|
||||
* This event is the first event generated when the user touches
|
||||
* the screen with a finger, and it's meant to decide what kind
|
||||
* of action we'll use for that touch interaction.
|
||||
*
|
||||
* The event is dispatched to the layout and based on what is underneath
|
||||
* the initial contact point it's then decided if we should pan
|
||||
* (finger scrolling) or drag the target element.
|
||||
*/
|
||||
class nsGestureNotifyEvent : public nsGUIEvent
|
||||
{
|
||||
public:
|
||||
enum ePanDirection {
|
||||
ePanNone,
|
||||
ePanVertical,
|
||||
ePanHorizontal,
|
||||
ePanBoth
|
||||
};
|
||||
|
||||
ePanDirection panDirection;
|
||||
PRPackedBool displayPanFeedback;
|
||||
|
||||
nsGestureNotifyEvent(PRBool aIsTrusted, PRUint32 aMsg, nsIWidget *aWidget):
|
||||
nsGUIEvent(aIsTrusted, aMsg, aWidget, NS_GESTURENOTIFY_EVENT),
|
||||
panDirection(ePanNone),
|
||||
displayPanFeedback(PR_FALSE)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class nsQueryContentEvent : public nsGUIEvent
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -144,7 +144,7 @@ PRBool nsWinGesture::InitLibrary()
|
|||
|
||||
#define GCOUNT 5
|
||||
|
||||
PRBool nsWinGesture::InitWinGestureSupport(HWND hWnd)
|
||||
PRBool nsWinGesture::SetWinGestureSupport(HWND hWnd, nsGestureNotifyEvent::ePanDirection aDirection)
|
||||
{
|
||||
if (!getGestureInfo)
|
||||
return PR_FALSE;
|
||||
|
@ -162,17 +162,27 @@ PRBool nsWinGesture::InitWinGestureSupport(HWND hWnd)
|
|||
config[1].dwBlock = 0;
|
||||
|
||||
config[2].dwID = GID_PAN;
|
||||
config[2].dwWant = GC_PAN|GC_PAN_WITH_INERTIA|
|
||||
GC_PAN_WITH_GUTTER;
|
||||
config[2].dwBlock = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY|
|
||||
GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
|
||||
|
||||
if (gEnableSingleFingerPanEvents) {
|
||||
config[2].dwWant = GC_PAN|GC_PAN_WITH_INERTIA|
|
||||
GC_PAN_WITH_GUTTER|
|
||||
GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
|
||||
config[2].dwBlock = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
|
||||
}
|
||||
else {
|
||||
config[2].dwWant = GC_PAN|GC_PAN_WITH_INERTIA|
|
||||
GC_PAN_WITH_GUTTER;
|
||||
config[2].dwBlock = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY|
|
||||
GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
|
||||
|
||||
if (aDirection == nsGestureNotifyEvent::ePanVertical ||
|
||||
aDirection == nsGestureNotifyEvent::ePanBoth)
|
||||
{
|
||||
config[2].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
|
||||
config[2].dwBlock -= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
|
||||
}
|
||||
|
||||
if (aDirection == nsGestureNotifyEvent::ePanHorizontal ||
|
||||
aDirection == nsGestureNotifyEvent::ePanBoth)
|
||||
{
|
||||
config[2].dwWant |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
|
||||
config[2].dwBlock -= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
config[3].dwWant = GC_TWOFINGERTAP;
|
||||
|
|
|
@ -194,7 +194,7 @@ public:
|
|||
nsWinGesture();
|
||||
|
||||
public:
|
||||
PRBool InitWinGestureSupport(HWND hWnd);
|
||||
PRBool SetWinGestureSupport(HWND hWnd, nsGestureNotifyEvent::ePanDirection aDirection);
|
||||
PRBool ShutdownWinGestureSupport();
|
||||
PRBool IsAvailable();
|
||||
|
||||
|
|
|
@ -436,6 +436,7 @@ nsWindow::nsWindow() : nsBaseWidget()
|
|||
mWindowType = eWindowType_child;
|
||||
mBorderStyle = eBorderStyle_default;
|
||||
mPopupType = ePopupTypeAny;
|
||||
mDisplayPanFeedback = PR_FALSE;
|
||||
mLastPoint.x = 0;
|
||||
mLastPoint.y = 0;
|
||||
mLastSize.width = 0;
|
||||
|
@ -715,20 +716,6 @@ nsWindow::StandardWindowCreate(nsIWidget *aParent,
|
|||
nsWindowCE::CreateSoftKeyMenuBar(mWnd);
|
||||
#endif
|
||||
|
||||
#if !defined(WINCE)
|
||||
// Enable gesture support for this window.
|
||||
if (mWindowType != eWindowType_invisible &&
|
||||
mWindowType != eWindowType_plugin &&
|
||||
mWindowType != eWindowType_java &&
|
||||
mWindowType != eWindowType_toplevel) {
|
||||
// eWindowType_toplevel is the top level main frame window. Gesture support
|
||||
// there prevents the user from interacting with the title bar or nc
|
||||
// areas using a single finger. Java and plugin windows can make their
|
||||
// own calls.
|
||||
mGesture.InitWinGestureSupport(mWnd);
|
||||
}
|
||||
#endif // !defined(WINCE)
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -4148,6 +4135,31 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
|
|||
case WM_GESTURE:
|
||||
result = OnGesture(wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_GESTURENOTIFY:
|
||||
{
|
||||
if (mWindowType != eWindowType_invisible &&
|
||||
mWindowType != eWindowType_plugin &&
|
||||
mWindowType != eWindowType_java &&
|
||||
mWindowType != eWindowType_toplevel) {
|
||||
// eWindowType_toplevel is the top level main frame window. Gesture support
|
||||
// there prevents the user from interacting with the title bar or nc
|
||||
// areas using a single finger. Java and plugin windows can make their
|
||||
// own calls.
|
||||
GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam;
|
||||
nsPointWin touchPoint;
|
||||
touchPoint = gestureinfo->ptsLocation;
|
||||
touchPoint.ScreenToClient(mWnd);
|
||||
nsGestureNotifyEvent gestureNotifyEvent(PR_TRUE, NS_GESTURENOTIFY_EVENT_START, this);
|
||||
gestureNotifyEvent.refPoint = touchPoint;
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&gestureNotifyEvent, status);
|
||||
mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback;
|
||||
mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection);
|
||||
}
|
||||
result = PR_FALSE; //should always bubble to DefWindowProc
|
||||
}
|
||||
break;
|
||||
#endif // !defined(WINCE)
|
||||
|
||||
case WM_CLEAR:
|
||||
|
@ -4735,7 +4747,7 @@ PRBool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam)
|
|||
scrollOverflowY = event.scrollOverflow;
|
||||
}
|
||||
|
||||
if (mWindowType != eWindowType_popup) {
|
||||
if (mDisplayPanFeedback) {
|
||||
mGesture.UpdatePanFeedbackX(mWnd, scrollOverflowX, endFeedback);
|
||||
mGesture.UpdatePanFeedbackY(mWnd, scrollOverflowY, endFeedback);
|
||||
mGesture.PanFeedbackFinalize(mWnd, endFeedback);
|
||||
|
|
|
@ -414,6 +414,7 @@ protected:
|
|||
HKL mLastKeyboardLayout;
|
||||
nsPopupType mPopupType;
|
||||
int mScrollSeriesCounter;
|
||||
PRPackedBool mDisplayPanFeedback;
|
||||
|
||||
static PRUint32 sInstanceCount;
|
||||
static TriStateBool sCanQuit;
|
||||
|
|
Загрузка…
Ссылка в новой задаче