PTASK_GROUP Group;
INT Index;
INT IconIndex;
+ WINDOWPLACEMENT wndpl;
union
{
TaskItem->hWnd = hWnd;
TaskItem->Index = -1;
TaskItem->Group = AddToTaskGroup(hWnd);
+ TaskItem->wndpl.length = sizeof(TaskItem->wndpl);
+ ::GetWindowPlacement(hWnd, &TaskItem->wndpl);
if (!m_IsDestroying)
{
}
CheckActivateTaskItem(TaskItem);
-
return FALSE;
}
BOOL CALLBACK EnumWindowsProc(IN HWND hWnd)
{
- /* Only show windows that still exist and are visible and none of explorer's
- special windows (such as the desktop or the tray window) */
- if (::IsWindow(hWnd) && ::IsWindowVisible(hWnd) &&
- !m_Tray->IsSpecialHWND(hWnd))
+ if (m_Tray->IsTaskWnd(hWnd))
{
- DWORD exStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
- /* Don't list popup windows and also no tool windows */
- if ((::GetWindow(hWnd, GW_OWNER) == NULL || exStyle & WS_EX_APPWINDOW) &&
- !(exStyle & WS_EX_TOOLWINDOW))
- {
- TRACE("Adding task for %p...\n", hWnd);
- AddTask(hWnd);
- }
-
+ TRACE("Adding task for %p...\n", hWnd);
+ AddTask(hWnd);
}
-
return TRUE;
}
return TRUE;
}
+ VOID SendPulseToTray(BOOL bDelete, HWND hwndActive)
+ {
+ HWND hwndTray = m_Tray->GetHWND();
+ ::SendMessage(hwndTray, TWM_PULSE, bDelete, (LPARAM)hwndActive);
+ }
+
BOOL HandleAppCommand(IN WPARAM wParam, IN LPARAM lParam)
{
BOOL Ret = FALSE;
break;
case HSHELL_WINDOWCREATED:
+ SendPulseToTray(FALSE, (HWND)lParam);
AddTask((HWND) lParam);
break;
case HSHELL_WINDOWDESTROYED:
/* The window still exists! Delay destroying it a bit */
- DeleteTask((HWND) lParam);
+ SendPulseToTray(TRUE, (HWND)lParam);
+ DeleteTask((HWND)lParam);
break;
case HSHELL_RUDEAPPACTIVATED:
case HSHELL_WINDOWACTIVATED:
- ActivateTask((HWND) lParam);
+ SendPulseToTray(FALSE, (HWND)lParam);
+ ActivateTask((HWND)lParam);
break;
case HSHELL_FLASH:
if (!bIsMinimized && bIsActive)
{
+ TaskItem->wndpl.length = sizeof(TaskItem->wndpl);
+ ::GetWindowPlacement(TaskItem->hWnd, &TaskItem->wndpl);
+
::ShowWindowAsync(TaskItem->hWnd, SW_MINIMIZE);
TRACE("Valid button clicked. App window Minimized.\n");
}
else
{
::SwitchToThisWindow(TaskItem->hWnd, TRUE);
+ ::SetWindowPlacement(TaskItem->hWnd, &TaskItem->wndpl);
+
TRACE("Valid button clicked. App window Restored.\n");
}
}
TaskItem = FindTaskItemByIndex((INT) wIndex);
if (TaskItem != NULL)
{
+ SendPulseToTray(FALSE, TaskItem->hWnd);
HandleTaskItemClick(TaskItem);
return TRUE;
}
return ei.hwndFound != NULL;
}
-CSimpleArray<HWND> g_MinimizedAll;
+/* Minimized window position info */
+struct MINWNDPOS
+{
+ HWND hwnd;
+ WINDOWPLACEMENT wndpl;
+};
+CSimpleArray<MINWNDPOS> g_MinimizedAll;
/*
* ITrayWindow
DWORD InSizeMove : 1;
DWORD IsDragging : 1;
DWORD NewPosSize : 1;
+ DWORD IgnorePulse : 1;
};
};
ZeroMemory(&m_TraySize, sizeof(m_TraySize));
ZeroMemory(&m_AutoHideOffset, sizeof(m_AutoHideOffset));
ZeroMemory(&m_MouseTrackingInfo, sizeof(m_MouseTrackingInfo));
+ IgnorePulse = TRUE;
}
virtual ~CTrayWindow()
return bPrevLock;
}
+ /* The task window is visible and non-WS_EX_TOOLWINDOW and
+ { has WS_EX_APPWINDOW style or has no owner } and is none of explorer's
+ special windows (such as the desktop or the tray window) */
+ BOOL STDMETHODCALLTYPE IsTaskWnd(HWND hWnd)
+ {
+ if (::IsWindow(hWnd) && ::IsWindowVisible(hWnd) && !IsSpecialHWND(hWnd))
+ {
+ DWORD exStyle = (DWORD)::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
+ if (((exStyle & WS_EX_APPWINDOW) || ::GetWindow(hWnd, GW_OWNER) == NULL) &&
+ !(exStyle & WS_EX_TOOLWINDOW))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
/*
* IContextMenu
return TRUE;
}
+#define TIMER_ID_IGNOREPULSERESET 888
+#define TIMER_IGNOREPULSERESET_TIMEOUT 200
+
+ LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ KillTimer(TIMER_ID_IGNOREPULSERESET);
+ return 0;
+ }
+
LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_Theme)
return (LRESULT)m_TaskSwitch;
}
+ void RestoreMinimizedNonTaskWnds(BOOL bDestroyed, HWND hwndActive)
+ {
+ for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i)
+ {
+ HWND hwnd = g_MinimizedAll[i].hwnd;
+ if (!hwnd || hwndActive == hwnd)
+ continue;
+
+ if (::IsWindowVisible(hwnd) && ::IsIconic(hwnd) &&
+ (!IsTaskWnd(hwnd) || !::IsWindowEnabled(hwnd)))
+ {
+ ::SetWindowPlacement(hwnd, &g_MinimizedAll[i].wndpl); // Restore
+ }
+ }
+
+ g_MinimizedAll.RemoveAll();
+
+ if (!bDestroyed)
+ ::SetForegroundWindow(hwndActive);
+ }
+
+ LRESULT OnPulse(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+ {
+ if (IgnorePulse)
+ return 0;
+
+ KillTimer(TIMER_ID_IGNOREPULSERESET);
+ IgnorePulse = TRUE;
+ RestoreMinimizedNonTaskWnds((BOOL)wParam, (HWND)lParam);
+ SetTimer(TIMER_ID_IGNOREPULSERESET, TIMER_IGNOREPULSERESET_TIMEOUT, NULL);
+ return 0;
+ }
+
LRESULT OnHotkey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return HandleHotKey(wParam);
HWND hwndDesktop;
HWND hTrayWnd;
HWND hwndProgman;
- BOOL bRet;
- CSimpleArray<HWND> *pMinimizedAll;
+ CSimpleArray<MINWNDPOS> *pMinimizedAll;
BOOL bShowDesktop;
};
static BOOL CALLBACK MinimizeWindowsProc(HWND hwnd, LPARAM lParam)
{
MINIMIZE_INFO *info = (MINIMIZE_INFO *)lParam;
- if (hwnd == info->hwndDesktop || hwnd == info->hTrayWnd ||
- hwnd == info->hwndProgman)
- {
- return TRUE;
- }
+ if (hwnd == info->hwndDesktop || hwnd == info->hTrayWnd || hwnd == info->hwndProgman)
+ return TRUE; // Ignore special windows
+
if (!info->bShowDesktop)
{
if (!::IsWindowEnabled(hwnd) || IsDialog(hwnd))
if (hwndOwner && !::IsWindowEnabled(hwndOwner))
return TRUE;
}
+
if (::IsWindowVisible(hwnd) && !::IsIconic(hwnd))
{
+ MINWNDPOS mwp;
+ mwp.hwnd = hwnd;
+ mwp.wndpl.length = sizeof(mwp.wndpl);
+ ::GetWindowPlacement(hwnd, &mwp.wndpl); // Save the position and status
+
+ info->pMinimizedAll->Add(mwp);
+
::ShowWindowAsync(hwnd, SW_MINIMIZE);
- info->bRet = TRUE;
- info->pMinimizedAll->Add(hwnd);
}
+
return TRUE;
}
VOID MinimizeAll(BOOL bShowDesktop = FALSE)
{
+ IgnorePulse = TRUE;
+ KillTimer(TIMER_ID_IGNOREPULSERESET);
+
MINIMIZE_INFO info;
info.hwndDesktop = GetDesktopWindow();;
info.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
info.hwndProgman = FindWindowW(L"Progman", NULL);
- info.bRet = FALSE;
info.pMinimizedAll = &g_MinimizedAll;
info.bShowDesktop = bShowDesktop;
EnumWindows(MinimizeWindowsProc, (LPARAM)&info);
- // invalid handles should be cleared to avoid mismatch of handles
- for (INT i = 0; i < g_MinimizedAll.GetSize(); ++i)
- {
- if (!::IsWindow(g_MinimizedAll[i]))
- g_MinimizedAll[i] = NULL;
- }
-
::SetForegroundWindow(m_DesktopWnd);
::SetFocus(m_DesktopWnd);
+ SetTimer(TIMER_ID_IGNOREPULSERESET, TIMER_IGNOREPULSERESET_TIMEOUT, NULL);
}
VOID ShowDesktop()
VOID RestoreAll()
{
+ IgnorePulse = TRUE;
+ KillTimer(TIMER_ID_IGNOREPULSERESET);
+
for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i)
{
- HWND hwnd = g_MinimizedAll[i];
+ HWND hwnd = g_MinimizedAll[i].hwnd;
if (::IsWindowVisible(hwnd) && ::IsIconic(hwnd))
{
- ::ShowWindowAsync(hwnd, SW_RESTORE);
+ ::SetWindowPlacement(hwnd, &g_MinimizedAll[i].wndpl);
}
}
+
g_MinimizedAll.RemoveAll();
+ SetTimer(TIMER_ID_IGNOREPULSERESET, TIMER_IGNOREPULSERESET_TIMEOUT, NULL);
}
LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
ProcessAutoHide();
}
-
- bHandled = FALSE;
- return TRUE;
+ else if (wParam == TIMER_ID_IGNOREPULSERESET)
+ {
+ KillTimer(TIMER_ID_IGNOREPULSERESET);
+ IgnorePulse = FALSE;
+ }
+ return 0;
}
LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
- /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
MESSAGE_HANDLER(WM_COMMAND, OnCommand)
MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)
MESSAGE_HANDLER(TWM_OPENSTARTMENU, OnOpenStartMenu)
MESSAGE_HANDLER(TWM_DOEXITWINDOWS, OnDoExitWindows)
MESSAGE_HANDLER(TWM_GETTASKSWITCH, OnGetTaskSwitch)
+ MESSAGE_HANDLER(TWM_PULSE, OnPulse)
ALT_MSG_MAP(1)
END_MSG_MAP()
#include <winnls.h>
#include <winuser.h>
#include <tchar.h>
+#include <undocuser.h> // For WM_POPUPSYSTEMMENU
#include "resource.h"
return lpString;
}
+typedef struct
+{
+ HWND hwndOwner;
+ HWND hwndTarget;
+} FIND_OWNED, *PFIND_OWNED;
+
+static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
+{
+ PFIND_OWNED pFindOwned = (PFIND_OWNED)lParam;
+ if (pFindOwned->hwndOwner == GetWindow(hwnd, GW_OWNER))
+ {
+ pFindOwned->hwndTarget = hwnd;
+ return FALSE;
+ }
+ return TRUE;
+}
+
LRESULT CALLBACK EmptyWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
- return DefWindowProc(hWnd, uMsg, wParam, lParam);
+ switch (uMsg)
+ {
+ case WM_POPUPSYSTEMMENU:
+ case WM_SYSCOMMAND:
+ {
+ /* Find the owned window */
+ FIND_OWNED FindOwned = { hWnd, NULL };
+ EnumWindows(EnumWindowsProc, (LPARAM)&FindOwned);
+ /* Forward message */
+ if (FindOwned.hwndTarget)
+ PostMessageW(FindOwned.hwndTarget, uMsg, wParam, lParam);
+ break;
+ }
+ case WM_ACTIVATE:
+ {
+ /* Find the owned window */
+ FIND_OWNED FindOwned = { hWnd, NULL };
+ EnumWindows(EnumWindowsProc, (LPARAM)&FindOwned);
+ if (FindOwned.hwndTarget)
+ {
+ if (LOWORD(wParam) != WA_INACTIVE) /* To be activated */
+ {
+ SetActiveWindow(FindOwned.hwndTarget);
+ return 0;
+ }
+ }
+ /* Fall through */
+ }
+ default:
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+ }
+ return 0;
}
// Registers a minimal window class for passing to the dll function