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 | 9 ++++--- 6 files changed, 71 insertions(+), 5 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..bfda0cfb2e4 100644 --- a/server/queue.c +++ b/server/queue.c @@ -564,7 +564,7 @@ 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 set_cursor_pos( struct desktop *desktop, int x, int y, int update_window_only ) { static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; const struct rawinput_device *device; @@ -572,7 +572,7 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y )
if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) { - update_desktop_cursor_pos( desktop, 0, x, y ); + if (!update_window_only) update_desktop_cursor_pos( desktop, 0, x, y ); return; }
@@ -627,7 +627,7 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsig /* warp the mouse to be inside the clip rect */ x = max( min( desktop_shm->cursor.x, new_rect.right - 1 ), new_rect.left ); y = max( min( desktop_shm->cursor.y, new_rect.bottom - 1 ), new_rect.top ); - if (x != desktop_shm->cursor.x || y != desktop_shm->cursor.y) set_cursor_pos( desktop, x, y ); + if (x != desktop_shm->cursor.x || y != desktop_shm->cursor.y) set_cursor_pos( desktop, x, y, 0 );
/* request clip cursor rectangle reset to the desktop thread */ if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, flags, FALSE ); @@ -4009,7 +4009,8 @@ DECL_HANDLER(set_cursor) } SHARED_WRITE_END;
- if (req->flags & SET_CURSOR_POS) set_cursor_pos( desktop, req->x, req->y ); + if (req->flags & SET_CURSOR_UPDATE) set_cursor_pos( desktop, reply->prev_x, reply->prev_y, 1 ); + if (req->flags & SET_CURSOR_POS) set_cursor_pos( desktop, req->x, req->y, 0 ); 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 );