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 * adding to the clip region the intersection of the target rectangle
* with an offset window 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; RECT rect;
WND *pWnd; 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; if (list[i] == end) break;
if (!(pWnd = WIN_FindWndPtr( list[i] ))) continue;
rect.left = pWnd->rectWindow.left + x; if (pWnd->dwStyle & WS_VISIBLE)
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 )) 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; HeapFree( GetProcessHeap(), 0, list );
WIN_ReleaseWndPtr(pWnd);
return (start == end);
} }
@ -230,7 +238,7 @@ static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
* DCE_GetVisRect() returns a rectangle either in client * DCE_GetVisRect() returns a rectangle either in client
* or in window coordinates (for DCX_WINDOW request). */ * or in window coordinates (for DCX_WINDOW request). */
if( (flags & DCX_CLIPCHILDREN) && wndPtr->child ) if (flags & DCX_CLIPCHILDREN)
{ {
if( flags & DCX_WINDOW ) if( flags & DCX_WINDOW )
{ {
@ -243,7 +251,7 @@ static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
else else
xoffset = yoffset = 0; 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 /* 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 * preference dialogs) gets here, we take the region for the parent window
* but apparently still need to clip the children of the child 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 ) if( flags & DCX_WINDOW )
{ {
@ -268,7 +276,7 @@ static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
xoffset += childWnd->rectClient.left; xoffset += childWnd->rectClient.left;
yoffset += childWnd->rectClient.top; yoffset += childWnd->rectClient.top;
DCE_AddClipRects( childWnd->child->hwndSelf, 0, hrgnClip, DCE_AddClipRects( childWnd->hwndSelf, 0, hrgnClip,
&rect, xoffset, yoffset ); &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 ) if (flags & DCX_CLIPSIBLINGS && wndPtr->parent )
DCE_AddClipRects( GetWindow( wndPtr->hwndSelf, GW_HWNDFIRST ), DCE_AddClipRects( wndPtr->parent, wndPtr->hwndSelf,
wndPtr->hwndSelf, hrgnClip, &rect, xoffset, yoffset ); hrgnClip, &rect, xoffset, yoffset );
/* Clip siblings of all ancestors that have the /* Clip siblings of all ancestors that have the
* WS_CLIPSIBLINGS style * WS_CLIPSIBLINGS style
@ -303,8 +311,8 @@ static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
yoffset -= wndPtr->rectClient.top; yoffset -= wndPtr->rectClient.top;
if(wndPtr->dwStyle & WS_CLIPSIBLINGS && wndPtr->parent) if(wndPtr->dwStyle & WS_CLIPSIBLINGS && wndPtr->parent)
{ {
DCE_AddClipRects( GetWindow( wndPtr->hwndSelf, GW_HWNDFIRST ), DCE_AddClipRects( wndPtr->parent, wndPtr->hwndSelf,
wndPtr->hwndSelf, hrgnClip, &rect, xoffset, yoffset ); 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 /* don't need to change the Zorder of hwnd if it's already inserted
* after hwndInsertAfter or when inserting hwnd after itself. * 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; winpos->flags |= SWP_NOZORDER;
} }
WIN_ReleaseWndPtr(wnd); WIN_ReleaseWndPtr(wnd);
@ -543,7 +552,10 @@ BOOL TTYDRV_SetWindowPos( WINDOWPOS *winpos )
} }
else else
if( winpos->hwndInsertAfter == HWND_BOTTOM ) if( winpos->hwndInsertAfter == HWND_BOTTOM )
winpos->flags |= ( wndPtr->next )? 0: SWP_NOZORDER; {
if (!GetWindow( wndPtr->hwndSelf, GW_HWNDNEXT ))
winpos->flags |= SWP_NOZORDER;
}
else else
if( !(winpos->flags & SWP_NOZORDER) ) if( !(winpos->flags & SWP_NOZORDER) )
if( GetWindow(winpos->hwndInsertAfter, GW_HWNDNEXT) == wndPtr->hwndSelf ) 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; RECT rc, cliprc;
WND* wnd = WIN_FindWndPtr( hwnd ); WND* wnd = WIN_FindWndPtr( hwnd );
if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE )) if (!wnd) return ERROR;
if (!WIN_IsWindowDrawable( wnd, TRUE ))
{ {
retVal = ERROR; WIN_ReleaseWndPtr( wnd );
goto END; return ERROR;
} }
hwnd = wnd->hwndSelf; /* make it a full handle */ hwnd = wnd->hwndSelf; /* make it a full handle */
WIN_ReleaseWndPtr( wnd );
GetClientRect(hwnd, &rc); GetClientRect(hwnd, &rc);
if (rect) IntersectRect(&rc, &rc, rect); if (rect) IntersectRect(&rc, &rc, rect);
@ -203,16 +205,22 @@ INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy,
if( flags & SW_SCROLLCHILDREN ) if( flags & SW_SCROLLCHILDREN )
{ {
RECT r; HWND *list = WIN_ListChildren( hwnd );
WND *w;
for( w =WIN_LockWndPtr(wnd->child); w; WIN_UpdateWndPtr(&w, w->next)) if (list)
{ {
r = w->rectWindow; int i;
if( !rect || IntersectRect(&r, &r, &rc) ) RECT r, dummy;
SetWindowPos(w->hwndSelf, 0, w->rectWindow.left + dx, for (i = 0; list[i]; i++)
w->rectWindow.top + dy, 0,0, SWP_NOZORDER | {
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW | GetWindowRect( list[i], &r );
SWP_DEFERERASE ); 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 ); if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
DeleteObject( hrgnClip ); DeleteObject( hrgnClip );
} }
END:
WIN_ReleaseWndPtr(wnd);
return retVal; 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 /* don't need to change the Zorder of hwnd if it's already inserted
* after hwndInsertAfter or when inserting hwnd after itself. * 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; winpos->flags |= SWP_NOZORDER;
} }
WIN_ReleaseWndPtr(wnd); WIN_ReleaseWndPtr(wnd);
@ -1306,20 +1307,6 @@ void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event )
* *
* Synchronize internal z-order with the window manager's. * 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, static Window __get_common_ancestor( Display *display, Window A, Window B,
Window** children, unsigned* total ) 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) static HWND query_zorder( Display *display, HWND hWndCheck)
{ {
HWND hwndInsertAfter = HWND_TOP; HWND hwndInsertAfter = HWND_TOP;
WND *pWndCheck = WIN_FindWndPtr(hWndCheck);
WND *top = WIN_FindWndPtr( GetTopWindow(0) );
WND *pWnd, *pWndZ = top;
Window w, parent, *children = NULL; Window w, parent, *children = NULL;
unsigned total, check, pos, best; 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); if (!(win = WIN_FindWndPtr( list[i] ))) continue;
WIN_ReleaseWndPtr(top); if ((win->dwExStyle & WS_EX_MANAGED) && (win->dwStyle & WS_VISIBLE))
return hwndInsertAfter; {
if (!hwndA) hwndA = list[i];
else
{
hwndB = list[i];
WIN_ReleaseWndPtr( win );
break;
}
}
WIN_ReleaseWndPtr( win );
} }
WIN_LockWndPtr(pWndZ); if (!hwndA || !hwndB) goto done;
WIN_LockWndPtr(pWnd);
WIN_ReleaseWndPtr(top);
parent = __get_common_ancestor( display, get_whole_window(pWndZ), parent = __get_common_ancestor( display, X11DRV_get_whole_window(hwndA),
get_whole_window(pWnd), &children, &total ); X11DRV_get_whole_window(hwndB), &children, &total );
if( parent && children ) 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 */ 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 ); check = __td_lookup( w, children, total );
best = 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 (list[i] == hWndCheck) continue;
if (!(GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_MANAGED)) continue;
if( pWnd != pWndCheck ) 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) || /* find a nearest Wine window precedes hWndCheck in the real z-order */
!(w = __get_top_decoration( display, get_whole_window(pWnd), parent )) ) best = pos;
continue; hwndInsertAfter = list[i];
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;
} }
if( best - check == 1 ) break;
} }
} }
} }
if( children ) TSXFree( children ); if( children ) TSXFree( children );
WIN_ReleaseWndPtr(pWnd);
WIN_ReleaseWndPtr(pWndZ); done:
WIN_ReleaseWndPtr(pWndCheck); HeapFree( GetProcessHeap(), 0, list );
return hwndInsertAfter; return hwndInsertAfter;
} }

