diff --git a/include/win.h b/include/win.h index 8d412095c70..42577afb3be 100644 --- a/include/win.h +++ b/include/win.h @@ -79,6 +79,7 @@ typedef struct #define WIN_NEEDS_INTERNALSOP 0x1000 /* Window was hidden by WIN_InternalShowOwnedPopups */ /* Window functions */ +extern WND *WIN_GetWndPtr( HWND hwnd ); extern int WIN_SuspendWndsLock( void ); extern void WIN_RestoreWndsLock(int ipreviousLock); extern WND* WIN_FindWndPtr( HWND hwnd ); @@ -115,6 +116,8 @@ inline static WND *WIN_FindWndPtr16( HWND16 hwnd ) return WIN_FindWndPtr( (HWND)(ULONG_PTR)hwnd ); } +#define BAD_WND_PTR ((WND *)1) /* returned by WIN_GetWndPtr on bad window handles */ + extern HWND CARET_GetHwnd(void); extern void CARET_GetRect(LPRECT lprc); /* windows/caret.c */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 2df30022471..c68f53c0030 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1579,6 +1579,7 @@ struct create_window_request struct request_header __header; user_handle_t parent; user_handle_t owner; + unsigned int atom; user_handle_t handle; }; @@ -1627,6 +1628,8 @@ struct get_window_children_request { struct request_header __header; user_handle_t parent; + unsigned int atom; + void* tid; int count; /* VARARG(children,user_handles); */ }; @@ -1919,6 +1922,6 @@ union generic_request struct get_window_tree_request get_window_tree; }; -#define SERVER_PROTOCOL_VERSION 55 +#define SERVER_PROTOCOL_VERSION 56 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index a7b7a2d3059..c5122ba2e00 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1410,6 +1410,7 @@ enum message_type @REQ(create_window) user_handle_t parent; /* parent window */ user_handle_t owner; /* owner window */ + unsigned int atom; /* class atom */ @REPLY user_handle_t handle; /* created window */ @END @@ -1452,6 +1453,8 @@ enum message_type /* Get a list of the window children */ @REQ(get_window_children) user_handle_t parent; /* parent window */ + unsigned int atom; /* class atom for the listed children */ + void* tid; /* thread owning the listed children */ @REPLY int count; /* total count of children */ VARARG(children,user_handles); /* children handles */ diff --git a/server/trace.c b/server/trace.c index 9ce6400b367..90d572dad9d 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1672,7 +1672,8 @@ static void dump_get_named_pipe_info_reply( const struct get_named_pipe_info_req static void dump_create_window_request( const struct create_window_request *req ) { fprintf( stderr, " parent=%08x,", req->parent ); - fprintf( stderr, " owner=%08x", req->owner ); + fprintf( stderr, " owner=%08x,", req->owner ); + fprintf( stderr, " atom=%08x", req->atom ); } static void dump_create_window_reply( const struct create_window_request *req ) @@ -1718,7 +1719,9 @@ static void dump_get_window_parents_reply( const struct get_window_parents_reque static void dump_get_window_children_request( const struct get_window_children_request *req ) { - fprintf( stderr, " parent=%08x", req->parent ); + fprintf( stderr, " parent=%08x,", req->parent ); + fprintf( stderr, " atom=%08x,", req->atom ); + fprintf( stderr, " tid=%p", req->tid ); } static void dump_get_window_children_reply( const struct get_window_children_request *req ) diff --git a/server/window.c b/server/window.c index ed64145e9ec..c57aadf09ee 100644 --- a/server/window.c +++ b/server/window.c @@ -14,14 +14,16 @@ struct window { - struct window *parent; /* parent window */ - struct window *owner; /* owner of this window */ - struct window *first_child; /* first child window */ - struct window *last_child; /* last child window */ - struct window *next; /* next window in Z-order */ - struct window *prev; /* prev window in Z-order */ - user_handle_t handle; /* full handle for this window */ - struct thread *thread; /* thread owning the window */ + struct window *parent; /* parent window */ + struct window *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 */ + struct window *next; /* next window in Z-order */ + struct window *prev; /* prev window in Z-order */ + user_handle_t handle; /* full handle for this window */ + struct thread *thread; /* thread owning the window */ + unsigned int atom; /* class atom */ }; static struct window *top_window; /* top-level (desktop) window */ @@ -35,16 +37,27 @@ inline static struct window *get_window( user_handle_t handle ) return ret; } +/* unlink a window from the tree */ +static void unlink_window( struct window *win ) +{ + struct window *parent = win->parent; + + assert( parent ); + + if (win->next) win->next->prev = win->prev; + else if (parent->last_child == win) parent->last_child = win->prev; + + if (win->prev) win->prev->next = win->next; + else if (parent->first_child == win) parent->first_child = win->next; + else if (parent->first_unlinked == win) parent->first_unlinked = win->next; +} + + /* link a window into the tree (or unlink it if the new parent is NULL) */ static void link_window( struct window *win, struct window *parent, struct window *previous ) { - if (win->parent) /* unlink it from the previous location */ - { - if (win->next) win->next->prev = win->prev; - else if (win->parent->last_child == win) win->parent->last_child = win->prev; - if (win->prev) win->prev->next = win->next; - else if (win->parent->first_child == win) win->parent->first_child = win->next; - } + unlink_window( win ); /* unlink it from the previous location */ + if (parent) { win->parent = parent; @@ -61,10 +74,12 @@ static void link_window( struct window *win, struct window *parent, struct windo parent->first_child = win; } } - else + else /* move it to parent unlinked list */ { - /* don't touch parent; an unlinked window still has a valid parent pointer */ - win->next = win->prev = NULL; + parent = win->parent; + if ((win->next = parent->first_unlinked)) win->next->prev = win; + win->prev = NULL; + parent->first_unlinked = win; } } @@ -75,6 +90,7 @@ static void destroy_window( struct window *win ) /* destroy all children */ while (win->first_child) destroy_window( win->first_child ); + while (win->first_unlinked) destroy_window( win->first_unlinked ); /* reset siblings owner */ if (win->parent) @@ -82,17 +98,20 @@ static void destroy_window( struct window *win ) 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) queue_cleanup_window( win->thread, win->handle ); free_user_handle( win->handle ); - link_window( win, NULL, NULL ); + unlink_window( win ); memset( win, 0x55, sizeof(*win) ); free( win ); } /* create a new window structure (note: the window is not linked in the window tree) */ -static struct window *create_window( struct window *parent, struct window *owner ) +static struct window *create_window( struct window *parent, struct window *owner, + unsigned int atom ) { struct window *win = mem_alloc( sizeof(*win) ); if (!win) return NULL; @@ -102,13 +121,22 @@ static struct window *create_window( struct window *parent, struct window *owner free( win ); return NULL; } - win->parent = parent; - win->owner = owner; - win->first_child = NULL; - win->last_child = NULL; - win->next = NULL; - win->prev = NULL; - win->thread = current; + win->parent = parent; + win->owner = owner; + win->first_child = NULL; + win->last_child = NULL; + win->first_unlinked = NULL; + win->thread = current; + win->atom = atom; + + if (parent) /* put it on parent unlinked list */ + { + if ((win->next = parent->first_unlinked)) win->next->prev = win; + win->prev = NULL; + parent->first_unlinked = win; + } + else win->next = win->prev = NULL; + return win; } @@ -148,7 +176,7 @@ DECL_HANDLER(create_window) { if (!top_window) { - if (!(top_window = create_window( NULL, NULL ))) return; + if (!(top_window = create_window( NULL, NULL, req->atom ))) return; top_window->thread = NULL; /* no thread owns the desktop */ } req->handle = top_window->handle; @@ -159,7 +187,7 @@ DECL_HANDLER(create_window) if (!(parent = get_window( req->parent ))) return; if (req->owner && !(owner = get_window( req->owner ))) return; - if (!(win = create_window( parent, owner ))) return; + if (!(win = create_window( parent, owner, req->atom ))) return; req->handle = win->handle; } } @@ -172,6 +200,12 @@ DECL_HANDLER(link_window) if (!(win = get_window( req->handle ))) return; if (req->parent && !(parent = get_window( req->parent ))) return; + + if (win == top_window) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } if (parent && req->previous) { if (req->previous == (user_handle_t)1) /* special case: HWND_BOTTOM */ @@ -254,7 +288,12 @@ DECL_HANDLER(get_window_children) size_t len; if (parent) - for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next) total++; + for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next) + { + if (req->atom && ptr->atom != req->atom) continue; + if (req->tid && get_thread_id(ptr->thread) != req->tid) continue; + total++; + } req->count = total; len = min( get_req_data_size(req), total * sizeof(user_handle_t) ); @@ -263,7 +302,11 @@ DECL_HANDLER(get_window_children) { user_handle_t *data = get_req_data(req); for (ptr = parent->first_child; ptr && len; ptr = ptr->next, len -= sizeof(*data)) + { + if (req->atom && ptr->atom != req->atom) continue; + if (req->tid && get_thread_id(ptr->thread) != req->tid) continue; *data++ = ptr->handle; + } } } diff --git a/windows/win.c b/windows/win.c index e0c5e31bf76..440bbdff292 100644 --- a/windows/win.c +++ b/windows/win.c @@ -30,7 +30,6 @@ DEFAULT_DEBUG_CHANNEL(win); DECLARE_DEBUG_CHANNEL(msg); -#define BAD_WND_PTR ((WND *)1) /* returned by get_wnd_ptr on bad window handles */ #define NB_USER_HANDLES (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) /**********************************************************************/ @@ -79,7 +78,7 @@ void WIN_RestoreWndsLock( int ipreviousLocks ) * * Create a window handle with the server. */ -static WND *create_window_handle( HWND parent, HWND owner, INT size ) +static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size ) { BOOL res; user_handle_t handle = 0; @@ -94,6 +93,7 @@ static WND *create_window_handle( HWND parent, HWND owner, INT size ) { req->parent = parent; req->owner = owner; + req->atom = atom; if ((res = !SERVER_CALL_ERR())) handle = req->handle; } SERVER_END_REQ; @@ -144,14 +144,45 @@ static WND *free_window_handle( HWND hwnd ) } +/******************************************************************* + * list_window_children + * + * Build an array of the children of a given window. The array must be + * freed with HeapFree. Returns NULL when no windows are found. + */ +static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid ) +{ + HWND *list = NULL; + + SERVER_START_VAR_REQ( get_window_children, REQUEST_MAX_VAR_SIZE ) + { + req->parent = hwnd; + req->atom = atom; + req->tid = (void *)tid; + if (!SERVER_CALL()) + { + user_handle_t *data = server_data_ptr(req); + int i, count = server_data_size(req) / sizeof(*data); + if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) )))) + { + for (i = 0; i < count; i++) list[i] = data[i]; + list[i] = 0; + } + } + } + SERVER_END_VAR_REQ; + return list; +} + + /*********************************************************************** - * get_wnd_ptr + * WIN_GetWndPtr * * Return a pointer to the WND structure if local to the process, * or BAD_WND_PTR is handle is local but not valid. * If ret value is a valid pointer, the user lock is held. */ -static WND *get_wnd_ptr( HWND hwnd ) +WND *WIN_GetWndPtr( HWND hwnd ) { WND * ptr; WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE; @@ -179,7 +210,7 @@ BOOL WIN_IsCurrentProcess( HWND hwnd ) { WND *ptr; - if (!(ptr = get_wnd_ptr( hwnd )) || ptr == BAD_WND_PTR) return FALSE; + if (!(ptr = WIN_GetWndPtr( hwnd )) || ptr == BAD_WND_PTR) return FALSE; USER_Unlock(); return TRUE; } @@ -195,7 +226,7 @@ BOOL WIN_IsCurrentThread( HWND hwnd ) WND *ptr; BOOL ret = FALSE; - if ((ptr = get_wnd_ptr( hwnd )) && ptr != BAD_WND_PTR) + if ((ptr = WIN_GetWndPtr( hwnd )) && ptr != BAD_WND_PTR) { ret = (ptr->tid == GetCurrentThreadId()); USER_Unlock(); @@ -218,7 +249,7 @@ HWND WIN_Handle32( HWND16 hwnd16 ) /* do sign extension for -2 and -3 */ if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16; - if ((ptr = get_wnd_ptr( hwnd ))) + if ((ptr = WIN_GetWndPtr( hwnd ))) { if (ptr != BAD_WND_PTR) { @@ -250,7 +281,7 @@ WND * WIN_FindWndPtr( HWND hwnd ) if (!hwnd) return NULL; - if ((ptr = get_wnd_ptr( hwnd ))) + if ((ptr = WIN_GetWndPtr( hwnd ))) { if (ptr != BAD_WND_PTR) { @@ -583,7 +614,8 @@ BOOL WIN_CreateDesktopWindow(void) &wndExtra, &winproc, &clsStyle, &dce ))) return FALSE; - pWndDesktop = create_window_handle( 0, 0, sizeof(WND) + wndExtra ); + pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), + sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) ); if (!pWndDesktop) return FALSE; hwndDesktop = pWndDesktop->hwndSelf; @@ -785,7 +817,7 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, /* Create the window structure */ - if (!(wndPtr = create_window_handle( parent, owner, + if (!(wndPtr = create_window_handle( parent, owner, classAtom, sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) ))) { TRACE("out of memory\n" ); @@ -1359,8 +1391,8 @@ BOOL WINAPI OpenIcon( HWND hwnd ) */ static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title ) { - HWND *list; - HWND retvalue; + HWND *list = NULL; + HWND retvalue = 0; int i = 0, len = 0; WCHAR *buffer = NULL; @@ -1371,37 +1403,29 @@ static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR tit if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0; } - if (!(list = WIN_ListChildren( parent ))) - { - if (buffer) HeapFree( GetProcessHeap(), 0, buffer ); - return 0; - } + if (!(list = list_window_children( parent, className, 0 ))) goto done; if (child) { child = WIN_GetFullHandle( child ); while (list[i] && list[i] != child) i++; - if (!list[i]) return 0; + if (!list[i]) goto done; i++; /* start from next window */ } - for ( ; list[i]; i++) + if (title) { - if (className && (GetClassWord(list[i], GCW_ATOM) != className)) - continue; /* Not the right class */ - - /* Now check the title */ - if (!title) break; - if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break; + while (list[i]) + { + if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break; + i++; + } } retvalue = list[i]; - HeapFree( GetProcessHeap(), 0, list ); - if (buffer) HeapFree( GetProcessHeap(), 0, buffer ); - /* In this case we need to check whether other processes - own a window with the given paramters on the Desktop, - but we don't, so let's at least warn about it */ - if (!retvalue) FIXME("Returning 0 without checking other processes\n"); + done: + if (list) HeapFree( GetProcessHeap(), 0, list ); + if (buffer) HeapFree( GetProcessHeap(), 0, buffer ); return retvalue; } @@ -2003,7 +2027,7 @@ BOOL WINAPI IsWindow( HWND hwnd ) WND *ptr; BOOL ret; - if ((ptr = get_wnd_ptr( hwnd ))) + if ((ptr = WIN_GetWndPtr( hwnd ))) { if (ptr == BAD_WND_PTR) return FALSE; USER_Unlock(); @@ -2029,7 +2053,7 @@ DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process ) WND *ptr; DWORD tid = 0; - if ((ptr = get_wnd_ptr( hwnd ))) + if ((ptr = WIN_GetWndPtr( hwnd ))) { if (ptr != BAD_WND_PTR) { @@ -2462,24 +2486,7 @@ HWND *WIN_ListParents( HWND hwnd ) */ HWND *WIN_ListChildren( HWND hwnd ) { - HWND *list = NULL; - - SERVER_START_VAR_REQ( get_window_children, REQUEST_MAX_VAR_SIZE ) - { - req->parent = hwnd; - if (!SERVER_CALL()) - { - user_handle_t *data = server_data_ptr(req); - int i, count = server_data_size(req) / sizeof(*data); - if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) )))) - { - for (i = 0; i < count; i++) list[i] = data[i]; - list[i] = 0; - } - } - } - SERVER_END_VAR_REQ; - return list; + return list_window_children( hwnd, 0, 0 ); } @@ -2533,16 +2540,14 @@ BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam ) HWND *list; int i, iWndsLocks; - if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE; + if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() ))) + return FALSE; /* Now call the callback function for every window */ iWndsLocks = WIN_SuspendWndsLock(); for (i = 0; list[i]; i++) - { - if (GetWindowThreadProcessId( list[i], NULL ) != id) continue; if (!func( list[i], lParam )) break; - } WIN_RestoreWndsLock(iWndsLocks); HeapFree( GetProcessHeap(), 0, list ); return TRUE;