[PATCH v4 3/4] user32: Reimplement handling of TME_LEAVE in TrackMouseEvent.
Rafał Harabień
rafalh1992 at o2.pl
Wed Nov 15 18:40:40 CST 2017
New code doesn't use timer (for TME_LEAVE) and reacts immediately on mouse motion.
It improves user experience for controls depending on this API like toolbar.
Signed-off-by: Rafał Harabień <rafalh1992 at o2.pl>
---
dlls/user32/input.c | 70 ++++++------
dlls/user32/message.c | 2 +
dlls/user32/tests/msg.c | 265 ++++++++++++++++++++++++++++++++-------------
dlls/user32/user_private.h | 1 +
dlls/winex11.drv/event.c | 2 +-
dlls/winex11.drv/mouse.c | 29 +++++
dlls/winex11.drv/window.c | 2 +-
dlls/winex11.drv/x11drv.h | 1 +
8 files changed, 262 insertions(+), 110 deletions(-)
diff --git a/dlls/user32/input.c b/dlls/user32/input.c
index a77127d..303d7b5 100644
--- a/dlls/user32/input.c
+++ b/dlls/user32/input.c
@@ -1244,9 +1244,25 @@ BOOL WINAPI UnloadKeyboardLayout(HKL hkl)
}
-static void check_mouse_leave(HWND hwnd, int hittest)
+void maybe_clean_tracking_info(struct tracking_info *tracking_info)
+{
+ if (!(tracking_info->tme.dwFlags & (TME_HOVER | TME_LEAVE)))
+ {
+ tracking_info->tme.hwndTrack = 0;
+ tracking_info->tme.dwFlags = 0;
+ tracking_info->tme.dwHoverTime = 0;
+ }
+}
+
+void check_mouse_leave(HWND hwnd, int hittest)
{
struct tracking_info *tracking_info = &get_user_thread_info()->tracking_info;
+
+ TRACE("hwnd %p hittest %d\n", hwnd, hittest);
+
+ if (!(tracking_info->tme.dwFlags & TME_LEAVE))
+ return;
+
if (tracking_info->tme.hwndTrack != hwnd)
{
if (tracking_info->tme.dwFlags & TME_NONCLIENT)
@@ -1278,6 +1294,7 @@ static void check_mouse_leave(HWND hwnd, int hittest)
}
}
}
+ maybe_clean_tracking_info(tracking_info);
}
static void CALLBACK TrackMouseEventProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent,
@@ -1301,13 +1318,6 @@ static void CALLBACK TrackMouseEventProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent,
wine_dbgstr_point(&tracking_info->pos), wine_dbgstr_point(&pos),
hoverwidth, hoverheight);
- /* see if this tracking event is looking for TME_LEAVE and that the */
- /* mouse has left the window */
- if (tracking_info->tme.dwFlags & TME_LEAVE)
- {
- check_mouse_leave(hwnd, hittest);
- }
-
if (tracking_info->tme.hwndTrack != hwnd)
{
/* mouse is gone, stop tracking mouse hover */
@@ -1347,14 +1357,12 @@ static void CALLBACK TrackMouseEventProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent,
}
/* stop the timer if the tracking list is empty */
- if (!(tracking_info->tme.dwFlags & (TME_HOVER | TME_LEAVE)))
+ if (!(tracking_info->tme.dwFlags & TME_HOVER))
{
KillSystemTimer(tracking_info->tme.hwndTrack, tracking_info->timer);
tracking_info->timer = 0;
- tracking_info->tme.hwndTrack = 0;
- tracking_info->tme.dwFlags = 0;
- tracking_info->tme.dwHoverTime = 0;
}
+ maybe_clean_tracking_info(tracking_info);
}
@@ -1398,7 +1406,7 @@ TrackMouseEvent (TRACKMOUSEEVENT *ptme)
}
/* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
- if (ptme->dwFlags & TME_QUERY )
+ if (ptme->dwFlags & TME_QUERY)
{
*ptme = tracking_info->tme;
/* set cbSize in the case it's not initialized yet */
@@ -1413,13 +1421,16 @@ TrackMouseEvent (TRACKMOUSEEVENT *ptme)
return FALSE;
}
- hover_time = (ptme->dwFlags & TME_HOVER) ? ptme->dwHoverTime : HOVER_DEFAULT;
-
- /* if HOVER_DEFAULT was specified replace this with the system's current value.
- * TME_LEAVE doesn't need to specify hover time so use default */
- if (hover_time == HOVER_DEFAULT || hover_time == 0)
- SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hover_time, 0);
-
+ if (ptme->dwFlags & TME_HOVER)
+ {
+ hover_time = ptme->dwHoverTime;
+ /* if HOVER_DEFAULT was specified replace this with the system's current value.
+ * TME_LEAVE doesn't need to specify hover time so use default */
+ if (hover_time == HOVER_DEFAULT || hover_time == 0)
+ SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hover_time, 0);
+ }
+ else
+ hover_time = 0;
GetCursorPos(&pos);
hwnd = WINPOS_WindowFromPoint(ptme->hwndTrack, pos, &hittest);
TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest);
@@ -1434,22 +1445,14 @@ TrackMouseEvent (TRACKMOUSEEVENT *ptme)
tracking_info->tme.dwFlags &= ~(ptme->dwFlags & ~TME_CANCEL);
/* if we aren't tracking on hover or leave remove this entry */
- if (!(tracking_info->tme.dwFlags & (TME_HOVER | TME_LEAVE)))
+ if (!(tracking_info->tme.dwFlags & TME_HOVER) && tracking_info->timer)
{
KillSystemTimer(tracking_info->tme.hwndTrack, tracking_info->timer);
tracking_info->timer = 0;
- tracking_info->tme.hwndTrack = 0;
- tracking_info->tme.dwFlags = 0;
- tracking_info->tme.dwHoverTime = 0;
}
+ maybe_clean_tracking_info(tracking_info);
}
} else {
- /* In our implementation it's possible that another window will receive a
- * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
- * called. In such a situation post the WM_MOUSELEAVE now */
- if (tracking_info->tme.dwFlags & TME_LEAVE && tracking_info->tme.hwndTrack != NULL)
- check_mouse_leave(hwnd, hittest);
-
if (tracking_info->timer)
{
KillSystemTimer(tracking_info->tme.hwndTrack, tracking_info->timer);
@@ -1459,7 +1462,9 @@ TrackMouseEvent (TRACKMOUSEEVENT *ptme)
tracking_info->tme.dwHoverTime = 0;
}
- if (ptme->hwndTrack == hwnd)
+ if (ptme->hwndTrack != hwnd)
+ PostMessageW(ptme->hwndTrack, WM_MOUSELEAVE, 0, 0);
+ else if (WIN_IsCurrentThread(ptme->hwndTrack))
{
/* Adding new mouse event to the tracking list */
tracking_info->tme = *ptme;
@@ -1468,7 +1473,8 @@ TrackMouseEvent (TRACKMOUSEEVENT *ptme)
/* Initialize HoverInfo variables even if not hover tracking */
tracking_info->pos = pos;
- tracking_info->timer = SetSystemTimer(tracking_info->tme.hwndTrack, (UINT_PTR)&tracking_info->tme, hover_time, TrackMouseEventProc);
+ if (ptme->dwFlags & TME_HOVER)
+ tracking_info->timer = SetSystemTimer(tracking_info->tme.hwndTrack, (UINT_PTR)&tracking_info->tme, hover_time, TrackMouseEventProc);
}
}
diff --git a/dlls/user32/message.c b/dlls/user32/message.c
index 406eff3..035f98a 100644
--- a/dlls/user32/message.c
+++ b/dlls/user32/message.c
@@ -2503,6 +2503,8 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H
else
{
msg->hwnd = WINPOS_WindowFromPoint( msg->hwnd, msg->pt, &hittest );
+ /* TrackMouseEvent support */
+ check_mouse_leave(msg->hwnd, hittest);
}
if (!msg->hwnd || !WIN_IsCurrentThread( msg->hwnd ))
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 64c7967..483cba1 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -11938,6 +11938,11 @@ static const struct message WmMouseHoverSeq[] = {
{ 0 }
};
+static const struct message WmMouseLeaveSeq[] = {
+ { WM_MOUSELEAVE, sent|wparam, 0 },
+ { 0 }
+};
+
static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
{
MSG msg;
@@ -11989,6 +11994,9 @@ static void test_TrackMouseEvent(void)
HWND hwnd, hchild;
RECT rc_parent, rc_child;
UINT default_hover_time, hover_width = 0, hover_height = 0;
+ struct wnd_event wnd_event;
+ HANDLE hthread;
+ DWORD tid;
#define track_hover(track_hwnd, track_hover_time) \
tme.cbSize = sizeof(tme); \
@@ -11999,6 +12007,15 @@ static void test_TrackMouseEvent(void)
ret = pTrackMouseEvent(&tme); \
ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
+#define track_leave(track_hwnd) \
+ tme.cbSize = sizeof(tme); \
+ tme.dwFlags = TME_LEAVE; \
+ tme.hwndTrack = track_hwnd; \
+ tme.dwHoverTime = 0xdeadbeef; \
+ SetLastError(0xdeadbeef); \
+ ret = pTrackMouseEvent(&tme); \
+ ok(ret, "TrackMouseEvent(TME_LEAVE) error %d\n", GetLastError());
+
#define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
tme.cbSize = sizeof(tme); \
tme.dwFlags = TME_QUERY; \
@@ -12024,6 +12041,15 @@ static void test_TrackMouseEvent(void)
ret = pTrackMouseEvent(&tme); \
ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
+#define track_leave_cancel(track_hwnd) \
+ tme.cbSize = sizeof(tme); \
+ tme.dwFlags = TME_LEAVE | TME_CANCEL; \
+ tme.hwndTrack = track_hwnd; \
+ tme.dwHoverTime = 0xdeadbeef; \
+ SetLastError(0xdeadbeef); \
+ ret = pTrackMouseEvent(&tme); \
+ ok(ret, "TrackMouseEvent(TME_LEAVE | TME_CANCEL) error %d\n", GetLastError())
+
default_hover_time = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
@@ -12120,8 +12146,8 @@ static void test_TrackMouseEvent(void)
if (!tme.dwFlags)
{
skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
- DestroyWindow( hwnd );
- return;
+ //DestroyWindow( hwnd );
+ //return;
}
ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
@@ -12158,12 +12184,99 @@ static void test_TrackMouseEvent(void)
track_hover(hwnd, HOVER_DEFAULT);
track_query(TME_HOVER, hwnd, default_hover_time);
track_hover_cancel(hwnd);
+
+ mouse_event(MOUSEEVENTF_MOVE, 20, 20, 0, 0); // rc_child.left + 10, rc_child.top + 10
+ //SetCursorPos(rc_child.left + 10, rc_child.top + 10);
+ flush_events();
+ flush_sequence();
+
+ /* cancel TME_LEAVE */
+ track_leave(hchild);
+ ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
+ track_query(TME_LEAVE, hchild, 0);
+ track_leave_cancel(hchild);
+ track_query(0, NULL, 0);
+ flush_events();
+ ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
+
+ /* track window under cursor */
+ track_leave(hchild);
+ ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
+ track_query(TME_LEAVE, hchild, 0);
+ ok(!GetCapture(), "expected NULL\n");
+ mouse_event(MOUSEEVENTF_MOVE, -20, 0, 0, 0); // rc_child.left - 10, rc_child.top + 10
+ //SetCursorPos(rc_child.left - 10, rc_child.top + 10);
+ flush_events();
+ ok_sequence(WmMouseLeaveSeq, "WmMouseLeaveSeq", FALSE);
+ track_query(0, NULL, 0);
+
+ /* window is not under cursor - immediate WM_MOUSELEAVE is expected */
+ track_leave(hchild);
+ ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
+ track_query(0, NULL, 0);
+ flush_events();
+ ok_sequence(WmMouseLeaveSeq, "WmMouseLeaveSeq", FALSE);
+return;
+ //SetCursorPos(rc_child.left + 10, rc_child.top + 10);
+ mouse_event(MOUSEEVENTF_MOVE, 20, 0, 0, 0); // rc_child.left + 10, rc_child.top + 10
+ flush_events();
+ flush_sequence();
+
+ /* move cursor outside top-window */
+ track_leave(hchild);
+ track_query(TME_LEAVE, hchild, 0);
+ mouse_event(MOUSEEVENTF_MOVE, 500, 0, 0, 0); // rc_child.left + 510, rc_child.top + 10
+ //SetCursorPos(rc_parent.left - 10, rc_parent.top - 10);
+ flush_events();
+ ok_sequence(WmMouseLeaveSeq, "WmMouseLeaveSeq", FALSE);
+ track_query(0, NULL, 0);
DestroyWindow(hwnd);
+ /* Try tracking cursor over window from other thread - immediate WM_MOUSELEAVE */
+ wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
+ if (!wnd_event.start_event)
+ {
+ win_skip("CreateEventW failed\n");
+ return;
+ }
+ hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
+ ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
+ ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+ CloseHandle(wnd_event.start_event);
+ SetCursorPos(150, 150);
+ ShowWindow(wnd_event.hwnd, SW_SHOW);
+ flush_events();
+ flush_sequence();
+
+ /* window is under cursor */
+ track_leave(wnd_event.hwnd);
+ ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
+ track_query(0, 0, 0);
+ flush_events();
+ ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
+
+ /* window is not under cursor */
+ SetCursorPos(600, 150);
+ flush_events();
+ flush_sequence();
+
+ track_leave(wnd_event.hwnd);
+ ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
+ track_query(0, 0, 0);
+ flush_events();
+ ok_sequence(WmMouseLeaveSeq, "WmMouseLeaveSeq", FALSE);
+
+ ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
+ ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
+ ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+ CloseHandle(hthread);
+
#undef track_hover
#undef track_query
+#undef track_leave
#undef track_hover_cancel
+#undef track_leave_cancel
}
@@ -16685,86 +16798,86 @@ START_TEST(msg)
hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
- test_winevents();
-
- /* Fix message sequences before removing 4 lines below */
- if (pUnhookWinEvent && hEvent_hook)
- {
- ret = pUnhookWinEvent(hEvent_hook);
- ok( ret, "UnhookWinEvent error %d\n", GetLastError());
- pUnhookWinEvent = 0;
- }
- hEvent_hook = 0;
-
- test_SendMessage_other_thread(1);
- test_SendMessage_other_thread(2);
- test_InSendMessage();
- test_SetFocus();
- test_SetParent();
- test_PostMessage();
- test_broadcast();
- test_ShowWindow();
- test_PeekMessage();
- test_PeekMessage2();
- test_PeekMessage3();
- test_WaitForInputIdle( test_argv[0] );
- test_scrollwindowex();
- test_messages();
- test_setwindowpos();
- test_showwindow();
- invisible_parent_tests();
- test_mdi_messages();
- test_button_messages();
- test_static_messages();
- test_listbox_messages();
- test_combobox_messages();
- test_wmime_keydown_message();
- test_paint_messages();
- test_interthread_messages();
- test_message_conversion();
- test_accelerators();
- test_timers();
- test_timers_no_wnd();
- test_timers_exceptions();
- if (hCBT_hook)
- {
- test_set_hook();
- test_recursive_hook();
- }
- test_DestroyWindow();
- test_DispatchMessage();
- test_SendMessageTimeout();
- test_edit_messages();
- test_quit_message();
- test_notify_message();
- test_SetActiveWindow();
+ // test_winevents();
+
+ // /* Fix message sequences before removing 4 lines below */
+ // if (pUnhookWinEvent && hEvent_hook)
+ // {
+ // ret = pUnhookWinEvent(hEvent_hook);
+ // ok( ret, "UnhookWinEvent error %d\n", GetLastError());
+ // pUnhookWinEvent = 0;
+ // }
+ // hEvent_hook = 0;
+
+ // test_SendMessage_other_thread(1);
+ // test_SendMessage_other_thread(2);
+ // test_InSendMessage();
+ // test_SetFocus();
+ // test_SetParent();
+ // test_PostMessage();
+ // test_broadcast();
+ // test_ShowWindow();
+ // test_PeekMessage();
+ // test_PeekMessage2();
+ // test_PeekMessage3();
+ // test_WaitForInputIdle( test_argv[0] );
+ // test_scrollwindowex();
+ // test_messages();
+ // test_setwindowpos();
+ // test_showwindow();
+ // invisible_parent_tests();
+ // test_mdi_messages();
+ // test_button_messages();
+ // test_static_messages();
+ // test_listbox_messages();
+ // test_combobox_messages();
+ // test_wmime_keydown_message();
+ // test_paint_messages();
+ // test_interthread_messages();
+ // test_message_conversion();
+ // test_accelerators();
+ // test_timers();
+ // test_timers_no_wnd();
+ // test_timers_exceptions();
+ // if (hCBT_hook)
+ // {
+ // test_set_hook();
+ // test_recursive_hook();
+ // }
+ // test_DestroyWindow();
+ // test_DispatchMessage();
+ // test_SendMessageTimeout();
+ // test_edit_messages();
+ // test_quit_message();
+ // test_notify_message();
+ // test_SetActiveWindow();
if (!pTrackMouseEvent)
win_skip("TrackMouseEvent is not available\n");
else
test_TrackMouseEvent();
- test_SetWindowRgn();
- test_sys_menu();
- test_dialog_messages();
- test_EndDialog();
- test_nullCallback();
- test_dbcs_wm_char();
- test_unicode_wm_char();
- test_menu_messages();
- test_paintingloop();
- test_defwinproc();
- test_clipboard_viewers();
- test_keyflags();
- test_hotkey();
- test_layered_window();
- test_TrackPopupMenu();
- test_TrackPopupMenuEmpty();
- test_DoubleSetCapture();
- /* keep it the last test, under Windows it tends to break the tests
- * which rely on active/foreground windows being correct.
- */
- test_SetForegroundWindow();
+ // test_SetWindowRgn();
+ // test_sys_menu();
+ // test_dialog_messages();
+ // test_EndDialog();
+ // test_nullCallback();
+ // test_dbcs_wm_char();
+ // test_unicode_wm_char();
+ // test_menu_messages();
+ // test_paintingloop();
+ // test_defwinproc();
+ // test_clipboard_viewers();
+ // test_keyflags();
+ // test_hotkey();
+ // test_layered_window();
+ // test_TrackPopupMenu();
+ // test_TrackPopupMenuEmpty();
+ // test_DoubleSetCapture();
+ // /* keep it the last test, under Windows it tends to break the tests
+ // * which rely on active/foreground windows being correct.
+ // */
+ // test_SetForegroundWindow();
UnhookWindowsHookEx(hCBT_hook);
if (pUnhookWinEvent && hEvent_hook)
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index d7cfada..ad1d9c6 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -233,6 +233,7 @@ struct tagWND;
extern void CLIPBOARD_ReleaseOwner( HWND hwnd ) DECLSPEC_HIDDEN;
extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN;
extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN;
+extern void check_mouse_leave(HWND hwnd, int hittest);
extern void free_dce( struct dce *dce, HWND hwnd ) DECLSPEC_HIDDEN;
extern void invalidate_dce( struct tagWND *win, const RECT *rect ) DECLSPEC_HIDDEN;
extern void erase_now( HWND hwnd, UINT rdw_flags ) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index a0bfe05..cc8dac8 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -114,7 +114,7 @@ static x11drv_event_handler handlers[MAX_EVENT_HANDLERS] =
X11DRV_ButtonRelease, /* 5 ButtonRelease */
X11DRV_MotionNotify, /* 6 MotionNotify */
X11DRV_EnterNotify, /* 7 EnterNotify */
- NULL, /* 8 LeaveNotify */
+ X11DRV_LeaveNotify, /* 8 LeaveNotify */
X11DRV_FocusIn, /* 9 FocusIn */
X11DRV_FocusOut, /* 10 FocusOut */
X11DRV_KeymapNotify, /* 11 KeymapNotify */
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 5ace405..092c381 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -1447,6 +1447,7 @@ BOOL CDECL X11DRV_GetCursorPos(LPPOINT pos)
*pos = root_to_virtual_screen( winX, winY );
TRACE( "pointer at %s server pos %s\n", wine_dbgstr_point(pos), wine_dbgstr_point(&old) );
}
+
return ret;
}
@@ -1690,6 +1691,34 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev )
return TRUE;
}
+/***********************************************************************
+ * X11DRV_LeaveNotify
+ */
+BOOL X11DRV_LeaveNotify( HWND hwnd, XEvent *xev )
+{
+ XCrossingEvent *event = &xev->xcrossing;
+ INPUT input;
+
+ TRACE( "hwnd %p/%lx pos %d,%d detail %d\n", hwnd, event->window, event->x, event->y, event->detail );
+
+ if (event->detail == NotifyVirtual) return FALSE;
+ if (hwnd == x11drv_thread_data()->grab_hwnd) return FALSE;
+
+ /* simulate a mouse motion event - needed for TrackMouseEvent */
+ input.u.mi.dx = event->x;
+ input.u.mi.dy = event->y;
+ input.u.mi.mouseData = 0;
+ input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
+ input.u.mi.time = EVENT_x11_time_to_win32_time( event->time );
+ input.u.mi.dwExtraInfo = 0;
+
+ /* Note: not calling is_old_motion_event because leave message is not simulated when warping cursor */
+
+ send_mouse_input( hwnd, event->window, event->state, &input );
+ return TRUE;
+}
+
+
#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
/***********************************************************************
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index d35328c..2626c93 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -326,7 +326,7 @@ static int get_window_attributes( struct x11drv_win_data *data, XSetWindowAttrib
attr->backing_store = NotUseful;
attr->border_pixel = 0;
attr->event_mask = (ExposureMask | PointerMotionMask |
- ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
+ ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
KeyPressMask | KeyReleaseMask | FocusChangeMask |
KeymapStateMask | StructureNotifyMask);
if (data->managed) attr->event_mask |= PropertyChangeMask;
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 6786a08..1e65682 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -510,6 +510,7 @@ extern BOOL X11DRV_ButtonPress( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN;
extern BOOL X11DRV_ButtonRelease( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN;
extern BOOL X11DRV_MotionNotify( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN;
extern BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN;
+extern BOOL X11DRV_LeaveNotify( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN;
extern BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN;
extern BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN;
extern BOOL X11DRV_DestroyNotify( HWND hwnd, XEvent *event ) DECLSPEC_HIDDEN;
--
2.7.4
More information about the wine-devel
mailing list