Reimplemented Get/SetActiveWindow, Get/SetFocus and
Get/SetForegroundWindow by storing the information in the
server. Implemented correct inter-process window activation.
diff --git a/windows/winpos.c b/windows/winpos.c
index f27fdea..cc26357 100644
--- a/windows/winpos.c
+++ b/windows/winpos.c
@@ -69,14 +69,12 @@
/* ----- internal variables ----- */
-static HWND hwndPrevActive = 0; /* Previously active window */
static HWND hGlobalShellWindow=0; /*the shell*/
static HWND hGlobalTaskmanWindow=0;
static HWND hGlobalProgmanWindow=0;
static LPCSTR atomInternalPos;
-extern HQUEUE16 hActiveQueue;
/***********************************************************************
* WINPOS_CreateInternalPosAtom
@@ -95,30 +93,7 @@
*/
void WINPOS_CheckInternalPos( HWND hwnd )
{
- LPINTERNALPOS lpPos;
- MESSAGEQUEUE *pMsgQ = 0;
- WND *wndPtr = WIN_GetPtr( hwnd );
-
- if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
-
- lpPos = (LPINTERNALPOS) GetPropA( hwnd, atomInternalPos );
-
- /* Retrieve the message queue associated with this window */
- pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
- if ( !pMsgQ )
- {
- WARN("\tMessage queue not found. Exiting!\n" );
- WIN_ReleasePtr( wndPtr );
- return;
- }
-
- if( hwnd == hwndPrevActive ) hwndPrevActive = 0;
-
- if( hwnd == PERQDATA_GetActiveWnd( pMsgQ->pQData ) )
- {
- PERQDATA_SetActiveWnd( pMsgQ->pQData, 0 );
- WARN("\tattempt to activate destroyed window!\n");
- }
+ LPINTERNALPOS lpPos = (LPINTERNALPOS) GetPropA( hwnd, atomInternalPos );
if( lpPos )
{
@@ -126,9 +101,6 @@
DestroyWindow( lpPos->hwndIconTitle );
HeapFree( GetProcessHeap(), 0, lpPos );
}
-
- QUEUE_Unlock( pMsgQ );
- WIN_ReleasePtr( wndPtr );
}
/***********************************************************************
@@ -641,132 +613,6 @@
/*******************************************************************
- * GetActiveWindow (USER32.@)
- */
-HWND WINAPI GetActiveWindow(void)
-{
- MESSAGEQUEUE *pCurMsgQ = 0;
-
- /* Get the messageQ for the current thread */
- if (!(pCurMsgQ = QUEUE_Current()))
-{
- WARN("\tCurrent message queue not found. Exiting!\n" );
- return 0;
- }
-
- /* Return the current active window from the perQ data of the current message Q */
- return PERQDATA_GetActiveWnd( pCurMsgQ->pQData );
-}
-
-
-/*******************************************************************
- * WINPOS_CanActivate
- */
-static BOOL WINPOS_CanActivate(HWND hwnd)
-{
- if (!hwnd) return FALSE;
- return ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_DISABLED|WS_CHILD)) == 0);
-}
-
-/*******************************************************************
- * WINPOS_IsVisible
- */
-static BOOL WINPOS_IsVisible(HWND hwnd)
-{
- if (!hwnd) return FALSE;
- return ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE) == WS_VISIBLE);
-}
-
-
-/*******************************************************************
- * SetActiveWindow (USER32.@)
- */
-HWND WINAPI SetActiveWindow( HWND hwnd )
-{
- HWND prev = 0;
- WND *wndPtr = WIN_FindWndPtr( hwnd );
- MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
-
- if (!wndPtr) return 0;
-
- if (wndPtr->dwStyle & (WS_DISABLED | WS_CHILD)) goto error;
-
- /* Get the messageQ for the current thread */
- if (!(pCurMsgQ = QUEUE_Current()))
- {
- WARN("\tCurrent message queue not found. Exiting!\n" );
- goto error;
- }
-
- /* Retrieve the message queue associated with this window */
- pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
- if ( !pMsgQ )
- {
- WARN("\tWindow message queue not found. Exiting!\n" );
- goto error;
- }
-
- /* Make sure that the window is associated with the calling threads
- * message queue. It must share the same perQ data.
- */
- if ( pCurMsgQ->pQData != pMsgQ->pQData )
- {
- QUEUE_Unlock( pMsgQ );
- goto error;
- }
-
- /* Save current active window */
- prev = PERQDATA_GetActiveWnd( pMsgQ->pQData );
- QUEUE_Unlock( pMsgQ );
- WIN_ReleaseWndPtr(wndPtr);
- WINPOS_SetActiveWindow( hwnd, FALSE, TRUE );
- return prev;
-
- error:
- WIN_ReleaseWndPtr(wndPtr);
- return 0;
-}
-
-
-/*******************************************************************
- * GetForegroundWindow (USER32.@)
- */
-HWND WINAPI GetForegroundWindow(void)
-{
- HWND hwndActive = 0;
-
- /* Get the foreground window (active window of hActiveQueue) */
- if ( hActiveQueue )
- {
- MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
- if ( pActiveQueue )
- hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
-
- QUEUE_Unlock( pActiveQueue );
- }
-
- return hwndActive;
-}
-
-/*******************************************************************
- * SetForegroundWindow (USER32.@)
- */
-BOOL WINAPI SetForegroundWindow( HWND hwnd )
-{
- if (!hwnd) return WINPOS_SetActiveWindow( 0, FALSE, TRUE );
-
- /* child windows get WM_CHILDACTIVATE message */
- if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
- return SendMessageA( hwnd, WM_CHILDACTIVATE, 0, 0 );
-
- hwnd = WIN_GetFullHandle( hwnd );
- if( hwnd == GetForegroundWindow() ) return FALSE;
-
- return WINPOS_SetActiveWindow( hwnd, FALSE, TRUE );
-}
-
-
-/*******************************************************************
* AllowSetForegroundWindow (USER32.@)
*/
BOOL WINAPI AllowSetForegroundWindow( DWORD procid )
@@ -1191,221 +1037,24 @@
}
}
+
/*******************************************************************
- * WINPOS_SetActiveWindow
+ * can_activate_window
*
- * SetActiveWindow() back-end. This is the only function that
- * can assign active status to a window. It must be called only
- * for the top level windows.
+ * Check if we can activate the specified window.
*/
-BOOL WINPOS_SetActiveWindow( HWND hWnd, BOOL fMouse, BOOL fChangeFocus)
+static BOOL can_activate_window( HWND hwnd )
{
- WND* wndPtr=0, *wndTemp;
- HQUEUE16 hOldActiveQueue, hNewActiveQueue;
- MESSAGEQUEUE *pOldActiveQueue = 0, *pNewActiveQueue = 0;
- WORD wIconized = 0;
- HWND hwndActive = 0;
- BOOL bRet = 0;
+ LONG style;
- TRACE("(%04x, %d, %d)\n", hWnd, fMouse, fChangeFocus );
-
- /* Get current active window from the active queue */
- if ( hActiveQueue )
- {
- pOldActiveQueue = QUEUE_Lock( hActiveQueue );
- if ( pOldActiveQueue )
- hwndActive = PERQDATA_GetActiveWnd( pOldActiveQueue->pQData );
- }
-
- if ((wndPtr = WIN_FindWndPtr(hWnd)))
- hWnd = wndPtr->hwndSelf; /* make it a full handle */
-
- /* paranoid checks */
- if( hWnd == GetDesktopWindow() || (bRet = (hWnd == hwndActive)) )
- goto CLEANUP_END;
-
-/* if (wndPtr && (GetFastQueue16() != wndPtr->hmemTaskQ))
- * return 0;
- */
- hOldActiveQueue = hActiveQueue;
-
- if( (wndTemp = WIN_FindWndPtr(hwndActive)) )
- {
- wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
- WIN_ReleaseWndPtr(wndTemp);
- }
- else
- TRACE("no current active window.\n");
-
- /* call CBT hook chain */
- if (HOOK_IsHooked( WH_CBT ))
- {
- CBTACTIVATESTRUCT cbt;
- cbt.fMouse = fMouse;
- cbt.hWndActive = hwndActive;
- if (HOOK_CallHooksA( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt )) goto CLEANUP_END;
- }
-
- /* set prev active wnd to current active wnd and send notification */
- if ((hwndPrevActive = hwndActive) && IsWindow(hwndPrevActive))
- {
- MESSAGEQUEUE *pTempActiveQueue = 0;
-
- SendNotifyMessageA( hwndPrevActive, WM_NCACTIVATE, FALSE, 0 );
- SendNotifyMessageA( hwndPrevActive, WM_ACTIVATE,
- MAKEWPARAM( WA_INACTIVE, wIconized ),
- (LPARAM)hWnd );
-
- /* check if something happened during message processing
- * (global active queue may have changed)
- */
- pTempActiveQueue = QUEUE_Lock( hActiveQueue );
- if(!pTempActiveQueue)
- goto CLEANUP_END;
-
- hwndActive = PERQDATA_GetActiveWnd( pTempActiveQueue->pQData );
- QUEUE_Unlock( pTempActiveQueue );
- if( hwndPrevActive != hwndActive )
- goto CLEANUP_END;
- }
-
- /* Set new active window in the message queue */
- hwndActive = hWnd;
- if ( wndPtr )
- {
- pNewActiveQueue = QUEUE_Lock( wndPtr->hmemTaskQ );
- if ( pNewActiveQueue )
- PERQDATA_SetActiveWnd( pNewActiveQueue->pQData, hwndActive );
- }
- else /* have to do this or MDI frame activation goes to hell */
- if( pOldActiveQueue )
- PERQDATA_SetActiveWnd( pOldActiveQueue->pQData, 0 );
-
- /* send palette messages */
- if (hWnd && SendMessageW( hWnd, WM_QUERYNEWPALETTE, 0, 0L))
- SendMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hWnd, 0 );
-
- /* if prev wnd is minimized redraw icon title */
- if( IsIconic( hwndPrevActive ) ) WINPOS_RedrawIconTitle(hwndPrevActive);
-
- /* managed windows will get ConfigureNotify event */
- if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && !(wndPtr->dwExStyle & WS_EX_MANAGED))
- {
- /* check Z-order and bring hWnd to the top */
- HWND tmp = GetTopWindow(0);
- while (tmp && !(GetWindowLongA( tmp, GWL_STYLE ) & WS_VISIBLE))
- tmp = GetWindow( tmp, GW_HWNDNEXT );
-
- if( tmp != hWnd )
- SetWindowPos(hWnd, HWND_TOP, 0,0,0,0,
- SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
- if (!IsWindow(hWnd))
- goto CLEANUP;
- }
-
- /* Get a handle to the new active queue */
- hNewActiveQueue = wndPtr ? wndPtr->hmemTaskQ : 0;
-
- /* send WM_ACTIVATEAPP if necessary */
- if (hOldActiveQueue != hNewActiveQueue)
- {
- HWND *list, *phwnd;
- DWORD old_thread = GetWindowThreadProcessId( hwndPrevActive, NULL );
- DWORD new_thread = GetWindowThreadProcessId( hwndActive, NULL );
-
- if ((list = WIN_ListChildren( GetDesktopWindow() )))
- {
- for (phwnd = list; *phwnd; phwnd++)
- {
- if (!IsWindow( *phwnd )) continue;
- if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
- SendNotifyMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
- }
- HeapFree( GetProcessHeap(), 0, list );
- }
-
- hActiveQueue = hNewActiveQueue;
-
- if ((list = WIN_ListChildren( GetDesktopWindow() )))
- {
- for (phwnd = list; *phwnd; phwnd++)
- {
- if (!IsWindow( *phwnd )) continue;
- if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
- SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
- }
- HeapFree( GetProcessHeap(), 0, list );
- }
-
- if (hWnd && !IsWindow(hWnd)) goto CLEANUP;
- }
-
- if (hWnd)
- {
- /* walk up to the first unowned window */
- HWND tmp = GetAncestor( hWnd, GA_ROOTOWNER );
- if ((wndTemp = WIN_FindWndPtr( tmp )))
- {
- /* and set last active owned popup */
- wndTemp->hwndLastActive = hWnd;
-
- wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
- WIN_ReleaseWndPtr(wndTemp);
- }
- SendMessageA( hWnd, WM_NCACTIVATE, TRUE, 0 );
- SendMessageA( hWnd, WM_ACTIVATE,
- MAKEWPARAM( (fMouse) ? WA_CLICKACTIVE : WA_ACTIVE, wIconized),
- (LPARAM)hwndPrevActive );
- if( !IsWindow(hWnd) ) goto CLEANUP;
- }
-
- /* change focus if possible */
- if ( fChangeFocus )
- {
- if ( pNewActiveQueue )
- {
- HWND hOldFocus = PERQDATA_GetFocusWnd( pNewActiveQueue->pQData );
-
- if ( !hOldFocus || GetAncestor( hOldFocus, GA_ROOT ) != hwndActive )
- FOCUS_SwitchFocus( pNewActiveQueue, hOldFocus,
- (wndPtr && (wndPtr->dwStyle & WS_MINIMIZE))?
- 0 : hwndActive );
- }
-
- if ( pOldActiveQueue &&
- ( !pNewActiveQueue ||
- pNewActiveQueue->pQData != pOldActiveQueue->pQData ) )
- {
- HWND hOldFocus = PERQDATA_GetFocusWnd( pOldActiveQueue->pQData );
- if ( hOldFocus )
- FOCUS_SwitchFocus( pOldActiveQueue, hOldFocus, 0 );
- }
- }
-
- if( !hwndPrevActive && wndPtr )
- {
- if (USER_Driver.pForceWindowRaise) USER_Driver.pForceWindowRaise( wndPtr->hwndSelf );
- }
-
- /* if active wnd is minimized redraw icon title */
- if( IsIconic(hwndActive) ) WINPOS_RedrawIconTitle(hwndActive);
-
- bRet = (hWnd == hwndActive); /* Success? */
-
-CLEANUP: /* Unlock the message queues before returning */
-
- if ( pNewActiveQueue )
- QUEUE_Unlock( pNewActiveQueue );
-
-CLEANUP_END:
-
- if ( pOldActiveQueue )
- QUEUE_Unlock( pOldActiveQueue );
-
- WIN_ReleaseWndPtr(wndPtr);
- return bRet;
+ if (!hwnd) return FALSE;
+ style = GetWindowLongW( hwnd, GWL_STYLE );
+ if (!(style & WS_VISIBLE)) return FALSE;
+ if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
+ return !(style & WS_DISABLED);
}
+
/*******************************************************************
* WINPOS_ActivateOtherWindow
*
@@ -1413,54 +1062,29 @@
*/
void WINPOS_ActivateOtherWindow(HWND hwnd)
{
- HWND hwndActive = 0;
- HWND hwndTo = 0;
- HWND hwndDefaultTo = 0;
- HWND owner;
+ HWND hwndTo, fg;
- /* Get current active window from the active queue */
- if ( hActiveQueue )
+ if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) && (hwndTo = GetWindow( hwnd, GW_OWNER )))
{
- MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
- if ( pActiveQueue )
- {
- hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
- QUEUE_Unlock( pActiveQueue );
- }
+ hwndTo = GetAncestor( hwndTo, GA_ROOT );
+ if (can_activate_window( hwndTo )) goto done;
}
- if (!(hwnd = WIN_IsCurrentThread( hwnd ))) return;
-
- if( hwnd == hwndPrevActive )
- hwndPrevActive = 0;
-
- if( hwndActive != hwnd && (hwndActive || USER_IsExitingThread( GetCurrentThreadId() )))
- return;
-
- if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) ||
- !(owner = GetWindow( hwnd, GW_OWNER )) ||
- !WINPOS_CanActivate((hwndTo = GetAncestor( owner, GA_ROOT ))) ||
- !WINPOS_IsVisible(hwndTo))
+ hwndTo = hwnd;
+ for (;;)
{
- HWND tmp = GetAncestor( hwnd, GA_ROOT );
- hwndTo = hwndPrevActive;
-
- while( !WINPOS_CanActivate(hwndTo) || !WINPOS_IsVisible(hwndTo))
- {
- /* by now owned windows should've been taken care of */
- if(!hwndDefaultTo && WINPOS_CanActivate(hwndTo))
- hwndDefaultTo = hwndTo;
- tmp = hwndTo = GetWindow( tmp, GW_HWNDNEXT );
- if( !hwndTo )
- {
- hwndTo = hwndDefaultTo;
- break;
- }
- }
+ if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
+ if (can_activate_window( hwndTo )) break;
}
- SetActiveWindow( hwndTo );
- hwndPrevActive = 0;
+ done:
+ fg = GetForegroundWindow();
+ TRACE("win = %x fg = %x\n", hwndTo, fg);
+ if (!fg || (hwnd == fg))
+ {
+ if (SetForegroundWindow( hwndTo )) return;
+ }
+ if (!SetActiveWindow( hwndTo )) SetActiveWindow(0);
}