From: Paul Gofman pgofman@codeweavers.com
--- dlls/user32/tests/msg.c | 51 +++++++++++++++++++++++++++++++++++- dlls/win32u/input.c | 13 +++++++++ dlls/win32u/win32u_private.h | 1 + dlls/win32u/window.c | 1 + server/protocol.def | 1 + server/queue.c | 24 ++++++++++------- 6 files changed, 81 insertions(+), 10 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 0347f0d73b0..590f50aa6b7 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -73,6 +73,8 @@ #define ARCH "none" #endif
+static void pump_msg_loop(HWND hwnd, HACCEL hAccel); + /* encoded DRAWITEMSTRUCT into an LPARAM */ typedef struct { @@ -108,6 +110,7 @@ typedef struct
static BOOL test_DestroyWindow_flag; static BOOL test_context_menu; +static BOOL ignore_mouse_messages = TRUE; static HWINEVENTHOOK hEvent_hook; static HHOOK hKBD_hook; static HHOOK hCBT_hook; @@ -6160,6 +6163,30 @@ static const struct message WmFrameChanged_move[] = { { 0 } };
+static const struct message WmMove_mouse[] = { + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE }, + { WM_MOVE, sent|defwinproc, 0 }, + { WM_GETTEXT, sent|optional }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* Win7 seems to send this twice. */ + { WM_SETCURSOR, sent|lparam, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent }, + /* WM_MOUSEMOVE with accompanying WM_SETCURSOR may sometimes appear a few extra times on Windows 7 with the + * same parameters. */ + { WM_SETCURSOR, sent|lparam|optional, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent|optional }, + { WM_SETCURSOR, sent|lparam|optional, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent|optional }, + { WM_SETCURSOR, sent|lparam|optional, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent|optional }, + { WM_SETCURSOR, sent|lparam|optional, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent|optional }, + { WM_SETCURSOR, sent|lparam|optional, 0, HTCLIENT | (WM_MOUSEMOVE << 16) }, + { WM_MOUSEMOVE, sent|optional }, + { 0 } +}; + static void test_setwindowpos(void) { HWND hwnd; @@ -6198,6 +6225,7 @@ static void test_setwindowpos(void) expect(sysX + X, rc.right); expect(winY + Y, rc.bottom);
+ GetWindowRect(hwnd, &rc); res = SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); ok_sequence(WmFrameChanged_move, "FrameChanged", FALSE); @@ -6207,6 +6235,26 @@ static void test_setwindowpos(void) expect(sysX, rc.right); expect(winY, rc.bottom);
+ /* get away from possible menu bar to avoid spurious position changed induced by WM. */ + res = SetWindowPos( hwnd, HWND_TOPMOST, 200, 200, 200, 200, SWP_SHOWWINDOW ); + ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res); + SetForegroundWindow( hwnd ); + SetActiveWindow( hwnd ); + flush_events(); + pump_msg_loop( hwnd, 0 ); + flush_sequence(); + GetWindowRect( hwnd, &rc ); + SetCursorPos( rc.left + 100, rc.top + 100 ); + flush_events(); + pump_msg_loop( hwnd, 0 ); + flush_sequence(); + ignore_mouse_messages = FALSE; + res = SetWindowPos( hwnd, 0, 205, 205, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); + ok(res == TRUE, "SetWindowPos expected TRUE, got %Id.\n", res); + flush_events(); + ok_sequence(WmMove_mouse, "MouseMove", FALSE); + ignore_mouse_messages = TRUE; + DestroyWindow(hwnd); }
@@ -10853,7 +10901,8 @@ static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message, case WM_NCMOUSEMOVE: case WM_SETCURSOR: case WM_IME_SELECT: - return 0; + if (ignore_mouse_messages) return 0; + break; }
msg.hwnd = hwnd; diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 0640b34ac2e..0577f460601 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -732,6 +732,19 @@ BOOL WINAPI NtUserSetCursorPos( INT x, INT y ) return ret; }
+/*********************************************************************** + * update_window_cursor_pos + */ +void update_window_cursor_pos(void) +{ + SERVER_START_REQ( set_cursor ) + { + req->flags = SET_CURSOR_UPDATE; + wine_server_call( req ); + } + SERVER_END_REQ; +} + /*********************************************************************** * get_cursor_pos */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 8956f83af75..06f9919267d 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -94,6 +94,7 @@ extern BOOL destroy_caret(void); extern HWND get_active_window(void); extern HWND get_capture(void); extern BOOL get_cursor_pos( POINT *pt ); +extern void update_window_cursor_pos(void); extern HWND get_focus(void); extern DWORD get_input_state(void); extern BOOL get_async_keyboard_state( BYTE state[256] ); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 48a7304b6b0..928287b15ee 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -3795,6 +3795,7 @@ BOOL set_window_pos( WINDOWPOS *winpos, int parent_x, int parent_y ) winpos->cx = new_rects.window.right - new_rects.window.left; winpos->cy = new_rects.window.bottom - new_rects.window.top; send_message( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos ); + update_window_cursor_pos(); }
if ((winpos->flags & (SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED)) != (SWP_NOSIZE|SWP_NOMOVE)) diff --git a/server/protocol.def b/server/protocol.def index a4f25e805f8..c0306113220 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3916,6 +3916,7 @@ typedef union #define SET_CURSOR_CLIP 0x08 #define SET_CURSOR_NOCLIP 0x10 #define SET_CURSOR_FSCLIP 0x20 +#define SET_CURSOR_UPDATE 0x40
/* Get the history of the 64 last cursor positions */ @REQ(get_cursor_history) diff --git a/server/queue.c b/server/queue.c index c99c8d8661b..2603c88f33b 100644 --- a/server/queue.c +++ b/server/queue.c @@ -563,19 +563,11 @@ static void update_desktop_cursor_handle( struct desktop *desktop, struct thread } }
-/* set the cursor position and queue the corresponding mouse message */ -static void set_cursor_pos( struct desktop *desktop, int x, int y ) +static void update_window_cursor_pos( struct desktop *desktop, int x, int y ) { static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; - const struct rawinput_device *device; struct message *msg;
- if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) - { - update_desktop_cursor_pos( desktop, 0, x, y ); - return; - } - if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return;
msg->msg = WM_MOUSEMOVE; @@ -584,6 +576,19 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) queue_hardware_message( desktop, msg, 1 ); }
+/* set the cursor position and queue the corresponding mouse message */ +static void set_cursor_pos( struct desktop *desktop, int x, int y ) +{ + const struct rawinput_device *device; + + if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) + { + update_desktop_cursor_pos( desktop, 0, x, y ); + return; + } + update_window_cursor_pos( desktop, x, y ); +} + /* retrieve default position and time for synthesized messages */ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsigned int *time ) { @@ -4009,6 +4014,7 @@ DECL_HANDLER(set_cursor) } SHARED_WRITE_END;
+ if (req->flags & SET_CURSOR_UPDATE) update_window_cursor_pos( desktop, reply->prev_x, reply->prev_y ); if (req->flags & SET_CURSOR_POS) set_cursor_pos( desktop, req->x, req->y ); if (req->flags & SET_CURSOR_CLIP) set_clip_rectangle( desktop, &req->clip, req->flags, 0 ); if (req->flags & SET_CURSOR_NOCLIP) set_clip_rectangle( desktop, NULL, SET_CURSOR_NOCLIP, 0 );