server: Scale coordinates in get_window_children_from_point based on DPI awareness.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2018-08-27 13:32:57 +02:00
parent 6d4e625cb2
commit 87d1a4a329
6 changed files with 65 additions and 45 deletions

View File

@ -260,6 +260,7 @@ static HWND *list_children_from_point( HWND hwnd, POINT pt )
req->parent = wine_server_user_handle( hwnd );
req->x = pt.x;
req->y = pt.y;
req->dpi = get_thread_dpi();
wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
if (!wine_server_call( req )) count = reply->count;
}
@ -289,6 +290,7 @@ HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
{
int i, res;
HWND ret, *list;
POINT win_pt;
if (!hwndScope) hwndScope = GetDesktopWindow();
@ -319,7 +321,8 @@ HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
*hittest = HTCLIENT;
break;
}
res = SendMessageW( list[i], WM_NCHITTEST, 0, MAKELONG(pt.x,pt.y) );
win_pt = point_thread_to_win_dpi( list[i], pt );
res = SendMessageW( list[i], WM_NCHITTEST, 0, MAKELPARAM( win_pt.x, win_pt.y ));
if (res != HTTRANSPARENT)
{
*hittest = res; /* Found the window */

View File

@ -3634,6 +3634,8 @@ struct get_window_children_from_point_request
user_handle_t parent;
int x;
int y;
int dpi;
char __pad_28[4];
};
struct get_window_children_from_point_reply
{
@ -6533,6 +6535,6 @@ union generic_reply
struct terminate_job_reply terminate_job_reply;
};
#define SERVER_PROTOCOL_VERSION 558
#define SERVER_PROTOCOL_VERSION 559
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -2609,6 +2609,7 @@ enum message_type
user_handle_t parent; /* parent window */
int x; /* point in parent coordinates */
int y;
int dpi; /* dpi for the point coordinates */
@REPLY
int count; /* total count of children */
VARARG(children,user_handles); /* children handles */

View File

@ -1745,7 +1745,8 @@ C_ASSERT( sizeof(struct get_window_children_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_window_children_from_point_request, parent) == 12 );
C_ASSERT( FIELD_OFFSET(struct get_window_children_from_point_request, x) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_window_children_from_point_request, y) == 20 );
C_ASSERT( sizeof(struct get_window_children_from_point_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_window_children_from_point_request, dpi) == 24 );
C_ASSERT( sizeof(struct get_window_children_from_point_request) == 32 );
C_ASSERT( FIELD_OFFSET(struct get_window_children_from_point_reply, count) == 8 );
C_ASSERT( sizeof(struct get_window_children_from_point_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_window_tree_request, handle) == 12 );

View File

@ -3181,6 +3181,7 @@ static void dump_get_window_children_from_point_request( const struct get_window
fprintf( stderr, " parent=%08x", req->parent );
fprintf( stderr, ", x=%d", req->x );
fprintf( stderr, ", y=%d", req->y );
fprintf( stderr, ", dpi=%d", req->dpi );
}
static void dump_get_window_children_from_point_reply( const struct get_window_children_from_point_reply *req )

View File

