Removed next and child fields in the window structure and use

WIN_ListChildren instead.
This commit is contained in:
Alexandre Julliard 2001-10-11 20:49:40 +00:00
parent d30d2d8efc
commit 80593bf842
7 changed files with 319 additions and 297 deletions

View file

@ -175,28 +175,36 @@ fail:
* adding to the clip region the intersection of the target rectangle
* with an offset window rectangle.
*/
static BOOL DCE_AddClipRects( HWND start, HWND end, HRGN hrgnClip, LPRECT lpRect, int x, int y )
static void DCE_AddClipRects( HWND parent, HWND end, HRGN hrgnClip, LPRECT lpRect, int x, int y )
{
RECT rect;
WND *pWnd;
int i;
HWND *list = WIN_ListChildren( parent );
for (pWnd = WIN_FindWndPtr(start); (pWnd && (pWnd->hwndSelf != end)); WIN_UpdateWndPtr(&pWnd,pWnd->next))
if (!list) return;
for (i = 0; list[i]; i++)
{
if( !(pWnd->dwStyle & WS_VISIBLE) ) continue;
rect.left = pWnd->rectWindow.left + x;
rect.top = pWnd->rectWindow.top + y;
rect.right = pWnd->rectWindow.right + x;
rect.bottom = pWnd->rectWindow.bottom + y;
if( IntersectRect( &rect, &rect, lpRect ))
if (list[i] == end) break;
if (!(pWnd = WIN_FindWndPtr( list[i] ))) continue;
if (pWnd->dwStyle & WS_VISIBLE)
{
if(!REGION_UnionRectWithRgn( hrgnClip, &rect )) break;
rect.left = pWnd->rectWindow.left + x;
rect.top = pWnd->rectWindow.top + y;
rect.right = pWnd->rectWindow.right + x;
rect.bottom = pWnd->rectWindow.bottom + y;
if( IntersectRect( &rect, &rect, lpRect ))
{
if(!REGION_UnionRectWithRgn( hrgnClip, &rect ))
{
WIN_ReleaseWndPtr( pWnd );
break;
}
}
}
WIN_ReleaseWndPtr( pWnd );
}
start = pWnd->hwndSelf;
WIN_ReleaseWndPtr(pWnd);
return (start == end);
HeapFree( GetProcessHeap(), 0, list );
}
@ -230,7 +238,7 @@ static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
* DCE_GetVisRect() returns a rectangle either in client
* or in window coordinates (for DCX_WINDOW request). */
if( (flags & DCX_CLIPCHILDREN) && wndPtr->child )
if (flags & DCX_CLIPCHILDREN)
{
if( flags & DCX_WINDOW )
{
@ -243,7 +251,7 @@ static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
else
xoffset = yoffset = 0;
DCE_AddClipRects( wndPtr->child->hwndSelf, 0, hrgnClip, &rect, xoffset, yoffset );
DCE_AddClipRects( wndPtr->hwndSelf, 0, hrgnClip, &rect, xoffset, yoffset );
}
/* We may need to clip children of child window, if a window with PARENTDC
@ -251,7 +259,7 @@ static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
* preference dialogs) gets here, we take the region for the parent window
* but apparently still need to clip the children of the child window... */
if( (cflags & DCX_CLIPCHILDREN) && childWnd && childWnd->child )
if( (cflags & DCX_CLIPCHILDREN) && childWnd)
{
if( flags & DCX_WINDOW )
{
@ -268,7 +276,7 @@ static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
xoffset += childWnd->rectClient.left;
yoffset += childWnd->rectClient.top;
DCE_AddClipRects( childWnd->child->hwndSelf, 0, hrgnClip,
DCE_AddClipRects( childWnd->hwndSelf, 0, hrgnClip,
&rect, xoffset, yoffset );
}
@ -287,8 +295,8 @@ static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
}
if (flags & DCX_CLIPSIBLINGS && wndPtr->parent )
DCE_AddClipRects( GetWindow( wndPtr->hwndSelf, GW_HWNDFIRST ),
wndPtr->hwndSelf, hrgnClip, &rect, xoffset, yoffset );
DCE_AddClipRects( wndPtr->parent, wndPtr->hwndSelf,
hrgnClip, &rect, xoffset, yoffset );
/* Clip siblings of all ancestors that have the
* WS_CLIPSIBLINGS style
@ -303,8 +311,8 @@ static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
yoffset -= wndPtr->rectClient.top;
if(wndPtr->dwStyle & WS_CLIPSIBLINGS && wndPtr->parent)
{
DCE_AddClipRects( GetWindow( wndPtr->hwndSelf, GW_HWNDFIRST ),
wndPtr->hwndSelf, hrgnClip, &rect, xoffset, yoffset );
DCE_AddClipRects( wndPtr->parent, wndPtr->hwndSelf,
hrgnClip, &rect, xoffset, yoffset );
}
}
@ -501,7 +509,8 @@ BOOL TTYDRV_SetWindowPos( WINDOWPOS *winpos )
/* don't need to change the Zorder of hwnd if it's already inserted
* after hwndInsertAfter or when inserting hwnd after itself.
*/
if(( wnd->next == wndPtr ) || (winpos->hwnd == winpos->hwndInsertAfter))
if ((winpos->hwnd == winpos->hwndInsertAfter) ||
(winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
winpos->flags |= SWP_NOZORDER;
}
WIN_ReleaseWndPtr(wnd);
@ -543,7 +552,10 @@ BOOL TTYDRV_SetWindowPos( WINDOWPOS *winpos )
}
else
if( winpos->hwndInsertAfter == HWND_BOTTOM )
winpos->flags |= ( wndPtr->next )? 0: SWP_NOZORDER;
{
if (!GetWindow( wndPtr->hwndSelf, GW_HWNDNEXT ))
winpos->flags |= SWP_NOZORDER;
}
else
if( !(winpos->flags & SWP_NOZORDER) )
if( GetWindow(winpos->hwndInsertAfter, GW_HWNDNEXT) == wndPtr->hwndSelf )

View file

@ -144,12 +144,14 @@ INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy,
RECT rc, cliprc;
WND* wnd = WIN_FindWndPtr( hwnd );
if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE ))
if (!wnd) return ERROR;
if (!WIN_IsWindowDrawable( wnd, TRUE ))
{
retVal = ERROR;
goto END;
WIN_ReleaseWndPtr( wnd );
return ERROR;
}
hwnd = wnd->hwndSelf; /* make it a full handle */
WIN_ReleaseWndPtr( wnd );
GetClientRect(hwnd, &rc);
if (rect) IntersectRect(&rc, &rc, rect);
@ -203,16 +205,22 @@ INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy,
if( flags & SW_SCROLLCHILDREN )
{
RECT r;
WND *w;
for( w =WIN_LockWndPtr(wnd->child); w; WIN_UpdateWndPtr(&w, w->next))
HWND *list = WIN_ListChildren( hwnd );
if (list)
{
r = w->rectWindow;
if( !rect || IntersectRect(&r, &r, &rc) )
SetWindowPos(w->hwndSelf, 0, w->rectWindow.left + dx,
w->rectWindow.top + dy, 0,0, SWP_NOZORDER |
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
SWP_DEFERERASE );
int i;
RECT r, dummy;
for (i = 0; list[i]; i++)
{
GetWindowRect( list[i], &r );
MapWindowPoints( 0, hwnd, (POINT *)&r, 2 );
if (!rect || IntersectRect(&dummy, &r, &rc))
SetWindowPos( list[i], 0, r.left + dx, r.top + dy, 0, 0,
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
SWP_NOREDRAW | SWP_DEFERERASE );
}
HeapFree( GetProcessHeap(), 0, list );
}
}
@ -230,7 +238,5 @@ INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy,
if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
DeleteObject( hrgnClip );
}
END:
WIN_ReleaseWndPtr(wnd);
return retVal;
}

