📄 taskswnd.c
字号:
NewBtnSize = (rcClient.right - (uiBtnsPerLine * tbm.cxButtonSpacing)) / uiBtnsPerLine;
/* Determine the minimum and maximum width of a button */
if (Horizontal)
uiMax = GetSystemMetrics(SM_CXMINIMIZED);
else
uiMax = rcClient.right;
uiMin = GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE));
if (NewBtnSize < uiMin)
NewBtnSize = uiMin;
if (NewBtnSize > uiMax)
NewBtnSize = uiMax;
This->ButtonSize.cx = NewBtnSize;
/* Recalculate how many buttons actually fit into one line */
uiBtnsPerLine = rcClient.right / (NewBtnSize + tbm.cxButtonSpacing);
if (uiBtnsPerLine == 0)
uiBtnsPerLine++;
This->TbButtonsPerLine = uiBtnsPerLine;
tbbi.cbSize = sizeof(tbbi);
tbbi.dwMask = TBIF_BYINDEX | TBIF_SIZE | TBIF_STATE;
tbbi.cx = (INT)NewBtnSize;
for (ui = 0; ui != This->ToolbarBtnCount; ui++)
{
tbbi.fsState = TBSTATE_ENABLED;
/* Check if we're updating a button that is the last one in the
line. If so, we need to set the TBSTATE_WRAP flag! */
if ((ui + 1) % uiBtnsPerLine == 0)
tbbi.fsState |= TBSTATE_WRAP;
if (This->ActiveTaskItem != NULL &&
This->ActiveTaskItem->Index == ui)
{
tbbi.fsState |= TBSTATE_CHECKED;
}
SendMessage(This->hWndToolbar,
TB_SETBUTTONINFO,
(WPARAM)ui,
(LPARAM)&tbbi);
}
#if 0
/* FIXME: Force the window to the correct position in case some idiot
did something to us */
SetWindowPos(This->hWndToolbar,
NULL,
0,
0,
rcClient.right, /* FIXME */
rcClient.bottom, /* FIXME */
SWP_NOACTIVATE | SWP_NOZORDER);
#endif
}
else
{
This->TbButtonsPerLine = 0;
This->ButtonSize.cx = 0;
}
}
TaskSwitchWnd_EndUpdate(This);
}
static BOOL CALLBACK
TaskSwitchWnd_EnumWindowsProc(IN HWND hWnd,
IN LPARAM lParam)
{
PTASK_SWITCH_WND This = (PTASK_SWITCH_WND)lParam;
/* 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) &&
!ITrayWindow_IsSpecialHWND(This->Tray,
hWnd))
{
/* Don't list popup windows and also no tool windows */
if (GetWindow(hWnd,
GW_OWNER) == NULL &&
!(GetWindowLong(hWnd,
GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
{
TaskSwitchWnd_AddTask(This,
hWnd);
}
}
return TRUE;
}
static LRESULT CALLBACK
TaskSwichWnd_ToolbarSubclassedProc(IN HWND hWnd,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam,
IN UINT_PTR uIdSubclass,
IN DWORD_PTR dwRefData)
{
LRESULT Ret;
Ret = DefSubclassProc(hWnd,
msg,
wParam,
lParam);
if (msg == WM_NCHITTEST && Ret == HTCLIENT)
{
POINT pt;
/* See if the mouse is on a button */
pt.x = (SHORT)LOWORD(lParam);
pt.y = (SHORT)HIWORD(lParam);
if (MapWindowPoints(HWND_DESKTOP,
hWnd,
&pt,
1) != 0 &&
(INT)SendMessage(hWnd,
TB_HITTEST,
0,
(LPARAM)&pt) < 0)
{
/* Make the control appear to be transparent outside of any buttons */
Ret = HTTRANSPARENT;
}
}
return Ret;
}
static VOID
TaskSwitchWnd_Create(IN OUT PTASK_SWITCH_WND This)
{
This->hWndToolbar = CreateWindowEx(0,
TOOLBARCLASSNAME,
szRunningApps,
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_LIST |
TBSTYLE_TRANSPARENT |
CCS_TOP | CCS_NORESIZE | CCS_NODIVIDER,
0,
0,
0,
0,
This->hWnd,
NULL,
hExplorerInstance,
NULL);
if (This->hWndToolbar != NULL)
{
SIZE BtnSize;
/* Identify the version we're using */
SendMessage(This->hWndToolbar,
TB_BUTTONSTRUCTSIZE,
sizeof(TBBUTTON),
0);
/* Calculate the default button size. Don't save this in This->ButtonSize.cx so that
the actual button width gets updated correctly on the first recalculation */
BtnSize.cx = GetSystemMetrics(SM_CXMINIMIZED);
This->ButtonSize.cy = BtnSize.cy = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE));
SendMessage(This->hWndToolbar,
TB_SETBUTTONSIZE,
0,
(LPARAM)MAKELONG(BtnSize.cx,
BtnSize.cy));
/* We don't want to see partially clipped buttons...not that we could see them... */
#if 1
SendMessage(This->hWndToolbar,
TB_SETEXTENDEDSTYLE,
0,
TBSTYLE_EX_HIDECLIPPEDBUTTONS);
#endif
/* Set proper spacing between buttons */
TaskSwitchWnd_UpdateTbButtonSpacing(This,
ITrayWindow_IsHorizontal(This->Tray),
0);
/* Register the shell hook */
This->ShellHookMsg = RegisterWindowMessage(TEXT("SHELLHOOK"));
RegisterShellHook(This->hWnd,
3); /* 1 if not NT! We're targeting NT so we don't care! */
/* Add all windows to the toolbar */
EnumWindows(TaskSwitchWnd_EnumWindowsProc,
(LPARAM)This);
/* Recalculate the button size */
TaskSwitchWnd_UpdateButtonsSize(This,
FALSE);
/* Subclass the toolbar control because it doesn't provide a
NM_NCHITTEST notification */
This->IsToolbarSubclassed = SetWindowSubclass(This->hWndToolbar,
TaskSwichWnd_ToolbarSubclassedProc,
TSW_TOOLBAR_SUBCLASS_ID,
(DWORD_PTR)This);
}
}
static VOID
TaskSwitchWnd_NCDestroy(IN OUT PTASK_SWITCH_WND This)
{
This->IsDestroying = TRUE;
/* Unregister the shell hook */
RegisterShellHook(This->hWnd,
FALSE);
TaskSwitchWnd_DeleteAllTasks(This);
}
static BOOL
TaskSwitchWnd_HandleAppCommand(IN OUT PTASK_SWITCH_WND This,
IN WPARAM wParam,
IN LPARAM lParam)
{
BOOL Ret = FALSE;
switch (GET_APPCOMMAND_LPARAM(lParam))
{
case APPCOMMAND_BROWSER_SEARCH:
Ret = SHFindFiles(NULL,
NULL);
break;
case APPCOMMAND_BROWSER_HOME:
case APPCOMMAND_LAUNCH_MAIL:
default:
DbgPrint("Shell app command %d unhandled!\n", (INT)GET_APPCOMMAND_LPARAM(lParam));
break;
}
return Ret;
}
static LRESULT
TaskSwitchWnd_HandleShellHookMsg(IN OUT PTASK_SWITCH_WND This,
IN WPARAM wParam,
IN LPARAM lParam)
{
BOOL Ret = FALSE;
switch ((INT)wParam)
{
case HSHELL_APPCOMMAND:
TaskSwitchWnd_HandleAppCommand(This,
wParam,
lParam);
Ret = TRUE;
break;
case HSHELL_WINDOWCREATED:
TaskSwitchWnd_AddTask(This,
(HWND)lParam);
Ret = TRUE;
break;
case HSHELL_WINDOWDESTROYED:
/* The window still exists! Delay destroying it a bit */
TaskSwitchWnd_DeleteTask(This,
(HWND)lParam);
Ret = TRUE;
break;
case HSHELL_ACTIVATESHELLWINDOW:
goto UnhandledShellMessage;
case HSHELL_RUDEAPPACTIVATED:
goto UnhandledShellMessage;
case HSHELL_WINDOWACTIVATED:
TaskSwitchWnd_ActivateTask(This,
(HWND)lParam);
Ret = TRUE;
break;
case HSHELL_GETMINRECT:
goto UnhandledShellMessage;
case HSHELL_FLASH:
TaskSwitchWnd_FlashTask(This,
(HWND)lParam);
Ret = TRUE;
break;
case HSHELL_REDRAW:
TaskSwitchWnd_RedrawTask(This,
(HWND)lParam);
Ret = TRUE;
break;
case HSHELL_TASKMAN:
case HSHELL_LANGUAGE:
case HSHELL_SYSMENU:
case HSHELL_ENDTASK:
case HSHELL_ACCESSIBILITYSTATE:
case HSHELL_WINDOWREPLACED:
case HSHELL_WINDOWREPLACING:
default:
{
static const struct {
INT msg;
LPCWSTR msg_name;
} hshell_msg[] = {
{HSHELL_WINDOWCREATED, L"HSHELL_WINDOWCREATED"},
{HSHELL_WINDOWDESTROYED, L"HSHELL_WINDOWDESTROYED"},
{HSHELL_ACTIVATESHELLWINDOW, L"HSHELL_ACTIVATESHELLWINDOW"},
{HSHELL_WINDOWACTIVATED, L"HSHELL_WINDOWACTIVATED"},
{HSHELL_GETMINRECT, L"HSHELL_GETMINRECT"},
{HSHELL_REDRAW, L"HSHELL_REDRAW"},
{HSHELL_TASKMAN, L"HSHELL_TASKMAN"},
{HSHELL_LANGUAGE, L"HSHELL_LANGUAGE"},
{HSHELL_SYSMENU, L"HSHELL_SYSMENU"},
{HSHELL_ENDTASK, L"HSHELL_ENDTASK"},
{HSHELL_ACCESSIBILITYSTATE, L"HSHELL_ACCESSIBILITYSTATE"},
{HSHELL_APPCOMMAND, L"HSHELL_APPCOMMAND"},
{HSHELL_WINDOWREPLACED, L"HSHELL_WINDOWREPLACED"},
{HSHELL_WINDOWREPLACING, L"HSHELL_WINDOWREPLACING"},
{HSHELL_RUDEAPPACTIVATED, L"HSHELL_RUDEAPPACTIVATED"},
};
int i, found;
UnhandledShellMessage:
for (i = 0, found = 0; i != sizeof(hshell_msg) / sizeof(hshell_msg[0]); i++)
{
if (hshell_msg[i].msg == (INT)wParam)
{
DbgPrint("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg[i].msg_name, lParam);
found = 1;
break;
}
}
if (!found)
{
DbgPrint("Shell message %d unhandled (lParam = 0x%p)!\n", (INT)wParam, lParam);
}
break;
}
}
return Ret;
}
static VOID
TaskSwitchWnd_EnableGrouping(IN OUT PTASK_SWITCH_WND This,
IN BOOL bEnable)
{
This->IsGroupingEnabled = bEnable;
/* Collapse or expand groups if neccessary */
TaskSwitchWnd_UpdateButtonsSize(This,
FALSE);
}
static LRESULT
TaskSwichWnd_HandleItemPaint(IN OUT PTASK_SWITCH_WND This,
IN OUT NMTBCUSTOMDRAW *nmtbcd)
{
HFONT hCaptionFont, hBoldCaptionFont;
LRESULT Ret = CDRF_DODEFAULT;
#if TASK_USE_DRAWCAPTIONTEMP != 0
UINT uidctFlags = DC_TEXT | DC_ICON | DC_NOSENDMSG;
#endif
if (!IS_TASKGROUP_PTR(nmtbcd->nmcd.lItemlParam))
{
PTASK_ITEM TaskItem = GET_TASKITEM_PTR(nmtbcd->nmcd.lItemlParam);
if (TaskItem != NULL && IsWindow(TaskItem->hWnd))
{
hCaptionFont = ITrayWindow_GetCaptionFonts(This->Tray,
&hBoldCaptionFont);
if (nmtbcd->nmcd.uItemState & CDIS_CHECKED)
hCaptionFont = hBoldCaptionFont;
#if TASK_USE_DRAWCAPTIONTEMP != 0
/* Make sure we don't draw on the button edges */
InflateRect(&nmtbcd->nmcd.rc,
-GetSystemMetrics(SM_CXEDGE),
-GetSystemMetrics(SM_CYEDGE));
if ((nmtbcd->nmcd.uItemState & CDIS_MARKED) && TaskItem->RenderFlashed)
{
/* This is a slight glitch. We have to move the rectangle so that
the button content appears to be pressed. However, when flashing
is enabled, we can see a light line at the top and left inner
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -