Bug 297080 - "Mouse cursor stays in pointer form, moving from content area to other window" [p=kinetik@flim.org (Matthew Gregan) r+sr=roc a1.9=damons]

This commit is contained in:
reed@reedloden.com 2008-03-12 15:44:45 -07:00
Родитель 75b740fd49
Коммит e17d7baefa
6 изменённых файлов: 62 добавлений и 27 удалений

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

@ -827,24 +827,12 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
}
break;
case NS_MOUSE_EXIT:
// If the event coordinate is within the bounds of the view,
// and this is not the top-level window, then it's not really
// an exit --- we may have traversed widget boundaries but
// If the event is not a top-level window exit, then it's not
// really an exit --- we may have traversed widget boundaries but
// we're still in our toplevel window.
// On the other hand, if we exit a toplevel window, then
// it's really an exit even if the mouse is still in the
// window bounds --- the mouse probably moved into some
// "on top" window.
{
nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
nsIWidget* parentWidget = mouseEvent->widget->GetParent();
nsPoint eventPoint;
eventPoint = nsLayoutUtils::TranslateWidgetToView(aPresContext,
mouseEvent->widget,
mouseEvent->refPoint,
aView);
if (parentWidget &&
(aView->GetBounds() - aView->GetPosition()).Contains(eventPoint)) {
if (mouseEvent->exit != nsMouseEvent::eTopLevel) {
// treat it as a move so we don't generate spurious "exit"
// events Any necessary exit events will be generated by
// GenerateMouseEnterExit

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

@ -649,12 +649,13 @@ public:
enum buttonType { eLeftButton = 0, eMiddleButton = 1, eRightButton = 2 };
enum reasonType { eReal, eSynthesized };
enum contextType { eNormal, eContextMenuKey };
enum exitType { eChild, eTopLevel };
nsMouseEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w,
reasonType aReason, contextType aContext = eNormal)
: nsMouseEvent_base(isTrusted, msg, w, NS_MOUSE_EVENT),
acceptActivation(PR_FALSE), reason(aReason), context(aContext),
clickCount(0)
exit(eChild), clickCount(0)
{
if (msg == NS_MOUSE_MOVE) {
flags |= NS_EVENT_FLAG_CANT_CANCEL;
@ -676,6 +677,7 @@ public:
PRPackedBool acceptActivation;
reasonType reason : 4;
contextType context : 4;
exitType exit;
/// The number of mouse clicks
PRUint32 clickCount;

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

@ -1524,6 +1524,10 @@ NS_IMETHODIMP nsChildView::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect)
// Invokes callback and ProcessEvent methods on Event Listener object
NS_IMETHODIMP nsChildView::DispatchEvent(nsGUIEvent* event, nsEventStatus& aStatus)
{
#ifdef DEBUG
debug_DumpEvent(stdout, event->widget, event, nsCAutoString("something"), 0);
#endif
aStatus = nsEventStatus_eIgnore;
nsCOMPtr<nsIWidget> kungFuDeathGrip(mParentWidget ? mParentWidget : this);
@ -2884,7 +2888,8 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
PRUint32 msg,
nsIWidget *widget,
nsMouseEvent::reasonType aReason,
NSPoint* localEventLocation)
NSPoint* localEventLocation,
nsMouseEvent::exitType type)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
@ -2903,6 +2908,8 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
macEvent.modifiers = ::GetCurrentEventKeyModifiers();
event.nativeMsg = &macEvent;
event.exit = type;
nsEventStatus status;
widget->DispatchEvent(&event, status);
return status;
@ -2944,7 +2951,8 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
if (sLastViewEntered) {
nsIWidget* lastViewEnteredWidget = [(NSView<mozView>*)sLastViewEntered widget];
NSPoint exitEventLocation = [sLastViewEntered convertPoint:windowEventLocation fromView:nil];
SendGeckoMouseEnterOrExitEvent(PR_TRUE, NS_MOUSE_EXIT, lastViewEnteredWidget, nsMouseEvent::eReal, &exitEventLocation);
SendGeckoMouseEnterOrExitEvent(PR_TRUE, NS_MOUSE_EXIT, lastViewEnteredWidget, nsMouseEvent::eReal,
&exitEventLocation, nsMouseEvent::eChild);
sLastViewEntered = nil;
}
return;
@ -2968,7 +2976,8 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
NSPoint exitEventLocation = [sLastViewEntered convertPoint:windowEventLocation fromView:nil];
// NSLog(@"sending NS_MOUSE_EXIT event with point %f,%f\n", exitEventLocation.x, exitEventLocation.y);
nsIWidget* lastViewEnteredWidget = [(NSView<mozView>*)sLastViewEntered widget];
SendGeckoMouseEnterOrExitEvent(PR_TRUE, NS_MOUSE_EXIT, lastViewEnteredWidget, nsMouseEvent::eReal, &exitEventLocation);
SendGeckoMouseEnterOrExitEvent(PR_TRUE, NS_MOUSE_EXIT, lastViewEnteredWidget, nsMouseEvent::eReal,
&exitEventLocation, nsMouseEvent::eTopLevel);
sLastViewEntered = nil;
}
return;
@ -2985,7 +2994,8 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
NSPoint exitEventLocation = [sLastViewEntered convertPoint:windowEventLocation fromView:nil];
// NSLog(@"sending NS_MOUSE_EXIT event with point %f,%f\n", exitEventLocation.x, exitEventLocation.y);
nsIWidget* lastViewEnteredWidget = [(NSView<mozView>*)sLastViewEntered widget];
SendGeckoMouseEnterOrExitEvent(PR_TRUE, NS_MOUSE_EXIT, lastViewEnteredWidget, nsMouseEvent::eReal, &exitEventLocation);
SendGeckoMouseEnterOrExitEvent(PR_TRUE, NS_MOUSE_EXIT, lastViewEnteredWidget, nsMouseEvent::eReal,
&exitEventLocation, nsMouseEvent::eChild);
// The mouse exit event we just sent may have destroyed this widget, bail if that happened.
if (!mGeckoChild)
@ -2993,7 +3003,8 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
}
// NSLog(@"sending NS_MOUSE_ENTER event with point %f,%f\n", viewEventLocation.x, viewEventLocation.y);
SendGeckoMouseEnterOrExitEvent(PR_TRUE, NS_MOUSE_ENTER, mGeckoChild, nsMouseEvent::eReal, &viewEventLocation);
SendGeckoMouseEnterOrExitEvent(PR_TRUE, NS_MOUSE_ENTER, mGeckoChild, nsMouseEvent::eReal,
&viewEventLocation, nsMouseEvent::eChild);
// The mouse enter event we just sent may have destroyed this widget, bail if that happened.
if (!mGeckoChild)

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

