Try to always keep the server window Z-order in sync with the X11 one
using a heuristic based on mouse and expose events.
diff --git a/server/protocol.def b/server/protocol.def
index 9602819..c899ce9 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1916,6 +1916,13 @@
#define UPDATE_NOREGION 0x40 /* don't return a region, only the flags */
+/* Update the z order of a window so that a given rectangle is fully visible */
+@REQ(update_window_zorder)
+ user_handle_t window; /* handle to the window */
+ rectangle_t rect; /* rectangle that must be visible */
+@END
+
+
/* Mark parts of a window as needing a redraw */
@REQ(redraw_window)
user_handle_t window; /* handle to the window */
diff --git a/server/request.h b/server/request.h
index 3902c7b..dc57117 100644
--- a/server/request.h
+++ b/server/request.h
@@ -257,6 +257,7 @@
DECL_HANDLER(get_window_region);
DECL_HANDLER(set_window_region);
DECL_HANDLER(get_update_region);
+DECL_HANDLER(update_window_zorder);
DECL_HANDLER(redraw_window);
DECL_HANDLER(set_window_property);
DECL_HANDLER(remove_window_property);
@@ -446,6 +447,7 @@
(req_handler)req_get_window_region,
(req_handler)req_set_window_region,
(req_handler)req_get_update_region,
+ (req_handler)req_update_window_zorder,
(req_handler)req_redraw_window,
(req_handler)req_set_window_property,
(req_handler)req_remove_window_property,
diff --git a/server/trace.c b/server/trace.c
index 266673f..a07a54c 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2302,6 +2302,13 @@
dump_varargs_rectangles( cur_size );
}
+static void dump_update_window_zorder_request( const struct update_window_zorder_request *req )
+{
+ fprintf( stderr, " window=%p,", req->window );
+ fprintf( stderr, " rect=" );
+ dump_rectangle( &req->rect );
+}
+
static void dump_redraw_window_request( const struct redraw_window_request *req )
{
fprintf( stderr, " window=%p,", req->window );
@@ -2839,6 +2846,7 @@
(dump_func)dump_get_window_region_request,
(dump_func)dump_set_window_region_request,
(dump_func)dump_get_update_region_request,
+ (dump_func)dump_update_window_zorder_request,
(dump_func)dump_redraw_window_request,
(dump_func)dump_set_window_property_request,
(dump_func)dump_remove_window_property_request,
@@ -3027,6 +3035,7 @@
(dump_func)dump_get_update_region_reply,
(dump_func)0,
(dump_func)0,
+ (dump_func)0,
(dump_func)dump_remove_window_property_reply,
(dump_func)dump_get_window_property_reply,
(dump_func)dump_get_window_properties_reply,
@@ -3211,6 +3220,7 @@
"get_window_region",
"set_window_region",
"get_update_region",
+ "update_window_zorder",
"redraw_window",
"set_window_property",
"remove_window_property",
diff --git a/server/window.c b/server/window.c
index 219a244..ae46dc9 100644
--- a/server/window.c
+++ b/server/window.c
@@ -645,15 +645,23 @@
}
+/* compute the intersection of two rectangles; return 0 if the result is empty */
+static inline int intersect_rect( rectangle_t *dst, const rectangle_t *src1, const rectangle_t *src2 )
+{
+ dst->left = max( src1->left, src2->left );
+ dst->top = max( src1->top, src2->top );
+ dst->right = min( src1->right, src2->right );
+ dst->bottom = min( src1->bottom, src2->bottom );
+ return (dst->left < dst->right && dst->top < dst->bottom);
+}
+
+
/* set the region to the client rect clipped by the window rect, in parent-relative coordinates */
static void set_region_client_rect( struct region *region, struct window *win )
{
rectangle_t rect;
- rect.left = max( win->window_rect.left, win->client_rect.left );
- rect.top = max( win->window_rect.top, win->client_rect.top );
- rect.right = min( win->window_rect.right, win->client_rect.right );
- rect.bottom = min( win->window_rect.bottom, win->client_rect.bottom );
+ intersect_rect( &rect, &win->window_rect, &win->client_rect );
set_region_rect( region, &rect );
}
@@ -1667,6 +1675,29 @@
}
+/* update the z order of a window so that a given rectangle is fully visible */
+DECL_HANDLER(update_window_zorder)
+{
+ rectangle_t tmp;
+ struct window *ptr, *win = get_window( req->window );
+
+ if (!win || !win->parent || !is_visible( win )) return; /* nothing to do */
+
+ LIST_FOR_EACH_ENTRY( ptr, &win->parent->children, struct window, entry )
+ {
+ if (ptr == win) break;
+ if (!(ptr->style & WS_VISIBLE)) continue;
+ if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
+ if (!intersect_rect( &tmp, &ptr->visible_rect, &req->rect )) continue;
+ if (ptr->win_region && !rect_in_region( ptr->win_region, &req->rect )) continue;
+ /* found a window obscuring the rectangle, now move win above this one */
+ list_remove( &win->entry );
+ list_add_before( &ptr->entry, &win->entry );
+ break;
+ }
+}
+
+
/* mark parts of a window as needing a redraw */
DECL_HANDLER(redraw_window)
{