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