@ -658,6 +658,29 @@ static void map_dpi_region( struct window *win, struct region *region, unsigned
scale_region( region, from, to );
}
/* convert coordinates from client to screen coords */
static inline void client_to_screen( struct window *win, int *x, int *y )
{
for ( ; win && !is_desktop_window(win); win = win->parent)
{
*x += win->client_rect.left;
*y += win->client_rect.top;
}
}
/* convert coordinates from screen to client coords and dpi */
static void screen_to_client( struct window *win, int *x, int *y, unsigned int dpi )
{
int offset_x = 0, offset_y = 0;
if (is_desktop_window( win )) return;
client_to_screen( win, &offset_x, &offset_y );
map_dpi_point( win, x, y, dpi, win->dpi );
*x -= offset_x;
*y -= offset_y;
}
/* check if window and all its ancestors are visible */
static int is_visible( const struct window *win )
{
@ -686,18 +709,19 @@ int is_window_transparent( user_handle_t window )
return (win->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT);
}
/* check if point is inside the window */
static inline int is_point_in_window( struct window *win, int x, int y )
/* check if point is inside the window, and map to window dpi */
static int is_point_in_window( struct window *win, int *x, int *y, unsigned int dpi )
{
if (!(win->style & WS_VISIBLE)) return 0; /* not visible */
if ((win->style & (WS_POPUP|WS_CHILD|WS_DISABLED)) == (WS_CHILD|WS_DISABLED))
return 0; /* disabled child */
if ((win->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
return 0; /* transparent */
if (!point_in_rect( &win->visible_rect, x, y ))
map_dpi_point( win, x, y, dpi, win->dpi );
if (!point_in_rect( &win->visible_rect, *x, *y ))
return 0; /* not in window */
if (win->win_region &&
!point_in_region( win->win_region, x - win->window_rect.left, y - win->window_rect.top ))
!point_in_region( win->win_region, *x - win->window_rect.left, *y - win->window_rect.top ))
return 0; /* not in window region */
return 1;
}
@ -732,15 +756,18 @@ static struct window *child_window_from_point( struct window *parent, int x, int
LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry )
{
if (!is_point_in_window( ptr, x, y )) continue; /* skip it */
int x_child = x, y_child = y;
if (!is_point_in_window( ptr, &x_child, &y_child, parent->dpi )) continue; /* skip it */
/* if window is minimized or disabled, return at once */
if (ptr->style & (WS_MINIMIZE|WS_DISABLED)) return ptr;
/* if point is not in client area, return at once */
if (!point_in_rect( &ptr->client_rect, x, y )) return ptr;
if (!point_in_rect( &ptr->client_rect, x_child, y_child )) return ptr;
return child_window_from_point( ptr, x - ptr->client_rect.left, y - ptr->client_rect.top );
return child_window_from_point( ptr, x_child - ptr->client_rect.left,
y_child - ptr->client_rect.top );
}
return parent; /* not found any child */
}
@ -753,13 +780,15 @@ static int get_window_children_from_point( struct window *parent, int x, int y,
LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry )
{
if (!is_point_in_window( ptr, x, y )) continue; /* skip it */
int x_child = x, y_child = y;
if (!is_point_in_window( ptr, &x_child, &y_child, parent->dpi )) continue; /* skip it */
/* if point is in client area, and window is not minimized or disabled, check children */
if (!(ptr->style & (WS_MINIMIZE|WS_DISABLED)) && point_in_rect( &ptr->client_rect, x, y ))
if (!(ptr->style & (WS_MINIMIZE|WS_DISABLED)) && point_in_rect( &ptr->client_rect, x_child, y_child ))
{
if (!get_window_children_from_point( ptr, x - ptr->client_rect.left,
y - ptr->client_rect.top, array ))
if (!get_window_children_from_point( ptr, x_child - ptr->client_rect.left,
y_child - ptr->client_rect.top, array ))
return 0;
}
@ -778,7 +807,9 @@ user_handle_t shallow_window_from_point( struct desktop *desktop, int x, int y )
LIST_FOR_EACH_ENTRY( ptr, &desktop->top_window->children, struct window, entry )
{
if (!is_point_in_window( ptr, x, y )) continue; /* skip it */
int x_child = x, y_child = y;
if (!is_point_in_window( ptr, &x_child, &y_child, 0 )) continue; /* skip it */
return ptr->handle;
}
return desktop->top_window->handle;
@ -788,35 +819,26 @@ user_handle_t shallow_window_from_point( struct desktop *desktop, int x, int y )
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 );
screen_to_client( win, &x, &y, 0 );
win = child_window_from_point( win, x, y );
if (!win->thread) return NULL;
return (struct thread *)grab_object( win->thread );
}
/* return list of all windows containing point (in absolute coords) */
static int all_windows_from_point( struct window *top, int x, int y, struct user_handle_array *array )
static int all_windows_from_point( struct window *top, int x, int y, unsigned int dpi,
struct user_handle_array *array )
{
struct window *ptr;
/* make point relative to top window */
for (ptr = top->parent; ptr && !is_desktop_window(ptr); ptr = ptr->parent)
if (!is_desktop_window( top ) && !is_desktop_window( top->parent ))
{
x -= ptr->client_rect.left;
y -= ptr->client_rect.top;
screen_to_client( top->parent, &x, &y, dpi );
dpi = top->parent->dpi;
}
if (!is_point_in_window( top, x, y )) return 1;
if (!is_point_in_window( top, &x, &y, dpi )) return 1;
/* if point is in client area, and window is not minimized or disabled, check children */
if (!(top->style & (WS_MINIMIZE|WS_DISABLED)) && point_in_rect( &top->client_rect, x, y ))
{
@ -915,16 +937,6 @@ static struct region *intersect_window_region( struct region *region, struct win
}
/* convert coordinates from client to screen coords */
static inline void client_to_screen( struct window *win, int *x, int *y )
{
for ( ; win && !is_desktop_window(win); win = win->parent)
{
*x += win->client_rect.left;
*y += win->client_rect.top;
}
}
/* convert coordinates from client to screen coords */
static inline void client_to_screen_rect( struct window *win, rectangle_t *rect )
{
@ -2219,7 +2231,7 @@ DECL_HANDLER(get_window_children_from_point)
array.handles = NULL;
array.count = 0;
array.total = 0;
if (!all_windows_from_point( parent, req->x, req->y, &array )) return;
if (!all_windows_from_point( parent, req->x, req->y, req->dpi, &array )) return;
reply->count = array.count;
len = min( get_reply_max_size(), array.count * sizeof(user_handle_t) );