* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <precomp.h>
-
-/* By default we don't use DrawCaptionTemp() because it causes some minimal
- drawing glitches with the toolbar custom painting code */
-#define TASK_USE_DRAWCAPTIONTEMP 1
+#include "precomp.h"
/* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every
5 seconds */
struct
{
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
- /* DisplayTooltip is TRUE when the group button text didn't fit into
- the button. */
- DWORD DisplayTooltip : 1;
-
-#endif
-
DWORD IsCollapsed : 1;
};
};
HWND hWnd;
PTASK_GROUP Group;
INT Index;
-
-#if !(TASK_USE_DRAWCAPTIONTEMP != 0)
-
INT IconIndex;
-#endif
+
union
{
struct
{
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
- /* DisplayTooltip is TRUE when the window text didn't fit into the
- button. */
- DWORD DisplayTooltip : 1;
-
-#endif
-
/* IsFlashing is TRUE when the task bar item should be flashing. */
DWORD IsFlashing : 1;
PTASK_ITEM TaskItems;
PTASK_ITEM ActiveTaskItem;
+ HTHEME TaskBandTheme;
HWND hWndToolbar;
UINT TbButtonsPerLine;
WORD ToolbarBtnCount;
+ HIMAGELIST TaskIcons;
union
{
static VOID TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This,
IN BOOL bRedrawDisabled);
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
-#define TaskSwitchWnd_GetWndTextFromTaskItem(a,b) NULL
-
-#else /* !TASK_USE_DRAWCAPTIONTEMP */
-
static LPTSTR
TaskSwitchWnd_GetWndTextFromTaskItem(IN OUT PTASK_SWITCH_WND This,
IN PTASK_ITEM TaskItem)
return NULL;
}
-#endif
#if DUMP_TASKS != 0
static VOID
/* FIXME: Implement */
}
+static HICON
+TaskSwitchWnd_GetWndIcon(HWND hwnd)
+{
+ HICON hIcon = 0;
+
+ SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
+
+ if (!hIcon)
+ SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
+
+ if (!hIcon)
+ SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
+
+ if (!hIcon)
+ hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICONSM);
+
+ if (!hIcon)
+ hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICON);
+
+ return hIcon;
+}
static INT
TaskSwitchWnd_UpdateTaskItemButton(IN OUT PTASK_SWITCH_WND This,
IN PTASK_ITEM TaskItem)
{
TBBUTTONINFO tbbi;
+ HICON icon;
ASSERT(TaskItem->Index >= 0);
tbbi.cbSize = sizeof(tbbi);
- tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT;
+ tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT | TBIF_IMAGE;
tbbi.fsState = TBSTATE_ENABLED;
if (This->ActiveTaskItem == TaskItem)
tbbi.fsState |= TBSTATE_CHECKED;
+ if (TaskItem->RenderFlashed)
+ tbbi.fsState |= TBSTATE_MARKED;
+
/* 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 (This->TbButtonsPerLine != 0 &&
tbbi.pszText = TaskSwitchWnd_GetWndTextFromTaskItem(This,
TaskItem);
+ icon = TaskSwitchWnd_GetWndIcon(TaskItem->hWnd);
+ TaskItem->IconIndex = ImageList_ReplaceIcon(This->TaskIcons,
+ TaskItem->IconIndex,
+ icon);
+ tbbi.iImage = TaskItem->IconIndex;
+
if (!SendMessage(This->hWndToolbar,
TB_SETBUTTONINFO,
(WPARAM)TaskItem->Index,
return TaskItem->Index;
}
+static VOID
+TaskSwitchWnd_RemoveIcon(IN OUT PTASK_SWITCH_WND This,
+ IN PTASK_ITEM TaskItem)
+{
+ TBBUTTONINFO tbbi;
+ PTASK_ITEM currentTaskItem, LastItem;
+
+ if (TaskItem->IconIndex == -1)
+ return;
+
+ tbbi.cbSize = sizeof(tbbi);
+ tbbi.dwMask = TBIF_IMAGE;
+
+ currentTaskItem = This->TaskItems;
+ LastItem = currentTaskItem + This->TaskItemCount;
+ while (currentTaskItem != LastItem)
+ {
+ if (currentTaskItem->IconIndex > TaskItem->IconIndex)
+ {
+ currentTaskItem->IconIndex--;
+ tbbi.iImage = currentTaskItem->IconIndex;
+
+ SendMessage(This->hWndToolbar,
+ TB_SETBUTTONINFO,
+ currentTaskItem->Index,
+ (LPARAM)&tbbi);
+ }
+ currentTaskItem++;
+ }
+
+ ImageList_Remove(This->TaskIcons, TaskItem->IconIndex);
+}
+
static PTASK_ITEM
TaskSwitchWnd_FindLastTaskItemOfGroup(IN OUT PTASK_SWITCH_WND This,
IN PTASK_GROUP TaskGroup OPTIONAL,
{
TBBUTTON tbBtn;
INT iIndex;
+ HICON icon;
if (TaskItem->Index >= 0)
{
TaskItem->Group);
}
- tbBtn.iBitmap = 0;
+ icon = TaskSwitchWnd_GetWndIcon(TaskItem->hWnd);
+ TaskItem->IconIndex = ImageList_AddIcon(This->TaskIcons, icon);
+
+ tbBtn.iBitmap = TaskItem->IconIndex;
tbBtn.fsState = TBSTATE_ENABLED | TBSTATE_ELLIPSES;
tbBtn.fsStyle = BTNS_CHECK | BTNS_NOPREFIX | BTNS_SHOWTEXT;
tbBtn.dwData = TaskItem->Index;
{
TaskSwitchWnd_BeginUpdate(This);
+ TaskSwitchWnd_RemoveIcon(This, TaskItem);
iIndex = TaskItem->Index;
if (SendMessage(This->hWndToolbar,
TB_DELETEBUTTON,
/* Allocate a new task group */
TaskGroup = HeapAlloc(hProcessHeap,
- 0,
+ HEAP_ZERO_MEMORY,
sizeof(*TaskGroup));
if (TaskGroup != NULL)
{
- ZeroMemory(TaskGroup,
- sizeof(*TaskGroup));
-
TaskGroup->dwTaskCount = 1;
TaskGroup->dwProcessId = dwProcessId;
TaskGroup->Index = -1;
ASSERT(This->AllocatedTaskItems >= This->TaskItemCount);
- if (This->TaskItemCount != 0)
+ if (This->TaskItemCount == 0)
+ {
+ This->TaskItems = HeapAlloc(hProcessHeap,
+ 0,
+ TASK_ITEM_ARRAY_ALLOC * sizeof(*This->TaskItems));
+ if (This->TaskItems != NULL)
+ {
+ This->AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC;
+ }
+ else
+ return NULL;
+ }
+ else if (This->TaskItemCount >= This->AllocatedTaskItems)
{
PTASK_ITEM NewArray;
SIZE_T NewArrayLength, ActiveTaskItemIndex;
else
return NULL;
}
- else
- {
- This->TaskItems = HeapAlloc(hProcessHeap,
- 0,
- TASK_ITEM_ARRAY_ALLOC * sizeof(*This->TaskItems));
- if (This->TaskItems != NULL)
- {
- This->AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC;
- }
- else
- return NULL;
- }
return This->TaskItems + This->TaskItemCount++;
}
if (TaskItem != NULL)
TaskGroup = TaskItem->Group;
- if (This->IsGroupingEnabled && TaskGroup != NULL)
+ if (This->IsGroupingEnabled &&
+ TaskGroup != NULL &&
+ TaskGroup->IsCollapsed)
{
- if (TaskGroup->IsCollapsed)
- {
- /* FIXME */
- }
- else
- goto ChangeTaskItemButton;
+ /* FIXME */
+ return;
}
- else
+
+ if (ActiveTaskItem != NULL)
{
-ChangeTaskItemButton:
- if (ActiveTaskItem != NULL)
- {
- PTASK_GROUP ActiveTaskGroup;
+ PTASK_GROUP ActiveTaskGroup;
- if (ActiveTaskItem == TaskItem)
- return;
+ if (ActiveTaskItem == TaskItem)
+ return;
- ActiveTaskGroup = ActiveTaskItem->Group;
+ ActiveTaskGroup = ActiveTaskItem->Group;
- if (This->IsGroupingEnabled && ActiveTaskGroup != NULL)
- {
- if (ActiveTaskGroup->IsCollapsed)
- {
- if (ActiveTaskGroup == TaskGroup)
- return;
+ if (This->IsGroupingEnabled &&
+ ActiveTaskGroup != NULL &&
+ ActiveTaskGroup->IsCollapsed)
+ {
+ if (ActiveTaskGroup == TaskGroup)
+ return;
- /* FIXME */
- }
- else
- goto ChangeActiveTaskItemButton;
- }
- else
+ /* FIXME */
+ }
+ else
+ {
+ This->ActiveTaskItem = NULL;
+ if (ActiveTaskItem->Index >= 0)
{
-ChangeActiveTaskItemButton:
- This->ActiveTaskItem = NULL;
- if (ActiveTaskItem->Index >= 0)
- {
- TaskSwitchWnd_UpdateTaskItemButton(This,
- ActiveTaskItem);
- }
+ TaskSwitchWnd_UpdateTaskItemButton(This,
+ ActiveTaskItem);
}
}
+ }
- This->ActiveTaskItem = TaskItem;
+ This->ActiveTaskItem = TaskItem;
- if (TaskItem != NULL && TaskItem->Index >= 0)
- {
- TaskSwitchWnd_UpdateTaskItemButton(This,
- TaskItem);
- }
+ if (TaskItem != NULL && TaskItem->Index >= 0)
+ {
+ TaskSwitchWnd_UpdateTaskItemButton(This,
+ TaskItem);
}
}
TaskSwitchWnd_FlashTaskItem(IN OUT PTASK_SWITCH_WND This,
IN OUT PTASK_ITEM TaskItem)
{
- /* FIXME: Implement */
+ TaskItem->RenderFlashed = 1;
+ TaskSwitchWnd_UpdateTaskItemButton(This,
+ TaskItem);
}
static BOOL
else if (TaskItem->Index >= 0)
{
UpdateTaskItem:
+ TaskItem->RenderFlashed = 0;
TaskSwitchWnd_UpdateTaskItemButton(This,
TaskItem);
}
/* Don't list popup windows and also no tool windows */
if (GetWindow(hWnd,
GW_OWNER) == NULL &&
- !(GetWindowLongPtr(hWnd,
- GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
+ !(GetWindowLong(hWnd,
+ GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
{
TaskSwitchWnd_AddTask(This,
hWnd);
return Ret;
}
+static VOID
+TaskSwitchWnd_UpdateTheme(IN OUT PTASK_SWITCH_WND This)
+{
+ if (This->TaskBandTheme)
+ CloseThemeData(This->TaskBandTheme);
+
+ if (IsThemeActive())
+ This->TaskBandTheme = OpenThemeData(This->hWnd, L"TaskBand");
+ else
+ This->TaskBandTheme = NULL;
+}
+
static VOID
TaskSwitchWnd_Create(IN OUT PTASK_SWITCH_WND This)
{
HMODULE hShell32;
SIZE BtnSize;
+ SetWindowTheme(This->hWndToolbar, L"TaskBand", NULL);
+ TaskSwitchWnd_UpdateTheme(This);
/* Identify the version we're using */
SendMessage(This->hWndToolbar,
TB_BUTTONSTRUCTSIZE,
sizeof(TBBUTTON),
0);
+ This->TaskIcons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1000);
+ SendMessage(This->hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM)This->TaskIcons);
+
/* 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);
}
}
+ CloseThemeData(This->TaskBandTheme);
TaskSwitchWnd_DeleteAllTasks(This);
}
break;
case HSHELL_TASKMAN:
+ PostMessage(ITrayWindow_GetHWND(This->Tray), TWM_OPENSTARTMENU,0, 0);
+ break;
+
case HSHELL_LANGUAGE:
case HSHELL_SYSMENU:
case HSHELL_ENDTASK:
return FALSE;
}
+
+static VOID
+TaskSwitchWnd_HandleTaskItemRightClick(IN OUT PTASK_SWITCH_WND This,
+ IN OUT PTASK_ITEM TaskItem)
+{
+
+ HMENU hmenu = GetSystemMenu(TaskItem->hWnd, FALSE);
+
+ if (hmenu) {
+ POINT pt;
+ int cmd;
+ GetCursorPos(&pt);
+ cmd = TrackPopupMenu(hmenu, TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_RETURNCMD, pt.x, pt.y, 0, This->hWndToolbar, NULL);
+ if (cmd) {
+ SetForegroundWindow(TaskItem->hWnd); // reactivate window after the context menu has closed
+ PostMessage(TaskItem->hWnd, WM_SYSCOMMAND, cmd, 0);
+ }
+ }
+}
+
+static VOID
+TaskSwitchWnd_HandleTaskGroupRightClick(IN OUT PTASK_SWITCH_WND This,
+ IN OUT PTASK_GROUP TaskGroup)
+{
+ /* TODO: Show task group right click menu */
+}
+
+static BOOL
+TaskSwitchWnd_HandleButtonRightClick(IN OUT PTASK_SWITCH_WND This,
+ IN WORD wIndex)
+{
+ PTASK_ITEM TaskItem;
+ PTASK_GROUP TaskGroup;
+ if (This->IsGroupingEnabled)
+ {
+ TaskGroup = FindTaskGroupByIndex(This,
+ (INT)wIndex);
+ if (TaskGroup != NULL && TaskGroup->IsCollapsed)
+ {
+ TaskSwitchWnd_HandleTaskGroupRightClick(This,
+ TaskGroup);
+ return TRUE;
+ }
+ }
+
+ TaskItem = FindTaskItemByIndex(This,
+ (INT)wIndex);
+
+ if (TaskItem != NULL)
+ {
+ TaskSwitchWnd_HandleTaskItemRightClick(This,
+ TaskItem);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
static LRESULT
TaskSwichWnd_HandleItemPaint(IN OUT PTASK_SWITCH_WND This,
IN OUT NMTBCUSTOMDRAW *nmtbcd)
{
- HFONT hCaptionFont, hBoldCaptionFont;
LRESULT Ret = CDRF_DODEFAULT;
PTASK_GROUP TaskGroup;
PTASK_ITEM TaskItem;
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
- UINT uidctFlags = DC_TEXT | DC_ICON | DC_NOSENDMSG;
-
-#endif
TaskItem = FindTaskItemByIndex(This,
(INT)nmtbcd->nmcd.dwItemSpec);
TaskGroup = FindTaskGroupByIndex(This,
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
- border. We need to fill that area with the flashing color. Note
- that since we're using DrawCaptionTemp() the flashing color is
- COLOR_ACTIVECAPTION, not COLOR_HIGHLIGHT! */
- FillRect(nmtbcd->nmcd.hdc,
- &nmtbcd->nmcd.rc,
- (HBRUSH)(COLOR_ACTIVECAPTION + 1));
-
- /* Make the button content appear pressed. This however draws a bit
- into the right and bottom border of the button edge, making it
- look a bit odd. However, selecting a clipping region to prevent
- that from happening causes problems with DrawCaptionTemp()! */
- OffsetRect(&nmtbcd->nmcd.rc,
- 1,
- 1);
-
- /* Render flashed */
- uidctFlags |= DC_ACTIVE;
- }
- else
- {
- uidctFlags |= DC_INBUTTON;
- if (nmtbcd->nmcd.uItemState & CDIS_CHECKED)
- uidctFlags |= DC_ACTIVE;
- }
-
- if (DrawCapTemp != NULL)
- {
- /* Draw the button content */
- TaskItem->DisplayTooltip = !DrawCapTemp(TaskItem->hWnd,
- nmtbcd->nmcd.hdc,
- &nmtbcd->nmcd.rc,
- hCaptionFont,
- NULL,
- NULL,
- uidctFlags);
- }
-
- return CDRF_SKIPDEFAULT;
-
-#else /* !TASK_USE_DRAWCAPTIONTEMP */
-
/* Make the entire button flashing if neccessary */
if (nmtbcd->nmcd.uItemState & CDIS_MARKED)
{
- if (TaskItem->RenderFlashed)
+ Ret = TBCDRF_NOBACKGROUND;
+ if (!This->TaskBandTheme)
{
- nmtbcd->hbrMonoDither = GetSysColorBrush(COLOR_HIGHLIGHT);
- nmtbcd->clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
- nmtbcd->nHLStringBkMode = TRANSPARENT;
-
- /* We don't really need to set clrMark because we set the
- background mode to TRANSPARENT! */
- nmtbcd->clrMark = GetSysColor(COLOR_HIGHLIGHT);
-
- Ret |= TBCDRF_USECDCOLORS;
+ SelectObject(nmtbcd->nmcd.hdc, GetSysColorBrush(COLOR_HIGHLIGHT));
+ Rectangle(nmtbcd->nmcd.hdc,
+ nmtbcd->nmcd.rc.left,
+ nmtbcd->nmcd.rc.top,
+ nmtbcd->nmcd.rc.right,
+ nmtbcd->nmcd.rc.bottom);
}
else
- Ret |= TBCDRF_NOMARK;
+ {
+ DrawThemeBackground(This->TaskBandTheme, nmtbcd->nmcd.hdc, TDP_FLASHBUTTON, 0, &nmtbcd->nmcd.rc, 0);
+ }
+ nmtbcd->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ return Ret;
}
-
- /* Select the font we want to use */
- SelectObject(nmtbcd->nmcd.hdc,
- hCaptionFont);
- return Ret | CDRF_NEWFONT;
-
-#endif
-
}
}
else if (TaskGroup != NULL)
{
/* FIXME: Implement painting for task groups */
}
-
return Ret;
}
switch (nmtbcd->nmcd.dwDrawStage)
{
-#if TASK_USE_DRAWCAPTIONTEMP != 0
-
- case CDDS_ITEMPREPAINT:
- /* We handle drawing in the post-paint stage so that we
- don't have to draw the button edges, etc */
- Ret = CDRF_NOTIFYPOSTPAINT;
- break;
-
- case CDDS_ITEMPOSTPAINT:
-
-#else /* !TASK_USE_DRAWCAPTIONTEMP */
-
case CDDS_ITEMPREPAINT:
-
-#endif
-
Ret = TaskSwichWnd_HandleItemPaint(This,
nmtbcd);
break;
return Ret;
}
+static VOID
+TaskSwitchWnd_DrawBackground(HWND hwnd,
+ HDC hdc)
+{
+ RECT rect;
+
+ GetClientRect(hwnd, &rect);
+ DrawThemeParentBackground(hwnd, hdc, &rect);
+}
+
static LRESULT CALLBACK
TaskSwitchWndProc(IN HWND hwnd,
IN UINT uMsg,
{
switch (uMsg)
{
+ case WM_THEMECHANGED:
+ TaskSwitchWnd_UpdateTheme(This);
+ break;
+ case WM_ERASEBKGND:
+ TaskSwitchWnd_DrawBackground(hwnd, (HDC)wParam);
+ break;
case WM_SIZE:
{
SIZE szClient;
(LPARAM)&pt);
if (iBtn >= 0)
{
- /* FIXME: Display the system menu of the window */
+ TaskSwitchWnd_HandleButtonRightClick(This,
+ iBtn);
}
else
goto ForwardContextMenuMsg;
case WM_NCCREATE:
{
LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
- This = (PTASK_SWITCH_WND)HeapAlloc(hProcessHeap,
- 0,
- sizeof(*This));
+ This = HeapAlloc(hProcessHeap,
+ HEAP_ZERO_MEMORY,
+ sizeof(*This));
if (This == NULL)
return FALSE;
- ZeroMemory(This,
- sizeof(*This));
This->hWnd = hwnd;
This->hWndNotify = CreateStruct->hwndParent;
This->Tray = (ITrayWindow*)CreateStruct->lpCreateParams;
#if DUMP_TASKS != 0
case WM_TIMER:
- switch(wParam)
+ switch (wParam)
{
case 1:
TaskSwitchWnd_DumpTasks(This);
break;
#endif
+ case WM_KLUDGEMINRECT:
+ {
+ PTASK_ITEM TaskItem = TaskSwitchWnd_FindTaskItem(This, (HWND)wParam);
+ if (TaskItem)
+ {
+ RECT* prcMinRect = (RECT*)lParam;
+ RECT rcItem, rcToolbar;
+ SendMessageW(This->hWndToolbar,TB_GETITEMRECT, TaskItem->Index, (LPARAM)&rcItem);
+ GetWindowRect(This->hWndToolbar, &rcToolbar);
+
+ OffsetRect(&rcItem, rcToolbar.left, rcToolbar.top);
+
+ *prcMinRect = rcItem;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
default:
/* HandleDefaultMessage: */
if (uMsg == This->ShellHookMsg && This->ShellHookMsg != 0)