Store window class atom in the server.

Keep unlinked windows on a separate list.
Implemented inter-process FindWindow().
oldstable
Alexandre Julliard 2001-10-09 23:26:40 +00:00
parent 5bcd11631f
commit 844ceb98ba
6 changed files with 148 additions and 88 deletions

View File

@ -79,6 +79,7 @@ typedef struct
#define WIN_NEEDS_INTERNALSOP 0x1000 /* Window was hidden by WIN_InternalShowOwnedPopups */ #define WIN_NEEDS_INTERNALSOP 0x1000 /* Window was hidden by WIN_InternalShowOwnedPopups */
/* Window functions */ /* Window functions */
extern WND *WIN_GetWndPtr( HWND hwnd );
extern int WIN_SuspendWndsLock( void ); extern int WIN_SuspendWndsLock( void );
extern void WIN_RestoreWndsLock(int ipreviousLock); extern void WIN_RestoreWndsLock(int ipreviousLock);
extern WND* WIN_FindWndPtr( HWND hwnd ); extern WND* WIN_FindWndPtr( HWND hwnd );
@ -115,6 +116,8 @@ inline static WND *WIN_FindWndPtr16( HWND16 hwnd )
return WIN_FindWndPtr( (HWND)(ULONG_PTR)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 HWND CARET_GetHwnd(void);
extern void CARET_GetRect(LPRECT lprc); /* windows/caret.c */ extern void CARET_GetRect(LPRECT lprc); /* windows/caret.c */

View File

@ -1579,6 +1579,7 @@ struct create_window_request
struct request_header __header; struct request_header __header;
user_handle_t parent; user_handle_t parent;
user_handle_t owner; user_handle_t owner;
unsigned int atom;
user_handle_t handle; user_handle_t handle;
}; };
@ -1627,6 +1628,8 @@ struct get_window_children_request
{ {
struct request_header __header; struct request_header __header;
user_handle_t parent; user_handle_t parent;
unsigned int atom;
void* tid;
int count; int count;
/* VARARG(children,user_handles); */ /* VARARG(children,user_handles); */
}; };
@ -1919,6 +1922,6 @@ union generic_request
struct get_window_tree_request get_window_tree; struct get_window_tree_request get_window_tree;
}; };
#define SERVER_PROTOCOL_VERSION 55 #define SERVER_PROTOCOL_VERSION 56
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -1410,6 +1410,7 @@ enum message_type
@REQ(create_window) @REQ(create_window)
user_handle_t parent; /* parent window */ user_handle_t parent; /* parent window */
user_handle_t owner; /* owner window */ user_handle_t owner; /* owner window */
unsigned int atom; /* class atom */
@REPLY @REPLY
user_handle_t handle; /* created window */ user_handle_t handle; /* created window */
@END @END
@ -1452,6 +1453,8 @@ enum message_type
/* Get a list of the window children */ /* Get a list of the window children */
@REQ(get_window_children) @REQ(get_window_children)
user_handle_t parent; /* parent window */ user_handle_t parent; /* parent window */
unsigned int atom; /* class atom for the listed children */
void* tid; /* thread owning the listed children */
@REPLY @REPLY
int count; /* total count of children */ int count; /* total count of children */
VARARG(children,user_handles); /* children handles */ VARARG(children,user_handles); /* children handles */

View File

@ -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 ) static void dump_create_window_request( const struct create_window_request *req )
{ {
fprintf( stderr, " parent=%08x,", req->parent ); 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 ) 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 ) 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 ) static void dump_get_window_children_reply( const struct get_window_children_request *req )

View File

