Commit 7dafa617 authored by Alexandre Julliard's avatar Alexandre Julliard

Fixed a number of bugs in the handling of window parent and owner and

added a regression test (based on the work of Bill Medland).
parent e70d08be
...@@ -3,4 +3,5 @@ class.ok ...@@ -3,4 +3,5 @@ class.ok
sysparams.ok sysparams.ok
testlist.c testlist.c
user32_test.exe.spec.c user32_test.exe.spec.c
win.ok
wsprintf.ok wsprintf.ok
...@@ -8,6 +8,7 @@ IMPORTS = user32 gdi32 advapi32 ...@@ -8,6 +8,7 @@ IMPORTS = user32 gdi32 advapi32
CTESTS = \ CTESTS = \
class.c \ class.c \
sysparams.c \ sysparams.c \
win.c \
wsprintf.c wsprintf.c
@MAKE_TEST_RULES@ @MAKE_TEST_RULES@
......
...@@ -102,7 +102,7 @@ extern HWND WIN_IsCurrentProcess( HWND hwnd ); ...@@ -102,7 +102,7 @@ extern HWND WIN_IsCurrentProcess( HWND hwnd );
extern HWND WIN_IsCurrentThread( HWND hwnd ); extern HWND WIN_IsCurrentThread( HWND hwnd );
extern void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter ); extern void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter );
extern void WIN_UnlinkWindow( HWND hwnd ); 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_SetStyle( HWND hwnd, LONG style );
extern LONG WIN_SetExStyle( HWND hwnd, LONG style ); extern LONG WIN_SetExStyle( HWND hwnd, LONG style );
extern void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient ); extern void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient );
......
...@@ -2491,6 +2491,7 @@ struct set_window_owner_reply ...@@ -2491,6 +2491,7 @@ struct set_window_owner_reply
{ {
struct reply_header __header; struct reply_header __header;
user_handle_t full_owner; user_handle_t full_owner;
user_handle_t prev_owner;
}; };
...@@ -3210,6 +3211,6 @@ union generic_reply ...@@ -3210,6 +3211,6 @@ union generic_reply
struct get_window_properties_reply get_window_properties_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 */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -1751,6 +1751,7 @@ enum message_type ...@@ -1751,6 +1751,7 @@ enum message_type
user_handle_t owner; /* new owner */ user_handle_t owner; /* new owner */
@REPLY @REPLY
user_handle_t full_owner; /* full handle of new owner */ user_handle_t full_owner; /* full handle of new owner */
user_handle_t prev_owner; /* full handle of previous owner */
@END @END
......
...@@ -1993,7 +1993,8 @@ static void dump_set_window_owner_request( const struct set_window_owner_request ...@@ -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 ) 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 ) static void dump_get_window_info_request( const struct get_window_info_request *req )
......
...@@ -53,7 +53,7 @@ enum property_type ...@@ -53,7 +53,7 @@ enum property_type
struct window struct window
{ {
struct window *parent; /* parent 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 *first_child; /* first child in Z-order */
struct window *last_child; /* last 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 */ 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 ...@@ -110,11 +110,7 @@ static void link_window( struct window *win, struct window *parent, struct windo
if (parent) 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->prev = previous))
{ {
if ((win->next = previous->next)) win->next->prev = win; if ((win->next = previous->next)) win->next->prev = win;
...@@ -241,16 +237,6 @@ static void destroy_window( struct window *win ) ...@@ -241,16 +237,6 @@ static void destroy_window( struct window *win )
while (win->first_child) destroy_window( win->first_child ); while (win->first_child) destroy_window( win->first_child );
while (win->first_unlinked) destroy_window( win->first_unlinked ); 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->thread->queue)
{ {
if (win->paint_count) inc_queue_paint_count( win->thread, -win->paint_count ); 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 ...@@ -276,7 +262,7 @@ static struct window *create_window( struct window *parent, struct window *owner
return NULL; return NULL;
} }
win->parent = parent; win->parent = parent;
win->owner = owner; win->owner = owner ? owner->handle : 0;
win->first_child = NULL; win->first_child = NULL;
win->last_child = NULL; win->last_child = NULL;
win->first_unlinked = NULL; win->first_unlinked = NULL;
...@@ -390,6 +376,7 @@ DECL_HANDLER(create_window) ...@@ -390,6 +376,7 @@ DECL_HANDLER(create_window)
{ {
if (!(top_window = create_window( NULL, NULL, req->atom ))) return; if (!(top_window = create_window( NULL, NULL, req->atom ))) return;
top_window->thread = NULL; /* no thread owns the desktop */ 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; reply->handle = top_window->handle;
} }
...@@ -400,9 +387,9 @@ DECL_HANDLER(create_window) ...@@ -400,9 +387,9 @@ DECL_HANDLER(create_window)
if (!(parent = get_window( req->parent ))) return; if (!(parent = get_window( req->parent ))) return;
if (req->owner && !(owner = get_window( req->owner ))) return; if (req->owner && !(owner = get_window( req->owner ))) return;
if (owner == top_window) owner = NULL; 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 ); set_error( STATUS_ACCESS_DENIED );
return; return;
} }
...@@ -464,17 +451,17 @@ DECL_HANDLER(destroy_window) ...@@ -464,17 +451,17 @@ DECL_HANDLER(destroy_window)
DECL_HANDLER(set_window_owner) DECL_HANDLER(set_window_owner)
{ {
struct window *win = get_window( req->handle ); struct window *win = get_window( req->handle );
struct window *owner = get_window( req->owner ); struct window *owner = NULL;
if (!win || !owner) return; if (!win) return;
if (owner->parent != win->parent) 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 ); set_error( STATUS_ACCESS_DENIED );
return; return;
} }
win->owner = owner; reply->prev_owner = win->owner;
reply->full_owner = owner->handle; reply->full_owner = win->owner = owner ? owner->handle : 0;
} }
...@@ -502,7 +489,13 @@ DECL_HANDLER(get_window_info) ...@@ -502,7 +489,13 @@ DECL_HANDLER(get_window_info)
DECL_HANDLER(set_window_info) DECL_HANDLER(set_window_info)
{ {
struct window *win = get_window( req->handle ); struct window *win = get_window( req->handle );
if (!win) return; if (!win) return;
if (req->flags && win == top_window)
{
set_error( STATUS_ACCESS_DENIED );
return;
}
reply->old_style = win->style; reply->old_style = win->style;
reply->old_ex_style = win->ex_style; reply->old_ex_style = win->ex_style;
reply->old_id = win->id; reply->old_id = win->id;
...@@ -578,7 +571,7 @@ DECL_HANDLER(get_window_tree) ...@@ -578,7 +571,7 @@ DECL_HANDLER(get_window_tree)
{ {
struct window *parent = win->parent; struct window *parent = win->parent;
reply->parent = parent->handle; 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->next_sibling = win->next ? win->next->handle : 0;
reply->prev_sibling = win->prev ? win->prev->handle : 0; reply->prev_sibling = win->prev ? win->prev->handle : 0;
reply->first_sibling = parent->first_child ? parent->first_child->handle : 0; reply->first_sibling = parent->first_child ? parent->first_child->handle : 0;
......
...@@ -422,11 +422,7 @@ void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter ) ...@@ -422,11 +422,7 @@ void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
req->previous = hwndInsertAfter; req->previous = hwndInsertAfter;
if (!wine_server_call( req )) if (!wine_server_call( req ))
{ {
if (reply->full_parent && reply->full_parent != wndPtr->parent) if (reply->full_parent) wndPtr->parent = reply->full_parent;
{
wndPtr->owner = 0; /* reset owner when changing parent */
wndPtr->parent = reply->full_parent;
}
} }
} }
...@@ -440,24 +436,30 @@ void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter ) ...@@ -440,24 +436,30 @@ void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
* *
* Change the owner of a window. * 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 ); WND *win = WIN_GetPtr( hwnd );
HWND ret = 0;
if (!win) return; if (!win) return 0;
if (win == WND_OTHER_PROCESS) if (win == WND_OTHER_PROCESS)
{ {
if (IsWindow(hwnd)) ERR( "cannot set owner %x on other process window %x\n", owner, hwnd ); 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 ) SERVER_START_REQ( set_window_owner )
{ {
req->handle = hwnd; req->handle = hwnd;
req->owner = owner; 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; SERVER_END_REQ;
WIN_ReleasePtr( win ); WIN_ReleasePtr( win );
return ret;
} }
...@@ -758,22 +760,17 @@ BOOL WIN_CreateDesktopWindow(void) ...@@ -758,22 +760,17 @@ BOOL WIN_CreateDesktopWindow(void)
pWndDesktop->parent = 0; pWndDesktop->parent = 0;
pWndDesktop->owner = 0; pWndDesktop->owner = 0;
pWndDesktop->class = class; pWndDesktop->class = class;
pWndDesktop->hInstance = 0;
pWndDesktop->text = NULL; pWndDesktop->text = NULL;
pWndDesktop->hmemTaskQ = 0; pWndDesktop->hmemTaskQ = 0;
pWndDesktop->hrgnUpdate = 0; pWndDesktop->hrgnUpdate = 0;
pWndDesktop->hwndLastActive = hwndDesktop; pWndDesktop->hwndLastActive = hwndDesktop;
pWndDesktop->dwStyle = 0;
pWndDesktop->dwExStyle = 0;
pWndDesktop->clsStyle = clsStyle; pWndDesktop->clsStyle = clsStyle;
pWndDesktop->dce = NULL; pWndDesktop->dce = NULL;
pWndDesktop->pVScroll = NULL; pWndDesktop->pVScroll = NULL;
pWndDesktop->pHScroll = NULL; pWndDesktop->pHScroll = NULL;
pWndDesktop->wIDmenu = 0;
pWndDesktop->helpContext = 0; pWndDesktop->helpContext = 0;
pWndDesktop->flags = 0; pWndDesktop->flags = 0;
pWndDesktop->hSysMenu = 0; pWndDesktop->hSysMenu = 0;
pWndDesktop->userdata = 0;
pWndDesktop->winproc = winproc; pWndDesktop->winproc = winproc;
pWndDesktop->cbWndExtra = wndExtra; pWndDesktop->cbWndExtra = wndExtra;
...@@ -792,7 +789,19 @@ BOOL WIN_CreateDesktopWindow(void) ...@@ -792,7 +789,19 @@ BOOL WIN_CreateDesktopWindow(void)
SetRect( &rect, 0, 0, cs.cx, cs.cy ); SetRect( &rect, 0, 0, cs.cx, cs.cy );
WIN_SetRectangles( hwndDesktop, &rect, &rect ); 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 )) if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
{ {
...@@ -1033,10 +1042,12 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, ...@@ -1033,10 +1042,12 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
WARN("Bad parent %04x\n", cs->hwndParent ); WARN("Bad parent %04x\n", cs->hwndParent );
return 0; return 0;
} }
if (cs->style & WS_CHILD) parent = WIN_GetFullHandle(cs->hwndParent); if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
else owner = GetAncestor( cs->hwndParent, GA_ROOT ); 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" ); WARN("No parent for child window\n" );
return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */ 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 ) ...@@ -1864,7 +1875,12 @@ static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
LONG retvalue = 0; LONG retvalue = 0;
WND *wndPtr; 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 ))) if (!(wndPtr = WIN_GetPtr( hwnd )))
{ {
...@@ -1991,6 +2007,12 @@ static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval, ...@@ -1991,6 +2007,12 @@ static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
} }
wndPtr = WIN_GetPtr( hwnd ); 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) if (offset >= 0)
{ {
...@@ -2033,8 +2055,16 @@ static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval, ...@@ -2033,8 +2055,16 @@ static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
newval = style.styleNew; newval = style.styleNew;
break; break;
case GWL_HWNDPARENT: case GWL_HWNDPARENT:
if (wndPtr->parent == GetDesktopWindow())
{
WIN_ReleasePtr( wndPtr );
return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
}
else
{
WIN_ReleasePtr( wndPtr ); WIN_ReleasePtr( wndPtr );
return (LONG)SetParent( hwnd, (HWND)newval ); return (LONG)SetParent( hwnd, (HWND)newval );
}
case GWL_WNDPROC: case GWL_WNDPROC:
retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval, WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
...@@ -2436,8 +2466,8 @@ HWND WINAPI GetParent( HWND hwnd ) ...@@ -2436,8 +2466,8 @@ HWND WINAPI GetParent( HWND hwnd )
req->handle = hwnd; req->handle = hwnd;
if (!wine_server_call_err( req )) if (!wine_server_call_err( req ))
{ {
if (style & WS_CHILD) retvalue = reply->parent; if (style & WS_POPUP) retvalue = reply->owner;
else retvalue = reply->owner; else if (style & WS_CHILD) retvalue = reply->parent;
} }
} }
SERVER_END_REQ; SERVER_END_REQ;
...@@ -2445,8 +2475,8 @@ HWND WINAPI GetParent( HWND hwnd ) ...@@ -2445,8 +2475,8 @@ HWND WINAPI GetParent( HWND hwnd )
} }
else else
{ {
if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent; if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner; else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
WIN_ReleasePtr( wndPtr ); WIN_ReleasePtr( wndPtr );
} }
return retvalue; return retvalue;
...@@ -2461,8 +2491,9 @@ HWND WINAPI GetAncestor( HWND hwnd, UINT type ) ...@@ -2461,8 +2491,9 @@ HWND WINAPI GetAncestor( HWND hwnd, UINT type )
WND *win; WND *win;
HWND *list, ret = 0; HWND *list, ret = 0;
if (type == GA_PARENT) switch(type)
{ {
case GA_PARENT:
if (!(win = WIN_GetPtr( hwnd ))) if (!(win = WIN_GetPtr( hwnd )))
{ {
SetLastError( ERROR_INVALID_WINDOW_HANDLE ); SetLastError( ERROR_INVALID_WINDOW_HANDLE );
...@@ -2482,9 +2513,9 @@ HWND WINAPI GetAncestor( HWND hwnd, UINT type ) ...@@ -2482,9 +2513,9 @@ HWND WINAPI GetAncestor( HWND hwnd, UINT type )
} }
SERVER_END_REQ; SERVER_END_REQ;
} }
return ret; break;
}
case GA_ROOT:
if (!(list = WIN_ListParents( hwnd ))) return 0; if (!(list = WIN_ListParents( hwnd ))) return 0;
if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */ if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
...@@ -2495,15 +2526,17 @@ HWND WINAPI GetAncestor( HWND hwnd, UINT type ) ...@@ -2495,15 +2526,17 @@ HWND WINAPI GetAncestor( HWND hwnd, UINT type )
ret = list[count - 2]; /* get the one before the desktop */ ret = list[count - 2]; /* get the one before the desktop */
} }
HeapFree( GetProcessHeap(), 0, list ); HeapFree( GetProcessHeap(), 0, list );
break;
if (ret && type == GA_ROOTOWNER) case GA_ROOTOWNER:
{ if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
for (;;) for (;;)
{ {
HWND owner = GetWindow( ret, GW_OWNER ); HWND parent = GetParent( ret );
if (!owner) break; if (!parent) break;
ret = owner; ret = parent;
} }
break;
} }
return ret; return ret;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment