From 3f1bbdcae35fe3841465106f71090445484bf274 Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Tue, 14 Oct 2014 13:28:47 +0200 Subject: [PATCH] server: Send mouse hardware messages to thread owning top-most window. Also don't limit mouse message scope to top-most window when message comes from SendInput or window that generated the event is minimized/transparent. --- dlls/user32/tests/input.c | 4 ++-- dlls/user32/tests/win.c | 2 +- server/queue.c | 26 +++++++++++++++----------- server/user.h | 3 ++- server/window.c | 34 +++++++++++++++++++++++++++++----- 5 files changed, 49 insertions(+), 20 deletions(-) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index f741e789578..3ce05701d14 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1803,8 +1803,8 @@ static void test_Input_mouse(void) } } ok(hittest_no && hittest_no<50, "expected WM_NCHITTEST message\n"); - todo_wine ok(got_button_down, "expected WM_RBUTTONDOWN message\n"); - todo_wine ok(got_button_up, "expected WM_RBUTTONUP message\n"); + ok(got_button_down, "expected WM_RBUTTONDOWN message\n"); + ok(got_button_up, "expected WM_RBUTTONUP message\n"); DestroyWindow(static_win); /* click through HTTRANSPARENT top-level window */ diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index ad983dfd07f..cfc2a021afd 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -7295,7 +7295,7 @@ static void window_from_point_proc(HWND parent) DispatchMessageA(&msg); } ok(got_hittest, "transparent window didn't get WM_NCHITTEST message\n"); - todo_wine ok(got_click, "button under static window didn't get WM_LBUTTONUP\n"); + ok(got_click, "button under static window didn't get WM_LBUTTONUP\n"); ret = WaitForSingleObject(end_event, 5000); ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret); diff --git a/server/queue.c b/server/queue.c index 601629ecd77..71dfc11d434 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1379,11 +1379,13 @@ found: /* find the window that should receive a given hardware message */ static user_handle_t find_hardware_message_window( struct desktop *desktop, struct thread_input *input, - struct message *msg, unsigned int *msg_code ) + struct message *msg, unsigned int *msg_code, + struct thread **thread ) { struct hardware_msg_data *data = msg->data; user_handle_t win = 0; + *thread = NULL; *msg_code = msg->msg; if (msg->msg == WM_INPUT) { @@ -1397,14 +1399,16 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru if (*msg_code < WM_SYSKEYDOWN) *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN; } } - else /* mouse message */ + else if (!input || !(win = input->capture)) /* mouse message */ { - if (!input || !(win = input->capture)) - { - if (!(win = msg->win) || !is_window_visible( win ) || is_window_transparent( win )) - win = window_from_point( desktop, data->x, data->y ); - } + if (is_window_visible( msg->win ) && !is_window_transparent( msg->win )) win = msg->win; + else win = shallow_window_from_point( desktop, data->x, data->y ); + + *thread = window_thread_from_point( win, data->x, data->y ); } + + if (!*thread) + *thread = get_window_thread( win ); return win; } @@ -1491,8 +1495,8 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg } else input = desktop->foreground_input; - win = find_hardware_message_window( desktop, input, msg, &msg_code ); - if (!win || !(thread = get_window_thread(win))) + win = find_hardware_message_window( desktop, input, msg, &msg_code, &thread ); + if (!win || !thread) { if (input) update_input_key_state( input->desktop, input->keystate, msg ); free_message( msg ); @@ -1928,8 +1932,8 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user struct hardware_msg_data *data = msg->data; ptr = list_next( &input->msg_list, ptr ); - win = find_hardware_message_window( input->desktop, input, msg, &msg_code ); - if (!win || !(win_thread = get_window_thread( win ))) + win = find_hardware_message_window( input->desktop, input, msg, &msg_code, &win_thread ); + if (!win || !win_thread) { /* no window at all, remove it */ update_input_key_state( input->desktop, input->keystate, msg ); diff --git a/server/user.h b/server/user.h index 8535903185e..08d0959f3c2 100644 --- a/server/user.h +++ b/server/user.h @@ -157,7 +157,8 @@ extern int is_window_visible( user_handle_t window ); extern int is_window_transparent( user_handle_t window ); extern int make_window_active( user_handle_t window ); extern struct thread *get_window_thread( user_handle_t handle ); -extern user_handle_t window_from_point( struct desktop *desktop, int x, int y ); +extern user_handle_t shallow_window_from_point( struct desktop *desktop, int x, int y ); +extern struct thread *window_thread_from_point( user_handle_t scope, int x, int y ); extern user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread ); extern struct window_class *get_window_class( user_handle_t window ); diff --git a/server/window.c b/server/window.c index 484cd225b05..9efdd69d38a 100644 --- a/server/window.c +++ b/server/window.c @@ -727,14 +727,38 @@ static int get_window_children_from_point( struct window *parent, int x, int y, return 1; } -/* find window containing point (in absolute coords) */ -user_handle_t window_from_point( struct desktop *desktop, int x, int y ) +/* get handle of root of top-most window containing point */ +user_handle_t shallow_window_from_point( struct desktop *desktop, int x, int y ) { - struct window *ret; + struct window *ptr; if (!desktop->top_window) return 0; - ret = child_window_from_point( desktop->top_window, x, y ); - return ret->handle; + + LIST_FOR_EACH_ENTRY( ptr, &desktop->top_window->children, struct window, entry ) + { + if (!is_point_in_window( ptr, x, y )) continue; /* skip it */ + return ptr->handle; + } + return desktop->top_window->handle; +} + +/* return thread of top-most window containing point (in absolute coords) */ +struct thread *window_thread_from_point( user_handle_t scope, int x, int y ) +{ + struct window *win = get_user_object( scope, USER_WINDOW ); + struct window *ptr; + + if (!win) return NULL; + + for (ptr = win; ptr && !is_desktop_window(ptr); ptr = ptr->parent) + { + x -= ptr->client_rect.left; + y -= ptr->client_rect.top; + } + + ptr = child_window_from_point( win, x, y ); + if (!ptr->thread) return NULL; + return (struct thread *)grab_object( ptr->thread ); } /* return list of all windows containing point (in absolute coords) */