View file

@ -707,7 +707,8 @@ static BOOL fixup_flags( WINDOWPOS *winpos )
/* don't need to change the Zorder of hwnd if it's already inserted
* after hwndInsertAfter or when inserting hwnd after itself.
*/
if ((wnd->next == wndPtr ) || (winpos->hwnd == winpos->hwndInsertAfter))
if ((winpos->hwnd == winpos->hwndInsertAfter) ||
(winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
winpos->flags |= SWP_NOZORDER;
}
WIN_ReleaseWndPtr(wnd);
@ -1306,20 +1307,6 @@ void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event )
*
* Synchronize internal z-order with the window manager's.
*/
static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
{
/* return TRUE if we have at least two managed windows */
for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
if( ((*pWndA)->dwExStyle & WS_EX_MANAGED) &&
((*pWndA)->dwStyle & WS_VISIBLE )) break;
if( *pWndA )
for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
if( ((*pWndB)->dwExStyle & WS_EX_MANAGED) &&
((*pWndB)->dwStyle & WS_VISIBLE )) break;
return ((*pWndB) != NULL);
}
static Window __get_common_ancestor( Display *display, Window A, Window B,
Window** children, unsigned* total )
{
@ -1369,29 +1356,39 @@ static unsigned __td_lookup( Window w, Window* list, unsigned max )
static HWND query_zorder( Display *display, HWND hWndCheck)
{
HWND hwndInsertAfter = HWND_TOP;
WND *pWndCheck = WIN_FindWndPtr(hWndCheck);
WND *top = WIN_FindWndPtr( GetTopWindow(0) );
WND *pWnd, *pWndZ = top;
Window w, parent, *children = NULL;
unsigned total, check, pos, best;
HWND *list = WIN_ListChildren( GetDesktopWindow() );
HWND hwndA = 0, hwndB = 0;
WND *win;
int i;
if( !__check_query_condition(&pWndZ, &pWnd) )
/* find at least two managed windows */
if (!list) return 0;
for (i = 0; list[i]; i++)
{
WIN_ReleaseWndPtr(pWndCheck);
WIN_ReleaseWndPtr(top);
return hwndInsertAfter;
if (!(win = WIN_FindWndPtr( list[i] ))) continue;
if ((win->dwExStyle & WS_EX_MANAGED) && (win->dwStyle & WS_VISIBLE))
{
if (!hwndA) hwndA = list[i];
else
{
hwndB = list[i];
WIN_ReleaseWndPtr( win );
break;
}
}
WIN_ReleaseWndPtr( win );
}
WIN_LockWndPtr(pWndZ);
WIN_LockWndPtr(pWnd);
WIN_ReleaseWndPtr(top);
if (!hwndA || !hwndB) goto done;
parent = __get_common_ancestor( display, get_whole_window(pWndZ),
get_whole_window(pWnd), &children, &total );
parent = __get_common_ancestor( display, X11DRV_get_whole_window(hwndA),
X11DRV_get_whole_window(hwndB), &children, &total );
if( parent && children )
{
/* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
/* w is the ancestor if hWndCheck that is a direct descendant of 'parent' */
w = __get_top_decoration( display, get_whole_window(pWndCheck), parent );
w = __get_top_decoration( display, X11DRV_get_whole_window(hWndCheck), parent );
if( w != children[total-1] ) /* check if at the top */
{
@ -1399,32 +1396,28 @@ static HWND query_zorder( Display *display, HWND hWndCheck)
check = __td_lookup( w, children, total );
best = total;
for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
/* go through all windows in Wine z-order... */
for (i = 0; list[i]; i++)
{
/* go through all windows in Wine z-order... */
if( pWnd != pWndCheck )
if (list[i] == hWndCheck) continue;
if (!(GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_MANAGED)) continue;
if (!(w = __get_top_decoration( display, X11DRV_get_whole_window(list[i]),
parent ))) continue;
pos = __td_lookup( w, children, total );
if( pos < best && pos > check )
{
if( !(pWnd->dwExStyle & WS_EX_MANAGED) ||
!(w = __get_top_decoration( display, get_whole_window(pWnd), parent )) )
continue;
pos = __td_lookup( w, children, total );
if( pos < best && pos > check )
{
/* find a nearest Wine window precedes
* pWndCheck in the real z-order... */
best = pos;
hwndInsertAfter = pWnd->hwndSelf;
}
if( best - check == 1 ) break;
/* find a nearest Wine window precedes hWndCheck in the real z-order */
best = pos;
hwndInsertAfter = list[i];
}
if( best - check == 1 ) break;
}
}
}
if( children ) TSXFree( children );
WIN_ReleaseWndPtr(pWnd);
WIN_ReleaseWndPtr(pWndZ);
WIN_ReleaseWndPtr(pWndCheck);
done:
HeapFree( GetProcessHeap(), 0, list );
return hwndInsertAfter;
}

View file

@ -22,15 +22,13 @@ struct tagMESSAGEQUEUE;
typedef struct tagWND
{
struct tagWND *next; /* Next sibling */
struct tagWND *child; /* First child */
HWND hwndSelf; /* Handle of this window */
HWND parent; /* Window parent */
HWND owner; /* Window owner */
struct tagCLASS *class; /* Window class */
HWINDOWPROC winproc; /* Window procedure */
DWORD dwMagic; /* Magic number (must be WND_MAGIC) */
DWORD tid; /* Owner thread id */
HWND hwndSelf; /* Handle of this window */
HINSTANCE hInstance; /* Window hInstance (from CreateWindow) */
RECT rectClient; /* Client area rel. to parent client area */
RECT rectWindow; /* Whole window rel. to parent client area */
@ -124,7 +122,7 @@ extern void CARET_GetRect(LPRECT lprc); /* windows/caret.c */
extern BOOL16 DRAG_QueryUpdate( HWND, SEGPTR, BOOL );
extern HBRUSH DEFWND_ControlColor( HDC hDC, UINT ctlType ); /* windows/defwnd.c */
extern void PROPERTY_RemoveWindowProps( WND *pWnd ); /* windows/property.c */
extern void PROPERTY_RemoveWindowProps( HWND hwnd ); /* windows/property.c */
/* Classes functions */
struct tagCLASS; /* opaque structure */

View file

@ -231,10 +231,12 @@ HANDLE WINAPI RemovePropW( HWND hwnd, LPCWSTR str )
*
* Remove all properties of a window.
*/
void PROPERTY_RemoveWindowProps( WND *pWnd )
void PROPERTY_RemoveWindowProps( HWND hwnd )
{
PROPERTY *prop, *next;
WND *pWnd = WIN_FindWndPtr( hwnd );
if (!pWnd) return;
for (prop = pWnd->pProp; (prop); prop = next)
{
next = prop->next;
@ -242,6 +244,7 @@ void PROPERTY_RemoveWindowProps( WND *pWnd )
HeapFree( GetProcessHeap(), 0, prop );
}
pWnd->pProp = NULL;
WIN_ReleaseWndPtr( pWnd );
}

View file

@ -383,16 +383,8 @@ void WIN_UnlinkWindow( HWND hwnd )
*/
void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
{
WND *wndPtr, **ppWnd, *parentPtr = NULL;
BOOL ret;
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return;
if (parent && !(parentPtr = WIN_FindWndPtr( parent )))
{
WIN_ReleaseWndPtr(wndPtr);
return;
}
SERVER_START_REQ( link_window )
{
req->handle = hwnd;
@ -401,42 +393,88 @@ void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
ret = !SERVER_CALL_ERR();
}
SERVER_END_REQ;
if (!ret) goto done;
/* first unlink it if it is linked */
if (wndPtr->parent)
if (ret && parent)
{
WND *ptr = WIN_FindWndPtr( wndPtr->parent );
ppWnd = &ptr->child;
while (*ppWnd && *ppWnd != wndPtr) ppWnd = &(*ppWnd)->next;
if (*ppWnd) *ppWnd = wndPtr->next;
WIN_ReleaseWndPtr( ptr );
WND *wndPtr = WIN_FindWndPtr( hwnd );
if (wndPtr)
{
wndPtr->parent = WIN_GetFullHandle(parent);
WIN_ReleaseWndPtr( wndPtr );
}
}
}
if (parentPtr)
/***********************************************************************
* find_child_to_repaint
*
* Find a window that needs repaint among the children of the specified window.
*/
static HWND find_child_to_repaint( HWND parent )
{
int i;
HWND ret = 0;
HWND *list;
if (!parent) parent = GetDesktopWindow();
if (!(list = list_window_children( parent, 0, 0 ))) return 0;
for (i = 0; list[i] && !ret; i++)
{
wndPtr->parent = parentPtr->hwndSelf;
if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
WND *win = WIN_GetWndPtr( list[i] );
if (win == BAD_WND_PTR) continue; /* ignore it */
if (!win)
{
ppWnd = &parentPtr->child; /* Point to first sibling hwnd */
if (hwndInsertAfter == HWND_BOTTOM) /* Find last sibling hwnd */
while (*ppWnd) ppWnd = &(*ppWnd)->next;
/* doesn't belong to this process, but check children */
ret = find_child_to_repaint( list[i] );
continue;
}
else /* Normal case */
if (!(win->dwStyle & WS_VISIBLE))
{
WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
if (!afterPtr) goto done;
ppWnd = &afterPtr->next;
WIN_ReleaseWndPtr(afterPtr);
USER_Unlock();
continue;
}
if ((win->tid != GetCurrentThreadId()) ||
(!win->hrgnUpdate && !(win->flags & WIN_INTERNAL_PAINT)))
{
/* does not need repaint, check children */
USER_Unlock();
ret = find_child_to_repaint( list[i] );
continue;
}
wndPtr->next = *ppWnd;
*ppWnd = wndPtr;
}
else wndPtr->next = NULL; /* unlinked */
done:
WIN_ReleaseWndPtr( parentPtr );
WIN_ReleaseWndPtr( wndPtr );
/* now we have something */
ret = list[i];
if (!(win->dwExStyle & WS_EX_TRANSPARENT))
{
/* not transparent, we can repaint it */
USER_Unlock();
break;
}
USER_Unlock();
/* transparent window, look for non-transparent sibling to paint first */
for (i++; list[i]; i++)
{
if (!(win = WIN_GetWndPtr( list[i] ))) continue;
if (win == BAD_WND_PTR) continue;
if (!(win->dwStyle & WS_VISIBLE))
{
USER_Unlock();
continue;
}
if (!(win->dwExStyle & WS_EX_TRANSPARENT) &&
(win->hrgnUpdate || (win->flags & WIN_INTERNAL_PAINT)))
{
ret = list[i];
USER_Unlock();
break;
}
USER_Unlock();
}
}
HeapFree( GetProcessHeap(), 0, list );
return ret;
}
@ -447,55 +485,27 @@ void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
*/
HWND WIN_FindWinToRepaint( HWND hwnd )
{
HWND hwndRet;
WND *pWnd;
/* Note: the desktop window never gets WM_PAINT messages
* The real reason why is because Windows DesktopWndProc
* does ValidateRgn inside WM_ERASEBKGND handler.
*/
if (hwnd == GetDesktopWindow()) hwnd = 0;
pWnd = hwnd ? WIN_FindWndPtr(hwnd) : WIN_LockWndPtr(pWndDesktop->child);
for ( ; pWnd ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
if (hwnd)
{
if (!(pWnd->dwStyle & WS_VISIBLE)) continue;
if ((pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)) &&
WIN_IsCurrentThread( pWnd->hwndSelf ))
break;
if (pWnd->child )
/* check the window itself first */
WND *win = WIN_FindWndPtr( hwnd );
if (!win) return 0;
if ((win->dwStyle & WS_VISIBLE) &&
(win->hrgnUpdate || (win->flags & WIN_INTERNAL_PAINT)))
{
if ((hwndRet = WIN_FindWinToRepaint( pWnd->child->hwndSelf )) )
{
WIN_ReleaseWndPtr(pWnd);
return hwndRet;
}
WIN_ReleaseWndPtr( win );
return hwnd;
}
WIN_ReleaseWndPtr( win );
}
if(!pWnd)
{
TRACE("nothing found\n");
return 0;
}
hwndRet = pWnd->hwndSelf;
/* look among siblings if we got a transparent window */
while (pWnd)
{
if (!(pWnd->dwExStyle & WS_EX_TRANSPARENT) &&
(pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)) &&
WIN_IsCurrentThread( pWnd->hwndSelf ))
{
hwndRet = pWnd->hwndSelf;
WIN_ReleaseWndPtr(pWnd);
break;
}
WIN_UpdateWndPtr(&pWnd,pWnd->next);
}
TRACE("found %04x\n",hwndRet);
return hwndRet;
/* now check its children */
return find_child_to_repaint( hwnd );
}
@ -503,34 +513,33 @@ HWND WIN_FindWinToRepaint( HWND hwnd )
* WIN_DestroyWindow
*
* Destroy storage associated to a window. "Internals" p.358
* returns a locked wndPtr->next
*/
static WND* WIN_DestroyWindow( WND* wndPtr )
static void WIN_DestroyWindow( HWND hwnd )
{
HWND hwnd = wndPtr->hwndSelf;
WND *pWnd;
WND *wndPtr;
HWND *list;
TRACE("%04x\n", wndPtr->hwndSelf );
TRACE("%04x\n", hwnd );
/* free child windows */
WIN_LockWndPtr(wndPtr->child);
while ((pWnd = wndPtr->child))
if ((list = WIN_ListChildren( hwnd )))
{
wndPtr->child = WIN_DestroyWindow( pWnd );
WIN_ReleaseWndPtr(pWnd);
int i;
for (i = 0; list[i]; i++) WIN_DestroyWindow( list[i] );
HeapFree( GetProcessHeap(), 0, list );
}
/*
* Clear the update region to make sure no WM_PAINT messages will be
* generated for this window while processing the WM_NCDESTROY.
*/
RedrawWindow( wndPtr->hwndSelf, NULL, 0,
RedrawWindow( hwnd, NULL, 0,
RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
/*
* Send the WM_NCDESTROY to the window being destroyed.
*/
SendMessageA( wndPtr->hwndSelf, WM_NCDESTROY, 0, 0);
SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
/* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
@ -539,12 +548,10 @@ static WND* WIN_DestroyWindow( WND* wndPtr )
/* free resources associated with the window */
TIMER_RemoveWindowTimers( wndPtr->hwndSelf );
PROPERTY_RemoveWindowProps( wndPtr );
TIMER_RemoveWindowTimers( hwnd );
PROPERTY_RemoveWindowProps( hwnd );
/* toss stale messages from the queue */
QUEUE_CleanupWindow( hwnd );
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return;
wndPtr->hmemTaskQ = 0;
if (!(wndPtr->dwStyle & WS_CHILD))
@ -558,16 +565,13 @@ static WND* WIN_DestroyWindow( WND* wndPtr )
DestroyMenu( wndPtr->hSysMenu );
wndPtr->hSysMenu = 0;
}
USER_Driver.pDestroyWindow( wndPtr->hwndSelf );
DCE_FreeWindowDCE( wndPtr->hwndSelf ); /* Always do this to catch orphaned DCs */
USER_Driver.pDestroyWindow( hwnd );
DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
CLASS_RemoveWindow( wndPtr->class );
wndPtr->class = NULL;
wndPtr->dwMagic = 0; /* Mark it as invalid */
WIN_UpdateWndPtr(&pWnd,wndPtr->next);
return pWnd;
WIN_ReleaseWndPtr( wndPtr );
}
/***********************************************************************
@ -622,8 +626,6 @@ BOOL WIN_CreateDesktopWindow(void)
hwndDesktop = pWndDesktop->hwndSelf;
pWndDesktop->tid = 0; /* nobody owns the desktop */
pWndDesktop->next = NULL;
pWndDesktop->child = NULL;
pWndDesktop->parent = 0;
pWndDesktop->owner = 0;
pWndDesktop->class = class;
@ -838,10 +840,8 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
/* Fill the window structure */
wndPtr->tid = GetCurrentThreadId();
wndPtr->next = NULL;
wndPtr->child = NULL;
wndPtr->owner = owner;
wndPtr->tid = GetCurrentThreadId();
wndPtr->owner = owner;
wndPtr->parent = parent;
wndPtr->class = classPtr;
wndPtr->winproc = winproc;
@ -960,12 +960,12 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
}
else wndPtr->wIDmenu = (UINT)cs->hMenu;
if (!USER_Driver.pCreateWindow( wndPtr->hwndSelf, cs, unicode))
if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
{
WARN("aborted by WM_xxCREATE!\n");
WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
WIN_ReleaseWndPtr( wndPtr );
WIN_DestroyWindow( hwnd );
CLASS_RemoveWindow( classPtr );
WIN_ReleaseWndPtr(wndPtr);
return 0;
}
@ -1352,7 +1352,7 @@ BOOL WINAPI DestroyWindow( HWND hwnd )
/* Destroy the window storage */
WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
WIN_DestroyWindow( hwnd );
retvalue = TRUE;
end:
WIN_ReleaseWndPtr(wndPtr);

