Update :hover state and mouse cursor and send mouse events when the position of the pointer changes due to scrolling or reflow. b=20022 r=roc sr=bryner

This commit is contained in:
dbaron%dbaron.org 2004-02-04 00:11:59 +00:00
Родитель 9f8a1c2d19
Коммит b506c7e4d8
8 изменённых файлов: 180 добавлений и 108 удалений

Просмотреть файл

@ -1581,11 +1581,6 @@ nsEventStateManager::DoWheelScroll(nsIPresContext* aPresContext,
nsIScrollableView* sv = nsnull;
nsIFrame* focusFrame = nsnull;
// Create a mouseout event that we fire to the content before
// scrolling, to allow tooltips to disappear, etc.
nsMouseEvent mouseOutEvent(NS_MOUSE_EXIT, aMSEvent->widget);
nsIPresShell *presShell = aPresContext->PresShell();
// Otherwise, check for a focused content element
@ -1627,8 +1622,6 @@ nsEventStateManager::DoWheelScroll(nsIPresContext* aPresContext,
PRBool passToParent;
if (sv) {
GenerateMouseEnterExit(aPresContext, &mouseOutEvent);
// If we're already at the scroll limit for this view, scroll the
// parent view instead.

Просмотреть файл

@ -1292,6 +1292,7 @@ protected:
nsresult WillCauseReflow();
nsresult DidCauseReflow();
void DidDoReflow();
nsresult ProcessReflowCommands(PRBool aInterruptible);
nsresult ClearReflowEventStatus();
void PostReflowEvent();
@ -2847,10 +2848,7 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
}
DidCauseReflow();
HandlePostedDOMEvents();
HandlePostedAttributeChanges();
HandlePostedReflowCallbacks();
DidDoReflow();
if (mViewManager && mCaret && !mViewEventListener) {
nsIScrollableView* scrollingView = nsnull;
@ -2996,9 +2994,7 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
}
#endif
HandlePostedDOMEvents();
HandlePostedAttributeChanges();
HandlePostedReflowCallbacks();
DidDoReflow();
if (!firstReflow) {
//Set resize event timer
@ -3514,10 +3510,7 @@ PresShell::StyleChangeReflow()
}
DidCauseReflow();
HandlePostedDOMEvents();
HandlePostedAttributeChanges();
HandlePostedReflowCallbacks();
DidDoReflow();
return NS_OK; //XXX this needs to be real. MMP
}
@ -4879,6 +4872,8 @@ PresShell::UnsuppressAndInvalidate()
if (focusController) // Unsuppress now that we've shown the new window and focused it.
focusController->SetSuppressFocus(PR_FALSE, "PresShell suppression on Web page loads");
mViewManager->SynthesizeMouseMove(PR_FALSE);
}
NS_IMETHODIMP
@ -6090,7 +6085,7 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
aStatus, aView);
// 2. Give event to the DOM for third party and JS use.
if ((GetCurrentEventFrame()) && NS_SUCCEEDED (rv)) {
if ((GetCurrentEventFrame()) && NS_SUCCEEDED(rv)) {
if (mCurrentEventContent) {
rv = mCurrentEventContent->HandleDOMEvent(mPresContext, aEvent, nsnull,
aFlags, aStatus);
@ -6334,6 +6329,16 @@ PresShell::DidCauseReflow()
return NS_OK;
}
void
PresShell::DidDoReflow()
{
HandlePostedDOMEvents();
HandlePostedAttributeChanges();
HandlePostedReflowCallbacks();
if (!mPaintingSuppressed)
mViewManager->SynthesizeMouseMove(PR_FALSE);
}
nsresult
PresShell::ProcessReflowCommands(PRBool aInterruptible)
{
@ -6468,15 +6473,13 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible)
// If there are no more reflow commands in the queue, we'll want
// to remove the ``dummy request''.
DoneRemovingReflowCommands();
DidDoReflow();
}
MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this));
MOZ_TIMER_STOP(mReflowWatch);
HandlePostedDOMEvents();
HandlePostedAttributeChanges();
HandlePostedReflowCallbacks();
if (mShouldUnsuppressPainting && mReflowCommands.Count() == 0) {
// We only unlock if we're out of reflows. It's pointless
// to unlock if reflows are still pending, since reflows

Просмотреть файл

@ -1292,6 +1292,7 @@ protected:
nsresult WillCauseReflow();
nsresult DidCauseReflow();
void DidDoReflow();
nsresult ProcessReflowCommands(PRBool aInterruptible);
nsresult ClearReflowEventStatus();
void PostReflowEvent();
@ -2847,10 +2848,7 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
}
DidCauseReflow();
HandlePostedDOMEvents();
HandlePostedAttributeChanges();
HandlePostedReflowCallbacks();
DidDoReflow();
if (mViewManager && mCaret && !mViewEventListener) {
nsIScrollableView* scrollingView = nsnull;
@ -2996,9 +2994,7 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
}
#endif
HandlePostedDOMEvents();
HandlePostedAttributeChanges();
HandlePostedReflowCallbacks();
DidDoReflow();
if (!firstReflow) {
//Set resize event timer
@ -3514,10 +3510,7 @@ PresShell::StyleChangeReflow()
}
DidCauseReflow();
HandlePostedDOMEvents();
HandlePostedAttributeChanges();
HandlePostedReflowCallbacks();
DidDoReflow();
return NS_OK; //XXX this needs to be real. MMP
}
@ -4879,6 +4872,8 @@ PresShell::UnsuppressAndInvalidate()
if (focusController) // Unsuppress now that we've shown the new window and focused it.
focusController->SetSuppressFocus(PR_FALSE, "PresShell suppression on Web page loads");
mViewManager->SynthesizeMouseMove(PR_FALSE);
}
NS_IMETHODIMP
@ -6090,7 +6085,7 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
aStatus, aView);
// 2. Give event to the DOM for third party and JS use.
if ((GetCurrentEventFrame()) && NS_SUCCEEDED (rv)) {
if ((GetCurrentEventFrame()) && NS_SUCCEEDED(rv)) {
if (mCurrentEventContent) {
rv = mCurrentEventContent->HandleDOMEvent(mPresContext, aEvent, nsnull,
aFlags, aStatus);
@ -6334,6 +6329,16 @@ PresShell::DidCauseReflow()
return NS_OK;
}
void
PresShell::DidDoReflow()
{
HandlePostedDOMEvents();
HandlePostedAttributeChanges();
HandlePostedReflowCallbacks();
if (!mPaintingSuppressed)
mViewManager->SynthesizeMouseMove(PR_FALSE);
}
nsresult
PresShell::ProcessReflowCommands(PRBool aInterruptible)
{
@ -6468,15 +6473,13 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible)
// If there are no more reflow commands in the queue, we'll want
// to remove the ``dummy request''.
DoneRemovingReflowCommands();
DidDoReflow();
}
MOZ_TIMER_DEBUGLOG(("Stop: Reflow: PresShell::ProcessReflowCommands(), this=%p\n", this));
MOZ_TIMER_STOP(mReflowWatch);
HandlePostedDOMEvents();
HandlePostedAttributeChanges();
HandlePostedReflowCallbacks();
if (mShouldUnsuppressPainting && mReflowCommands.Count() == 0) {
// We only unlock if we're out of reflows. It's pointless
// to unlock if reflows are still pending, since reflows

Просмотреть файл

@ -520,6 +520,12 @@ public:
PRUint16 aMinTwips,
nsRectVisibility *aRectVisibility)=0;
/**
* Dispatch a mouse move event based on the most recent mouse
* position. This is used when the contents of the page moved
* (aFromScroll is false) or scrolled (aFromScroll is true).
*/
NS_IMETHOD SynthesizeMouseMove(PRBool aFromScroll)=0;
};
//update view now?