@ -146,6 +146,11 @@ NS_IMETHODIMP
nsCommonWidget::DispatchEvent(nsGUIEvent *aEvent,
nsEventStatus &aStatus)
{
#ifdef DEBUG
debug_DumpEvent(stdout, aEvent->widget, aEvent,
nsCAutoString("something"), 0);
#endif
aStatus = nsEventStatus_eIgnore;
// send it to the standard callback

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

@ -1920,6 +1920,20 @@ nsWindow::OnEnterNotifyEvent(GtkWidget *aWidget, GdkEventCrossing *aEvent)
DispatchEvent(&event, status);
}
static PRBool
is_top_level_mouse_exit(GdkWindow* aWindow, GdkEventCrossing *aEvent)
{
gint x = gint(aEvent->x_root);
gint y = gint(aEvent->y_root);
GdkDisplay* display = gdk_drawable_get_display(aWindow);
GdkWindow* winAtPt = gdk_display_get_window_at_pointer(display, &x, &y);
if (!winAtPt)
return PR_TRUE;
GdkWindow* topLevelAtPt = gdk_window_get_toplevel(winAtPt);
GdkWindow* topLevelWidget = gdk_window_get_toplevel(aWindow);
return topLevelAtPt != topLevelWidget;
}
void
nsWindow::OnLeaveNotifyEvent(GtkWidget *aWidget, GdkEventCrossing *aEvent)
{
@ -1934,6 +1948,9 @@ nsWindow::OnLeaveNotifyEvent(GtkWidget *aWidget, GdkEventCrossing *aEvent)
event.time = aEvent->time;
event.exit = is_top_level_mouse_exit(mDrawingarea->inner_window, aEvent)
? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
LOG(("OnLeaveNotify: %p\n", (void *)this));
nsEventStatus status;

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

@ -4346,16 +4346,15 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT
#ifndef WINCE
case WM_MOUSELEAVE:
{
// We use MINLONG | MINSHORT as the mouse position to make sure
// EventStateManager doesn't convert this EXIT message to
// a MOVE message (besides, WM_MOUSELEAVE doesn't have the position
// in lParam).
// We also need to check mouse button states and put them in for
// We need to check mouse button states and put them in for
// wParam.
WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
| (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
| (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, MINLONG | MINSHORT);
// Synthesize an event position because we don't get one from
// WM_MOUSELEAVE.
LPARAM pos = lParamToClient(::GetMessagePos());
DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos);
}
break;
#endif
@ -5658,6 +5657,16 @@ PRBool nsWindow::OnResize(nsRect &aWindowRect)
return PR_FALSE;
}
static PRBool IsTopLevelMouseExit(HWND aWnd)
{
DWORD pos = ::GetMessagePos();
POINT mp;
mp.x = GET_X_LPARAM(pos);
mp.y = GET_Y_LPARAM(pos);
HWND mouseTopLevel = nsWindow::GetTopLevelHWND(::WindowFromPoint(mp));
return nsWindow::GetTopLevelHWND(aWnd) != mouseTopLevel;
}
//-------------------------------------------------------------------------
//
// Deal with all sort of mouse event
@ -5763,6 +5772,9 @@ PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
gLastClickCount = 0;
}
else if (aEventType == NS_MOUSE_EXIT) {
event.exit = IsTopLevelMouseExit(mWnd) ? nsMouseEvent::eTopLevel : nsMouseEvent::eChild;
}
event.clickCount = gLastClickCount;
#ifdef NS_DEBUG_XX