diff --git a/dlls/user/tests/.cvsignore b/dlls/user/tests/.cvsignore
index 4b8da69621f297c4cddf3e917026a8215ce19719..a05f2ec869c4191c4355186e5063baf97b1cbd9e 100644
--- a/dlls/user/tests/.cvsignore
+++ b/dlls/user/tests/.cvsignore
@@ -3,4 +3,5 @@ class.ok
 sysparams.ok
 testlist.c
 user32_test.exe.spec.c
+win.ok
 wsprintf.ok
diff --git a/dlls/user/tests/Makefile.in b/dlls/user/tests/Makefile.in
index 8aae4d4e53c7af9f863f7b94db2623b5b09dfdb7..7e3d7b40cbaf30b9618d6f8f56db5582464a1b77 100644
--- a/dlls/user/tests/Makefile.in
+++ b/dlls/user/tests/Makefile.in
@@ -8,6 +8,7 @@ IMPORTS   = user32 gdi32 advapi32
 CTESTS = \
 	class.c \
 	sysparams.c \
+	win.c \
 	wsprintf.c
 
 @MAKE_TEST_RULES@
diff --git a/dlls/user/tests/win.c b/dlls/user/tests/win.c
new file mode 100644
index 0000000000000000000000000000000000000000..38958e956089f442ae8edf006b3cdcb523c21b39
--- /dev/null
+++ b/dlls/user/tests/win.c
@@ -0,0 +1,401 @@
+/*
+ * Unit tests for window handling
+ *
+ * Copyright 2002 Bill Medland
+ * Copyright 2002 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+
+static HWND (WINAPI *pGetAncestor)(HWND,UINT);
+
+static HWND hwndMain, hwndMain2;
+
+/* check the values returned by the various parent/owner functions on a given window */
+static void check_parents( HWND hwnd, HWND ga_parent, HWND gwl_parent, HWND get_parent,
+                           HWND gw_owner, HWND ga_root, HWND ga_root_owner )
+{
+    HWND res;
+
+    if (pGetAncestor)
+    {
+        res = pGetAncestor( hwnd, GA_PARENT );
+        ok( res == ga_parent, "Wrong result for GA_PARENT %x expected %x", res, ga_parent );
+    }
+    res = GetWindowLongW( hwnd, GWL_HWNDPARENT );
+    ok( res == gwl_parent, "Wrong result for GWL_HWNDPARENT %x expected %x", res, gwl_parent );
+    res = GetParent( hwnd );
+    ok( res == get_parent, "Wrong result for GetParent %x expected %x", res, get_parent );
+    res = GetWindow( hwnd, GW_OWNER );
+    ok( res == gw_owner, "Wrong result for GW_OWNER %x expected %x", res, gw_owner );
+    if (pGetAncestor)
+    {
+        res = pGetAncestor( hwnd, GA_ROOT );
+        ok( res == ga_root, "Wrong result for GA_ROOT %x expected %x", res, ga_root );
+        res = pGetAncestor( hwnd, GA_ROOTOWNER );
+        ok( res == ga_root_owner, "Wrong result for GA_ROOTOWNER %x expected %x", res, ga_root_owner );
+    }
+}
+
+
+static HWND create_tool_window( LONG style, HWND parent )
+{
+    HWND ret = CreateWindowExA(0, "ToolWindowClass", "Tool window 1", style,
+                               0, 0, 100, 100, parent, 0, 0, NULL );
+    ok( ret != 0, "Creation failed" );
+    return ret;
+}
+
+/* test parent and owner values for various combinations */
+static void test_parent_owner(void)
+{
+    LONG style;
+    HWND test, owner, ret;
+    HWND desktop = GetDesktopWindow();
+    HWND child = create_tool_window( WS_CHILD, hwndMain );
+
+    trace( "main window %x main2 %x desktop %x child %x\n", hwndMain, hwndMain2, desktop, child );
+
+    /* child without parent, should fail */
+    test = CreateWindowExA(0, "ToolWindowClass", "Tool window 1",
+                           WS_CHILD, 0, 0, 100, 100, 0, 0, 0, NULL );
+    ok( !test, "WS_CHILD without parent created" );
+
+    /* desktop window */
+    check_parents( desktop, 0, 0, 0, 0, 0, 0 );
+    style = GetWindowLongW( desktop, GWL_STYLE );
+    ok( !SetWindowLongW( desktop, GWL_STYLE, WS_POPUP ), "Set GWL_STYLE on desktop succeeded" );
+    ok( !SetWindowLongW( desktop, GWL_STYLE, 0 ), "Set GWL_STYLE on desktop succeeded" );
+    ok( GetWindowLongW( desktop, GWL_STYLE ) == style, "Desktop style changed" );
+
+    /* normal child window */
+    test = create_tool_window( WS_CHILD, hwndMain );
+    trace( "created child %x\n", test );
+    check_parents( test, hwndMain, hwndMain, hwndMain, 0, hwndMain, hwndMain );
+    SetWindowLongW( test, GWL_STYLE, 0 );
+    check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
+    SetWindowLongW( test, GWL_STYLE, WS_POPUP );
+    check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
+    SetWindowLongW( test, GWL_STYLE, WS_POPUP|WS_CHILD );
+    check_parents( test, hwndMain, hwndMain, 0, 0, hwndMain, test );
+    SetWindowLongW( test, GWL_STYLE, WS_CHILD );
+    DestroyWindow( test );
+
+    /* child of desktop */
+    test = create_tool_window( WS_CHILD, desktop );
+    trace( "created child of desktop %x\n", test );
+    check_parents( test, desktop, 0, desktop, 0, test, desktop );
+    SetWindowLongW( test, GWL_STYLE, WS_POPUP );
+    check_parents( test, desktop, 0, 0, 0, test, test );
+    SetWindowLongW( test, GWL_STYLE, 0 );
+    check_parents( test, desktop, 0, 0, 0, test, test );
+    DestroyWindow( test );
+
+    /* child of child */
+    test = create_tool_window( WS_CHILD, child );
+    trace( "created child of child %x\n", test );
+    check_parents( test, child, child, child, 0, hwndMain, hwndMain );
+    SetWindowLongW( test, GWL_STYLE, 0 );
+    check_parents( test, child, child, 0, 0, hwndMain, test );
+    SetWindowLongW( test, GWL_STYLE, WS_POPUP );
+    check_parents( test, child, child, 0, 0, hwndMain, test );
+    DestroyWindow( test );
+
+    /* not owned top-level window */
+    test = create_tool_window( 0, 0 );
+    trace( "created top-level %x\n", test );
+    check_parents( test, desktop, 0, 0, 0, test, test );
+    SetWindowLongW( test, GWL_STYLE, WS_POPUP );
+    check_parents( test, desktop, 0, 0, 0, test, test );
+    SetWindowLongW( test, GWL_STYLE, WS_CHILD );
+    check_parents( test, desktop, 0, desktop, 0, test, desktop );
+    DestroyWindow( test );
+
+    /* owned top-level window */
+    test = create_tool_window( 0, hwndMain );
+    trace( "created owned top-level %x\n", test );
+    check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
+    SetWindowLongW( test, GWL_STYLE, WS_POPUP );
+    check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
+    SetWindowLongW( test, GWL_STYLE, WS_CHILD );
+    check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop );
+    DestroyWindow( test );
+
+    /* not owned popup */
+    test = create_tool_window( WS_POPUP, 0 );
+    trace( "created popup %x\n", test );
+    check_parents( test, desktop, 0, 0, 0, test, test );
+    SetWindowLongW( test, GWL_STYLE, WS_CHILD );
+    check_parents( test, desktop, 0, desktop, 0, test, desktop );
+    SetWindowLongW( test, GWL_STYLE, 0 );
+    check_parents( test, desktop, 0, 0, 0, test, test );
+    DestroyWindow( test );
+
+    /* owned popup */
+    test = create_tool_window( WS_POPUP, hwndMain );
+    trace( "created owned popup %x\n", test );
+    check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
+    SetWindowLongW( test, GWL_STYLE, WS_CHILD );
+    check_parents( test, desktop, hwndMain, desktop, hwndMain, test, desktop );
+    SetWindowLongW( test, GWL_STYLE, 0 );
+    check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
+    DestroyWindow( test );
+
+    /* top-level window owned by child (same as owned by top-level) */
+    test = create_tool_window( 0, child );
+    trace( "created top-level owned by child %x\n", test );
+    check_parents( test, desktop, hwndMain, 0, hwndMain, test, test );
+    DestroyWindow( test );
+
+    /* popup owned by desktop (same as not owned) */
+    test = create_tool_window( WS_POPUP, desktop );
+    trace( "created popup owned by desktop %x\n", test );
+    check_parents( test, desktop, 0, 0, 0, test, test );
+    DestroyWindow( test );
+
+    /* popup owned by child (same as owned by top-level) */
+    test = create_tool_window( WS_POPUP, child );
+    trace( "created popup owned by child %x\n", test );
+    check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
+    DestroyWindow( test );
+
+    /* not owned popup with WS_CHILD (same as WS_POPUP only) */
+    test = create_tool_window( WS_POPUP | WS_CHILD, 0 );
+    trace( "created WS_CHILD popup %x\n", test );
+    check_parents( test, desktop, 0, 0, 0, test, test );
+    DestroyWindow( test );
+
+    /* owned popup with WS_CHILD (same as WS_POPUP only) */
+    test = create_tool_window( WS_POPUP | WS_CHILD, hwndMain );
+    trace( "created owned WS_CHILD popup %x\n", test );
+    check_parents( test, desktop, hwndMain, hwndMain, hwndMain, test, hwndMain );
+    DestroyWindow( test );
+
+    /******************** parent changes *************************/
+    trace( "testing parent changes\n" );
+
+    /* desktop window */
+    check_parents( desktop, 0, 0, 0, 0, 0, 0 );
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, hwndMain2 );
+    ok( !ret, "Set GWL_HWNDPARENT succeeded on desktop" );
+    check_parents( desktop, 0, 0, 0, 0, 0, 0 );
+    ok( !SetParent( desktop, hwndMain ), "SetParent succeeded on desktop" );
+    check_parents( desktop, 0, 0, 0, 0, 0, 0 );
+
+    /* normal child window */
+    test = create_tool_window( WS_CHILD, hwndMain );
+    trace( "created child %x\n", test );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, hwndMain2 );
+    ok( ret == hwndMain, "GWL_HWNDPARENT return value %x expected %x", ret, hwndMain );
+    check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, child );
+    ok( ret == hwndMain2, "GWL_HWNDPARENT return value %x expected %x", ret, hwndMain2 );
+    check_parents( test, child, child, child, 0, hwndMain, hwndMain );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, desktop );
+    ok( ret == child, "GWL_HWNDPARENT return value %x expected %x", ret, child );
+    check_parents( test, desktop, 0, desktop, 0, test, desktop );
+
+    /* window is now child of desktop so GWL_HWNDPARENT changes owner from now on */
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, child );
+    ok( ret == 0, "GWL_HWNDPARENT return value %x expected %x", ret, 0 );
+    check_parents( test, desktop, child, desktop, child, test, desktop );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, 0 );
+    ok( ret == child, "GWL_HWNDPARENT return value %x expected %x", ret, child );
+    check_parents( test, desktop, 0, desktop, 0, test, desktop );
+    DestroyWindow( test );
+
+    /* not owned top-level window */
+    test = create_tool_window( 0, 0 );
+    trace( "created top-level %x\n", test );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, hwndMain2 );
+    ok( ret == 0, "GWL_HWNDPARENT return value %x expected %x", ret, 0 );
+    check_parents( test, desktop, hwndMain2, 0, hwndMain2, test, test );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, child );
+    ok( ret == hwndMain2, "GWL_HWNDPARENT return value %x expected %x", ret, hwndMain2 );
+    check_parents( test, desktop, child, 0, child, test, test );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, 0 );
+    ok( ret == child, "GWL_HWNDPARENT return value %x expected %x", ret, child );
+    check_parents( test, desktop, 0, 0, 0, test, test );
+    DestroyWindow( test );
+
+    /* not owned popup */
+    test = create_tool_window( WS_POPUP, 0 );
+    trace( "created popup %x\n", test );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, hwndMain2 );
+    ok( ret == 0, "GWL_HWNDPARENT return value %x expected %x", ret, 0 );
+    check_parents( test, desktop, hwndMain2, hwndMain2, hwndMain2, test, hwndMain2 );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, child );
+    ok( ret == hwndMain2, "GWL_HWNDPARENT return value %x expected %x", ret, hwndMain2 );
+    check_parents( test, desktop, child, child, child, test, hwndMain );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, 0 );
+    ok( ret == child, "GWL_HWNDPARENT return value %x expected %x", ret, child );
+    check_parents( test, desktop, 0, 0, 0, test, test );
+    DestroyWindow( test );
+
+    /* normal child window */
+    test = create_tool_window( WS_CHILD, hwndMain );
+    trace( "created child %x\n", test );
+
+    ret = SetParent( test, desktop );
+    ok( ret == hwndMain, "SetParent return value %x expected %x", ret, hwndMain );
+    check_parents( test, desktop, 0, desktop, 0, test, desktop );
+
+    ret = SetParent( test, child );
+    ok( ret == desktop, "SetParent return value %x expected %x", ret, desktop );
+    check_parents( test, child, child, child, 0, hwndMain, hwndMain );
+
+    ret = SetParent( test, hwndMain2 );
+    ok( ret == child, "SetParent return value %x expected %x", ret, child );
+    check_parents( test, hwndMain2, hwndMain2, hwndMain2, 0, hwndMain2, hwndMain2 );
+    DestroyWindow( test );
+
+    /* not owned top-level window */
+    test = create_tool_window( 0, 0 );
+    trace( "created top-level %x\n", test );
+
+    ret = SetParent( test, child );
+    ok( ret == desktop, "SetParent return value %x expected %x", ret, desktop );
+    check_parents( test, child, child, 0, 0, hwndMain, test );
+    DestroyWindow( test );
+
+    /* owned popup */
+    test = create_tool_window( WS_POPUP, hwndMain2 );
+    trace( "created owned popup %x\n", test );
+
+    ret = SetParent( test, child );
+    ok( ret == desktop, "SetParent return value %x expected %x", ret, desktop );
+    check_parents( test, child, child, hwndMain2, hwndMain2, hwndMain, hwndMain2 );
+
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, hwndMain );
+    ok( ret == child, "GWL_HWNDPARENT return value %x expected %x", ret, child );
+    check_parents( test, hwndMain, hwndMain, hwndMain2, hwndMain2, hwndMain, hwndMain2 );
+    DestroyWindow( test );
+
+    /**************** test owner destruction *******************/
+
+    /* owned child popup */
+    owner = create_tool_window( 0, 0 );
+    test = create_tool_window( WS_POPUP, owner );
+    trace( "created owner %x and popup %x\n", owner, test );
+    ret = SetParent( test, child );
+    ok( ret == desktop, "SetParent return value %x expected %x", ret, desktop );
+    check_parents( test, child, child, owner, owner, hwndMain, owner );
+    /* window is now child of 'child' but owned by 'owner' */
+    DestroyWindow( owner );
+    ok( IsWindow(test), "Window %x destroyed by owner destruction", test );
+    check_parents( test, child, child, owner, owner, hwndMain, owner );
+    ok( !IsWindow(owner), "Owner %x not destroyed", owner );
+    DestroyWindow(test);
+
+    /* owned top-level popup */
+    owner = create_tool_window( 0, 0 );
+    test = create_tool_window( WS_POPUP, owner );
+    trace( "created owner %x and popup %x\n", owner, test );
+    check_parents( test, desktop, owner, owner, owner, test, owner );
+    DestroyWindow( owner );
+    ok( !IsWindow(test), "Window %x not destroyed by owner destruction", test );
+
+    /* top-level popup owned by child */
+    owner = create_tool_window( WS_CHILD, hwndMain2 );
+    test = create_tool_window( WS_POPUP, 0 );
+    trace( "created owner %x and popup %x\n", owner, test );
+    ret = (HWND)SetWindowLongW( test, GWL_HWNDPARENT, owner );
+    ok( ret == 0, "GWL_HWNDPARENT return value %x expected %x", ret, 0 );
+    check_parents( test, desktop, owner, owner, owner, test, hwndMain2 );
+    DestroyWindow( owner );
+    ok( IsWindow(test), "Window %x destroyed by owner destruction", test );
+    ok( !IsWindow(owner), "Owner %x not destroyed", owner );
+    check_parents( test, desktop, owner, owner, owner, test, owner );
+    DestroyWindow(test);
+
+    /* final cleanup */
+    DestroyWindow(child);
+}
+
+
+static BOOL RegisterWindowClasses(void)
+{
+    WNDCLASSA cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = DefWindowProcA;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(0);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, IDC_ARROWA);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "MainWindowClass";
+
+    if(!RegisterClassA(&cls)) return FALSE;
+
+    cls.style = 0;
+    cls.lpfnWndProc = DefWindowProcA;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(0);
+    cls.hIcon = 0;
+    cls.hCursor = LoadCursorA(0, IDC_ARROWA);
+    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "ToolWindowClass";
+
+    if(!RegisterClassA(&cls)) return FALSE;
+
+    return TRUE;
+}
+
+
+START_TEST(win)
+{
+    pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" );
+
+    if (!RegisterWindowClasses()) assert(0);
+
+    hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window",
+                               WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                               WS_MAXIMIZEBOX | WS_POPUP,
+                               100, 100, 200, 200,
+                               0, 0, 0, NULL);
+    hwndMain2 = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window 2",
+                                WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                                WS_MAXIMIZEBOX | WS_POPUP,
+                                100, 100, 200, 200,
+                                0, 0, 0, NULL);
+    assert( hwndMain );
+    assert( hwndMain2 );
+
+    test_parent_owner();
+}
diff --git a/include/win.h b/include/win.h
index 4cbc86bb37fa64978a88b9b7bafe7002dc6932ee..7c69f62aa28fa13ac9fb12f22d82ab9dc6ee66de 100644
--- a/include/win.h
+++ b/include/win.h
@@ -102,7 +102,7 @@ extern HWND WIN_IsCurrentProcess( HWND hwnd );
 extern HWND WIN_IsCurrentThread( HWND hwnd );
 extern void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter );
 extern void WIN_UnlinkWindow( HWND hwnd );