View file

@ -282,6 +282,90 @@ BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
}
/***********************************************************************
* find_child_from_point
*
* Find the child that contains pt. Helper for WindowFromPoint.
* pt is in parent client coordinates.
* lparam is the param to pass in the WM_NCHITTEST message.
*/
static HWND find_child_from_point( HWND parent, POINT pt, INT *hittest, LPARAM lparam )
{
int i, res;
WND *wndPtr;
HWND *list = WIN_ListChildren( parent );
if (!list) return 0;
for (i = 0; list[i]; i++)
{
if (!(wndPtr = WIN_FindWndPtr( list[i] ))) continue;
/* If point is in window, and window is visible, and it */
/* is enabled (or it's a top-level window), then explore */
/* its children. Otherwise, go to the next window. */
if (!(wndPtr->dwStyle & WS_VISIBLE)) goto next; /* not visible -> skip */
if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD | WS_DISABLED)) == (WS_CHILD | WS_DISABLED))
goto next; /* disabled child -> skip */
if ((wndPtr->dwExStyle & (WS_EX_LAYERED | WS_EX_TRANSPARENT)) == (WS_EX_LAYERED | WS_EX_TRANSPARENT))
goto next; /* transparent -> skip */
if (wndPtr->hrgnWnd)
{
if (!PtInRegion( wndPtr->hrgnWnd, pt.x - wndPtr->rectWindow.left,
pt.y - wndPtr->rectWindow.top ))
goto next; /* point outside window region -> skip */
}
else if (!PtInRect( &wndPtr->rectWindow, pt )) goto next; /* not in window -> skip */
TRACE( "%ld,%ld is inside %04x\n", pt.x, pt.y, list[i] );
/* If window is minimized or disabled, return at once */
if (wndPtr->dwStyle & WS_MINIMIZE)
{
WIN_ReleaseWndPtr( wndPtr );
*hittest = HTCAPTION;
return list[i];
}
if (wndPtr->dwStyle & WS_DISABLED)
{
WIN_ReleaseWndPtr( wndPtr );
*hittest = HTERROR;
return list[i];
}
/* If point is in client area, explore children */
if (PtInRect( &wndPtr->rectClient, pt ))
{
POINT new_pt;
HWND ret;
new_pt.x = pt.x - wndPtr->rectClient.left;
new_pt.y = pt.y - wndPtr->rectClient.top;
WIN_ReleaseWndPtr( wndPtr );
if ((ret = find_child_from_point( list[i], new_pt, hittest, lparam )))
return ret;
}
else WIN_ReleaseWndPtr( wndPtr );
/* Now it's inside window, send WM_NCCHITTEST (if same thread) */
if (!WIN_IsCurrentThread( list[i] ))
{
*hittest = HTCLIENT;
return list[i];
}
if ((res = SendMessageA( list[i], WM_NCHITTEST, 0, lparam )) != HTTRANSPARENT)
{
*hittest = res; /* Found the window */
return list[i];
}
continue; /* continue search with next sibling */
next:
WIN_ReleaseWndPtr( wndPtr );
}
return 0;
}
/***********************************************************************
* WINPOS_WindowFromPoint
*
@ -289,9 +373,9 @@ BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
*/
HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
{
WND *wndScope, *wndPtr, *wndTmp;
HWND hwnd_ret = 0;
WND *wndScope;
POINT xy = pt;
int res;
TRACE("scope %04x %ld,%ld\n", hwndScope, pt.x, pt.y);
@ -300,115 +384,41 @@ HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
hwndScope = wndScope->hwndSelf; /* make it a full handle */
*hittest = HTERROR;
wndPtr = WIN_LockWndPtr(wndScope->child);
if( wndScope->dwStyle & WS_DISABLED )
{
*hittest = HTERROR;
goto end;
WIN_ReleaseWndPtr(wndScope);
return 0;
}
if (wndScope->parent)
MapWindowPoints( GetDesktopWindow(), wndScope->parent, &xy, 1 );
if (xy.x < wndScope->rectClient.left || pt.x >= wndScope->rectClient.right ||
xy.y < wndScope->rectClient.top || pt.y >= wndScope->rectClient.bottom ||
wndScope->dwStyle & WS_MINIMIZE)
goto hittest;
xy.x -= wndScope->rectClient.left;
xy.y -= wndScope->rectClient.top;
for (;;)
if (!(wndScope->dwStyle & WS_MINIMIZE) && PtInRect( &wndScope->rectClient, xy ))
{
while (wndPtr)
{
/* If point is in window, and window is visible, and it */
/* is enabled (or it's a top-level window), then explore */
/* its children. Otherwise, go to the next window. */
HWND ret;
if ((wndPtr->dwStyle & WS_VISIBLE) &&
((wndPtr->dwExStyle & (WS_EX_LAYERED | WS_EX_TRANSPARENT)) != (WS_EX_LAYERED | WS_EX_TRANSPARENT)) &&
(!(wndPtr->dwStyle & WS_DISABLED) ||
((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)) &&
(wndPtr->hrgnWnd ?
PtInRegion(wndPtr->hrgnWnd, xy.x - wndPtr->rectWindow.left,
xy.y - wndPtr->rectWindow.top) :
((xy.x >= wndPtr->rectWindow.left) &&
(xy.x < wndPtr->rectWindow.right) &&
(xy.y >= wndPtr->rectWindow.top) &&
(xy.y < wndPtr->rectWindow.bottom))))
{
TRACE("%ld,%ld is inside %04x\n", xy.x, xy.y, wndPtr->hwndSelf);
hwnd_ret = wndPtr->hwndSelf; /* Got a suitable window */
/* If window is minimized or disabled, return at once */
if (wndPtr->dwStyle & WS_MINIMIZE)
{
*hittest = HTCAPTION;
goto end;
}
if (wndPtr->dwStyle & WS_DISABLED)
{
*hittest = HTERROR;
goto end;
}
/* If point is not in client area, ignore the children */
if ((xy.x < wndPtr->rectClient.left) ||
(xy.x >= wndPtr->rectClient.right) ||
(xy.y < wndPtr->rectClient.top) ||
(xy.y >= wndPtr->rectClient.bottom)) break;
xy.x -= wndPtr->rectClient.left;
xy.y -= wndPtr->rectClient.top;
WIN_UpdateWndPtr(&wndPtr,wndPtr->child);
}
else
{
WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
}
}
hittest:
/* If nothing found, try the scope window */
if (!hwnd_ret) hwnd_ret = hwndScope;
/* Send the WM_NCHITTEST message (only if to the same task) */
if (WIN_IsCurrentThread( hwnd_ret ))
{
INT res = SendMessageA( hwnd_ret, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ) );
if (res != HTTRANSPARENT)
{
*hittest = res; /* Found the window */
goto end;
}
}
else
{
*hittest = HTCLIENT;
goto end;
}
if (!(wndTmp = WIN_FindWndPtr( hwnd_ret ))) break;
/* If no children found in last search, make point relative to parent */
if (!wndPtr)
{
xy.x += wndTmp->rectClient.left;
xy.y += wndTmp->rectClient.top;
}
/* Restart the search from the next sibling */
WIN_UpdateWndPtr(&wndPtr,wndTmp->next);
hwnd_ret = wndTmp->parent;
WIN_ReleaseWndPtr( wndTmp );
xy.x -= wndScope->rectClient.left;
xy.y -= wndScope->rectClient.top;
WIN_ReleaseWndPtr( wndScope );
if ((ret = find_child_from_point( hwndScope, xy, hittest, MAKELONG( pt.x, pt.y ) )))
return ret;
}
else WIN_ReleaseWndPtr( wndScope );
end:
WIN_ReleaseWndPtr(wndPtr);
WIN_ReleaseWndPtr(wndScope);
return hwnd_ret;
/* If nothing found, try the scope window */
if (!WIN_IsCurrentThread( hwndScope ))
{
*hittest = HTCLIENT;
return hwndScope;
}
res = SendMessageA( hwndScope, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ) );
if (res != HTTRANSPARENT)
{
*hittest = res; /* Found the window */
return hwndScope;
}
*hittest = HTNOWHERE;
return 0;
}