-- v5: win32u: Sync cursor position on window position change.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/user32/tests/msg.c | 51 ++++++++++++++++++++++++++++++++++++++++- server/queue.c | 9 ++++++++ server/user.h | 1 + server/window.c | 8 +++++-- 4 files changed, 66 insertions(+), 3 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/server/queue.c b/server/queue.c index c99c8d8661b..767b595e650 100644 --- a/server/queue.c +++ b/server/queue.c @@ -584,6 +584,15 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) queue_hardware_message( desktop, msg, 1 ); }
+/* sync cursor position after window change */ +void update_cursor_pos( struct desktop *desktop ) +{ + const desktop_shm_t *desktop_shm; + + desktop_shm = desktop->shared; + set_cursor_pos( desktop, desktop_shm->cursor.x, desktop_shm->cursor.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 ) { diff --git a/server/user.h b/server/user.h index 6f9612ffb93..c9547fb390f 100644 --- a/server/user.h +++ b/server/user.h @@ -127,6 +127,7 @@ extern int attach_thread_input( struct thread *thread_from, struct thread *threa extern void detach_thread_input( struct thread *thread_from ); extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsigned int flags, int reset ); +extern void update_cursor_pos( struct desktop *desktop ); extern void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam ); extern void send_notify_message( user_handle_t win, unsigned int message, diff --git a/server/window.c b/server/window.c index 412592fbc71..76e01d618db 100644 --- a/server/window.c +++ b/server/window.c @@ -2401,11 +2401,11 @@ DECL_HANDLER(get_window_tree) /* set the position and Z order of a window */ DECL_HANDLER(set_window_pos) { - rectangle_t window_rect, client_rect, visible_rect, surface_rect, valid_rect; + rectangle_t window_rect, client_rect, visible_rect, surface_rect, valid_rect, old_client; const rectangle_t *extra_rects = get_req_data(); struct window *previous = NULL; struct window *top, *win = get_window( req->handle ); - unsigned int flags = req->swp_flags; + unsigned int flags = req->swp_flags, orig_style;
if (!win) return; if (!win->parent) flags |= SWP_NOZORDER; /* no Z order for the desktop */ @@ -2470,8 +2470,12 @@ DECL_HANDLER(set_window_pos) if (win->paint_flags & PAINT_HAS_PIXEL_FORMAT) update_pixel_format_flags( win );
win->monitor_dpi = req->monitor_dpi; + old_client = win->client_rect; + orig_style = win->style; set_window_pos( win, previous, flags, &window_rect, &client_rect, &visible_rect, &surface_rect, &valid_rect ); + if ((win->style & orig_style & WS_VISIBLE) && memcmp( &old_client, &win->client_rect, sizeof(old_client) )) + update_cursor_pos( win->desktop );
if (win->paint_flags & SET_WINPOS_LAYERED_WINDOW) validate_whole_window( win );
v5: - sync mouse position in (set_window_pos) server call.
Rémi Bernon (@rbernon) commented about server/window.c:
/* set the position and Z order of a window */ DECL_HANDLER(set_window_pos) {
- rectangle_t window_rect, client_rect, visible_rect, surface_rect, valid_rect;
- rectangle_t window_rect, client_rect, visible_rect, surface_rect, valid_rect, old_client; const rectangle_t *extra_rects = get_req_data(); struct window *previous = NULL; struct window *top, *win = get_window( req->handle );
- unsigned int flags = req->swp_flags;
- unsigned int flags = req->swp_flags, orig_style;
```suggestion:-0+0 unsigned int flags = req->swp_flags, old_style; ```
For consistency with old_client.
Rémi Bernon (@rbernon) commented about server/window.c:
if (win->paint_flags & PAINT_HAS_PIXEL_FORMAT) update_pixel_format_flags( win ); win->monitor_dpi = req->monitor_dpi;
- old_client = win->client_rect;
- orig_style = win->style; set_window_pos( win, previous, flags, &window_rect, &client_rect, &visible_rect, &surface_rect, &valid_rect );
- if ((win->style & orig_style & WS_VISIBLE) && memcmp( &old_client, &win->client_rect, sizeof(old_client) ))
Do we actually need to check whether client rect has been moved? What if both the window and client rects are moved at the same time, compensating eachother and causing the client rect to stay at the same place, will that skip the WM_MOUSEMOVE?