@ -14,14 +14,16 @@
struct window struct window
{ {
struct window *parent; /* parent window */ struct window *parent; /* parent window */
struct window *owner; /* owner of this window */ struct window *owner; /* owner of this window */
struct window *first_child; /* first child window */ struct window *first_child; /* first child in Z-order */
struct window *last_child; /* last child window */ struct window *last_child; /* last child in Z-order */
struct window *next; /* next window in Z-order */ struct window *first_unlinked; /* first child not linked in the Z-order list */
struct window *prev; /* prev window in Z-order */ struct window *next; /* next window in Z-order */
user_handle_t handle; /* full handle for this window */ struct window *prev; /* prev window in Z-order */
struct thread *thread; /* thread owning the window */ 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 */ 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; 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) */ /* 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 ) static void link_window( struct window *win, struct window *parent, struct window *previous )
{ {
if (win->parent) /* unlink it from the previous location */ unlink_window( win ); /* 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;
}
if (parent) if (parent)
{ {
win->parent = parent; win->parent = parent;
@ -61,10 +74,12 @@ static void link_window( struct window *win, struct window *parent, struct windo
parent->first_child = win; 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 */ parent = win->parent;
win->next = win->prev = NULL; 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 */ /* destroy all children */
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 );
/* reset siblings owner */ /* reset siblings owner */
if (win->parent) if (win->parent)
@ -82,17 +98,20 @@ static void destroy_window( struct window *win )
struct window *ptr; struct window *ptr;
for (ptr = win->parent->first_child; ptr; ptr = ptr->next) for (ptr = win->parent->first_child; ptr; ptr = ptr->next)
if (ptr->owner == win) ptr->owner = NULL; 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 ); if (win->thread->queue) queue_cleanup_window( win->thread, win->handle );
free_user_handle( win->handle ); free_user_handle( win->handle );
link_window( win, NULL, NULL ); unlink_window( win );
memset( win, 0x55, sizeof(*win) ); memset( win, 0x55, sizeof(*win) );
free( win ); free( win );
} }
/* create a new window structure (note: the window is not linked in the window tree) */ /* 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) ); struct window *win = mem_alloc( sizeof(*win) );
if (!win) return NULL; if (!win) return NULL;
@ -102,13 +121,22 @@ static struct window *create_window( struct window *parent, struct window *owner
free( win ); free( win );
return NULL; return NULL;
} }
win->parent = parent; win->parent = parent;
win->owner = owner; win->owner = owner;
win->first_child = NULL; win->first_child = NULL;
win->last_child = NULL; win->last_child = NULL;
win->next = NULL; win->first_unlinked = NULL;
win->prev = NULL; win->thread = current;
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; return win;
} }
@ -148,7 +176,7 @@ DECL_HANDLER(create_window)
{ {
if (!top_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 */ top_window->thread = NULL; /* no thread owns the desktop */
} }
req->handle = top_window->handle; req->handle = top_window->handle;
@ -159,7 +187,7 @@ 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 (!(win = create_window( parent, owner ))) return; if (!(win = create_window( parent, owner, req->atom ))) return;
req->handle = win->handle; req->handle = win->handle;
} }
} }
@ -172,6 +200,12 @@ DECL_HANDLER(link_window)
if (!(win = get_window( req->handle ))) return; if (!(win = get_window( req->handle ))) return;
if (req->parent && !(parent = get_window( req->parent ))) 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 (parent && req->previous)
{ {
if (req->previous == (user_handle_t)1) /* special case: HWND_BOTTOM */ if (req->previous == (user_handle_t)1) /* special case: HWND_BOTTOM */
@ -254,7 +288,12 @@ DECL_HANDLER(get_window_children)
size_t len; size_t len;
if (parent) 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; req->count = total;
len = min( get_req_data_size(req), total * sizeof(user_handle_t) ); 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); user_handle_t *data = get_req_data(req);
for (ptr = parent->first_child; ptr && len; ptr = ptr->next, len -= sizeof(*data)) 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; *data++ = ptr->handle;
}
} }
} }

View File