Просмотреть файл

@ -646,6 +646,8 @@ NS_IMETHODIMP nsScrollPortView::ScrollToImpl(nscoord aX, nscoord aY, PRUint32 aU
mOffsetY = aY;
Scroll(scrolledView, dxPx, dyPx, t2p, 0);
mViewManager->SynthesizeMouseMove(PR_TRUE);
// notify the listeners.
if (nsnull != mListeners) {

Просмотреть файл

@ -317,60 +317,49 @@ static void PrintZTreeNode(DisplayZTreeNode* aNode, PRInt32 aIndent)
//-------------- Begin Invalidate Event Definition ------------------------
struct nsInvalidateEvent : public PLEvent {
nsInvalidateEvent(nsViewManager* aViewManager);
~nsInvalidateEvent() { }
struct nsViewManagerEvent : public PLEvent {
nsViewManagerEvent(nsViewManager* aViewManager);
~nsViewManagerEvent() { }
void HandleEvent() {
NS_ASSERTION(nsnull != mViewManager,"ViewManager is null");
// Search for valid view manager before trying to access it
// This is just a safety check. We should never have a circumstance
// where the view manager has been destroyed and the invalidate event
// which it owns is still around. The invalidate event should be destroyed
// by the RevokeEvent in the viewmanager's destructor.
PRBool found = PR_FALSE;
PRInt32 index;
PRInt32 count = nsViewManager::GetViewManagerCount();
const nsVoidArray* viewManagers = nsViewManager::GetViewManagerArray();
for (index = 0; index < count; index++) {
nsViewManager* vm = (nsViewManager*)viewManagers->ElementAt(index);
if (vm == mViewManager) {
found = PR_TRUE;
}
}
virtual void HandleEvent() = 0;
if (found) {
mViewManager->ProcessInvalidateEvent();
} else {
NS_ASSERTION(PR_FALSE, "bad view manager asked to process invalidate event");
}
};
nsViewManager* mViewManager; // Weak Reference. The viewmanager will destroy any pending
// invalidate events in it's destructor.
nsViewManager* ViewManager() {
// |owner| is a weak pointer, but the view manager will destroy any
// pending invalidate events in it's destructor.
return NS_STATIC_CAST(nsViewManager*, owner);
}
};
static void PR_CALLBACK HandlePLEvent(nsInvalidateEvent* aEvent)
static void* PR_CALLBACK HandlePLEvent(PLEvent* aEvent)
{
NS_ASSERTION(nsnull != aEvent,"Event is null");
aEvent->HandleEvent();
nsViewManagerEvent *event = NS_STATIC_CAST(nsViewManagerEvent*, aEvent);
event->HandleEvent();
return nsnull;
}
static void PR_CALLBACK DestroyPLEvent(nsInvalidateEvent* aEvent)
static void PR_CALLBACK DestroyPLEvent(PLEvent* aEvent)
{
NS_ASSERTION(nsnull != aEvent,"Event is null");
delete aEvent;
nsViewManagerEvent *event = NS_STATIC_CAST(nsViewManagerEvent*, aEvent);
delete event;
}
nsInvalidateEvent::nsInvalidateEvent(nsViewManager* aViewManager)
nsViewManagerEvent::nsViewManagerEvent(nsViewManager* aViewManager)
{
NS_ASSERTION(aViewManager, "null parameter");
mViewManager = aViewManager; // Assign weak reference
PL_InitEvent(this, aViewManager,
(PLHandleEventProc) ::HandlePLEvent,
(PLDestroyEventProc) ::DestroyPLEvent);
PL_InitEvent(this, aViewManager, ::HandlePLEvent, ::DestroyPLEvent);
}
struct nsInvalidateEvent : public nsViewManagerEvent {
nsInvalidateEvent(nsViewManager *aViewManager)
: nsViewManagerEvent(aViewManager) { }
virtual void HandleEvent() {
ViewManager()->ProcessInvalidateEvent();
}
};
//-------------- End Invalidate Event Definition ---------------------------
// Compare two Z-index values taking into account topmost and
@ -398,9 +387,8 @@ void
nsViewManager::PostInvalidateEvent()
{
nsCOMPtr<nsIEventQueue> eventQueue;
mEventQueueService->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
getter_AddRefs(eventQueue));
mEventQueueService->GetSpecialEventQueue(
nsIEventQueueService::UI_THREAD_EVENT_QUEUE, getter_AddRefs(eventQueue));
NS_ASSERTION(nsnull != eventQueue, "Event queue is null");
if (eventQueue != mInvalidateEventQueue) {
@ -417,7 +405,10 @@ nsIRenderingContext* nsViewManager::gCleanupContext = nsnull;
nsVoidArray* nsViewManager::gViewManagers = nsnull;
PRUint32 nsViewManager::gLastUserEventTime = 0;
#define NOT_IN_WINDOW PR_INT32_MIN
nsViewManager::nsViewManager()
: mMouseLocation(NOT_IN_WINDOW, NOT_IN_WINDOW)
{
if (gViewManagers == nsnull) {
NS_ASSERTION(mVMCount == 0, "View Manager count is incorrect");
@ -460,6 +451,7 @@ nsViewManager::~nsViewManager()
NS_ASSERTION(nsnull != eventQueue, "Event queue is null");
eventQueue->RevokeEvents(this);
mInvalidateEventQueue = nsnull;
mSynthMouseMoveEventQueue = nsnull;
NS_IF_RELEASE(mRootWindow);
@ -468,7 +460,10 @@ nsViewManager::~nsViewManager()
NS_ASSERTION((mVMCount > 0), "underflow of viewmanagers");
--mVMCount;
PRBool removed = gViewManagers->RemoveElement(this);
#ifdef DEBUG
PRBool removed =
#endif
gViewManagers->RemoveElement(this);
NS_ASSERTION(removed, "Viewmanager instance not was not in the global list of viewmanagers");
if (0 == mVMCount) {
@ -1968,27 +1963,33 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
}
if (nsnull != view) {
float t2p;
mContext->GetAppUnitsToDevUnits(t2p);
float p2t;
mContext->GetDevUnitsToAppUnits(p2t);
//Calculate the proper offset for the view we're going to
offset.x = offset.y = 0;
if (baseView != view) {
//Get offset from root of baseView
nsView *parent;
parent = baseView;
while (mRootView != parent) {
parent->ConvertToParentCoords(&offset.x, &offset.y);
parent = parent->GetParent();
}
//Get offset from root of baseView
for (nsView *parent = baseView; parent != mRootView;
parent = parent->GetParent())
parent->ConvertToParentCoords(&offset.x, &offset.y);
//Subtract back offset from root of view
parent = view;
while (mRootView != parent) {
parent->ConvertFromParentCoords(&offset.x, &offset.y);
parent = parent->GetParent();
}
if (aEvent->message == NS_MOUSE_MOVE) {
mMouseLocation.MoveTo(NSTwipsToIntPixels(offset.x, t2p) +
aEvent->point.x,
NSTwipsToIntPixels(offset.y, t2p) +
aEvent->point.y);
} else if (aEvent->message == NS_MOUSE_EXIT && view == mRootView) {
mMouseLocation.MoveTo(NOT_IN_WINDOW, NOT_IN_WINDOW);
}
//Subtract back offset from root of view
for (nsView *parent = view; parent != mRootView;
parent = parent->GetParent())
parent->ConvertFromParentCoords(&offset.x, &offset.y);
//Dispatch the event
//Before we start mucking with coords, make sure we know our baseline
aEvent->refPoint.x = aEvent->point.x;
@ -1999,11 +2000,6 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
baseView->GetDimensions(baseViewDimensions);
}
float t2p;
mContext->GetAppUnitsToDevUnits(t2p);
float p2t;
mContext->GetDevUnitsToAppUnits(p2t);
aEvent->point.x = baseViewDimensions.x + NSIntPixelsToTwips(aEvent->point.x, p2t);
aEvent->point.y = baseViewDimensions.y + NSIntPixelsToTwips(aEvent->point.y, p2t);
@ -2014,8 +2010,6 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
// From here on out, "this" could have been deleted!!!
// From here on out, "this" could have been deleted!!!
aEvent->point.x -= offset.x;
aEvent->point.y -= offset.y;
@ -4024,11 +4018,11 @@ nsViewManager::FlushPendingInvalidates()
return NS_OK;
}
nsresult
nsViewManager::ProcessInvalidateEvent() {
void
nsViewManager::ProcessInvalidateEvent()
{
FlushPendingInvalidates();
mInvalidateEventQueue = nsnull;
return NS_OK;
}
nsresult
@ -4076,3 +4070,64 @@ nsViewManager::GetLastUserEventTime(PRUint32& aTime)
aTime = gLastUserEventTime;
return NS_OK;
}
struct nsSynthMouseMoveEvent : public nsViewManagerEvent {
nsSynthMouseMoveEvent(nsViewManager *aViewManager, PRBool aFromScroll)
: nsViewManagerEvent(aViewManager),
mFromScroll(aFromScroll)
{
}
virtual void HandleEvent() {
ViewManager()->ProcessSynthMouseMoveEvent(mFromScroll);
}
PRBool mFromScroll;
};
NS_IMETHODIMP
nsViewManager::SynthesizeMouseMove(PRBool aFromScroll)
{
if (mMouseLocation == nsPoint(NOT_IN_WINDOW, NOT_IN_WINDOW))
return NS_OK;
nsCOMPtr<nsIEventQueue> eventQueue;
mEventQueueService->GetSpecialEventQueue(
nsIEventQueueService::UI_THREAD_EVENT_QUEUE, getter_AddRefs(eventQueue));
NS_ASSERTION(nsnull != eventQueue, "Event queue is null");
if (eventQueue != mSynthMouseMoveEventQueue) {
nsSynthMouseMoveEvent *ev = new nsSynthMouseMoveEvent(this, aFromScroll);
eventQueue->PostEvent(ev);
mSynthMouseMoveEventQueue = eventQueue;
}
return NS_OK;
}
void
nsViewManager::ProcessSynthMouseMoveEvent(PRBool aFromScroll)
{
// allow new event to be posted while handling this one only if the
// source of the event is a scroll (to prevent infinite reflow loops)
if (aFromScroll)
mSynthMouseMoveEventQueue = nsnull;
if (mMouseLocation == nsPoint(NOT_IN_WINDOW, NOT_IN_WINDOW)) {
mSynthMouseMoveEventQueue = nsnull;
return;
}
nsMouseEvent event(NS_MOUSE_MOVE, mRootView->GetWidget(),
nsMouseEvent::eSynthesized);
event.point = mMouseLocation;
event.time = PR_IntervalNow();
// XXX set event.isShift, event.isControl, event.isAlt, event.isMeta ?
nsEventStatus status;
DispatchEvent(&event, &status);
if (!aFromScroll)
mSynthMouseMoveEventQueue = nsnull;
}

Просмотреть файл

@ -61,6 +61,7 @@ class nsISupportsArray;
struct DisplayListElement2;
struct DisplayZTreeNode;
class BlendingBuffers;
struct nsViewManagerEvent;
//Uncomment the following line to enable generation of viewmanager performance data.
#ifdef MOZ_PERF_METRICS
@ -213,7 +214,7 @@ public:
NS_IMETHOD SetDefaultBackgroundColor(nscolor aColor);
NS_IMETHOD GetDefaultBackgroundColor(nscolor* aColor);
NS_IMETHOD GetLastUserEventTime(PRUint32& aTime);
nsresult ProcessInvalidateEvent();
void ProcessInvalidateEvent();
static PRInt32 GetViewManagerCount();
static const nsVoidArray* GetViewManagerArray();
static PRUint32 gLastUserEventTime;
@ -232,6 +233,9 @@ public:
PRUint16 aMinTwips,
nsRectVisibility *aRectVisibility);
NS_IMETHOD SynthesizeMouseMove(PRBool aFromScroll);
void ProcessSynthMouseMoveEvent(PRBool aFromScroll);
protected:
virtual ~nsViewManager();
void ProcessPendingUpdates(nsView *aView);
@ -389,6 +393,7 @@ private:
nsIScrollableView *mRootScrollable;
PRInt32 mCachingWidgetChanges;
nscolor mDefaultBackgroundColor;
nsPoint mMouseLocation; // device units, relative to mRootView
nsHashtable mMapPlaceholderViewToZTreeNode;
@ -415,6 +420,7 @@ protected:
PRBool mHasPendingInvalidates;
nsCOMPtr<nsIEventQueueService> mEventQueueService;
nsCOMPtr<nsIEventQueue> mInvalidateEventQueue;
nsCOMPtr<nsIEventQueue> mSynthMouseMoveEventQueue;
void PostInvalidateEvent();
#ifdef NS_VM_PERF_METRICS

Просмотреть файл

@ -351,11 +351,14 @@ struct nsInputEvent : public nsGUIEvent
struct nsMouseEvent : public nsInputEvent
{
enum reasonType { eReal, eSynthesized };
nsMouseEvent(PRUint32 msg = 0,
nsIWidget *w = nsnull,
reasonType aReason = eReal,
PRUint8 structType = NS_MOUSE_EVENT)
: nsInputEvent(msg, w, structType),
clickCount(0), acceptActivation(PR_FALSE)
clickCount(0), acceptActivation(PR_FALSE), reason(aReason)
{
}
@ -364,6 +367,7 @@ struct nsMouseEvent : public nsInputEvent
/// Special return code for MOUSE_ACTIVATE to signal
/// if the target accepts activation (1), or denies it (0)
PRBool acceptActivation;
reasonType reason;
};
/**