Store window class atom in the server.

Keep unlinked windows on a separate list.
Implemented inter-process FindWindow().
This commit is contained in:
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 */
/* 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 */

View File

@ -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 */

View File

@ -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 */

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 )
{
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 )

View File

@ -16,12 +16,14 @@ 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 *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;
@ -106,9 +125,18 @@ static struct window *create_window( struct window *parent, struct window *owner
win->owner = owner;
win->first_child = NULL;
win->last_child = NULL;
win->next = NULL;
win->prev = 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,8 +302,12 @@ 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;
}
}
}

View File

@ -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)
{
while (list[i])
{
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;
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;