[USER32] Make App Switcher use the owner window's icon (#1299)
[reactos.git] / win32ss / user / user32 / controls / appswitch.c
index c2898b9..ecd48b4 100644 (file)
@@ -165,31 +165,24 @@ void CompleteSwitch(BOOL doSwitch)
 BOOL CALLBACK EnumerateCallback(HWND window, LPARAM lParam)
 {
    HICON hIcon;
+   HWND hwndIcon, hwndOwner;
 
    UNREFERENCED_PARAMETER(lParam);
 
-   if (!IsWindowVisible(window))
-            return TRUE;
-
-   if (GetWindow(window, GW_OWNER) != NULL)
-       return TRUE;
-
-   GetClassNameW(window, windowText, _countof(windowText));
-   if ((wcscmp(L"Shell_TrayWnd", windowText)==0) ||
-       (wcscmp(L"Progman", windowText)==0) )
-            return TRUE;
+   hwndOwner = GetWindow(window, GW_OWNER);
+   hwndIcon = (hwndOwner ? hwndOwner : window);
 
    // First try to get the big icon assigned to the window
-   hIcon = (HICON)SendMessageW(window, WM_GETICON, ICON_BIG, 0);
+   hIcon = (HICON)SendMessageW(hwndIcon, WM_GETICON, ICON_BIG, 0);
    if (!hIcon)
    {
       // If no icon is assigned, try to get the icon assigned to the windows' class
-      hIcon = (HICON)GetClassLongPtrW(window, GCL_HICON);
+      hIcon = (HICON)GetClassLongPtrW(hwndIcon, GCL_HICON);
       if (!hIcon)
       {
          // If we still don't have an icon, see if we can do with the small icon,
          // or a default application icon
-         hIcon = (HICON)SendMessageW(window, WM_GETICON, ICON_SMALL2, 0);
+         hIcon = (HICON)SendMessageW(hwndIcon, WM_GETICON, ICON_SMALL2, 0);
          if (!hIcon)
          {
             // using windows logo icon as default
@@ -216,17 +209,40 @@ BOOL CALLBACK EnumerateCallback(HWND window, LPARAM lParam)
    return TRUE;
 }
 
-// Function mostly compatible with the normal EnumWindows,
+// 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 EnumWindowsZOrder(WNDENUMPROC callback, LPARAM lParam)
 {
-    HWND next = GetTopWindow(NULL);
-    while (next != NULL)
+    HWND hwnd, hwndOwner;
+    WCHAR szClass[64];
+    DWORD ExStyle;
+
+    for (hwnd = GetTopWindow(NULL); hwnd; hwnd = GetWindow(hwnd, GW_HWNDNEXT))
     {
-        if(!callback(next, lParam))
-         break;
-        next = GetWindow(next, GW_HWNDNEXT);
+        if (!IsWindowVisible(hwnd))
+            continue;
+
+        // check special windows
+        if (!GetClassNameW(hwnd, szClass, _countof(szClass)) ||
+            wcscmp(szClass, L"Shell_TrayWnd") == 0 ||
+            wcscmp(szClass, L"Progman") == 0)
+        {
+            continue;
+        }
+
+        ExStyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
+        if (ExStyle & WS_EX_TOOLWINDOW)
+            continue;
+
+        hwndOwner = GetWindow(hwnd, GW_OWNER);
+        if ((ExStyle & WS_EX_APPWINDOW) || !IsWindowVisible(hwndOwner))
+        {
+            if (!callback(hwnd, lParam))
+                break;
+
+            continue;
+        }
     }
 }
 
@@ -415,9 +431,16 @@ BOOL ProcessHotKey(VOID)
       windowCount=0;
       EnumWindowsZOrder(EnumerateCallback, 0);
 
-      if (windowCount < 2)
+      if (windowCount == 0)
          return FALSE;
 
+      if (windowCount == 1)
+      {
+         selectedWindow = 0;
+         CompleteSwitch(TRUE);
+         return TRUE;
+      }
+
       selectedWindow = 1;
 
       TRACE("[ATbot] HotKey Received. Opening window.\n");
@@ -471,6 +494,50 @@ void RotateTasks(BOOL bShift)
     }
 }
 
+static void MoveLeft(void)
+{
+    selectedWindow = selectedWindow - 1;
+    if (selectedWindow < 0)
+        selectedWindow = windowCount - 1;
+    InvalidateRect(switchdialog, NULL, TRUE);
+}
+
+static void MoveRight(void)
+{
+    selectedWindow = (selectedWindow + 1) % windowCount;
+    InvalidateRect(switchdialog, NULL, TRUE);
+}
+
+static void MoveUp(void)
+{
+    INT iRow = selectedWindow / nCols;
+    INT iCol = selectedWindow % nCols;
+
+    --iRow;
+    if (iRow < 0)
+        iRow = nRows - 1;
+
+    selectedWindow = iRow * nCols + iCol;
+    if (selectedWindow >= windowCount)
+        selectedWindow = windowCount - 1;
+    InvalidateRect(switchdialog, NULL, TRUE);
+}
+
+static void MoveDown(void)
+{
+    INT iRow = selectedWindow / nCols;
+    INT iCol = selectedWindow % nCols;
+
+    ++iRow;
+    if (iRow >= nRows)
+        iRow = 0;
+
+    selectedWindow = iRow * nCols + iCol;
+    if (selectedWindow >= windowCount)
+        selectedWindow = windowCount - 1;
+    InvalidateRect(switchdialog, NULL, TRUE);
+}
+
 VOID
 DestroyAppWindows(VOID)
 {
@@ -586,21 +653,34 @@ LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam )
                 if (Esc) break;
                 if (GetKeyState(VK_SHIFT) < 0)
                 {
-                   selectedWindow = selectedWindow - 1;
-                   if (selectedWindow < 0)
-                      selectedWindow = windowCount - 1;
+                    MoveLeft();
                 }
                 else
                 {
-                   selectedWindow = (selectedWindow + 1)%windowCount;
+                    MoveRight();
                 }
-                InvalidateRect(switchdialog, NULL, TRUE);
              }
              else if ( msg.wParam == VK_ESCAPE )
              {
                 if (!Esc) break;
                 RotateTasks(GetKeyState(VK_SHIFT) < 0);
              }
+             else if ( msg.wParam == VK_LEFT )
+             {
+                MoveLeft();
+             }
+             else if ( msg.wParam == VK_RIGHT )
+             {
+                MoveRight();
+             }
+             else if ( msg.wParam == VK_UP )
+             {
+                MoveUp();
+             }
+             else if ( msg.wParam == VK_DOWN )
+             {
+                MoveDown();
+             }
           }
           break;
         }