mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2104 lines
58 KiB
2104 lines
58 KiB
#include "cabinet.h"
|
|
#include "rcids.h"
|
|
#include <trayp.h>
|
|
|
|
#define USERDRAW
|
|
|
|
extern TRAYSTUFF g_ts;
|
|
|
|
#define HSHELL_OVERFLOW (WM_USER+42) // BUGBUG - BobDay move to WINUSER.W
|
|
|
|
#ifdef HSHELL_SYSMENU
|
|
#ifdef WINNT
|
|
#define USE_SYSMENU_TIMEOUT
|
|
#else
|
|
// BUGBUG - When Nashville/Memphis USER have the HSHELL_SYSMENU feature, then
|
|
// remove this #ifdef
|
|
#endif
|
|
#endif
|
|
|
|
typedef struct {
|
|
TC_ITEM tcitem;
|
|
DWORD dwFlags;
|
|
} TASKTABITEM, * PTASKTABITEM;
|
|
|
|
//
|
|
#define RECTWIDTH(rc) ((rc).right-(rc).left)
|
|
#define RECTHEIGHT(rc) ((rc).bottom-(rc).top)
|
|
#define ResizeWindow(hwnd, cWidth, cHeight) \
|
|
SetWindowPos(hwnd, 0, 0, 0, cWidth, cHeight, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER)
|
|
|
|
#define IDC_FOLDERTABS 1
|
|
#define SHOULDFLASH 0x000000001
|
|
#define SHOULDTIP 0x000000002
|
|
HFONT g_hfontCapBold = NULL;
|
|
HFONT g_hfontCapNormal = NULL;
|
|
|
|
void SetWindowStyleBit(HWND hWnd, DWORD dwBit, DWORD dwValue);
|
|
|
|
//
|
|
// Tasks Class definition
|
|
//
|
|
|
|
typedef struct _CTasks {
|
|
IShellView sv;
|
|
int cRef;
|
|
|
|
IShellBrowser * psb;
|
|
|
|
HWND hwnd; // the view window
|
|
HWND hwndTab; // owner draw listbox of tasks
|
|
HINSTANCE hInstance;
|
|
|
|
UINT WM_ShellHook;
|
|
|
|
//int iBannerRes; // which banner string to show
|
|
int xBanner; // the x location of the banner
|
|
int xBannerOld;
|
|
int cxBanner; // width of the banner
|
|
int cyBanner;
|
|
int dxBanner;
|
|
int iBannerBounce;
|
|
HDC hdcBanner;
|
|
HBITMAP hbmBanner;
|
|
|
|
short iSysMenuCount;
|
|
HWND hwndSysMenu;
|
|
DWORD dwPos;
|
|
|
|
} CTasks, * PTasks;
|
|
|
|
#define IDT_BANNER 1
|
|
#define IDT_SYSMENU 2
|
|
|
|
#define TIMEOUT_SYSMENU 2000
|
|
#define TIMEOUT_SYSMENU_HUNG 125
|
|
|
|
void UpdateButtonSize(PTasks ptasks);
|
|
BOOL TaskList_SwitchToSelection(PTasks ptasks);
|
|
STDMETHODIMP CTasksShellView_DestroyViewWindow(IShellView * psv);
|
|
ULONG STDMETHODCALLTYPE CTasksShellView_AddRef(IShellView * psv);
|
|
LRESULT _HandleWinIniChange(PTasks ptasks, WPARAM wParam, LPARAM lParam);
|
|
void Cabinet_InitGlobalMetrics(WPARAM, LPTSTR);
|
|
void NukeBanner(PTasks ptasks);
|
|
void DrawBanner(PTasks ptasks, HDC hdc);
|
|
void ResurrectBanner(PTasks ptasks);
|
|
DWORD Tray_GetStuckPlace();
|
|
void Tray_HandleFullScreenApp(BOOL fFullScreen, HWND hwnd);
|
|
|
|
BOOL Window_IsNormal(HWND hwnd)
|
|
{
|
|
return (hwnd != v_hwndTray) && (hwnd != v_hwndDesktop) && IsWindow(hwnd);
|
|
}
|
|
|
|
#ifndef USERDRAW
|
|
//---------------------------------------------------------------------------
|
|
HICON Window_GetIcon(HWND hwnd)
|
|
{
|
|
HICON hIcon;
|
|
|
|
hIcon = (HICON)SendMessage(hwnd, WM_GETICON, FALSE, 0L);
|
|
if (!hIcon)
|
|
{
|
|
hIcon = (HICON)SendMessage(hwnd, WM_QUERYDRAGICON, 0, 0L);
|
|
if (!hIcon)
|
|
{
|
|
hIcon = GetClassIcon(hwnd);
|
|
}
|
|
}
|
|
return hIcon;
|
|
}
|
|
#endif
|
|
|
|
//======================================================================
|
|
//
|
|
HWND TabCtrl_GetItemHwnd(HWND hwnd, int i)
|
|
{
|
|
TASKTABITEM item;
|
|
|
|
item.tcitem.lParam = 0;
|
|
item.tcitem.mask = TCIF_PARAM;
|
|
|
|
TabCtrl_GetItem(hwnd, i, (TC_ITEM *)&item);
|
|
return (HWND)item.tcitem.lParam;
|
|
}
|
|
|
|
DWORD TabCtrl_GetItemFlags(HWND hwnd, int i)
|
|
{
|
|
TASKTABITEM item;
|
|
|
|
item.tcitem.mask = TCIF_PARAM;
|
|
TabCtrl_GetItem(hwnd, i, (TC_ITEM *)&item);
|
|
return item.dwFlags;
|
|
}
|
|
|
|
void TabCtrl_SetItemFlags(HWND hwnd, int i, DWORD dwFlags)
|
|
{
|
|
TASKTABITEM item;
|
|
|
|
item.tcitem.mask = TCIF_PARAM;
|
|
if (TabCtrl_GetItem(hwnd, i, (TC_ITEM *)&item)) {
|
|
item.dwFlags = dwFlags;
|
|
TabCtrl_SetItem(hwnd, i, (TC_ITEM *)&item);
|
|
}
|
|
}
|
|
|
|
int FindItem(PTasks ptasks, HWND hwnd)
|
|
{
|
|
int iMax;
|
|
HWND hwndTask;
|
|
int i;
|
|
|
|
iMax = (int)TabCtrl_GetItemCount(ptasks->hwndTab);
|
|
for ( i = 0; i <= iMax; i++)
|
|
{
|
|
hwndTask = (HWND)TabCtrl_GetItemHwnd(ptasks->hwndTab, i);
|
|
if (hwndTask == hwnd) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void CheckNeedScrollbars(PTasks ptasks, int cyRow, int cItems, int iCols, int iRows,
|
|
int iItemWidth, LPRECT lprcView)
|
|
{
|
|
DWORD dwStuck = Tray_GetStuckPlace();
|
|
SCROLLINFO si;
|
|
RECT rcTabs;
|
|
int cxRow = iItemWidth + g_cyTabSpace;
|
|
int iVisibleColumns = ((RECTWIDTH(*lprcView) + g_cyTabSpace) / cxRow);
|
|
int iVisibleRows = ((RECTHEIGHT(*lprcView) + g_cyTabSpace) / cyRow);
|
|
int x,y, cx,cy;
|
|
|
|
rcTabs = *lprcView;
|
|
|
|
if (!iVisibleColumns)
|
|
iVisibleColumns = 1;
|
|
if (!iVisibleRows)
|
|
iVisibleRows = 1;
|
|
|
|
si.cbSize = SIZEOF(SCROLLINFO);
|
|
si.fMask = SIF_PAGE | SIF_RANGE;
|
|
si.nMin = 0;
|
|
si.nPage = 0;
|
|
si.nPos = 0;
|
|
|
|
if (STUCK_HORIZONTAL(dwStuck)) {
|
|
// do vertical scrollbar
|
|
// -1 because it's 0 based.
|
|
si.nMax = (cItems + iVisibleColumns - 1) / iVisibleColumns -1 ;
|
|
si.nPage = iVisibleRows;
|
|
|
|
// we're actually going to need the scrollbars
|
|
if (si.nPage <= (UINT)si.nMax) {
|
|
// this effects the vis columns and therefore nMax and nPage
|
|
rcTabs.right -= g_cxVScroll;
|
|
iVisibleColumns = ((RECTWIDTH(rcTabs) + g_cyTabSpace) / cxRow);
|
|
if (!iVisibleColumns)
|
|
iVisibleColumns = 1;
|
|
si.nMax = (cItems + iVisibleColumns - 1) / iVisibleColumns -1 ;
|
|
}
|
|
|
|
SetScrollInfo(ptasks->hwnd, SB_VERT, &si, TRUE);
|
|
si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
|
|
GetScrollInfo(ptasks->hwnd, SB_VERT, &si);
|
|
x = 0;
|
|
y = -si.nPos * cyRow;
|
|
cx = cxRow * iVisibleColumns;
|
|
// +1 because si.nMax is zero based
|
|
cy = cyRow * (si.nMax +1);
|
|
|
|
// nuke the other scroll bar
|
|
si.nMax = 0;
|
|
si.nPos = 0;
|
|
si.nMin = 0;
|
|
si.nPage = 0;
|
|
SetScrollInfo(ptasks->hwnd, SB_HORZ, &si, TRUE);
|
|
|
|
} else {
|
|
// do horz scrollbar
|
|
si.nMax = iCols -1;
|
|
si.nPage = iVisibleColumns;
|
|
|
|
// we're actually going to need the scrollbars
|
|
if (si.nPage <= (UINT)si.nMax) {
|
|
// this effects the vis columns and therefore nMax and nPage
|
|
rcTabs.bottom -= g_cyHScroll;
|
|
iVisibleRows = ((RECTHEIGHT(rcTabs) + g_cyTabSpace) / cyRow);
|
|
if (!iVisibleRows)
|
|
iVisibleRows = 1;
|
|
si.nMax = (cItems + iVisibleRows - 1) / iVisibleRows -1 ;
|
|
}
|
|
|
|
SetScrollInfo(ptasks->hwnd, SB_HORZ, &si, TRUE);
|
|
si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
|
|
GetScrollInfo(ptasks->hwnd, SB_HORZ, &si);
|
|
y = 0;
|
|
x = -si.nPos * cxRow;
|
|
|
|
cx = cxRow * (si.nMax + 1);
|
|
cy = cyRow * iVisibleRows;
|
|
|
|
// nuke the other scroll bar
|
|
si.nMax = 0;
|
|
si.nPos = 0;
|
|
si.nMin = 0;
|
|
si.nPage = 0;
|
|
SetScrollInfo(ptasks->hwnd, SB_VERT, &si, TRUE);
|
|
}
|
|
SetWindowPos(ptasks->hwndTab, 0, x,y, cx, cy, SWP_NOACTIVATE| SWP_NOZORDER);
|
|
}
|
|
|
|
void NukeScrollbars(PTasks ptasks)
|
|
{
|
|
SCROLLINFO si;
|
|
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
|
|
si.cbSize = SIZEOF(SCROLLINFO);
|
|
si.nMin = 0;
|
|
si.nMax = 0;
|
|
si.nPage = 0;
|
|
si.nPos = 0;
|
|
|
|
SetScrollInfo(ptasks->hwnd, SB_VERT, &si, TRUE);
|
|
SetScrollInfo(ptasks->hwnd, SB_HORZ, &si, TRUE);
|
|
}
|
|
|
|
//======================================================================
|
|
// this checks the size of the tab's items. it shrinks them to
|
|
// make sure that all are visible on the window. min size is smallicon size
|
|
// plus 3*xedge. max size is small icons size.
|
|
void CheckSize(PTasks ptasks, BOOL fForceResize)
|
|
{
|
|
RECT rc;
|
|
int iWinWidth;
|
|
int iWinHeight;
|
|
int cItems;
|
|
int iIdeal;
|
|
int cyRow;
|
|
int iMax, iMin;
|
|
int iRows;
|
|
int iOldWidth;
|
|
RECT rcItem;
|
|
|
|
GetWindowRect(ptasks->hwnd, &rc);
|
|
if (IsRectEmpty(&rc) || !(GetWindowLong(ptasks->hwndTab, GWL_STYLE) & WS_VISIBLE))
|
|
return;
|
|
|
|
iWinWidth = RECTWIDTH(rc);
|
|
iWinHeight = RECTHEIGHT(rc);
|
|
cItems = TabCtrl_GetItemCount(ptasks->hwndTab);
|
|
TabCtrl_GetItemRect(ptasks->hwndTab, 0, &rcItem);
|
|
iOldWidth = RECTWIDTH(rcItem);
|
|
|
|
// we need to add the iButtonSpace on the nominator because there are n-1 spaces.
|
|
// we need to add the iButtonSpace in the denominator because that's the full height
|
|
// of a row
|
|
cyRow = RECTHEIGHT(rcItem) + g_cyTabSpace;
|
|
iRows = (iWinHeight + g_cyTabSpace) / cyRow;
|
|
if (iRows == 0) iRows = 1;
|
|
if (cItems) {
|
|
DWORD dwStuck;
|
|
// interbutton spacing by the tabs
|
|
int iCols;
|
|
|
|
// We need to round up so that iCols is the smallest number such that
|
|
// iCols*iRows >= cItems
|
|
iCols = (cItems + iRows - 1) / iRows;
|
|
iIdeal = (iWinWidth / iCols) - g_cyTabSpace;
|
|
dwStuck = Tray_GetStuckPlace();
|
|
|
|
// now check if we want to bail..
|
|
// bail if we're increasing the width, but not by very much
|
|
//
|
|
// use the ideal width for this calculation
|
|
if (STUCK_HORIZONTAL(dwStuck) && !fForceResize && (iOldWidth < iIdeal) && ((iOldWidth / (iIdeal - iOldWidth)) >= 3)) {
|
|
return;
|
|
}
|
|
|
|
if (STUCK_HORIZONTAL(dwStuck))
|
|
iMax = g_cxMinimized;
|
|
else
|
|
iMax = iWinWidth;
|
|
iMin = g_cySize + 2*g_cxEdge;
|
|
iIdeal = min(iMax, iIdeal);
|
|
iIdeal = max(iMin, iIdeal);
|
|
TabCtrl_SetItemSize(ptasks->hwndTab, iIdeal, g_cySize + 2 * g_cyEdge);
|
|
|
|
// if we're forced to the minimum size, then we may need some scrollbars
|
|
if (iIdeal == iMin) {
|
|
CheckNeedScrollbars(ptasks, cyRow, cItems, iCols, iRows, iIdeal, &rc);
|
|
} else {
|
|
NukeScrollbars(ptasks);
|
|
SetWindowPos(ptasks->hwndTab, 0, 0, 0,iWinWidth, iWinHeight, SWP_NOACTIVATE | SWP_NOZORDER);
|
|
}
|
|
} else {
|
|
TabCtrl_SetItemSize(ptasks->hwndTab, g_cxMinimized, g_cySize + 2 * g_cyEdge);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Delete an item from the listbox but resize the buttons if needed.
|
|
void TaskList_DeleteItem(PTasks ptasks, UINT i)
|
|
{
|
|
//ImageList... delete icon
|
|
#ifndef USERDRAW
|
|
TASKTABITEM item;
|
|
|
|
item.tcitem.mask = TCIF_IMAGE;
|
|
TabCtrl_GetItem(ptasks->hwndTab, i, (TC_ITEM *)&item);
|
|
#endif
|
|
TabCtrl_DeleteItem(ptasks->hwndTab, i); // delete first to avoid refresh
|
|
#ifndef USERDRAW
|
|
TabCtrl_RemoveImage(ptasks->hwndTab, item.tcitem.iImage);
|
|
#endif
|
|
|
|
#ifdef TESTBANNER
|
|
if (TabCtrl_GetItemCount(ptasks->hwndTab) == 0)
|
|
{
|
|
ptasks->iBannerBounce = 0;
|
|
SetWindowStyleBit(ptasks->hwnd, WS_CLIPCHILDREN, 0);
|
|
SetTimer(ptasks->hwnd, IDT_BANNER, 5, NULL);
|
|
}
|
|
#endif
|
|
|
|
CheckSize(ptasks, FALSE);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Insert an item into the listbox but resize the buttons if required.
|
|
int TaskList_InsertItem(PTasks ptasks, HWND hwndTask)
|
|
{
|
|
TASKTABITEM ti;
|
|
#ifndef USERDRAW
|
|
HIMAGELIST himl;
|
|
HICON hIcon;
|
|
TCHAR szText[CCHSZNORMAL];
|
|
#endif
|
|
|
|
NukeBanner(ptasks);
|
|
|
|
#ifndef USERDRAW
|
|
himl = (HIMAGELIST)TabCtrl_GetImageList(ptasks->hwndTab);
|
|
ti.tcitem.mask = TCIF_IMAGE | TCIF_PARAM | TCIF_TEXT;
|
|
hIcon = Window_GetIcon(hwndTask);
|
|
ti.tcitem.iImage = hIcon ? ImageList_AddIcon(himl, hIcon) : -1;
|
|
GetWindowText(hwndTask, szText, ARRAYSIZE(szText));
|
|
ti.tcitem.pszText = szText;
|
|
#else
|
|
ti.tcitem.mask = TCIF_PARAM;
|
|
#endif
|
|
ti.tcitem.lParam = (LPARAM)hwndTask;
|
|
ti.dwFlags = 0L;
|
|
TabCtrl_InsertItem(ptasks->hwndTab, 0x7FFF, (TC_ITEM*)&ti);
|
|
|
|
CheckSize(ptasks, FALSE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Adds the given window to the task list.
|
|
// Returns it's position in the list or -1 of there's a problem.
|
|
// NB No check is made to see if it's already in the list.
|
|
int TaskList_AddWindow(PTasks ptasks, HWND hwnd)
|
|
{
|
|
int iInsert = -1;
|
|
|
|
if (Window_IsNormal(hwnd))
|
|
{
|
|
// Button.
|
|
if (FindItem(ptasks, hwnd) != -1)
|
|
return -1;
|
|
|
|
if(TaskList_InsertItem(ptasks, hwnd) == 0)
|
|
return -1;
|
|
}
|
|
return iInsert;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// If the given window is in the task list then it is selected.
|
|
// If it's not in the list then it is added.
|
|
void TaskList_SelectWindow(PTasks ptasks, HWND hwnd)
|
|
{
|
|
int i; // Initialize to zero for the empty case
|
|
int iCurSel;
|
|
|
|
// Are there any items?
|
|
|
|
// Some item has the focus, is it selected?
|
|
iCurSel = TabCtrl_GetCurSel(ptasks->hwndTab);
|
|
i = -1;
|
|
|
|
// We aren't highlighting the correct task. Find it.
|
|
if (IsWindow(hwnd)) {
|
|
i = FindItem(ptasks, hwnd);
|
|
if (i == -1) {
|
|
|
|
// Didn't find it - better add it now.
|
|
i = TaskList_AddWindow(ptasks, hwnd);
|
|
} else if (i == iCurSel) {
|
|
|
|
return; // the current one is already selected
|
|
}
|
|
}
|
|
|
|
// passing -1 is ok
|
|
TabCtrl_SetCurSel(ptasks->hwndTab, i);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Set the focus to the given window
|
|
// If fAutomin is set the old task will be re-minimising if it was restored
|
|
// during the last switch_to.
|
|
void TaskList_SwitchToWindow(PTasks ptasks, HWND hwnd)
|
|
{
|
|
// use GetLastActivePopup (if it's a visible window) so we don't change
|
|
// what child had focus all the time
|
|
HWND hwndLastActive = GetLastActivePopup(hwnd);
|
|
|
|
if (IsWindowVisible(hwndLastActive))
|
|
hwnd = hwndLastActive;
|
|
|
|
SwitchToThisWindow(hwnd, TRUE);
|
|
}
|
|
|
|
void CALLBACK _FakeSystemMenuCallback(HWND hwnd, UINT uiMsg,
|
|
DWORD dwData, LRESULT result)
|
|
{
|
|
PTasks ptasks = (PTasks)dwData;
|
|
KillTimer(ptasks->hwnd, IDT_SYSMENU);
|
|
|
|
//
|
|
// Since we fake system menu's sometimes, we can come through here
|
|
// 1 or 2 times per system menu request (once for the real one and
|
|
// once for the fake one). Only decrement it down to 0. Don't go neg.
|
|
//
|
|
if (ptasks->iSysMenuCount) // Decrement it if any outstanding...
|
|
ptasks->iSysMenuCount--;
|
|
|
|
ptasks->dwPos = 0; // Indicates that we aren't doing a menu now
|
|
if (ptasks->iSysMenuCount <= 0) {
|
|
SendMessage(g_ts.hwndTrayTips, TTM_ACTIVATE, TRUE, 0L);
|
|
}
|
|
}
|
|
|
|
#ifdef USE_SYSMENU_TIMEOUT
|
|
void _HandleSysMenuTimeout(PTasks ptasks)
|
|
{
|
|
HMENU hPopup;
|
|
HWND hwndTask = ptasks->hwndSysMenu;
|
|
DWORD dwPos = ptasks->dwPos;
|
|
|
|
KillTimer(ptasks->hwnd, IDT_SYSMENU);
|
|
|
|
hPopup = GetSystemMenu(hwndTask, FALSE);
|
|
|
|
if (hPopup)
|
|
{
|
|
//
|
|
// Disable everything on the popup menu _except_ close
|
|
//
|
|
|
|
int cItems = GetMenuItemCount(hPopup);
|
|
int iItem = 0;
|
|
for (; iItem < cItems; iItem++)
|
|
{
|
|
UINT ID = GetMenuItemID(hPopup, iItem);
|
|
if (ID != SC_CLOSE)
|
|
{
|
|
EnableMenuItem(hPopup, iItem, MF_BYPOSITION | MF_GRAYED);
|
|
}
|
|
|
|
}
|
|
|
|
// BUGBUG (RAID 10667) Until this user bug is fixed, we
|
|
// must be the foreground window
|
|
|
|
SetForegroundWindow(ptasks->hwnd);
|
|
SetFocus(ptasks->hwnd);
|
|
|
|
TrackPopupMenu(hPopup,
|
|
TPM_RIGHTBUTTON,
|
|
LOWORD(dwPos), HIWORD(dwPos),
|
|
0,
|
|
ptasks->hwnd,
|
|
NULL);
|
|
}
|
|
|
|
// Turn back on tooltips
|
|
_FakeSystemMenuCallback(hwndTask, WM_SYSMENU, (DWORD)ptasks, 0);
|
|
}
|
|
|
|
void _HandleSysMenu( PTasks ptasks, HWND hwnd )
|
|
{
|
|
//
|
|
// At this point, USER32 just told us that the app is now about to bring
|
|
// up its own system menu. We can therefore put away our fake system
|
|
// menu.
|
|
//
|
|
DefWindowProc(ptasks->hwnd, WM_CANCELMODE, 0, 0); // Close menu
|
|
KillTimer(ptasks->hwnd, IDT_SYSMENU);
|
|
}
|
|
#endif
|
|
|
|
void TaskList_FakeSystemMenu(PTasks ptasks, HWND hwndTask, DWORD dwPos)
|
|
{
|
|
DWORD dwTimeout = TIMEOUT_SYSMENU;
|
|
|
|
if (ptasks->iSysMenuCount <= 0) {
|
|
SendMessage(g_ts.hwndTrayTips, TTM_ACTIVATE, FALSE, 0L);
|
|
}
|
|
|
|
// HACKHACK: sleep to give time to switch to them. (user needs this... )
|
|
Sleep(20);
|
|
|
|
#ifdef USE_SYSMENU_TIMEOUT
|
|
//
|
|
// ** Advanced System Menu functionality **
|
|
//
|
|
// If the app doesn't put up its system menu within a reasonable timeout,
|
|
// then we popup a fake menu for it anyway. Suppport for this is required
|
|
// in USER32 (basically it needs to tell us when to turn off our timeout
|
|
// timer).
|
|
//
|
|
// If the user-double right-clicks on the task bar, they get a really
|
|
// short timeout. If the app is already hung, then they get a really
|
|
// short timeout. Otherwise, they get the relatively long timeout.
|
|
//
|
|
if (ptasks->dwPos != 0) // 2nd right-click (on a double-right click)
|
|
dwTimeout = TIMEOUT_SYSMENU_HUNG;
|
|
|
|
//
|
|
// We check to see if the app in question is hung, and if so, simulate
|
|
// speed up the timeout process. It will happen soon enough.
|
|
//
|
|
#ifdef WINNT
|
|
if (IsHungAppWindow(hwndTask))
|
|
#else
|
|
if (IsHungThread(GetWindowThreadProcessId(hwndTask, NULL)))
|
|
#endif
|
|
dwTimeout = TIMEOUT_SYSMENU_HUNG;
|
|
|
|
ptasks->hwndSysMenu = hwndTask;
|
|
ptasks->dwPos = dwPos;
|
|
SetTimer(ptasks->hwnd, IDT_SYSMENU, dwTimeout, NULL);
|
|
#endif
|
|
|
|
ptasks->iSysMenuCount++;
|
|
if (!SendMessageCallback(hwndTask, WM_SYSMENU, 0, dwPos, _FakeSystemMenuCallback, (DWORD)ptasks)) {
|
|
_FakeSystemMenuCallback(hwndTask, WM_SYSMENU, (DWORD)ptasks, 0);
|
|
}
|
|
}
|
|
|
|
void TaskList_SysMenuForItem(PTasks ptasks, int i, DWORD dwPos)
|
|
{
|
|
HWND hwndTask = (HWND)TabCtrl_GetItemHwnd(ptasks->hwndTab, i);
|
|
|
|
// set foreground first so that we'll switch to it.
|
|
SetForegroundWindow(GetLastActivePopup(hwndTask));
|
|
TaskList_SelectWindow(ptasks, hwndTask);
|
|
PostMessage(ptasks->hwnd, TM_POSTEDRCLICK, (WPARAM)hwndTask, (LPARAM)dwPos);
|
|
}
|
|
|
|
BOOL TaskList_PostFakeSystemMenu(PTasks ptasks, DWORD dwPos)
|
|
{
|
|
int i;
|
|
BOOL fRet;
|
|
TC_HITTESTINFO tcht;
|
|
|
|
if (dwPos != (DWORD)-1) {
|
|
tcht.pt.x = LOWORD(dwPos);
|
|
tcht.pt.y = HIWORD(dwPos);
|
|
|
|
ScreenToClient(ptasks->hwndTab, &tcht.pt);
|
|
i = SendMessage(ptasks->hwndTab, TCM_HITTEST, 0, (LPARAM)&tcht);
|
|
} else {
|
|
i = TabCtrl_GetCurFocus(ptasks->hwndTab);
|
|
}
|
|
fRet = (i != -1);
|
|
if (fRet) {
|
|
TaskList_SysMenuForItem(ptasks, i, dwPos);
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
LRESULT TaskList_HandleNotify(PTasks ptasks, LPNMHDR lpnm)
|
|
{
|
|
switch (lpnm->code) {
|
|
case NM_CLICK: {
|
|
TC_HITTESTINFO hitinfo;
|
|
HWND hwnd;
|
|
int i;
|
|
DWORD dwPos = GetMessagePos();
|
|
hitinfo.pt.x = LOWORD(dwPos);
|
|
hitinfo.pt.y = HIWORD(dwPos);
|
|
|
|
// did the click happen on the currently selected tab?
|
|
// if so, tab ctrl isn't going to send us a message. so di it ourselves
|
|
i = TabCtrl_GetCurSel(ptasks->hwndTab);
|
|
ScreenToClient(ptasks->hwndTab, &hitinfo.pt);
|
|
if (i == TabCtrl_HitTest(ptasks->hwndTab, &hitinfo)) {
|
|
hwnd = TabCtrl_GetItemHwnd(ptasks->hwndTab, i);
|
|
if (hwnd == GetForegroundWindow()) {
|
|
if (IsIconic(hwnd))
|
|
ShowWindow(hwnd, SW_RESTORE);
|
|
|
|
} else {
|
|
TaskList_SwitchToSelection(ptasks);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case TCN_SELCHANGE:
|
|
TaskList_SwitchToSelection(ptasks);
|
|
break;
|
|
|
|
case TTN_SHOW:
|
|
SetWindowPos(g_ts.hwndTrayTips,
|
|
HWND_TOP,
|
|
0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
break;
|
|
|
|
case TTN_NEEDTEXT: {
|
|
LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)lpnm;
|
|
HWND hwnd;
|
|
TASKTABITEM item;
|
|
|
|
item.tcitem.lParam = 0;
|
|
item.tcitem.mask = TCIF_PARAM;
|
|
|
|
TabCtrl_GetItem(ptasks->hwndTab, lpttt->hdr.idFrom, (TC_ITEM *)&item);
|
|
|
|
hwnd = (HWND)item.tcitem.lParam;
|
|
// do an IsWindow check because user might (does) sometimes
|
|
// send us a redraw item as it's dying, and since we do
|
|
// a postmessage, we don't get it till we're dead
|
|
//DebugMsg(DM_TRACE, "NeedText for hwnd %d, dwflags = %d", hwnd, item.dwFlags);
|
|
if ((item.dwFlags & SHOULDTIP) && IsWindow(hwnd))
|
|
{
|
|
#if defined(WINDOWS_ME)
|
|
DWORD exStyle;
|
|
|
|
exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
|
if (exStyle & WS_EX_RTLREADING)
|
|
lpttt->uFlags |= TTF_RTLREADING;
|
|
else
|
|
lpttt->uFlags &= ~TTF_RTLREADING;
|
|
#endif
|
|
|
|
// BUGBUG If you're not unicode, you deserve to hang
|
|
|
|
#ifdef UNICODE
|
|
InternalGetWindowText(hwnd, lpttt->szText, ARRAYSIZE(lpttt->szText));
|
|
#else
|
|
GetWindowText(hwnd, lpttt->szText, ARRAYSIZE(lpttt->szText));
|
|
#endif
|
|
}
|
|
else
|
|
lpttt->szText[0] = 0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
return 0L;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Switch to a single task (Doesn't do anything if more than one item
|
|
// is selected.)
|
|
// Returns TRUE if a switch took place.
|
|
BOOL TaskList_SwitchToSelection(PTasks ptasks)
|
|
{
|
|
HWND hwndTask;
|
|
int iItem;
|
|
|
|
iItem = (int)SendMessage(ptasks->hwndTab,TCM_GETCURSEL, 0, 0);
|
|
if (iItem != -1)
|
|
{
|
|
hwndTask = (HWND)TabCtrl_GetItemHwnd(ptasks->hwndTab, iItem);
|
|
if (Window_IsNormal(hwndTask))
|
|
{
|
|
TaskList_SwitchToWindow(ptasks, hwndTask);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Window went away?
|
|
TaskList_DeleteItem(ptasks, iItem);
|
|
}
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CALLBACK TaskList_BuildCallback(HWND hwnd, LPARAM lParam)
|
|
{
|
|
PTasks ptasks = (PTasks)lParam;
|
|
if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !GetWindow(hwnd, GW_OWNER) &&
|
|
(!(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))) {
|
|
|
|
TaskList_AddWindow(ptasks, hwnd);
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
LRESULT _HandleCreate(HWND hwnd, LPVOID lpCreateParams)
|
|
{
|
|
PTasks ptasks = lpCreateParams;
|
|
|
|
SetWindowInt(hwnd, 0, (UINT)ptasks);
|
|
|
|
ptasks->hwnd = hwnd;
|
|
|
|
// Create a listbox in the client area.
|
|
ptasks->hwndTab = CreateWindow(WC_TABCONTROL, NULL,
|
|
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE |
|
|
TCS_FOCUSNEVER | TCS_OWNERDRAWFIXED | TCS_MULTILINE | TCS_BUTTONS | TCS_FIXEDWIDTH,
|
|
0,0,0,0, hwnd, (HMENU)IDC_FOLDERTABS, ptasks->hInstance, NULL);
|
|
|
|
if (ptasks->hwndTab)
|
|
{
|
|
TOOLINFO ti;
|
|
#ifndef USERDRAW
|
|
HIMAGELIST himl;
|
|
TabCtrl_SetPadding(ptasks->hwndTab, g_cxEdge, g_cyEdge);
|
|
#endif
|
|
TabCtrl_SetItemExtra(ptasks->hwndTab, (SIZEOF(TASKTABITEM) - SIZEOF(TC_ITEM)) + SIZEOF(HWND));
|
|
|
|
// initial size
|
|
TabCtrl_SetItemSize(ptasks->hwndTab, g_cxMinimized, g_cySize + 2 * g_cyEdge);
|
|
|
|
ti.cbSize = SIZEOF(ti);
|
|
ti.uFlags = TTF_IDISHWND;
|
|
ti.hwnd = ptasks->hwndTab;
|
|
ti.uId = (UINT)ptasks->hwndTab;
|
|
ti.lpszText = 0;
|
|
if (g_ts.hwndTrayTips) {
|
|
SendMessage(g_ts.hwndTrayTips, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
|
|
SendMessage(ptasks->hwndTab, TCM_SETTOOLTIPS, (WPARAM)g_ts.hwndTrayTips, 0L);
|
|
}
|
|
|
|
ptasks->WM_ShellHook = RegisterWindowMessage(c_szShellHook);
|
|
RegisterShellHook(hwnd, 3); // 3 = magic flag
|
|
|
|
#ifndef USERDRAW
|
|
himl = ImageList_Create(g_cxSmIcon, g_cySmIcon, TRUE, 0, 5);
|
|
TabCtrl_SetImageList(ptasks->hwndTab, himl);
|
|
#endif
|
|
|
|
// force getting of font, calc of metrics
|
|
_HandleWinIniChange(ptasks, 0, 0);
|
|
if (!SHRestricted(REST_STARTBANNER))
|
|
{
|
|
SetTimer(hwnd, IDT_BANNER, 5, NULL);
|
|
}
|
|
|
|
EnumWindows(TaskList_BuildCallback, (LPARAM)ptasks);
|
|
return 0; // success
|
|
}
|
|
|
|
// Failure.
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
LRESULT _HandleDestroy(PTasks ptasks)
|
|
{
|
|
RegisterShellHook(ptasks->hwnd, FALSE);
|
|
|
|
ptasks->hwnd = NULL;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int _HandleScroll(PTasks ptasks, UINT code, int nPos, UINT sb)
|
|
{
|
|
|
|
SCROLLINFO si;
|
|
|
|
si.cbSize = SIZEOF(SCROLLINFO);
|
|
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
|
|
GetScrollInfo(ptasks->hwnd, sb, &si);
|
|
si.nMax -= (si.nPage -1);
|
|
|
|
switch (code) {
|
|
case SB_BOTTOM:
|
|
nPos = si.nMax;
|
|
break;
|
|
|
|
case SB_TOP:
|
|
nPos = 0;
|
|
break;
|
|
|
|
case SB_ENDSCROLL:
|
|
nPos = si.nPos;
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
nPos = si.nPos + 1;
|
|
break;
|
|
|
|
case SB_LINEUP:
|
|
nPos = si.nPos - 1;
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
nPos = si.nPos + si.nPage;
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
nPos = si.nPos - si.nPage;
|
|
break;
|
|
|
|
case SB_THUMBPOSITION:
|
|
case SB_THUMBTRACK:
|
|
break;
|
|
}
|
|
if (nPos > (int)(si.nMax))
|
|
nPos = si.nMax;
|
|
if (nPos < 0 )
|
|
nPos = 0;
|
|
|
|
SetScrollPos(ptasks->hwnd, sb, nPos, TRUE);
|
|
|
|
return nPos;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
LRESULT _HandleVScroll(PTasks ptasks, UINT code, int nPos)
|
|
{
|
|
RECT rcItem;
|
|
int cyRow;
|
|
|
|
nPos = _HandleScroll(ptasks, code, nPos, SB_VERT);
|
|
|
|
TabCtrl_GetItemRect(ptasks->hwndTab, 0, &rcItem);
|
|
cyRow = RECTHEIGHT(rcItem) + g_cyTabSpace;
|
|
SetWindowPos(ptasks->hwndTab, 0, 0, -nPos * cyRow , 0, 0, SWP_NOACTIVATE | SWP_NOSIZE |SWP_NOZORDER);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT _HandleHScroll(PTasks ptasks, UINT code, int nPos)
|
|
{
|
|
RECT rcItem;
|
|
int cxRow;
|
|
|
|
nPos = _HandleScroll(ptasks, code, nPos, SB_HORZ);
|
|
|
|
TabCtrl_GetItemRect(ptasks->hwndTab, 0, &rcItem);
|
|
cxRow = RECTWIDTH(rcItem) + g_cyTabSpace;
|
|
SetWindowPos(ptasks->hwndTab, 0, -nPos * cxRow, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE |SWP_NOZORDER);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
LRESULT _HandleSize(PTasks ptasks, UINT fwSizeType)
|
|
{
|
|
// Make the listbox fill the parent;
|
|
if (fwSizeType != SIZE_MINIMIZED)
|
|
{
|
|
CheckSize(ptasks, TRUE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Have the task list show the given window.
|
|
// NB Ignore taskman itself.
|
|
LRESULT _HandleActivate(PTasks ptasks, HWND hwndActive)
|
|
{
|
|
|
|
if (Window_IsNormal(hwndActive)) {
|
|
TaskList_SelectWindow(ptasks, hwndActive);
|
|
} else
|
|
TabCtrl_SetCurSel(ptasks->hwndTab, -1);
|
|
|
|
if (hwndActive) {
|
|
ENTERCRITICAL;
|
|
g_ts.hwndLastActive = hwndActive;
|
|
LEAVECRITICAL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void _HandleOtherWindowDestroyed(PTasks ptasks, HWND hwndDestroyed)
|
|
{
|
|
int i;
|
|
MSG msg;
|
|
|
|
if (PeekMessage(&msg, NULL, TM_WINDOWDESTROYED, TM_WINDOWDESTROYED,
|
|
PM_NOREMOVE) && msg.hwnd==ptasks->hwnd)
|
|
{
|
|
// Don's use ShowWindow(SW_HIDE) since we don't want a repaint until
|
|
// we are all done
|
|
SetWindowStyleBit(ptasks->hwndTab, WS_VISIBLE, 0);
|
|
}
|
|
else
|
|
{
|
|
if (!(GetWindowLong(ptasks->hwndTab, GWL_STYLE) & WS_VISIBLE))
|
|
ShowWindow(ptasks->hwndTab, SW_SHOWNORMAL);
|
|
}
|
|
|
|
// Look for the destoyed window.
|
|
i = FindItem(ptasks, hwndDestroyed);
|
|
if (i != -1)
|
|
TaskList_DeleteItem(ptasks, i);
|
|
|
|
if (g_ts.pPositions)
|
|
TrayHandleWindowDestroyed(hwndDestroyed);
|
|
|
|
if (g_ts.hwndLastActive == hwndDestroyed) {
|
|
ENTERCRITICAL;
|
|
if (g_ts.hwndLastActive == hwndDestroyed) {
|
|
g_ts.hwndLastActive = NULL;
|
|
}
|
|
LEAVECRITICAL;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void _HandleOverflow(PTasks ptasks)
|
|
{
|
|
int i;
|
|
|
|
BOOL fFoundDestroyedItems = FALSE;
|
|
HWND hwnd;
|
|
|
|
for (i = (int)TabCtrl_GetItemCount(ptasks->hwndTab) - 1; i >= 0; i--)
|
|
{
|
|
hwnd = (HWND)TabCtrl_GetItemHwnd(ptasks->hwndTab, i);
|
|
if (!IsWindow(hwnd))
|
|
{
|
|
if (!fFoundDestroyedItems)
|
|
{
|
|
// Don's use ShowWindow(SW_HIDE) since we don't want a repaint until
|
|
// we are all done
|
|
SetWindowStyleBit(ptasks->hwndTab, WS_VISIBLE, 0);
|
|
fFoundDestroyedItems = TRUE;
|
|
}
|
|
|
|
// And delete this item...
|
|
TaskList_DeleteItem(ptasks, i);
|
|
}
|
|
}
|
|
|
|
// If we deleted items call off to destroy stuff out of save list
|
|
if (fFoundDestroyedItems)
|
|
{
|
|
ShowWindow(ptasks->hwndTab, SW_SHOWNORMAL);
|
|
if (g_ts.pPositions)
|
|
TrayHandleWindowDestroyed(NULL);
|
|
}
|
|
|
|
}
|
|
|
|
void _HandleOtherWindowCreated(PTasks ptasks, HWND hwndCreated)
|
|
{
|
|
MSG msg;
|
|
|
|
while (PeekMessage(&msg, NULL, TM_WINDOWDESTROYED, TM_WINDOWDESTROYED, PM_REMOVE)) {
|
|
_HandleOtherWindowDestroyed(ptasks, (HWND)msg.lParam);
|
|
}
|
|
TaskList_AddWindow(ptasks, hwndCreated);
|
|
}
|
|
|
|
void _HandleGetMinRect(PTasks ptasks, HWND hwndShell, LPPOINTS lprc)
|
|
{
|
|
int i;
|
|
RECT rc;
|
|
RECT rcTask;
|
|
|
|
i = FindItem(ptasks, hwndShell);
|
|
if (i == -1)
|
|
return;
|
|
|
|
// Found it in our list.
|
|
TabCtrl_GetItemRect(ptasks->hwndTab, i, &rc);
|
|
|
|
MapWindowPoints(ptasks->hwndTab, HWND_DESKTOP, (LPPOINT)&rc, 2);
|
|
lprc[0].x = (short)rc.left;
|
|
lprc[0].y = (short)rc.top;
|
|
lprc[1].x = (short)rc.right;
|
|
lprc[1].y = (short)rc.bottom;
|
|
|
|
// make sure the rect is within out client area
|
|
GetClientRect(ptasks->hwnd, &rcTask);
|
|
MapWindowPoints(ptasks->hwnd, HWND_DESKTOP, (LPPOINT)&rcTask, 2);
|
|
if (lprc[0].x < rcTask.left) {
|
|
lprc[1].x = lprc[0].x = (short)rcTask.left;
|
|
lprc[1].x++;
|
|
}
|
|
if (lprc[0].x > rcTask.right) {
|
|
lprc[1].x = lprc[0].x = (short)rcTask.right;
|
|
lprc[1].x++;
|
|
}
|
|
if (lprc[0].y < rcTask.top) {
|
|
lprc[1].y = lprc[0].y = (short)rcTask.top;
|
|
lprc[1].y++;
|
|
}
|
|
if (lprc[0].y > rcTask.bottom) {
|
|
lprc[1].y = lprc[0].y = (short)rcTask.bottom;
|
|
lprc[1].y++;
|
|
}
|
|
}
|
|
|
|
void RedrawItem(PTasks ptasks, HWND hwndShell, WPARAM code )
|
|
{
|
|
TOOLINFO ti;
|
|
int i = FindItem(ptasks, hwndShell);
|
|
|
|
ti.cbSize = SIZEOF(ti);
|
|
if (i != -1) {
|
|
RECT rc;
|
|
DWORD dwFlags;
|
|
|
|
// set the bit saying whether we should flash or not
|
|
dwFlags = TabCtrl_GetItemFlags(ptasks->hwndTab, i);
|
|
if (((code == HSHELL_FLASH) ? 1 : 0) !=
|
|
((dwFlags & SHOULDFLASH) ? 1 : 0)) {
|
|
|
|
// only do the set if this bit changed.
|
|
if (code == HSHELL_FLASH)
|
|
dwFlags |= SHOULDFLASH;
|
|
else
|
|
dwFlags &= ~SHOULDFLASH;
|
|
TabCtrl_SetItemFlags(ptasks->hwndTab, i, dwFlags);
|
|
}
|
|
|
|
if (TabCtrl_GetItemRect(ptasks->hwndTab, i, &rc)) {
|
|
InflateRect(&rc, -g_cxEdge, -g_cyEdge);
|
|
RedrawWindow(ptasks->hwndTab, &rc, NULL, RDW_INVALIDATE);
|
|
}
|
|
|
|
ti.hwnd = ptasks->hwndTab;
|
|
ti.uId = i;
|
|
ti.lpszText = LPSTR_TEXTCALLBACK;
|
|
SendMessage(g_ts.hwndTrayTips, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// We get notification about activation etc here. This saves having
|
|
// a fine-grained timer.
|
|
LRESULT _HandleShellHook(PTasks ptasks, int code, LPARAM lParam)
|
|
{
|
|
#define hwndShell ((HWND)lParam)
|
|
#define shiHwndShell ((HWND)((LPSHELLHOOKINFO)lParam)->hwnd)
|
|
#define shiLpRect ((LPPOINTS)&((LPSHELLHOOKINFO)lParam)->rc)
|
|
|
|
//
|
|
// Too noisy, use your private flag
|
|
//
|
|
#ifdef YOUR_PRIVATE_DEBUG_FLAG
|
|
DebugMsg(DM_TRACE, TEXT("_HandleShellHook %d %x"), code, lParam);
|
|
#endif
|
|
|
|
// Tell library function that we have processed this message.
|
|
RegisterShellHook(ptasks->hwnd, 5);
|
|
|
|
|
|
switch (code) {
|
|
case HSHELL_GETMINRECT:
|
|
_HandleGetMinRect(ptasks, shiHwndShell, shiLpRect);
|
|
return TRUE;
|
|
|
|
case HSHELL_WINDOWACTIVATED:
|
|
case HSHELL_RUDEAPPACTIVATED:
|
|
{
|
|
BOOL fFullScreen;
|
|
|
|
// we're in normal mode if
|
|
// 1) user tells us we are or
|
|
// 2) the window they tell us is valid, has a sysmenu and we're in auto-hide
|
|
// 3) or the tray is the dude being activated
|
|
if ((code == HSHELL_WINDOWACTIVATED) ||
|
|
|
|
(hwndShell && (g_ts.uAutoHide & AH_ON) &&
|
|
GetWindowLong(hwndShell, GWL_STYLE) & WS_SYSMENU) ||
|
|
|
|
(!hwndShell && (GetForegroundWindow() == v_hwndTray))) {
|
|
|
|
fFullScreen = FALSE;
|
|
|
|
} else {
|
|
|
|
fFullScreen = TRUE;
|
|
|
|
}
|
|
|
|
Tray_HandleFullScreenApp(fFullScreen, hwndShell);
|
|
// NB - We shouldn't need to do this but we're getting rude-app activation
|
|
// msgs when there aren't any.
|
|
_HandleActivate(ptasks, hwndShell);
|
|
break;
|
|
}
|
|
|
|
case HSHELL_WINDOWCREATED:
|
|
_HandleOtherWindowCreated(ptasks, hwndShell);
|
|
break;
|
|
|
|
case HSHELL_WINDOWDESTROYED:
|
|
if (!PostMessage(ptasks->hwnd, TM_WINDOWDESTROYED, 0, (LPARAM)hwndShell))
|
|
{
|
|
_HandleOtherWindowDestroyed(ptasks, hwndShell);
|
|
}
|
|
break;
|
|
|
|
case HSHELL_ACTIVATESHELLWINDOW:
|
|
SwitchToThisWindow(v_hwndTray, TRUE);
|
|
SetForegroundWindow(v_hwndTray);
|
|
break;
|
|
|
|
case HSHELL_TASKMAN:
|
|
|
|
//
|
|
// On NT, we've arranged for winlogon/user to send a -1 lParam to indicate
|
|
// that the real task list should be displayed (normally the lParam is
|
|
// the hwnd)
|
|
//
|
|
|
|
#if defined(WINNT)
|
|
if (-1 == (ULONG) lParam)
|
|
{
|
|
RunSystemMonitor();
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
PostMessage(v_hwndTray, TM_ACTASTASKSW, 0, 0L);
|
|
#if defined(WINNT)
|
|
}
|
|
#endif
|
|
|
|
return TRUE;
|
|
|
|
#ifdef USE_SYSMENU_TIMEOUT
|
|
case HSHELL_SYSMENU:
|
|
_HandleSysMenu(ptasks,(HWND)lParam);
|
|
break;
|
|
#endif
|
|
|
|
case HSHELL_REDRAW:
|
|
case HSHELL_FLASH:
|
|
RedrawItem(ptasks, hwndShell, code);
|
|
break;
|
|
case HSHELL_OVERFLOW:
|
|
// maybe go and clean out the items which have no window anymore...
|
|
_HandleOverflow(ptasks);
|
|
break;
|
|
}
|
|
return 0;
|
|
|
|
#undef hwndShell
|
|
#undef shiHwndShell
|
|
#undef shiLpRect
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
LRESULT _HandleWinIniChange(PTasks ptasks, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (wParam == SPI_SETNONCLIENTMETRICS ||
|
|
((!wParam) && (!lParam || (lstrcmpi((LPTSTR)lParam, c_szMetrics) == 0)))) {
|
|
|
|
HFONT hfontTemp;
|
|
NONCLIENTMETRICS ncm;
|
|
|
|
int cyOld;
|
|
int cyNew;
|
|
RECT rc;
|
|
DWORD dwStuck;
|
|
|
|
/////// reset the font
|
|
ncm.cbSize = SIZEOF(ncm);
|
|
if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, SIZEOF(ncm), &ncm, 0))
|
|
return 0;
|
|
|
|
////// make the bold font
|
|
ncm.lfCaptionFont.lfWeight = FW_BOLD;
|
|
hfontTemp = CreateFontIndirect(&ncm.lfCaptionFont);
|
|
if (hfontTemp) {
|
|
if (g_hfontCapBold)
|
|
DeleteObject(g_hfontCapBold);
|
|
|
|
g_hfontCapBold = hfontTemp;
|
|
}
|
|
|
|
////// make the non-bold font
|
|
ncm.lfCaptionFont.lfWeight = FW_NORMAL;
|
|
hfontTemp = CreateFontIndirect(&ncm.lfCaptionFont);
|
|
if (hfontTemp) {
|
|
if (g_hfontCapNormal)
|
|
DeleteObject(g_hfontCapNormal);
|
|
|
|
g_hfontCapNormal = hfontTemp;
|
|
}
|
|
|
|
|
|
// verify the size of the buttons.
|
|
TabCtrl_GetItemRect(ptasks->hwndTab, 0, &rc);
|
|
cyOld = RECTHEIGHT(rc);
|
|
CheckSize(ptasks, TRUE);
|
|
TabCtrl_GetItemRect(ptasks->hwndTab, 0, &rc);
|
|
cyNew = RECTHEIGHT(rc);
|
|
|
|
dwStuck = Tray_GetStuckPlace();
|
|
if (STUCK_HORIZONTAL(dwStuck) && (cyOld != cyNew)) {
|
|
// if the size has changed, resize the tray,
|
|
|
|
// make sure it's at least one row height
|
|
GetWindowRect(v_hwndTray, &rc);
|
|
if (RECTHEIGHT(rc) < cyNew) {
|
|
if (rc.top <= 0)
|
|
rc.bottom = rc.top + cyNew;
|
|
else
|
|
rc.top = rc.bottom - cyNew;
|
|
}
|
|
SendMessage(v_hwndTray, WM_SIZING, 0, (LPARAM)&rc);
|
|
SetWindowPos(v_hwndTray, 0, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc),
|
|
SWP_NOACTIVATE | SWP_NOZORDER);
|
|
} else {
|
|
// otherwise just redraw it all
|
|
RedrawWindow(ptasks->hwndTab, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT _HandleSizing(PTasks ptasks, LPRECT lpRect)
|
|
{
|
|
int iHeight;
|
|
int iItemHeight;
|
|
RECT rcItem;
|
|
|
|
lpRect->bottom += g_cyEdge*2;
|
|
iHeight = RECTHEIGHT(*lpRect);
|
|
|
|
// full height of one row including y inter button spacing
|
|
TabCtrl_GetItemRect(ptasks->hwndTab, 0, &rcItem);
|
|
|
|
iItemHeight = RECTHEIGHT(rcItem) + g_cyTabSpace;
|
|
iHeight += iItemHeight/2;
|
|
iHeight -= (iHeight % iItemHeight);
|
|
if (iHeight > g_cyTabSpace)
|
|
iHeight -= g_cyTabSpace;
|
|
lpRect->bottom = lpRect->top + iHeight;
|
|
return 0;
|
|
}
|
|
|
|
BOOL _HandleDrawItem(PTasks ptasks, LPDRAWITEMSTRUCT lpdis)
|
|
{
|
|
UINT uDCFlags;
|
|
struct TaskExtra {
|
|
HWND hwnd;
|
|
DWORD dwFlags;
|
|
} *info = (struct TaskExtra*)lpdis->itemData;
|
|
BOOL fTruncated;
|
|
|
|
if (!Window_IsNormal(info->hwnd)) {
|
|
//_HandleOtherWindowDestroyed(ptasks, info->hwnd);
|
|
// our shell hook should have prevented this
|
|
//Assert(0);
|
|
} else {
|
|
|
|
if (info->dwFlags & SHOULDFLASH) {
|
|
uDCFlags = DC_ACTIVE;
|
|
} else {
|
|
uDCFlags =
|
|
DC_INBUTTON |
|
|
((lpdis->itemState & ODS_SELECTED) ? DC_ACTIVE : 0);
|
|
}
|
|
if (lpdis->itemState & ODS_SELECTED) {
|
|
lpdis->rcItem.bottom++;
|
|
lpdis->rcItem.top++;
|
|
}
|
|
|
|
fTruncated = !DrawCaptionTemp(info->hwnd, lpdis->hDC, &lpdis->rcItem,
|
|
(lpdis->itemState & ODS_SELECTED) ? g_hfontCapBold : g_hfontCapNormal,
|
|
NULL, NULL, uDCFlags | DC_TEXT | DC_ICON | DC_NOSENDMSG);
|
|
|
|
//DebugMsg(DM_TRACE, "DrawCaptionTemp did not return %d... was %d", fTruncated, info->dwFlags & SHOULDTIP);
|
|
|
|
// save away info on whether we should tool tip or not
|
|
if (fTruncated)
|
|
info->dwFlags |= SHOULDTIP;
|
|
else
|
|
info->dwFlags &= ~SHOULDTIP;
|
|
|
|
if (lpdis->itemState & ODS_SELECTED) {
|
|
COLORREF clr;
|
|
HBRUSH hbr;
|
|
|
|
// now draw in that one line
|
|
if (uDCFlags == DC_ACTIVE) {
|
|
clr = SetBkColor(lpdis->hDC, GetSysColor(COLOR_ACTIVECAPTION));
|
|
} else {
|
|
hbr = (HBRUSH)DefWindowProc(ptasks->hwndTab, WM_CTLCOLORSCROLLBAR, (WPARAM)lpdis->hDC, (LPARAM)ptasks->hwndTab);
|
|
hbr = SelectObject(lpdis->hDC, hbr);
|
|
}
|
|
|
|
lpdis->rcItem.top--;
|
|
lpdis->rcItem.bottom = lpdis->rcItem.top + 1;
|
|
ExtTextOut(lpdis->hDC, 0, 0, ETO_OPAQUE, &lpdis->rcItem, NULL, 0,NULL);
|
|
|
|
if (uDCFlags == DC_ACTIVE) {
|
|
SetBkColor(lpdis->hDC, clr);
|
|
} else {
|
|
SelectObject(lpdis->hDC, hbr);
|
|
}
|
|
}
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void TaskList_TaskTab(PTasks ptasks, UINT iIncr)
|
|
{
|
|
int i;
|
|
int iCount = TabCtrl_GetItemCount(ptasks->hwndTab);
|
|
if (iCount) {
|
|
if (GetFocus() != ptasks->hwndTab)
|
|
SetFocus(ptasks->hwndTab);
|
|
// make sure nothing is selected
|
|
if (TabCtrl_GetCurSel(ptasks->hwndTab) != -1)
|
|
TaskList_SelectWindow(ptasks, NULL);
|
|
|
|
i = TabCtrl_GetCurFocus(ptasks->hwndTab);
|
|
if (iIncr < 0 && i == -1)
|
|
i = 0;
|
|
i = (i + iIncr + iCount) % iCount;
|
|
TabCtrl_SetCurFocus(ptasks->hwndTab, i);
|
|
}
|
|
}
|
|
|
|
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PTasks ptasks = (PTasks)GetWindowInt(hwnd, 0);
|
|
PAINTSTRUCT ps;
|
|
LRESULT lres;
|
|
|
|
switch (msg) {
|
|
case WM_CREATE:
|
|
return _HandleCreate(hwnd, ((LPCREATESTRUCT)lParam)->lpCreateParams);
|
|
|
|
case WM_DESTROY:
|
|
return _HandleDestroy(ptasks);
|
|
|
|
case WM_SIZE:
|
|
return _HandleSize(ptasks, wParam);
|
|
|
|
case WM_DRAWITEM:
|
|
return _HandleDrawItem(ptasks, (LPDRAWITEMSTRUCT)lParam);
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
NukeBanner(ptasks);
|
|
break;
|
|
|
|
case WM_WININICHANGE:
|
|
NukeBanner(ptasks);
|
|
Cabinet_InitGlobalMetrics(wParam, (LPTSTR)lParam);
|
|
_HandleWinIniChange(ptasks, wParam, lParam);
|
|
return SendMessage(ptasks->hwndTab, WM_WININICHANGE, wParam, lParam);
|
|
|
|
case WM_SIZING:
|
|
return _HandleSizing(ptasks, (LPRECT)lParam);
|
|
|
|
// this keeps our window from comming to the front on button down
|
|
// instead, we activate the window on the up click
|
|
// we only want this for the tree and the view window
|
|
// (the view window does this itself)
|
|
case WM_MOUSEACTIVATE: {
|
|
POINT pt;
|
|
RECT rc;
|
|
|
|
GetCursorPos(&pt);
|
|
GetWindowRect(ptasks->hwnd, &rc);
|
|
|
|
if ((LOWORD(lParam) == HTCLIENT) && PtInRect(&rc, pt))
|
|
return MA_NOACTIVATE;
|
|
else
|
|
goto DoDefault;
|
|
}
|
|
|
|
case WM_SETFOCUS:
|
|
SetFocus(ptasks->hwndTab);
|
|
break;
|
|
|
|
case WM_VSCROLL:
|
|
return _HandleVScroll(ptasks, LOWORD(wParam), HIWORD(wParam));
|
|
|
|
case WM_HSCROLL:
|
|
return _HandleHScroll(ptasks, LOWORD(wParam), HIWORD(wParam));
|
|
|
|
case WM_NOTIFY:
|
|
return TaskList_HandleNotify(ptasks, (LPNMHDR)lParam);
|
|
|
|
case WM_NCHITTEST:
|
|
lres = DefWindowProc(hwnd, msg, wParam, lParam);
|
|
if (lres == HTVSCROLL || lres == HTHSCROLL)
|
|
return lres;
|
|
else
|
|
return HTTRANSPARENT;
|
|
|
|
case WM_TIMER:
|
|
if (wParam == IDT_BANNER)
|
|
DrawBanner(ptasks, NULL);
|
|
#ifdef USE_SYSMENU_TIMEOUT
|
|
if (wParam == IDT_SYSMENU)
|
|
_HandleSysMenuTimeout(ptasks);
|
|
#endif
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
if (LOWORD(wParam) == SC_CLOSE)
|
|
{
|
|
BOOL fForce = GetKeyState(VK_CONTROL) & (1 << 16) ? TRUE : FALSE;
|
|
EndTask(ptasks->hwndSysMenu, FALSE , fForce);
|
|
}
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
DrawBanner(ptasks, BeginPaint(ptasks->hwnd, &ps));
|
|
EndPaint(ptasks->hwnd, &ps);
|
|
break;
|
|
|
|
case TM_POSTEDRCLICK:
|
|
// wparam is handle to the apps window
|
|
TaskList_FakeSystemMenu(ptasks, (HWND)wParam, (DWORD)lParam);
|
|
break;
|
|
|
|
case TM_TASKTAB:
|
|
TaskList_TaskTab(ptasks, wParam);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
if (SHRestricted(REST_NOTRAYCONTEXTMENU)) {
|
|
break;
|
|
}
|
|
|
|
// if we didn't find an item to put the sys menu up for, then
|
|
// pass on the WM_CONTExTMENU message
|
|
if (!TaskList_PostFakeSystemMenu(ptasks, lParam))
|
|
goto DoDefault;
|
|
DebugMsg(DM_TRACE, TEXT("Task GOT CONTEXT MENU!"));
|
|
break;
|
|
|
|
case TM_WINDOWDESTROYED:
|
|
_HandleOtherWindowDestroyed(ptasks, (HWND)lParam);
|
|
break;
|
|
|
|
case TM_SYSMENUCOUNT:
|
|
return ptasks->iSysMenuCount;
|
|
|
|
default:
|
|
DoDefault:
|
|
if ((ptasks != NULL) && (msg == ptasks->WM_ShellHook))
|
|
return _HandleShellHook(ptasks, (int)wParam, lParam);
|
|
else
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CTasksShellView_QueryInterface(IShellView * psv, REFIID riid, LPVOID * ppvObj)
|
|
{
|
|
PTasks this = IToClass(CTasks, sv, psv);
|
|
|
|
// If we just want the same interface or an unknown one, return
|
|
// this guy
|
|
//
|
|
if (IsEqualIID(riid, &IID_IShellView) || IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*ppvObj = &(this->sv);
|
|
// this->sv.lpVtbl->AddRef(&this->sv);
|
|
CTasksShellView_AddRef(&this->sv);
|
|
return S_OK;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CTasksShellView_AddRef(IShellView * psv)
|
|
{
|
|
PTasks this = IToClass(CTasks, sv, psv);
|
|
|
|
this->cRef++;
|
|
return this->cRef;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CTasksShellView_Release(IShellView * psv)
|
|
{
|
|
PTasks this = IToClass(CTasks, sv, psv);
|
|
|
|
this->cRef--;
|
|
if (this->cRef > 0)
|
|
{
|
|
return this->cRef;
|
|
}
|
|
|
|
// this->sv.lpVtbl->DestroyViewWindow(&this->sv);
|
|
CTasksShellView_DestroyViewWindow(&this->sv);
|
|
|
|
LocalFree((HLOCAL)this);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
const TCHAR c_szTaskSwClass[] = TEXT("MSTaskSwWClass");
|
|
|
|
|
|
BOOL CTasks_RegisterWindowClass(HINSTANCE hInstance)
|
|
{
|
|
WNDCLASSEX wc;
|
|
|
|
wc.cbSize = SIZEOF(WNDCLASSEX);
|
|
|
|
if (GetClassInfoEx(hInstance, c_szTaskSwClass, &wc))
|
|
return TRUE;
|
|
|
|
wc.lpszClassName = c_szTaskSwClass;
|
|
wc.lpfnWndProc = MainWndProc;
|
|
wc.style = 0;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = SIZEOF(PTasks);
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.hIconSm = NULL;
|
|
|
|
if (RegisterClassEx(&wc))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
STDMETHODIMP CTasksShellView_GetWindow(LPSHELLVIEW psv, HWND *lphwnd)
|
|
{
|
|
PTasks this = IToClass(CTasks, sv, psv);
|
|
*lphwnd = this->hwnd;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTasksShellView_ContextSensitiveHelp(LPSHELLVIEW psv, BOOL fEnterMode)
|
|
{
|
|
// BUGBUG: Implement it later!
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CTasksShellView_EnableModeless(LPSHELLVIEW psv, BOOL fEnable)
|
|
{
|
|
// We have no modeless window to be enabled/disabled
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTasksShellView_Refresh(LPSHELLVIEW psv)
|
|
{
|
|
// No need to refresh.
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTasksShellView_CreateViewWindow(IShellView * psv, IShellView *lpPrevView,
|
|
LPCFOLDERSETTINGS lpfs, IShellBrowser * psb, RECT *prc, HWND *phWnd)
|
|
{
|
|
PTasks this = IToClass(CTasks, sv, psv);
|
|
HWND hwndParent;
|
|
|
|
if (this->hwnd)
|
|
return E_UNEXPECTED;
|
|
|
|
// We need to make sure to store this before doing the GetWindowRect
|
|
//
|
|
this->psb = psb;
|
|
// This should never fail
|
|
psb->lpVtbl->GetWindow(psb, &hwndParent);
|
|
|
|
this->hInstance = GetWindowInstance(hwndParent);
|
|
|
|
if (!CTasks_RegisterWindowClass(this->hInstance))
|
|
return E_OUTOFMEMORY;
|
|
|
|
// this sets this->hwnd
|
|
|
|
CreateWindowEx(0, c_szTaskSwClass, NULL,
|
|
WS_CHILD | WS_VISIBLE,// | WS_CLIPCHILDREN,
|
|
0, 0, 0, 0, hwndParent, NULL, this->hInstance, (CTasks *)this);
|
|
|
|
*phWnd = this->hwnd;
|
|
return this->hwnd ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CTasksShellView_DestroyViewWindow(IShellView * psv)
|
|
{
|
|
PTasks this = IToClass(CTasks, sv, psv);
|
|
BOOL fSuccess = FALSE;
|
|
|
|
if (this->hwnd)
|
|
{
|
|
fSuccess = DestroyWindow(this->hwnd);
|
|
this->hwnd = NULL;
|
|
}
|
|
|
|
return fSuccess ? S_OK : E_UNEXPECTED;
|
|
}
|
|
|
|
STDMETHODIMP CTasksShellView_UIActivate(LPSHELLVIEW psv, UINT uState)
|
|
{
|
|
// No need to implement this.
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTasksShellView_GetCurrentInfo(IShellView * psv, LPFOLDERSETTINGS lpfs)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CTasksShellView_TranslateAccelerator(LPSHELLVIEW psv, LPMSG lpmsg)
|
|
{
|
|
// We have no accelerator for this guy.
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CTasksShellView_SV_AddViewOptionPages(IShellView *psv, DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
|
|
{
|
|
|
|
//
|
|
// Currently no pages to add
|
|
//
|
|
return ResultFromShort(0);
|
|
}
|
|
|
|
//
|
|
// Member: CTasksShellView::SaveViewState
|
|
//
|
|
HRESULT STDMETHODCALLTYPE CTasksShellView_SV_SaveViewState(IShellView *psv)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//
|
|
// Member: CTasksShellView::SelectItem
|
|
//
|
|
HRESULT STDMETHODCALLTYPE CTasksShellView_SelectItem(IShellView * psv, LPCITEMIDLIST pidlItem, BOOL fSelect)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
#pragma data_seg(".text", "CODE")
|
|
const IShellViewVtbl s_SVVtbl =
|
|
{
|
|
CTasksShellView_QueryInterface,
|
|
CTasksShellView_AddRef,
|
|
CTasksShellView_Release,
|
|
|
|
CTasksShellView_GetWindow,
|
|
CTasksShellView_ContextSensitiveHelp,
|
|
CTasksShellView_TranslateAccelerator,
|
|
CTasksShellView_EnableModeless,
|
|
CTasksShellView_UIActivate,
|
|
CTasksShellView_Refresh,
|
|
|
|
CTasksShellView_CreateViewWindow,
|
|
CTasksShellView_DestroyViewWindow,
|
|
CTasksShellView_GetCurrentInfo,
|
|
CTasksShellView_SV_AddViewOptionPages,
|
|
CTasksShellView_SV_SaveViewState,
|
|
CTasksShellView_SelectItem,
|
|
};
|
|
#pragma data_seg()
|
|
|
|
STDAPI Tasks_CreateInstance(REFIID riid, void **ppv)
|
|
{
|
|
HRESULT hres;
|
|
PTasks this = (PTasks)LocalAlloc(LPTR, SIZEOF(*this));
|
|
if (!this)
|
|
return E_OUTOFMEMORY; // error
|
|
|
|
this->sv.lpVtbl = (IShellViewVtbl *) &s_SVVtbl;
|
|
|
|
this->cRef = 1;
|
|
|
|
hres = CTasksShellView_QueryInterface(&this->sv, riid, ppv);
|
|
|
|
CTasksShellView_Release(&this->sv);
|
|
|
|
return hres;
|
|
}
|
|
|
|
#ifdef RANDOM_BANNERS
|
|
BOOL PickBanner(PTasks ptasks)
|
|
{
|
|
RECT rc;
|
|
|
|
if (ptasks->fBannerSuspend)
|
|
return FALSE;
|
|
|
|
GetClientRect(ptasks->hwnd, &rc);
|
|
ptasks->xBanner = rc.right;
|
|
ptasks->dxBanner = -10;
|
|
|
|
if (!ptasks->fBannerRandom) {
|
|
ptasks->iBannerRes = IDS_BANNERFIRST;
|
|
} else {
|
|
int irand;
|
|
#define NUM_BANNERS 12
|
|
#define RANDOM_RANGE 512
|
|
|
|
// get an evenly distributed range from 0-RANDOM_RANGE
|
|
irand = (GetTickCount() / 1024) % RANDOM_RANGE;
|
|
|
|
// chance of getting a message is NUM_BANNERS / RANDOM_RANGE
|
|
if (irand < NUM_BANNERS)
|
|
ptasks->iBannerRes = irand + IDS_BANNERFIRST + 1;
|
|
else {
|
|
NukeBanner(ptasks);
|
|
return FALSE;
|
|
}
|
|
}
|
|
ptasks->cxBanner = -1;
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
void GetNewLocation(PTasks ptasks)
|
|
{
|
|
if (ptasks->iBannerBounce > 0) {
|
|
if ((ptasks->xBanner >= (20 + (3 * ptasks->iBannerBounce))) &&
|
|
(ptasks->dxBanner > -3)) {
|
|
|
|
ptasks->dxBanner--;
|
|
|
|
} else if ((ptasks->xBanner >= (35 + (3 * ptasks->iBannerBounce))) &&
|
|
(ptasks->dxBanner > 0)
|
|
)
|
|
ptasks->dxBanner = -(3 + ptasks->iBannerBounce);
|
|
else if ((ptasks->xBanner <= 4) && (ptasks->dxBanner < 0)) {
|
|
ptasks->dxBanner = (3 + ptasks->iBannerBounce);
|
|
ptasks->xBanner = -ptasks->dxBanner;
|
|
ptasks->iBannerBounce--;
|
|
}
|
|
} else if (ptasks->xBanner <= 0) {
|
|
if (!ptasks->xBanner) {
|
|
KillTimer(ptasks->hwnd, IDT_BANNER);
|
|
ptasks->iBannerBounce = -1;
|
|
}
|
|
ptasks->xBanner = 0;
|
|
return;
|
|
} else {
|
|
|
|
if (ptasks->xBanner <= 35)
|
|
ptasks->iBannerBounce = 2;
|
|
}
|
|
ptasks->xBanner += ptasks->dxBanner;
|
|
|
|
}
|
|
|
|
void SetWindowStyleBit(HWND hWnd, DWORD dwBit, DWORD dwValue)
|
|
{
|
|
DWORD dwStyle;
|
|
|
|
dwStyle = GetWindowLong(hWnd, GWL_STYLE);
|
|
if ((dwStyle & dwBit) != dwValue) {
|
|
dwStyle ^= dwBit;
|
|
SetWindowLong(hWnd, GWL_STYLE, dwStyle);
|
|
}
|
|
}
|
|
|
|
void NukeBanner(PTasks ptasks)
|
|
{
|
|
#ifdef RANDOM_BANNERS
|
|
if (!ptasks->fBannerSuspend) {
|
|
RECT rc;
|
|
|
|
GetClientRect(ptasks->hwnd, &rc);
|
|
rc.bottom = ptasks->cyBanner + 2 * g_cyEdge;
|
|
ptasks->fBannerSuspend = TRUE;
|
|
KillTimer(ptasks->hwnd, IDT_BANNER);
|
|
RedrawWindow(ptasks->hwnd, &rc, NULL, RDW_INVALIDATE |RDW_ERASE | RDW_UPDATENOW);
|
|
SetWindowStyleBit(ptasks->hwnd, WS_CLIPCHILDREN, WS_CLIPCHILDREN);
|
|
ptasks->iBannerRes = 0;
|
|
}
|
|
#else
|
|
if (ptasks->iBannerBounce != -2) {
|
|
RECT rc;
|
|
KillTimer(ptasks->hwnd, IDT_BANNER);
|
|
RedrawWindow(ptasks->hwnd, &rc, NULL, RDW_INVALIDATE |RDW_ERASE | RDW_UPDATENOW);
|
|
SetWindowStyleBit(ptasks->hwnd, WS_CLIPCHILDREN, WS_CLIPCHILDREN);
|
|
if (ptasks->hdcBanner) {
|
|
DeleteDC(ptasks->hdcBanner);
|
|
ptasks->hdcBanner = NULL;
|
|
}
|
|
if (ptasks->hbmBanner) {
|
|
DeleteBitmap(ptasks->hbmBanner);
|
|
ptasks->hbmBanner = NULL;
|
|
}
|
|
ptasks->iBannerBounce = -2;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef RANDOM_BANNERS
|
|
void ResurrectBanner(PTasks ptasks)
|
|
{
|
|
if (ptasks->fBannerSuspend) {
|
|
ptasks->fBannerSuspend = 0;
|
|
ptasks->fBannerRandom = TRUE;
|
|
SetWindowStyleBit(ptasks->hwnd, WS_CLIPCHILDREN, 0);
|
|
SetTimer(ptasks->hwnd, IDT_BANNER, 5, NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void BltBanner(PTasks ptasks, HDC hdc)
|
|
{
|
|
BitBlt(hdc, ptasks->xBanner, 2*g_cyEdge, ptasks->cxBanner, ptasks->cyBanner,
|
|
ptasks->hdcBanner, 0, 0, SRCCOPY);
|
|
}
|
|
|
|
#define abs(x) (((x) < 0) ? -x : x)
|
|
void ScrollBanner(PTasks ptasks)
|
|
{
|
|
RECT rc;
|
|
RECT rcClip;
|
|
int dxBanner = ptasks->xBanner - ptasks->xBannerOld ;
|
|
int dxAbs = abs(dxBanner);
|
|
|
|
if (!ptasks->xBannerOld && ptasks->xBanner > 100) // ignore first
|
|
return;
|
|
|
|
#ifdef TESTBANNER
|
|
DebugMsg(DM_TRACE, TEXT("ScrollBanner, %d, %d"), ptasks->xBanner, ptasks->xBannerOld);
|
|
#endif
|
|
// now draw it
|
|
GetClientRect(ptasks->hwnd, &rc);
|
|
rc.bottom = ptasks->cyBanner + 2*g_cyEdge;
|
|
rcClip.left = ptasks->xBannerOld - dxAbs;
|
|
rcClip.right = rcClip.left + ptasks->cxBanner + dxAbs;
|
|
rcClip.left = max(rcClip.left, rc.left);
|
|
rcClip.right = min(rcClip.right, rc.right);
|
|
|
|
rcClip.top = rc.top;
|
|
rcClip.bottom = rc.bottom;
|
|
ScrollWindowEx(ptasks->hwnd, dxBanner, 0, &rcClip, NULL, NULL, NULL,
|
|
SW_INVALIDATE | SW_ERASE);
|
|
}
|
|
|
|
BOOL MakeBannerBitmap(PTasks ptasks)
|
|
{
|
|
BITMAP bm;
|
|
HBITMAP hbmPointer = NULL;
|
|
HDC hdcPointer = NULL;
|
|
TCHAR szBuffer[80];
|
|
HDC hdcUse = NULL;
|
|
HBITMAP hbmSave2;
|
|
SIZE size = {0,0};
|
|
RECT rc;
|
|
BOOL ret = FALSE;
|
|
HDC hdcDesk;
|
|
// get the string.
|
|
|
|
if (!LoadString(hinstCabinet, IDS_BANNERFIRST, szBuffer, ARRAYSIZE(szBuffer)))
|
|
return FALSE;
|
|
|
|
hbmPointer = LoadImage(hinstCabinet, MAKEINTRESOURCE(IDB_POINTER),
|
|
IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
|
|
if (!hbmPointer || (SIZEOF(BITMAP) != GetObject(hbmPointer, SIZEOF(bm), &bm))) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
hdcUse = CreateCompatibleDC(NULL);
|
|
hdcPointer = CreateCompatibleDC(NULL);
|
|
if (!hdcUse || !hdcPointer) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
SelectObject(hdcUse, g_hfontCapNormal);
|
|
GetTextExtentPoint(hdcUse, szBuffer, lstrlen(szBuffer), &size);
|
|
ptasks->cyBanner = (short)max(size.cy, bm.bmHeight);
|
|
ptasks->cxBanner = (short)(size.cx + bm.bmWidth);// plus maximum dx
|
|
|
|
|
|
hdcDesk = GetDC(NULL);
|
|
ptasks->hbmBanner = CreateCompatibleBitmap(hdcDesk, ptasks->cxBanner, ptasks->cyBanner);
|
|
ReleaseDC(NULL, hdcDesk);
|
|
if (!ptasks->hbmBanner) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
hbmSave2 = SelectBitmap(hdcPointer, hbmPointer);
|
|
SelectBitmap(hdcUse, ptasks->hbmBanner);
|
|
|
|
rc.top = rc.left = 0;
|
|
rc.right = ptasks->cxBanner;
|
|
rc.bottom = ptasks->cyBanner;
|
|
SetBkColor(hdcUse, GetSysColor(COLOR_BTNFACE));
|
|
SetTextColor(hdcUse, GetSysColor(COLOR_BTNTEXT));
|
|
|
|
ExtTextOut(hdcUse, bm.bmWidth, 00, ETO_OPAQUE, &rc, szBuffer, lstrlen(szBuffer), NULL);
|
|
BitBlt(hdcUse, 0, (ptasks->cyBanner - bm.bmHeight)/2, bm.bmWidth, bm.bmHeight,
|
|
hdcPointer, 0, 0, SRCCOPY);
|
|
|
|
SelectBitmap(hdcPointer, hbmSave2);
|
|
ptasks->hdcBanner = hdcUse;
|
|
hdcUse = NULL;
|
|
|
|
|
|
GetClientRect(ptasks->hwnd, &rc);
|
|
ptasks->xBanner = (short)rc.right;
|
|
ptasks->dxBanner = -10;
|
|
|
|
ret = TRUE;
|
|
|
|
Cleanup:
|
|
if (hdcUse)
|
|
DeleteDC(hdcUse);
|
|
|
|
if (hdcPointer)
|
|
DeleteDC(hdcPointer);
|
|
|
|
DeleteBitmap(hbmPointer);
|
|
return ret;
|
|
}
|
|
|
|
void DrawBanner(PTasks ptasks, HDC hdc)
|
|
{
|
|
DWORD dwStuck;
|
|
BOOL fNewLocation = !((BOOL)hdc);
|
|
|
|
// we've done it.. don't do it no mo
|
|
if (ptasks->iBannerBounce == -2)
|
|
return;
|
|
|
|
dwStuck = Tray_GetStuckPlace();
|
|
|
|
if (!STUCK_HORIZONTAL(dwStuck)) {
|
|
NukeBanner(ptasks);
|
|
return;
|
|
}
|
|
|
|
if (!ptasks->hbmBanner) {
|
|
if (!MakeBannerBitmap(ptasks)) {
|
|
NukeBanner(ptasks);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (fNewLocation) {
|
|
ptasks->xBannerOld = ptasks->xBanner;
|
|
GetNewLocation(ptasks);
|
|
ScrollBanner(ptasks);
|
|
} else {
|
|
UpdateWindow(ptasks->hwndTab);
|
|
BltBanner(ptasks, hdc);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL ShouldMinimize(HWND hwnd)
|
|
{
|
|
return IsWindowVisible(hwnd) &&
|
|
((GetWindowLong(hwnd, GWL_STYLE) & (WS_CAPTION | WS_SYSMENU)) == (WS_CAPTION | WS_SYSMENU)) &&
|
|
!IsMinimized(hwnd) && IsWindowEnabled(hwnd)
|
|
;
|
|
}
|
|
|
|
void SaveWindowPositions(UINT idRes);
|
|
|
|
BOOL CanMinimizeAll(HWND hwndView)
|
|
{
|
|
PTasks ptasks = (PTasks)GetWindowInt(hwndView, 0);
|
|
int i;
|
|
|
|
for ( i = (int)TabCtrl_GetItemCount(ptasks->hwndTab) -1; i >= 0; i--)
|
|
{
|
|
HWND hwnd = TabCtrl_GetItemHwnd(ptasks->hwndTab, i);
|
|
if (ShouldMinimize(hwnd))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void MinimizeAll(HWND hwndView)
|
|
{
|
|
PTasks ptasks = (PTasks)GetWindowInt(hwndView, 0);
|
|
LONG iAnimate;
|
|
ANIMATIONINFO ami;
|
|
int i;
|
|
|
|
// turn off animiations during this
|
|
ami.cbSize = SIZEOF(ANIMATIONINFO);
|
|
SystemParametersInfo(SPI_GETANIMATION, SIZEOF(ami), &ami, FALSE);
|
|
iAnimate = ami.iMinAnimate;
|
|
ami.iMinAnimate = FALSE;
|
|
SystemParametersInfo(SPI_SETANIMATION, SIZEOF(ami), &ami, FALSE);
|
|
|
|
SaveWindowPositions(IDS_MINIMIZEALL);
|
|
|
|
//
|
|
//EnumWindows(MinimizeEnumProc, 0);
|
|
// go through the tab control and minimize them.
|
|
// don't do enumwindows because we only want to minimize windows
|
|
// that are restorable via the tray
|
|
|
|
for ( i = (int)TabCtrl_GetItemCount(ptasks->hwndTab) -1; i >= 0; i--)
|
|
{
|
|
HWND hwnd = TabCtrl_GetItemHwnd(ptasks->hwndTab, i);
|
|
if (ShouldMinimize(hwnd))
|
|
ShowWindowAsync(hwnd, SW_SHOWMINNOACTIVE);
|
|
}
|
|
|
|
// restore animations state
|
|
ami.iMinAnimate = iAnimate;
|
|
SystemParametersInfo(SPI_SETANIMATION, SIZEOF(ami), &ami, FALSE);
|
|
}
|
|
|
|
int Task_HitTest(HWND hwndTask, POINTL ptl)
|
|
{
|
|
PTasks ptasks = (PTasks)GetWindowInt(hwndTask, 0);
|
|
if (ptasks)
|
|
{
|
|
TC_HITTESTINFO hitinfo = { {ptl.x, ptl.y}, TCHT_ONITEM };
|
|
ScreenToClient(ptasks->hwndTab, &hitinfo.pt);
|
|
return TabCtrl_HitTest(ptasks->hwndTab, &hitinfo);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void Task_SetCurSel(HWND hwndTask, int i)
|
|
{
|
|
PTasks ptasks = (PTasks)GetWindowInt(hwndTask, 0);
|
|
if (ptasks)
|
|
{
|
|
TabCtrl_SetCurSel(ptasks->hwndTab, i);
|
|
TaskList_SwitchToSelection(ptasks);
|
|
}
|
|
}
|