BOOL CALLBACK EnumerateCallback(HWND window, LPARAM lParam)
{
HICON hIcon;
- HWND hwndOwner;
UNREFERENCED_PARAMETER(lParam);
- if (!IsWindowVisible(window))
- return TRUE;
-
- hwndOwner = GetWindow(window, GW_OWNER);
- if (hwndOwner && IsWindowVisible(hwndOwner))
- return TRUE;
-
- GetClassNameW(window, windowText, _countof(windowText));
- if ((wcscmp(L"Shell_TrayWnd", windowText)==0) ||
- (wcscmp(L"Progman", windowText)==0) )
- return TRUE;
-
// First try to get the big icon assigned to the window
hIcon = (HICON)SendMessageW(window, WM_GETICON, ICON_BIG, 0);
if (!hIcon)
return TRUE;
}
-// Function mostly compatible with the normal EnumChildWindows,
-// except it lists in Z-Order and it doesn't ensure consistency
-// if a window is removed while enumerating
-void EnumChildWindowsZOrder(HWND hwnd, WNDENUMPROC callback, LPARAM lParam)
+static HWND GetNiceRootOwner(HWND hwnd)
{
- HWND next = GetTopWindow(hwnd);
- while (next != NULL)
+ HWND hwndOwner;
+ DWORD ExStyle, OwnerExStyle;
+
+ for (;;)
{
- if (!hwnd && !IsWindowVisible(next))
- {
- // UPDATE: Seek also the owned windows of the hidden top-level window.
- EnumChildWindowsZOrder(next, callback, lParam);
- }
+ // A window with WS_EX_APPWINDOW is treated as if it has no owner
+ ExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
+ if (ExStyle & WS_EX_APPWINDOW)
+ break;
+
+ // Is the owner visible?
+ // An window with WS_EX_TOOLWINDOW is treated as if it weren't visible
+ hwndOwner = GetWindow(hwnd, GW_OWNER);
+ OwnerExStyle = GetWindowLong(hwndOwner, GWL_EXSTYLE);
+ if (!IsWindowVisible(hwndOwner) || (OwnerExStyle & WS_EX_TOOLWINDOW))
+ break;
+
+ hwnd = hwndOwner;
+ }
+
+ return hwnd;
+}
+
+// c.f. http://blogs.msdn.com/b/oldnewthing/archive/2007/10/08/5351207.aspx
+BOOL IsAltTabWindow(HWND hwnd)
+{
+ DWORD ExStyle;
+ RECT rc;
+ HWND hwndTry, hwndWalk;
+ WCHAR szClass[64];
+
+ // must be visible
+ if (!IsWindowVisible(hwnd))
+ return FALSE;
+
+ // must not be WS_EX_TOOLWINDOW
+ ExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
+ if (ExStyle & WS_EX_TOOLWINDOW)
+ return FALSE;
+
+ // must be not empty rect
+ GetWindowRect(hwnd, &rc);
+ if (IsRectEmpty(&rc))
+ return FALSE;
+
+ // check special windows
+ if (!GetClassNameW(hwnd, szClass, _countof(szClass)) ||
+ wcscmp(szClass, L"Shell_TrayWnd") == 0 ||
+ wcscmp(szClass, L"Progman") == 0)
+ {
+ return TRUE;
+ }
+
+ // get 'nice' root owner
+ hwndWalk = GetNiceRootOwner(hwnd);
+
+ // walk back from hwndWalk toward hwnd
+ for (;;)
+ {
+ hwndTry = GetLastActivePopup(hwndWalk);
+ if (hwndTry == hwndWalk)
+ break;
- if (!callback(next, lParam))
+ ExStyle = GetWindowLong(hwndTry, GWL_EXSTYLE);
+ if (IsWindowVisible(hwndTry) && !(ExStyle & WS_EX_TOOLWINDOW))
break;
- next = GetWindow(next, GW_HWNDNEXT);
+ hwndWalk = hwndTry;
+ }
+
+ return hwnd == hwndTry; // Reached?
+}
+
+static BOOL CALLBACK
+EnumWindowsProc(HWND hwnd, LPARAM lParam)
+{
+ if (IsAltTabWindow(hwnd))
+ {
+ if (!EnumerateCallback(hwnd, lParam))
+ return FALSE;
}
+ return TRUE;
}
void ProcessMouseMessage(UINT message, LPARAM lParam)
{
if (!isOpen)
{
- windowCount=0;
- EnumChildWindowsZOrder(NULL, EnumerateCallback, 0);
+ windowCount = 0;
+ EnumWindows(EnumWindowsProc, 0);
- if (windowCount < 2)
+ if (windowCount == 0)
+ return FALSE;
+
+ if (windowCount == 1)
+ {
+ MakeWindowActive(windowList[0]);
+ return FALSE;
+ }
+
+ if (!CreateSwitcherWindow(User32Instance))
return FALSE;
selectedWindow = 1;
// Already in the loop.
if (switchdialog || Esc) return 0;
- hwndActive = GetActiveWindow();
- // Nothing is active so exit.
- if (!hwndActive) return 0;
-
if (lParam == VK_ESCAPE)
{
Esc = TRUE;
windowCount = 0;
- EnumChildWindowsZOrder(NULL, EnumerateCallback, 0);
+ EnumWindows(EnumWindowsProc, 0);
if (windowCount < 2)
return 0;
}
// Capture current active window.
- SetCapture( hwndActive );
+ hwndActive = GetActiveWindow();
+ if (hwndActive)
+ SetCapture(hwndActive);
switch (lParam)
{
case VK_TAB:
- if( !CreateSwitcherWindow(User32Instance) ) goto Exit;
- if( !GetDialogFont() ) goto Exit;
- if( !ProcessHotKey() ) goto Exit;
+ if (!GetDialogFont() || !ProcessHotKey())
+ goto Exit;
break;
case VK_ESCAPE:
default:
goto Exit;
}
+
+ if (!hwndActive)
+ goto Exit;
+
// Main message loop:
while (1)
{