@ -30,7 +30,6 @@
DEFAULT_DEBUG_CHANNEL(win); DEFAULT_DEBUG_CHANNEL(win);
DECLARE_DEBUG_CHANNEL(msg); 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) #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. * 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; BOOL res;
user_handle_t handle = 0; user_handle_t handle = 0;
@ -94,6 +93,7 @@ static WND *create_window_handle( HWND parent, HWND owner, INT size )
{ {
req->parent = parent; req->parent = parent;
req->owner = owner; req->owner = owner;
req->atom = atom;
if ((res = !SERVER_CALL_ERR())) handle = req->handle; if ((res = !SERVER_CALL_ERR())) handle = req->handle;
} }
SERVER_END_REQ; 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, * Return a pointer to the WND structure if local to the process,
* or BAD_WND_PTR is handle is local but not valid. * or BAD_WND_PTR is handle is local but not valid.
* If ret value is a valid pointer, the user lock is held. * 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; WND * ptr;
WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE; WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
@ -179,7 +210,7 @@ BOOL WIN_IsCurrentProcess( HWND hwnd )
{ {
WND *ptr; 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(); USER_Unlock();
return TRUE; return TRUE;
} }
@ -195,7 +226,7 @@ BOOL WIN_IsCurrentThread( HWND hwnd )
WND *ptr; WND *ptr;
BOOL ret = FALSE; 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()); ret = (ptr->tid == GetCurrentThreadId());
USER_Unlock(); USER_Unlock();
@ -218,7 +249,7 @@ HWND WIN_Handle32( HWND16 hwnd16 )
/* do sign extension for -2 and -3 */ /* do sign extension for -2 and -3 */
if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16; 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) if (ptr != BAD_WND_PTR)
{ {
@ -250,7 +281,7 @@ WND * WIN_FindWndPtr( HWND hwnd )
if (!hwnd) return NULL; if (!hwnd) return NULL;
if ((ptr = get_wnd_ptr( hwnd ))) if ((ptr = WIN_GetWndPtr( hwnd )))
{ {
if (ptr != BAD_WND_PTR) if (ptr != BAD_WND_PTR)
{ {
@ -583,7 +614,8 @@ BOOL WIN_CreateDesktopWindow(void)
&wndExtra, &winproc, &clsStyle, &dce ))) &wndExtra, &winproc, &clsStyle, &dce )))
return FALSE; 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; if (!pWndDesktop) return FALSE;
hwndDesktop = pWndDesktop->hwndSelf; hwndDesktop = pWndDesktop->hwndSelf;
@ -785,7 +817,7 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
/* Create the window structure */ /* 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) ))) sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
{ {
TRACE("out of memory\n" ); 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 ) static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
{ {
HWND *list; HWND *list = NULL;
HWND retvalue; HWND retvalue = 0;
int i = 0, len = 0; int i = 0, len = 0;
WCHAR *buffer = NULL; 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 (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
} }
if (!(list = WIN_ListChildren( parent ))) if (!(list = list_window_children( parent, className, 0 ))) goto done;
{
if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
return 0;
}
if (child) if (child)
{ {
child = WIN_GetFullHandle( child ); child = WIN_GetFullHandle( child );
while (list[i] && list[i] != child) i++; while (list[i] && list[i] != child) i++;
if (!list[i]) return 0; if (!list[i]) goto done;
i++; /* start from next window */ i++; /* start from next window */
} }
for ( ; list[i]; i++) if (title)
{ {
if (className && (GetClassWord(list[i], GCW_ATOM) != className)) while (list[i])
continue; /* Not the right class */ {
if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
/* Now check the title */ i++;
if (!title) break; }
if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
} }
retvalue = list[i]; retvalue = list[i];
HeapFree( GetProcessHeap(), 0, list );
if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
/* In this case we need to check whether other processes done:
own a window with the given paramters on the Desktop, if (list) HeapFree( GetProcessHeap(), 0, list );
but we don't, so let's at least warn about it */ if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
if (!retvalue) FIXME("Returning 0 without checking other processes\n");
return retvalue; return retvalue;
} }
@ -2003,7 +2027,7 @@ BOOL WINAPI IsWindow( HWND hwnd )
WND *ptr; WND *ptr;
BOOL ret; BOOL ret;
if ((ptr = get_wnd_ptr( hwnd ))) if ((ptr = WIN_GetWndPtr( hwnd )))
{ {
if (ptr == BAD_WND_PTR) return FALSE; if (ptr == BAD_WND_PTR) return FALSE;
USER_Unlock(); USER_Unlock();
@ -2029,7 +2053,7 @@ DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
WND *ptr; WND *ptr;
DWORD tid = 0; DWORD tid = 0;
if ((ptr = get_wnd_ptr( hwnd ))) if ((ptr = WIN_GetWndPtr( hwnd )))
{ {
if (ptr != BAD_WND_PTR) if (ptr != BAD_WND_PTR)
{ {
@ -2462,24 +2486,7 @@ HWND *WIN_ListParents( HWND hwnd )
*/ */
HWND *WIN_ListChildren( HWND hwnd ) HWND *WIN_ListChildren( HWND hwnd )
{ {
HWND *list = NULL; return list_window_children( hwnd, 0, 0 );
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;
} }
@ -2533,16 +2540,14 @@ BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
HWND *list; HWND *list;
int i, iWndsLocks; 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 */ /* Now call the callback function for every window */
iWndsLocks = WIN_SuspendWndsLock(); iWndsLocks = WIN_SuspendWndsLock();
for (i = 0; list[i]; i++) for (i = 0; list[i]; i++)
{
if (GetWindowThreadProcessId( list[i], NULL ) != id) continue;
if (!func( list[i], lParam )) break; if (!func( list[i], lParam )) break;
}
WIN_RestoreWndsLock(iWndsLocks); WIN_RestoreWndsLock(iWndsLocks);
HeapFree( GetProcessHeap(), 0, list ); HeapFree( GetProcessHeap(), 0, list );
return TRUE; return TRUE;