Implemented GetAncestor and removed WIN_GetTopParent.
Removed a few more accesses to the WND structure.
diff --git a/windows/win.c b/windows/win.c
index e070ab8..544dddc 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -406,7 +406,7 @@
wndPtr->hSysMenu = 0;
}
USER_Driver.pDestroyWindow( wndPtr->hwndSelf );
- DCE_FreeWindowDCE( wndPtr ); /* Always do this to catch orphaned DCs */
+ DCE_FreeWindowDCE( wndPtr->hwndSelf ); /* Always do this to catch orphaned DCs */
WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
CLASS_RemoveWindow( wndPtr->class );
wndPtr->class = NULL;
@@ -423,34 +423,21 @@
* Destroy all children of 'wnd' owned by the current thread.
* Return TRUE if something was done.
*/
-BOOL WIN_DestroyThreadWindows( HWND hwnd )
+void WIN_DestroyThreadWindows( HWND hwnd )
{
- BOOL ret = FALSE;
- WND *wnd = WIN_FindWndPtr( hwnd );
+ HWND *list;
+ int i;
- if (!wnd) return FALSE;
- while (wnd->child)
+ if (!(list = WIN_BuildWinArray( hwnd ))) return;
+ for (i = 0; list[i]; i++)
{
- WND *tmp = WIN_LockWndPtr(wnd->child);
- ret = FALSE;
- while (tmp)
- {
- if (GetWindowThreadProcessId( tmp->hwndSelf, NULL ) == GetCurrentThreadId())
- {
- DestroyWindow( tmp->hwndSelf );
- ret = TRUE;
- break;
- }
- if (tmp->child && WIN_DestroyThreadWindows( tmp->hwndSelf ))
- ret = TRUE;
- else
- WIN_UpdateWndPtr(&tmp,tmp->next);
- }
- WIN_ReleaseWndPtr(tmp);
- if (!ret) break;
+ if (!IsWindow( list[i] )) continue;
+ if (GetWindowThreadProcessId( list[i], NULL ) == GetCurrentThreadId())
+ DestroyWindow( list[i] );
+ else
+ WIN_DestroyThreadWindows( list[i] );
}
- WIN_ReleaseWndPtr( wnd );
- return ret;
+ WIN_ReleaseWinArray( list );
}
/***********************************************************************
@@ -698,10 +685,8 @@
wndPtr->owner = NULL;
else
{
- WND *tmpWnd = WIN_FindWndPtr(cs->hwndParent);
- wndPtr->owner = WIN_GetTopParentPtr(tmpWnd);
+ wndPtr->owner = WIN_FindWndPtr( GetAncestor( cs->hwndParent, GA_ROOT ));
WIN_ReleaseWndPtr(wndPtr->owner);
- WIN_ReleaseWndPtr(tmpWnd);
}
}
@@ -1053,92 +1038,40 @@
return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
}
+
/***********************************************************************
* WIN_SendDestroyMsg
*/
-static void WIN_SendDestroyMsg( WND* pWnd )
+static void WIN_SendDestroyMsg( HWND hwnd )
{
- if( CARET_GetHwnd() == pWnd->hwndSelf ) DestroyCaret();
+ if( CARET_GetHwnd() == hwnd) DestroyCaret();
if (USER_Driver.pResetSelectionOwner)
- USER_Driver.pResetSelectionOwner( pWnd->hwndSelf, TRUE );
+ USER_Driver.pResetSelectionOwner( hwnd, TRUE );
/*
* Send the WM_DESTROY to the window.
*/
- SendMessageA( pWnd->hwndSelf, WM_DESTROY, 0, 0);
+ SendMessageA( hwnd, WM_DESTROY, 0, 0);
/*
* This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
* make sure that the window still exists when we come back.
*/
- if (IsWindow(pWnd->hwndSelf))
+ if (IsWindow(hwnd))
{
- HWND* pWndArray = NULL;
- WND* pChild = NULL;
- int nKidCount = 0;
+ HWND* pWndArray;
+ int i;
- /*
- * Now, if the window has kids, we have to send WM_DESTROY messages
- * recursively to it's kids. It seems that those calls can also
- * trigger re-entrant calls to DestroyWindow for the kids so we must
- * protect against corruption of the list of siblings. We first build
- * a list of HWNDs representing all the kids.
- */
- pChild = WIN_LockWndPtr(pWnd->child);
- while( pChild )
- {
- nKidCount++;
- WIN_UpdateWndPtr(&pChild,pChild->next);
- }
+ if (!(pWndArray = WIN_BuildWinArray( hwnd ))) return;
- /*
- * If there are no kids, we're done.
- */
- if (nKidCount==0)
- return;
+ /* start from the end (FIXME: is this needed?) */
+ for (i = 0; pWndArray[i]; i++) ;
- pWndArray = HeapAlloc(GetProcessHeap(), 0, nKidCount*sizeof(HWND));
-
- /*
- * Sanity check
- */
- if (pWndArray==NULL)
- return;
-
- /*
- * Now, enumerate all the kids in a list, since we wait to make the SendMessage
- * call, our linked list of siblings should be safe.
- */
- nKidCount = 0;
- pChild = WIN_LockWndPtr(pWnd->child);
- while( pChild )
- {
- pWndArray[nKidCount] = pChild->hwndSelf;
- nKidCount++;
- WIN_UpdateWndPtr(&pChild,pChild->next);
- }
-
- /*
- * Now that we have a list, go through that list again and send the destroy
- * message to those windows. We are using the HWND to retrieve the
- * WND pointer so we are effectively checking that all the kid windows are
- * still valid before sending the message.
- */
- while (nKidCount>0)
- {
- pChild = WIN_FindWndPtr(pWndArray[--nKidCount]);
-
- if (pChild!=NULL)
- {
- WIN_SendDestroyMsg( pChild );
- WIN_ReleaseWndPtr(pChild);
- }
- }
-
- /*
- * Cleanup
- */
- HeapFree(GetProcessHeap(), 0, pWndArray);
+ while (--i >= 0)
+ {
+ if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
+ }
+ WIN_ReleaseWinArray( pWndArray );
}
else
WARN("\tdestroyed itself while in WM_DESTROY!\n");
@@ -1162,46 +1095,29 @@
WND * wndPtr;
BOOL retvalue;
HWND h;
- BOOL bFocusSet = FALSE;
TRACE("(%04x)\n", hwnd);
/* Initialization */
if (hwnd == GetDesktopWindow()) return FALSE; /* Can't destroy desktop */
- if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
/* Look whether the focus is within the tree of windows we will
* be destroying.
*/
- h = GetFocus16();
- while (h && (GetWindowLongA(h,GWL_STYLE) & WS_CHILD))
+ h = GetFocus();
+ if (h == hwnd || IsChild( hwnd, h ))
{
- if (h == hwnd)
- {
- SetFocus(GetParent(h));
- bFocusSet = TRUE;
- break;
- }
- h = GetParent(h);
- }
- /* If the focus is on the window we will destroy and it has no parent,
- * set the focus to 0.
- */
- if (! bFocusSet && (h == hwnd))
- {
- if (!(GetWindowLongA(h,GWL_STYLE) & WS_CHILD))
- SetFocus(0);
+ HWND parent = GetAncestor( hwnd, GA_PARENT );
+ if (parent == GetDesktopWindow()) parent = 0;
+ SetFocus( parent );
}
/* Call hooks */
- if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, hwnd, 0L) )
- {
- retvalue = FALSE;
- goto end;
- }
+ if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, hwnd, 0L) ) return FALSE;
+ if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
{
HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L );
@@ -1271,7 +1187,7 @@
/* Send destroy messages */
- WIN_SendDestroyMsg( wndPtr );
+ WIN_SendDestroyMsg( hwnd );
if (!IsWindow(hwnd))
{
retvalue = TRUE;
@@ -1348,70 +1264,50 @@
*
* Implementation of FindWindow() and FindWindowEx().
*/
-static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className,
- LPCWSTR title )
+static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
{
- WND *pWnd;
+ HWND *list;
HWND retvalue;
+ int i = 0, len = 0;
+ WCHAR *buffer = NULL;
+
+ if (!parent) parent = GetDesktopWindow();
+ if (title)
+ {
+ len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
+ if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
+ }
+
+ if (!(list = WIN_BuildWinArray( parent )))
+ {
+ if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
+ return 0;
+ }
if (child)
{
- if (!(pWnd = WIN_FindWndPtr( child ))) return 0;
- if (parent)
- {
- if (!pWnd->parent || (pWnd->parent->hwndSelf != parent))
- {
- retvalue = 0;
- goto end;
- }
- }
- else if (pWnd->parent != pWndDesktop)
- {
- retvalue = 0;
- goto end;
- }
- WIN_UpdateWndPtr(&pWnd,pWnd->next);
- }
- else
- {
- if (!(pWnd = parent ? WIN_FindWndPtr(parent) : WIN_LockWndPtr(pWndDesktop)))
- {
- retvalue = 0;
- goto end;
- }
- WIN_UpdateWndPtr(&pWnd,pWnd->child);
- }
- if (!pWnd)
- {
- retvalue = 0;
- goto end;
+ while (list[i] && list[i] != child) i++;
+ if (!list[i]) return 0;
+ i++; /* start from next window */
}
- for ( ; pWnd ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
+ for ( ; list[i]; i++)
{
- if (className && (GetClassWord(pWnd->hwndSelf, GCW_ATOM) != className))
+ if (className && (GetClassWord(list[i], GCW_ATOM) != className))
continue; /* Not the right class */
/* Now check the title */
-
- if (!title)
- {
- retvalue = pWnd->hwndSelf;
- goto end;
- }
- if (pWnd->text && !strcmpW( pWnd->text, title ))
- {
- retvalue = pWnd->hwndSelf;
- goto end;
- }
+ if (!title) break;
+ if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
}
- retvalue = 0;
+ retvalue = list[i];
+ WIN_ReleaseWinArray( 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 */
- FIXME("Returning 0 without checking other processes\n");
-end:
- WIN_ReleaseWndPtr(pWnd);
+ if (!retvalue) FIXME("Returning 0 without checking other processes\n");
return retvalue;
}
@@ -2165,38 +2061,38 @@
}
-/*****************************************************************
- * WIN_GetTopParent
- *
- * Get the top-level parent for a child window.
- * returns a locked pointer
- */
-WND* WIN_GetTopParentPtr( WND* pWnd )
-{
- WND *tmpWnd = WIN_LockWndPtr(pWnd);
-
- while( tmpWnd && (tmpWnd->dwStyle & WS_CHILD))
- {
- WIN_UpdateWndPtr(&tmpWnd,tmpWnd->parent);
- }
- return tmpWnd;
-}
/*****************************************************************
- * WIN_GetTopParent
- *
- * Get the top-level parent for a child window.
+ * GetAncestor (USER32.@)
*/
-HWND WIN_GetTopParent( HWND hwnd )
+HWND WINAPI GetAncestor( HWND hwnd, UINT type )
{
- HWND retvalue;
- WND *tmpPtr = WIN_FindWndPtr(hwnd);
- WND *wndPtr = WIN_GetTopParentPtr (tmpPtr );
-
- retvalue = wndPtr ? wndPtr->hwndSelf : 0;
- WIN_ReleaseWndPtr(tmpPtr);
- WIN_ReleaseWndPtr(wndPtr);
- return retvalue;
+ HWND ret;
+ WND *wndPtr, *parent;
+
+ if (hwnd == GetDesktopWindow()) return 0;
+ if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
+ parent = wndPtr->parent;
+
+ switch(type)
+ {
+ case GA_PARENT:
+ WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
+ break;
+ case GA_ROOT:
+ while (wndPtr->parent->hwndSelf != GetDesktopWindow())
+ WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
+ break;
+ case GA_ROOTOWNER:
+ while (wndPtr->parent->hwndSelf != GetDesktopWindow())
+ WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
+ while (wndPtr->owner)
+ WIN_UpdateWndPtr( &wndPtr, wndPtr->owner );
+ break;
+ }
+ ret = wndPtr->hwndSelf;
+ WIN_ReleaseWndPtr( wndPtr );
+ return ret;
}
@@ -2481,6 +2377,7 @@
BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
{
int count = 0;
+ WND *pWnd;
HWND *win_array = WIN_BuildWinArray( GetDesktopWindow() );
if (!win_array) return TRUE;
@@ -2491,10 +2388,10 @@
while (win_array[count]) count++;
while (--count >= 0)
{
- WND *pWnd = WIN_FindWndPtr( win_array[count] );
- if (!pWnd) continue;
+ if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
+ if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
- if (pWnd->owner && (pWnd->owner->hwndSelf == owner) && (pWnd->dwStyle & WS_POPUP))
+ if (pWnd->dwStyle & WS_POPUP)
{
if (fShow)
{
@@ -2545,7 +2442,7 @@
BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
{
int count = 0;
-
+ WND *pWnd;
HWND *win_array = WIN_BuildWinArray(GetDesktopWindow());
if (!win_array) return TRUE;
@@ -2553,10 +2450,10 @@
while (win_array[count]) count++;
while (--count >= 0)
{
- WND *pWnd = WIN_FindWndPtr( win_array[count] );
- if (!pWnd) continue;
+ if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
+ if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
- if (pWnd->owner && (pWnd->owner->hwndSelf == owner) && (pWnd->dwStyle & WS_POPUP))
+ if (pWnd->dwStyle & WS_POPUP)
{
if (fShow)
{
@@ -2797,21 +2694,17 @@
*/
BOOL WINAPI AnyPopup(void)
{
- WND *wndPtr = WIN_LockWndPtr(pWndDesktop->child);
+ int i;
BOOL retvalue;
-
- while (wndPtr)
+ HWND *list = WIN_BuildWinArray( GetDesktopWindow() );
+
+ if (!list) return FALSE;
+ for (i = 0; list[i]; i++)
{
- if (wndPtr->owner && (wndPtr->dwStyle & WS_VISIBLE))
- {
- retvalue = TRUE;
- goto end;
- }
- WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
+ if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
}
- retvalue = FALSE;
-end:
- WIN_ReleaseWndPtr(wndPtr);
+ retvalue = (list[i] != 0);
+ WIN_ReleaseWinArray( list );
return retvalue;
}