View File

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

View File

@ -231,10 +231,12 @@ HANDLE WINAPI RemovePropW( HWND hwnd, LPCWSTR str )
* *
* Remove all properties of a window. * Remove all properties of a window.
*/ */
void PROPERTY_RemoveWindowProps( WND *pWnd ) void PROPERTY_RemoveWindowProps( HWND hwnd )
{ {
PROPERTY *prop, *next; PROPERTY *prop, *next;
WND *pWnd = WIN_FindWndPtr( hwnd );
if (!pWnd) return;
for (prop = pWnd->pProp; (prop); prop = next) for (prop = pWnd->pProp; (prop); prop = next)
{ {
next = prop->next; next = prop->next;
@ -242,6 +244,7 @@ void PROPERTY_RemoveWindowProps( WND *pWnd )
HeapFree( GetProcessHeap(), 0, prop ); HeapFree( GetProcessHeap(), 0, prop );
} }
pWnd->pProp = NULL; 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 ) void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
{ {
WND *wndPtr, **ppWnd, *parentPtr = NULL;
BOOL ret; BOOL ret;
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return;
if (parent && !(parentPtr = WIN_FindWndPtr( parent )))
{
WIN_ReleaseWndPtr(wndPtr);
return;
}
SERVER_START_REQ( link_window ) SERVER_START_REQ( link_window )
{ {
req->handle = hwnd; req->handle = hwnd;
@ -401,42 +393,88 @@ void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
ret = !SERVER_CALL_ERR(); ret = !SERVER_CALL_ERR();
} }
SERVER_END_REQ; SERVER_END_REQ;
if (!ret) goto done; if (ret && parent)
/* first unlink it if it is linked */
if (wndPtr->parent)
{ {
WND *ptr = WIN_FindWndPtr( wndPtr->parent ); WND *wndPtr = WIN_FindWndPtr( hwnd );
ppWnd = &ptr->child; if (wndPtr)
while (*ppWnd && *ppWnd != wndPtr) ppWnd = &(*ppWnd)->next; {
if (*ppWnd) *ppWnd = wndPtr->next; wndPtr->parent = WIN_GetFullHandle(parent);
WIN_ReleaseWndPtr( ptr ); 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; WND *win = WIN_GetWndPtr( list[i] );
if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM)) if (win == BAD_WND_PTR) continue; /* ignore it */
if (!win)
{ {
ppWnd = &parentPtr->child; /* Point to first sibling hwnd */ /* doesn't belong to this process, but check children */
if (hwndInsertAfter == HWND_BOTTOM) /* Find last sibling hwnd */ ret = find_child_to_repaint( list[i] );
while (*ppWnd) ppWnd = &(*ppWnd)->next; continue;
} }
else /* Normal case */ if (!(win->dwStyle & WS_VISIBLE))
{ {
WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter ); USER_Unlock();
if (!afterPtr) goto done; continue;
ppWnd = &afterPtr->next; }
WIN_ReleaseWndPtr(afterPtr); 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: /* now we have something */
WIN_ReleaseWndPtr( parentPtr ); ret = list[i];
WIN_ReleaseWndPtr( wndPtr ); 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 WIN_FindWinToRepaint( HWND hwnd )
{ {
HWND hwndRet;
WND *pWnd;
/* Note: the desktop window never gets WM_PAINT messages /* Note: the desktop window never gets WM_PAINT messages
* The real reason why is because Windows DesktopWndProc * The real reason why is because Windows DesktopWndProc
* does ValidateRgn inside WM_ERASEBKGND handler. * does ValidateRgn inside WM_ERASEBKGND handler.
*/ */
if (hwnd == GetDesktopWindow()) hwnd = 0; if (hwnd == GetDesktopWindow()) hwnd = 0;
pWnd = hwnd ? WIN_FindWndPtr(hwnd) : WIN_LockWndPtr(pWndDesktop->child); if (hwnd)
for ( ; pWnd ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
{ {
if (!(pWnd->dwStyle & WS_VISIBLE)) continue; /* check the window itself first */
if ((pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)) && WND *win = WIN_FindWndPtr( hwnd );
WIN_IsCurrentThread( pWnd->hwndSelf )) if (!win) return 0;
break; if ((win->dwStyle & WS_VISIBLE) &&
if (pWnd->child ) (win->hrgnUpdate || (win->flags & WIN_INTERNAL_PAINT)))
{ {
if ((hwndRet = WIN_FindWinToRepaint( pWnd->child->hwndSelf )) ) WIN_ReleaseWndPtr( win );
{ return hwnd;
WIN_ReleaseWndPtr(pWnd);
return hwndRet;
}
} }
WIN_ReleaseWndPtr( win );
} }
/* now check its children */
if(!pWnd) return find_child_to_repaint( hwnd );
{
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;
} }
@ -503,34 +513,33 @@ HWND WIN_FindWinToRepaint( HWND hwnd )
* WIN_DestroyWindow * WIN_DestroyWindow
* *
* Destroy storage associated to a window. "Internals" p.358 * 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 *wndPtr;
WND *pWnd; HWND *list;
TRACE("%04x\n", wndPtr->hwndSelf ); TRACE("%04x\n", hwnd );
/* free child windows */ /* free child windows */
WIN_LockWndPtr(wndPtr->child); if ((list = WIN_ListChildren( hwnd )))
while ((pWnd = wndPtr->child))
{ {
wndPtr->child = WIN_DestroyWindow( pWnd ); int i;
WIN_ReleaseWndPtr(pWnd); 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 * Clear the update region to make sure no WM_PAINT messages will be
* generated for this window while processing the WM_NCDESTROY. * 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); RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
/* /*
* Send the WM_NCDESTROY to the window being destroyed. * 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? */ /* 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 */ /* free resources associated with the window */
TIMER_RemoveWindowTimers( wndPtr->hwndSelf ); TIMER_RemoveWindowTimers( hwnd );
PROPERTY_RemoveWindowProps( wndPtr ); PROPERTY_RemoveWindowProps( hwnd );
/* toss stale messages from the queue */ if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return;
QUEUE_CleanupWindow( hwnd );
wndPtr->hmemTaskQ = 0; wndPtr->hmemTaskQ = 0;
if (!(wndPtr->dwStyle & WS_CHILD)) if (!(wndPtr->dwStyle & WS_CHILD))
@ -558,16 +565,13 @@ static WND* WIN_DestroyWindow( WND* wndPtr )
DestroyMenu( wndPtr->hSysMenu ); DestroyMenu( wndPtr->hSysMenu );
wndPtr->hSysMenu = 0; wndPtr->hSysMenu = 0;
} }
USER_Driver.pDestroyWindow( wndPtr->hwndSelf ); USER_Driver.pDestroyWindow( hwnd );
DCE_FreeWindowDCE( wndPtr->hwndSelf ); /* Always do this to catch orphaned DCs */ DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW ); WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
CLASS_RemoveWindow( wndPtr->class ); CLASS_RemoveWindow( wndPtr->class );
wndPtr->class = NULL; wndPtr->class = NULL;
wndPtr->dwMagic = 0; /* Mark it as invalid */ wndPtr->dwMagic = 0; /* Mark it as invalid */
WIN_ReleaseWndPtr( wndPtr );
WIN_UpdateWndPtr(&pWnd,wndPtr->next);
return pWnd;
} }
/*********************************************************************** /***********************************************************************
@ -622,8 +626,6 @@ BOOL WIN_CreateDesktopWindow(void)
hwndDesktop = pWndDesktop->hwndSelf; hwndDesktop = pWndDesktop->hwndSelf;
pWndDesktop->tid = 0; /* nobody owns the desktop */ pWndDesktop->tid = 0; /* nobody owns the desktop */
pWndDesktop->next = NULL;
pWndDesktop->child = NULL;
pWndDesktop->parent = 0; pWndDesktop->parent = 0;
pWndDesktop->owner = 0; pWndDesktop->owner = 0;
pWndDesktop->class = class; pWndDesktop->class = class;
@ -838,10 +840,8 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
/* Fill the window structure */ /* Fill the window structure */
wndPtr->tid = GetCurrentThreadId(); wndPtr->tid = GetCurrentThreadId();
wndPtr->next = NULL; wndPtr->owner = owner;
wndPtr->child = NULL;
wndPtr->owner = owner;
wndPtr->parent = parent; wndPtr->parent = parent;
wndPtr->class = classPtr; wndPtr->class = classPtr;
wndPtr->winproc = winproc; wndPtr->winproc = winproc;
@ -960,12 +960,12 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
} }
else wndPtr->wIDmenu = (UINT)cs->hMenu; 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"); WARN("aborted by WM_xxCREATE!\n");
WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr )); WIN_ReleaseWndPtr( wndPtr );
WIN_DestroyWindow( hwnd );
CLASS_RemoveWindow( classPtr ); CLASS_RemoveWindow( classPtr );
WIN_ReleaseWndPtr(wndPtr);
return 0; return 0;
} }
@ -1352,7 +1352,7 @@ BOOL WINAPI DestroyWindow( HWND hwnd )
/* Destroy the window storage */ /* Destroy the window storage */
WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr )); WIN_DestroyWindow( hwnd );
retvalue = TRUE; retvalue = TRUE;
end: end:
WIN_ReleaseWndPtr(wndPtr); 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 * WINPOS_WindowFromPoint
* *
@ -289,9 +373,9 @@ BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
*/ */
HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest ) HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
{ {
WND *wndScope, *wndPtr, *wndTmp; WND *wndScope;
HWND hwnd_ret = 0;
POINT xy = pt; POINT xy = pt;
int res;
TRACE("scope %04x %ld,%ld\n", hwndScope, pt.x, pt.y); 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 */ hwndScope = wndScope->hwndSelf; /* make it a full handle */
*hittest = HTERROR; *hittest = HTERROR;
wndPtr = WIN_LockWndPtr(wndScope->child);
if( wndScope->dwStyle & WS_DISABLED ) if( wndScope->dwStyle & WS_DISABLED )
{ {
*hittest = HTERROR; WIN_ReleaseWndPtr(wndScope);
goto end; return 0;
} }
if (wndScope->parent) if (wndScope->parent)
MapWindowPoints( GetDesktopWindow(), wndScope->parent, &xy, 1 ); MapWindowPoints( GetDesktopWindow(), wndScope->parent, &xy, 1 );
if (xy.x < wndScope->rectClient.left || pt.x >= wndScope->rectClient.right || if (!(wndScope->dwStyle & WS_MINIMIZE) && PtInRect( &wndScope->rectClient, xy ))
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 (;;)
{ {
while (wndPtr) HWND ret;
{
/* 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) && xy.x -= wndScope->rectClient.left;
((wndPtr->dwExStyle & (WS_EX_LAYERED | WS_EX_TRANSPARENT)) != (WS_EX_LAYERED | WS_EX_TRANSPARENT)) && xy.y -= wndScope->rectClient.top;
(!(wndPtr->dwStyle & WS_DISABLED) || WIN_ReleaseWndPtr( wndScope );
((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)) && if ((ret = find_child_from_point( hwndScope, xy, hittest, MAKELONG( pt.x, pt.y ) )))
(wndPtr->hrgnWnd ? return ret;
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 );
} }
else WIN_ReleaseWndPtr( wndScope );
end: /* If nothing found, try the scope window */
WIN_ReleaseWndPtr(wndPtr); if (!WIN_IsCurrentThread( hwndScope ))
WIN_ReleaseWndPtr(wndScope); {
return hwnd_ret; *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;
} }