-extern void WIN_SetOwner( HWND hwnd, HWND owner );
+extern HWND WIN_SetOwner( HWND hwnd, HWND owner );
 extern LONG WIN_SetStyle( HWND hwnd, LONG style );
 extern LONG WIN_SetExStyle( HWND hwnd, LONG style );
 extern void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient );
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 0b7c4fd4d6b20c55c58b93448da781877c885c02..06e68663002e7593c16d440399f8d5a4eeea79d8 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -2491,6 +2491,7 @@ struct set_window_owner_reply
 {
     struct reply_header __header;
     user_handle_t  full_owner;
+    user_handle_t  prev_owner;
 };
 
 
@@ -3210,6 +3211,6 @@ union generic_reply
     struct get_window_properties_reply get_window_properties_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 82
+#define SERVER_PROTOCOL_VERSION 83
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index fd526e69ab555b4efba1a4369e52c1200d75e909..6e69e934669d75d7fcaec6ec8b41820c741cf1ed 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1751,6 +1751,7 @@ enum message_type
     user_handle_t  owner;       /* new owner */
 @REPLY
     user_handle_t  full_owner;  /* full handle of new owner */
+    user_handle_t  prev_owner;  /* full handle of previous owner */
 @END
 
 
diff --git a/server/trace.c b/server/trace.c
index 864e146e9ff7aa116d1e53e1e0d17f4e6f5cf9f8..70d7b9d379b51bd5757892a06e506292b3b9bfdb 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1993,7 +1993,8 @@ static void dump_set_window_owner_request( const struct set_window_owner_request
 
 static void dump_set_window_owner_reply( const struct set_window_owner_reply *req )
 {
-    fprintf( stderr, " full_owner=%08x", req->full_owner );
+    fprintf( stderr, " full_owner=%08x,", req->full_owner );
+    fprintf( stderr, " prev_owner=%08x", req->prev_owner );
 }
 
 static void dump_get_window_info_request( const struct get_window_info_request *req )
diff --git a/server/window.c b/server/window.c
index c5f836ebc414ebb3d79728247e9f003a68d259ea..e513b877297aa15a4253ce6d4d595d763e349647 100644
--- a/server/window.c
+++ b/server/window.c
@@ -53,7 +53,7 @@ enum property_type
 struct window
 {
     struct window   *parent;          /* parent window */
-    struct window   *owner;           /* owner of this window */
+    user_handle_t    owner;           /* owner of this window */
     struct window   *first_child;     /* first child in Z-order */
     struct window   *last_child;      /* last child in Z-order */
     struct window   *first_unlinked;  /* first child not linked in the Z-order list */
@@ -110,11 +110,7 @@ static void link_window( struct window *win, struct window *parent, struct windo
 
     if (parent)
     {
-        if (win->parent != parent)
-        {
-            win->owner = NULL;  /* reset owner if changing parent */
-            win->parent = parent;
-        }
+        win->parent = parent;
         if ((win->prev = previous))
         {
             if ((win->next = previous->next)) win->next->prev = win;
@@ -241,16 +237,6 @@ static void destroy_window( struct window *win )
     while (win->first_child) destroy_window( win->first_child );
     while (win->first_unlinked) destroy_window( win->first_unlinked );
 
-    /* reset siblings owner */
-    if (win->parent)
-    {
-        struct window *ptr;
-        for (ptr = win->parent->first_child; ptr; ptr = ptr->next)
-            if (ptr->owner == win) ptr->owner = NULL;
-        for (ptr = win->parent->first_unlinked; ptr; ptr = ptr->next)
-            if (ptr->owner == win) ptr->owner = NULL;
-    }
-
     if (win->thread->queue)
     {
         if (win->paint_count) inc_queue_paint_count( win->thread, -win->paint_count );
@@ -276,7 +262,7 @@ static struct window *create_window( struct window *parent, struct window *owner
         return NULL;
     }
     win->parent         = parent;
-    win->owner          = owner;
+    win->owner          = owner ? owner->handle : 0;
     win->first_child    = NULL;
     win->last_child     = NULL;
     win->first_unlinked = NULL;
@@ -390,6 +376,7 @@ DECL_HANDLER(create_window)
         {
             if (!(top_window = create_window( NULL, NULL, req->atom ))) return;
             top_window->thread = NULL;  /* no thread owns the desktop */
+            top_window->style  = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
         }
         reply->handle = top_window->handle;
     }
@@ -400,9 +387,9 @@ DECL_HANDLER(create_window)
         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 && owner->parent != parent)
+        else if (owner && parent != top_window)
         {
-            /* owner must be a sibling of the new window */
+            /* an owned window must be created as top-level */
             set_error( STATUS_ACCESS_DENIED );
             return;
         }
@@ -464,17 +451,17 @@ DECL_HANDLER(destroy_window)
 DECL_HANDLER(set_window_owner)
 {
     struct window *win = get_window( req->handle );
-    struct window *owner = get_window( req->owner );
+    struct window *owner = NULL;
 
-    if (!win || !owner) return;
-    if (owner->parent != win->parent)
+    if (!win) return;
+    if (req->owner && !(owner = get_window( req->owner ))) return;
+    if (win == top_window)
     {
-        /* owner has to be a sibling of window */
         set_error( STATUS_ACCESS_DENIED );
         return;
     }
-    win->owner = owner;
-    reply->full_owner = owner->handle;
+    reply->prev_owner = win->owner;
+    reply->full_owner = win->owner = owner ? owner->handle : 0;
 }
 
 
@@ -502,7 +489,13 @@ DECL_HANDLER(get_window_info)
 DECL_HANDLER(set_window_info)
 {
     struct window *win = get_window( req->handle );
+
     if (!win) return;
+    if (req->flags && win == top_window)
+    {
+        set_error( STATUS_ACCESS_DENIED );
+        return;
+    }
     reply->old_style     = win->style;
     reply->old_ex_style  = win->ex_style;
     reply->old_id        = win->id;
@@ -578,7 +571,7 @@ DECL_HANDLER(get_window_tree)
     {
         struct window *parent = win->parent;
         reply->parent        = parent->handle;
-        reply->owner         = win->owner ? win->owner->handle : 0;
+        reply->owner         = win->owner;
         reply->next_sibling  = win->next ? win->next->handle : 0;
         reply->prev_sibling  = win->prev ? win->prev->handle : 0;
         reply->first_sibling = parent->first_child ? parent->first_child->handle : 0;
diff --git a/windows/win.c b/windows/win.c
index 60940a612dda851b235cf27478f83a86b4a253fd..b63f7c5a830c68bd800f992486f5c6a394fdb865 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -422,11 +422,7 @@ void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
         req->previous = hwndInsertAfter;
         if (!wine_server_call( req ))
         {
-            if (reply->full_parent && reply->full_parent != wndPtr->parent)
-            {
-                wndPtr->owner = 0;  /* reset owner when changing parent */
-                wndPtr->parent = reply->full_parent;
-            }
+            if (reply->full_parent) wndPtr->parent = reply->full_parent;
         }
 
     }
@@ -440,24 +436,30 @@ void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
  *
  * Change the owner of a window.
  */
-void WIN_SetOwner( HWND hwnd, HWND owner )
+HWND WIN_SetOwner( HWND hwnd, HWND owner )
 {
     WND *win = WIN_GetPtr( hwnd );
+    HWND ret = 0;
 
-    if (!win) return;
+    if (!win) return 0;
     if (win == WND_OTHER_PROCESS)
     {
         if (IsWindow(hwnd)) ERR( "cannot set owner %x on other process window %x\n", owner, hwnd );
-        return;
+        return 0;
     }
     SERVER_START_REQ( set_window_owner )
     {
         req->handle = hwnd;
         req->owner  = owner;
-        if (!wine_server_call( req )) win->owner = reply->full_owner;
+        if (!wine_server_call( req ))
+        {
+            win->owner = reply->full_owner;
+            ret = reply->prev_owner;
+        }
     }
     SERVER_END_REQ;
     WIN_ReleasePtr( win );
+    return ret;
 }
 
 
@@ -758,22 +760,17 @@ BOOL WIN_CreateDesktopWindow(void)
     pWndDesktop->parent            = 0;
     pWndDesktop->owner             = 0;
     pWndDesktop->class             = class;
-    pWndDesktop->hInstance         = 0;
     pWndDesktop->text              = NULL;
     pWndDesktop->hmemTaskQ         = 0;
     pWndDesktop->hrgnUpdate        = 0;
     pWndDesktop->hwndLastActive    = hwndDesktop;
-    pWndDesktop->dwStyle           = 0;
-    pWndDesktop->dwExStyle         = 0;
     pWndDesktop->clsStyle          = clsStyle;
     pWndDesktop->dce               = NULL;
     pWndDesktop->pVScroll          = NULL;
     pWndDesktop->pHScroll          = NULL;
-    pWndDesktop->wIDmenu           = 0;
     pWndDesktop->helpContext       = 0;
     pWndDesktop->flags             = 0;
     pWndDesktop->hSysMenu          = 0;
-    pWndDesktop->userdata          = 0;
     pWndDesktop->winproc           = winproc;
     pWndDesktop->cbWndExtra        = wndExtra;
 
@@ -792,7 +789,19 @@ BOOL WIN_CreateDesktopWindow(void)
 
     SetRect( &rect, 0, 0, cs.cx, cs.cy );
     WIN_SetRectangles( hwndDesktop, &rect, &rect );
-    WIN_SetStyle( hwndDesktop, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
+
+    SERVER_START_REQ( set_window_info )
+    {
+        req->handle = hwndDesktop;
+        req->flags  = 0;  /* don't set anything, just retrieve */
+        wine_server_call( req );
+        pWndDesktop->dwStyle   = reply->old_style;
+        pWndDesktop->dwExStyle = reply->old_ex_style;
+        pWndDesktop->hInstance = (ULONG_PTR)reply->old_instance;
+        pWndDesktop->userdata  = (ULONG_PTR)reply->old_user_data;
+        pWndDesktop->wIDmenu   = reply->old_id;
+    }
+    SERVER_END_REQ;
 
     if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
     {
@@ -1033,10 +1042,12 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
             WARN("Bad parent %04x\n", cs->hwndParent );
 	    return 0;
 	}
-        if (cs->style & WS_CHILD) parent = WIN_GetFullHandle(cs->hwndParent);
-        else owner = GetAncestor( cs->hwndParent, GA_ROOT );
+        if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
+            parent = WIN_GetFullHandle(cs->hwndParent);
+        else
+            owner = GetAncestor( cs->hwndParent, GA_ROOT );
     }
-    else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP))
+    else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
     {
         WARN("No parent for child window\n" );
         return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
@@ -1864,7 +1875,12 @@ static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
     LONG retvalue = 0;
     WND *wndPtr;
 
-    if (offset == GWL_HWNDPARENT) return (LONG)GetParent( hwnd );
+    if (offset == GWL_HWNDPARENT)
+    {
+        HWND parent = GetAncestor( hwnd, GA_PARENT );
+        if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
+        return (LONG)parent;
+    }
 
     if (!(wndPtr = WIN_GetPtr( hwnd )))
     {
@@ -1991,6 +2007,12 @@ static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
     }
 
     wndPtr = WIN_GetPtr( hwnd );
+    if (wndPtr->hwndSelf == GetDesktopWindow())
+    {
+        /* can't change anything on the desktop window */
+        SetLastError( ERROR_ACCESS_DENIED );
+        return 0;
+    }
 
     if (offset >= 0)
     {
@@ -2033,8 +2055,16 @@ static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
             newval = style.styleNew;
             break;
         case GWL_HWNDPARENT:
-            WIN_ReleasePtr( wndPtr );
-            return (LONG)SetParent( hwnd, (HWND)newval );
+            if (wndPtr->parent == GetDesktopWindow())
+            {
+                WIN_ReleasePtr( wndPtr );
+                return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
+            }
+            else
+            {
+                WIN_ReleasePtr( wndPtr );
+                return (LONG)SetParent( hwnd, (HWND)newval );
+            }
         case GWL_WNDPROC:
             retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
             WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
@@ -2436,8 +2466,8 @@ HWND WINAPI GetParent( HWND hwnd )
                 req->handle = hwnd;
                 if (!wine_server_call_err( req ))
                 {
-                    if (style & WS_CHILD) retvalue = reply->parent;
-                    else retvalue = reply->owner;
+                    if (style & WS_POPUP) retvalue = reply->owner;
+                    else if (style & WS_CHILD) retvalue = reply->parent;
                 }
             }
             SERVER_END_REQ;
@@ -2445,8 +2475,8 @@ HWND WINAPI GetParent( HWND hwnd )
     }
     else
     {
-        if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
-        else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
+        if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
+        else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
         WIN_ReleasePtr( wndPtr );
     }
     return retvalue;
@@ -2461,8 +2491,9 @@ HWND WINAPI GetAncestor( HWND hwnd, UINT type )
     WND *win;
     HWND *list, ret = 0;
 
-    if (type == GA_PARENT)
+    switch(type)
     {
+    case GA_PARENT:
         if (!(win = WIN_GetPtr( hwnd )))
         {
             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
@@ -2482,28 +2513,30 @@ HWND WINAPI GetAncestor( HWND hwnd, UINT type )
             }
             SERVER_END_REQ;
         }
-        return ret;
-    }
+        break;
 
-    if (!(list = WIN_ListParents( hwnd ))) return 0;
+    case GA_ROOT:
+        if (!(list = WIN_ListParents( hwnd ))) return 0;
 
-    if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
-    else
-    {
-        int count = 2;
-        while (list[count]) count++;
-        ret = list[count - 2];  /* get the one before the desktop */
-    }
-    HeapFree( GetProcessHeap(), 0, list );
+        if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
+        else
+        {
+            int count = 2;
+            while (list[count]) count++;
+            ret = list[count - 2];  /* get the one before the desktop */
+        }
+        HeapFree( GetProcessHeap(), 0, list );
+        break;
 
-    if (ret && type == GA_ROOTOWNER)
-    {
+    case GA_ROOTOWNER:
+        if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
         for (;;)
         {
-            HWND owner = GetWindow( ret, GW_OWNER );
-            if (!owner) break;
-            ret = owner;
+            HWND parent = GetParent( ret );
+            if (!parent) break;
+            ret = parent;
         }
+        break;
     }
     return ret;
 }