Moved the WindowFromPoint functionality to the server so that we can
properly take into account the window region.
diff --git a/server/protocol.def b/server/protocol.def
index df2bf68..a2864be 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1777,6 +1777,17 @@
@END
+/* Get a list of the window children that contain a given point */
+@REQ(get_window_children_from_point)
+ user_handle_t parent; /* parent window */
+ int x; /* point in parent coordinates */
+ int y;
+@REPLY
+ int count; /* total count of children */
+ VARARG(children,user_handles); /* children handles */
+@END
+
+
/* Get window tree information from a window handle */
@REQ(get_window_tree)
user_handle_t handle; /* handle to the window */
diff --git a/server/region.c b/server/region.c
index ab6645c..e0035e9 100644
--- a/server/region.c
+++ b/server/region.c
@@ -758,3 +758,20 @@
dst->extents.bottom = max(src1->extents.bottom, src2->extents.bottom);
return dst;
}
+
+/* check if the given point is inside the region */
+int point_in_region( struct region *region, int x, int y )
+{
+ const rectangle_t *ptr, *end;
+
+ for (ptr = region->rects, end = region->rects + region->num_rects; ptr < end; ptr++)
+ {
+ if (ptr->top > y) return 0;
+ if (ptr->bottom <= y) continue;
+ /* now we are in the correct band */
+ if (ptr->left > x) return 0;
+ if (ptr->right <= x) continue;
+ return 1;
+ }
+ return 0;
+}
diff --git a/server/request.h b/server/request.h
index 86c7419..92e6d57 100644
--- a/server/request.h
+++ b/server/request.h
@@ -244,6 +244,7 @@
DECL_HANDLER(set_window_info);
DECL_HANDLER(get_window_parents);
DECL_HANDLER(get_window_children);
+DECL_HANDLER(get_window_children_from_point);
DECL_HANDLER(get_window_tree);
DECL_HANDLER(set_window_rectangles);
DECL_HANDLER(get_window_rectangles);
@@ -426,6 +427,7 @@
(req_handler)req_set_window_info,
(req_handler)req_get_window_parents,
(req_handler)req_get_window_children,
+ (req_handler)req_get_window_children_from_point,
(req_handler)req_get_window_tree,
(req_handler)req_set_window_rectangles,
(req_handler)req_get_window_rectangles,
diff --git a/server/trace.c b/server/trace.c
index f9445bc..1389608 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2105,6 +2105,20 @@
dump_varargs_user_handles( cur_size );
}
+static void dump_get_window_children_from_point_request( const struct get_window_children_from_point_request *req )
+{
+ fprintf( stderr, " parent=%p,", req->parent );
+ fprintf( stderr, " x=%d,", req->x );
+ fprintf( stderr, " y=%d", req->y );
+}
+
+static void dump_get_window_children_from_point_reply( const struct get_window_children_from_point_reply *req )
+{
+ fprintf( stderr, " count=%d,", req->count );
+ fprintf( stderr, " children=" );
+ dump_varargs_user_handles( cur_size );
+}
+
static void dump_get_window_tree_request( const struct get_window_tree_request *req )
{
fprintf( stderr, " handle=%p", req->handle );
@@ -2677,6 +2691,7 @@
(dump_func)dump_set_window_info_request,
(dump_func)dump_get_window_parents_request,
(dump_func)dump_get_window_children_request,
+ (dump_func)dump_get_window_children_from_point_request,
(dump_func)dump_get_window_tree_request,
(dump_func)dump_set_window_rectangles_request,
(dump_func)dump_get_window_rectangles_request,
@@ -2856,6 +2871,7 @@
(dump_func)dump_set_window_info_reply,
(dump_func)dump_get_window_parents_reply,
(dump_func)dump_get_window_children_reply,
+ (dump_func)dump_get_window_children_from_point_reply,
(dump_func)dump_get_window_tree_reply,
(dump_func)0,
(dump_func)dump_get_window_rectangles_reply,
@@ -3035,6 +3051,7 @@
"set_window_info",
"get_window_parents",
"get_window_children",
+ "get_window_children_from_point",
"get_window_tree",
"set_window_rectangles",
"get_window_rectangles",
diff --git a/server/user.h b/server/user.h
index 80ccddf..638ffc6 100644
--- a/server/user.h
+++ b/server/user.h
@@ -83,6 +83,7 @@
const struct region *src2 );
extern struct region *union_region( struct region *dst, const struct region *src1,
const struct region *src2 );
+extern int point_in_region( struct region *region, int x, int y );
static inline struct region *create_empty_region(void) { return create_region( NULL, 0 ); }
/* window functions */
diff --git a/server/window.c b/server/window.c
index fc08531..00a004e 100644
--- a/server/window.c
+++ b/server/window.c
@@ -66,9 +66,9 @@
struct window_class *class; /* window class */
atom_t atom; /* class atom */
user_handle_t last_active; /* last active popup */
- rectangle_t window_rect; /* window rectangle */
- rectangle_t client_rect; /* client rectangle */
- struct region *win_region; /* window region (for shaped windows) */
+ rectangle_t window_rect; /* window rectangle (relative to parent client area) */
+ rectangle_t client_rect; /* client rectangle (relative to parent client area) */
+ struct region *win_region; /* region for shaped windows (relative to window rect) */
unsigned int style; /* window style */
unsigned int ex_style; /* window extended style */
unsigned int id; /* window id */
@@ -83,6 +83,14 @@
char extra_bytes[1]; /* extra bytes storage */
};
+/* growable array of user handles */
+struct user_handle_array
+{
+ user_handle_t *handles;
+ int count;
+ int total;
+};
+
static struct window *top_window; /* top-level (desktop) window */
/* global window pointers */
@@ -145,6 +153,26 @@
}
}
+/* append a user handle to a handle array */
+static int add_handle_to_array( struct user_handle_array *array, user_handle_t handle )
+{
+ if (array->count >= array->total)
+ {
+ int new_total = max( array->total * 2, 32 );
+ user_handle_t *new_array = realloc( array->handles, new_total * sizeof(*new_array) );
+ if (!new_array)
+ {
+ free( array->handles );
+ set_error( STATUS_NO_MEMORY );
+ return 0;
+ }
+ array->handles = new_array;
+ array->total = new_total;
+ }
+ array->handles[array->count++] = handle;
+ return 1;
+}
+
/* set a window property */
static void set_property( struct window *win, atom_t atom, obj_handle_t handle,
enum property_type type )
@@ -377,6 +405,23 @@
return 1;
}
+/* check if point is inside the window */
+static inline int is_point_in_window( struct window *win, int x, int y )
+{
+ 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 (x < win->window_rect.left || x >= win->window_rect.right ||
+ y < win->window_rect.top || y >= win->window_rect.bottom)
+ 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 ))
+ return 0; /* not in window region */
+ return 1;
+}
+
/* find child of 'parent' that contains the given point (in parent-relative coords) */
static struct window *child_window_from_point( struct window *parent, int x, int y )
{
@@ -384,16 +429,7 @@
for (ptr = parent->first_child; ptr; ptr = ptr->next)
{
- if (!(ptr->style & WS_VISIBLE)) continue; /* not visible -> skip */
- if ((ptr->style & (WS_POPUP|WS_CHILD|WS_DISABLED)) == (WS_CHILD|WS_DISABLED))
- continue; /* disabled child -> skip */
- if ((ptr->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
- continue; /* transparent -> skip */
- if (x < ptr->window_rect.left || x >= ptr->window_rect.right ||
- y < ptr->window_rect.top || y >= ptr->window_rect.bottom)
- continue; /* not in window -> skip */
-
- /* FIXME: check window region here */
+ if (!is_point_in_window( ptr, x, y )) continue; /* skip it */
/* if window is minimized or disabled, return at once */
if (ptr->style & (WS_MINIMIZE|WS_DISABLED)) return ptr;
@@ -408,6 +444,32 @@
return parent; /* not found any child */
}
+/* find all children of 'parent' that contain the given point */
+static int get_window_children_from_point( struct window *parent, int x, int y,
+ struct user_handle_array *array )
+{
+ struct window *ptr;
+
+ for (ptr = parent->first_child; ptr; ptr = ptr->next)
+ {
+ if (!is_point_in_window( ptr, x, y )) 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)) &&
+ x >= ptr->client_rect.left && x < ptr->client_rect.right &&
+ y >= ptr->client_rect.top && y < ptr->client_rect.bottom)
+ {
+ if (!get_window_children_from_point( ptr, x - ptr->client_rect.left,
+ y - ptr->client_rect.top, array ))
+ return 0;
+ }
+
+ /* now add window to the array */
+ if (!add_handle_to_array( array, ptr->handle )) return 0;
+ }
+ return 1;
+}
+
/* find window containing point (in absolute coords) */
user_handle_t window_from_point( int x, int y )
{
@@ -418,6 +480,35 @@
return ret->handle;
}
+/* 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 )
+{
+ struct window *ptr;
+
+ /* make point relative to top window */
+ for (ptr = top->parent; ptr && ptr != top_window; ptr = ptr->parent)
+ {
+ x -= ptr->client_rect.left;
+ y -= ptr->client_rect.top;
+ }
+
+ if (!is_point_in_window( top, x, y )) return 1;
+
+ /* if point is in client area, and window is not minimized or disabled, check children */
+ if (!(top->style & (WS_MINIMIZE|WS_DISABLED)) &&
+ x >= top->client_rect.left && x < top->client_rect.right &&
+ y >= top->client_rect.top && y < top->client_rect.bottom)
+ {
+ if (!get_window_children_from_point( top, x - top->client_rect.left,
+ y - top->client_rect.top, array ))
+ return 0;
+ }
+ /* now add window to the array */
+ if (!add_handle_to_array( array, top->handle )) return 0;
+ return 1;
+}
+
+
/* return the thread owning a window */
struct thread *get_window_thread( user_handle_t handle )
{
@@ -825,6 +916,27 @@
}
+/* get a list of the window children that contain a given point */
+DECL_HANDLER(get_window_children_from_point)
+{
+ struct user_handle_array array;
+ struct window *parent = get_window( req->parent );
+ size_t len;
+
+ if (!parent) return;
+
+ array.handles = NULL;
+ array.count = 0;
+ array.total = 0;
+ if (!all_windows_from_point( parent, req->x, req->y, &array )) return;
+
+ reply->count = array.count;
+ len = min( get_reply_max_size(), array.count * sizeof(user_handle_t) );
+ if (len) set_reply_data_ptr( array.handles, len );
+ else free( array.handles );
+}
+
+
/* get window tree information from a window handle */
DECL_HANDLER(get_window_tree)
{