Put in place the basic infrastructure to allow supporting multiple
desktop windows.
diff --git a/server/protocol.def b/server/protocol.def
index d79d5ef..7d2c62d 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1769,6 +1769,13 @@
@END
+/* Retrieve the desktop window for the current thread */
+@REQ(get_desktop_window)
+@REPLY
+ user_handle_t handle; /* handle to the desktop window */
+@END
+
+
/* Set a window owner */
@REQ(set_window_owner)
user_handle_t handle; /* handle to the window */
diff --git a/server/request.h b/server/request.h
index b8cd447..ca98368 100644
--- a/server/request.h
+++ b/server/request.h
@@ -243,6 +243,7 @@
DECL_HANDLER(get_named_pipe_info);
DECL_HANDLER(create_window);
DECL_HANDLER(destroy_window);
+DECL_HANDLER(get_desktop_window);
DECL_HANDLER(set_window_owner);
DECL_HANDLER(get_window_info);
DECL_HANDLER(set_window_info);
@@ -453,6 +454,7 @@
(req_handler)req_get_named_pipe_info,
(req_handler)req_create_window,
(req_handler)req_destroy_window,
+ (req_handler)req_get_desktop_window,
(req_handler)req_set_window_owner,
(req_handler)req_get_window_info,
(req_handler)req_set_window_info,
diff --git a/server/trace.c b/server/trace.c
index 4f8d784..bb80613 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2226,6 +2226,15 @@
fprintf( stderr, " handle=%p", req->handle );
}
+static void dump_get_desktop_window_request( const struct get_desktop_window_request *req )
+{
+}
+
+static void dump_get_desktop_window_reply( const struct get_desktop_window_reply *req )
+{
+ fprintf( stderr, " handle=%p", req->handle );
+}
+
static void dump_set_window_owner_request( const struct set_window_owner_request *req )
{
fprintf( stderr, " handle=%p,", req->handle );
@@ -3206,6 +3215,7 @@
(dump_func)dump_get_named_pipe_info_request,
(dump_func)dump_create_window_request,
(dump_func)dump_destroy_window_request,
+ (dump_func)dump_get_desktop_window_request,
(dump_func)dump_set_window_owner_request,
(dump_func)dump_get_window_info_request,
(dump_func)dump_set_window_info_request,
@@ -3413,6 +3423,7 @@
(dump_func)dump_get_named_pipe_info_reply,
(dump_func)dump_create_window_reply,
(dump_func)0,
+ (dump_func)dump_get_desktop_window_reply,
(dump_func)dump_set_window_owner_reply,
(dump_func)dump_get_window_info_reply,
(dump_func)dump_set_window_info_reply,
@@ -3620,6 +3631,7 @@
"get_named_pipe_info",
"create_window",
"destroy_window",
+ "get_desktop_window",
"set_window_owner",
"get_window_info",
"set_window_info",
diff --git a/server/user.h b/server/user.h
index 44d8f38..5bf3735 100644
--- a/server/user.h
+++ b/server/user.h
@@ -38,6 +38,8 @@
USER_HOOK
};
+#define DESKTOP_ATOM ((atom_t)32769)
+
/* user handles functions */
extern user_handle_t alloc_user_handle( void *ptr, enum user_object type );
diff --git a/server/window.c b/server/window.c
index 1d6dbdc..0a4cdfa 100644
--- a/server/window.c
+++ b/server/window.c
@@ -96,8 +96,6 @@
int total;
};
-static struct window *top_window; /* top-level (desktop) window */
-
/* global window pointers */
static struct window *shell_window;
static struct window *shell_listview;
@@ -175,6 +173,12 @@
return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL;
}
+/* check if window is the desktop */
+static inline int is_desktop_window( const struct window *win )
+{
+ return !win->parent; /* only desktop windows have no parent */
+}
+
/* append a user handle to a handle array */
static int add_handle_to_array( struct user_handle_array *array, user_handle_t handle )
{
@@ -293,8 +297,6 @@
/* destroy a window */
static void destroy_window( struct window *win )
{
- assert( win != top_window );
-
/* destroy all children */
while (!list_empty(&win->children))
destroy_window( LIST_ENTRY( list_head(&win->children), struct window, entry ));
@@ -403,6 +405,21 @@
}
}
+/* get the desktop window */
+static struct window *get_desktop_window( int create )
+{
+ static struct window *top_window; /* FIXME: should be part of the desktop object */
+
+ if (!top_window && create)
+ {
+ if (!(top_window = create_window( NULL, NULL, DESKTOP_ATOM, 0 ))) return NULL;
+ current->desktop_users--;
+ top_window->thread = NULL; /* no thread owns the desktop */
+ top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+ }
+ return top_window;
+}
+
/* check whether child is a descendant of parent */
int is_child_window( user_handle_t parent, user_handle_t child )
{
@@ -422,7 +439,7 @@
int is_top_level_window( user_handle_t window )
{
struct window *win = get_user_object( window, USER_WINDOW );
- return (win && win->parent == top_window);
+ return (win && win->parent && is_desktop_window(win->parent));
}
/* make a window active if possible */
@@ -447,7 +464,7 @@
/* check if window and all its ancestors are visible */
static int is_visible( const struct window *win )
{
- while (win && win != top_window)
+ while (win && win->parent)
{
if (!(win->style & WS_VISIBLE)) return 0;
win = win->parent;
@@ -533,9 +550,9 @@
/* find window containing point (in absolute coords) */
user_handle_t window_from_point( int x, int y )
{
- struct window *ret;
+ struct window *ret, *top_window;
- if (!top_window) return 0;
+ if (!(top_window = get_desktop_window(0))) return 0;
ret = child_window_from_point( top_window, x, y );
return ret->handle;
}
@@ -546,7 +563,7 @@
struct window *ptr;
/* make point relative to top window */
- for (ptr = top->parent; ptr && ptr != top_window; ptr = ptr->parent)
+ for (ptr = top->parent; ptr; ptr = ptr->parent)
{
x -= ptr->client_rect.left;
y -= ptr->client_rect.top;
@@ -618,8 +635,11 @@
/* find a window that needs to receive a WM_PAINT; also clear its internal paint flag */
user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread )
{
- struct window *ptr, *win = find_child_to_repaint( top_window, thread );
+ struct window *ptr, *win, *top_window = get_desktop_window(0);
+ if (!top_window) return 0;
+
+ win = find_child_to_repaint( top_window, thread );
if (win && parent)
{
/* check that it is a child of the specified parent */
@@ -718,7 +738,7 @@
/* get the top-level window to clip against for a given window */
static inline struct window *get_top_clipping_window( struct window *win )
{
- while (win->parent && win->parent != top_window) win = win->parent;
+ while (win->parent && !is_desktop_window(win->parent)) win = win->parent;
return win;
}
@@ -916,7 +936,7 @@
if (!child->update_region) return;
- while (win->parent && win->parent != top_window)
+ while (win->parent)
{
/* map to parent client coords */
offset_x += win->window_rect.left;
@@ -1095,7 +1115,7 @@
/* if some parent is not visible start from the next sibling */
if (!is_visible( win )) return 0;
- for (ptr = from_child; ptr && ptr != top_window; ptr = ptr->parent)
+ for (ptr = from_child; ptr; ptr = ptr->parent)
{
if (!(ptr->style & WS_VISIBLE) || (ptr->style & WS_MINIMIZE)) from_sibling = ptr;
if (ptr == win) break;
@@ -1106,15 +1126,14 @@
if ((flags & UPDATE_NONCLIENT) && !(flags & (UPDATE_PAINT|UPDATE_INTERNALPAINT)))
{
- for (ptr = win->parent; ptr && ptr != top_window; ptr = ptr->parent)
+ for (ptr = win->parent; ptr; ptr = ptr->parent)
{
if (!(ptr->style & WS_CLIPCHILDREN) && win_needs_repaint( ptr ))
return 0;
}
if (from_child && !(flags & UPDATE_ALLCHILDREN))
{
- for (ptr = from_sibling ? from_sibling : from_child;
- ptr && ptr != top_window; ptr = ptr->parent)
+ for (ptr = from_sibling ? from_sibling : from_child; ptr; ptr = ptr->parent)
{
if (!(ptr->style & WS_CLIPCHILDREN) && win_needs_repaint( ptr )) from_sibling = ptr;
if (ptr == win) break;
@@ -1300,35 +1319,24 @@
/* create a window */
DECL_HANDLER(create_window)
{
- struct window *win;
+ struct window *win, *parent, *owner = NULL;
reply->handle = 0;
- if (!req->parent) /* return desktop window */
- {
- if (!top_window)
- {
- if (!(top_window = create_window( NULL, NULL, req->atom, req->instance ))) return;
- current->desktop_users--;
- top_window->thread = NULL; /* no thread owns the desktop */
- top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
- }
- win = top_window;
- }
- else
- {
- struct window *parent, *owner = NULL;
- if (!(parent = get_window( req->parent ))) return;
- if (req->owner && !(owner = get_window( req->owner ))) return;
- if (owner == top_window) owner = NULL;
- else if (owner && parent != top_window)
+ if (!(parent = get_window( req->parent ))) return;
+ if (req->owner)
+ {
+ if (!(owner = get_window( req->owner ))) return;
+ if (is_desktop_window(owner)) owner = NULL;
+ else if (!is_desktop_window(parent))
{
/* an owned window must be created as top-level */
set_error( STATUS_ACCESS_DENIED );
return;
}
- if (!(win = create_window( parent, owner, req->atom, req->instance ))) return;
}
+ if (!(win = create_window( parent, owner, req->atom, req->instance ))) return;
+
reply->handle = win->handle;
reply->extra = win->nb_extra_bytes;
reply->class_ptr = get_class_client_ptr( win->class );
@@ -1343,7 +1351,7 @@
if (!(win = get_window( req->handle ))) return;
if (req->parent && !(parent = get_window( req->parent ))) return;
- if (win == top_window)
+ if (is_desktop_window(win))
{
set_error( STATUS_INVALID_PARAMETER );
return;
@@ -1360,12 +1368,21 @@
struct window *win = get_window( req->handle );
if (win)
{
- if (win != top_window) destroy_window( win );
+ if (!is_desktop_window(win)) destroy_window( win );
else set_error( STATUS_ACCESS_DENIED );
}
}
+/* retrieve the desktop window for the current thread */
+DECL_HANDLER(get_desktop_window)
+{
+ struct window *win = get_desktop_window(1);
+
+ if (win) reply->handle = win->handle;
+}
+
+
/* set a window owner */
DECL_HANDLER(set_window_owner)
{
@@ -1374,7 +1391,7 @@
if (!win) return;
if (req->owner && !(owner = get_window( req->owner ))) return;
- if (win == top_window)
+ if (is_desktop_window(win))
{
set_error( STATUS_ACCESS_DENIED );
return;
@@ -1413,7 +1430,7 @@
struct window *win = get_window( req->handle );
if (!win) return;
- if (req->flags && win == top_window)
+ if (req->flags && is_desktop_window(win))
{
set_error( STATUS_ACCESS_DENIED );
return;
@@ -1805,7 +1822,7 @@
{
win->paint_flags &= ~PAINT_ERASE;
/* desktop window only gets erased, not repainted */
- if (win == top_window) validate_whole_window( win );
+ if (is_desktop_window(win)) validate_whole_window( win );
}
}
}