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 );
         }
     }
 }