4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <commoncontrols.h>
24 /* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every
27 #define DEBUG_SHELL_HOOK 0
29 #define MAX_TASKS_COUNT (0x7FFF)
30 #define TASK_ITEM_ARRAY_ALLOC 64
32 const WCHAR szTaskSwitchWndClass
[] = L
"MSTaskSwWClass";
33 const WCHAR szRunningApps
[] = L
"Running Applications";
40 { HSHELL_WINDOWCREATED
, L
"HSHELL_WINDOWCREATED" },
41 { HSHELL_WINDOWDESTROYED
, L
"HSHELL_WINDOWDESTROYED" },
42 { HSHELL_ACTIVATESHELLWINDOW
, L
"HSHELL_ACTIVATESHELLWINDOW" },
43 { HSHELL_WINDOWACTIVATED
, L
"HSHELL_WINDOWACTIVATED" },
44 { HSHELL_GETMINRECT
, L
"HSHELL_GETMINRECT" },
45 { HSHELL_REDRAW
, L
"HSHELL_REDRAW" },
46 { HSHELL_TASKMAN
, L
"HSHELL_TASKMAN" },
47 { HSHELL_LANGUAGE
, L
"HSHELL_LANGUAGE" },
48 { HSHELL_SYSMENU
, L
"HSHELL_SYSMENU" },
49 { HSHELL_ENDTASK
, L
"HSHELL_ENDTASK" },
50 { HSHELL_ACCESSIBILITYSTATE
, L
"HSHELL_ACCESSIBILITYSTATE" },
51 { HSHELL_APPCOMMAND
, L
"HSHELL_APPCOMMAND" },
52 { HSHELL_WINDOWREPLACED
, L
"HSHELL_WINDOWREPLACED" },
53 { HSHELL_WINDOWREPLACING
, L
"HSHELL_WINDOWREPLACING" },
54 { HSHELL_RUDEAPPACTIVATED
, L
"HSHELL_RUDEAPPACTIVATED" },
58 typedef struct _TASK_GROUP
60 /* We have to use a linked list instead of an array so we don't have to
61 update all pointers to groups in the task item array when removing
63 struct _TASK_GROUP
*Next
;
74 DWORD IsCollapsed
: 1;
77 } TASK_GROUP
, *PTASK_GROUP
;
79 typedef struct _TASK_ITEM
92 /* IsFlashing is TRUE when the task bar item should be flashing. */
95 /* RenderFlashed is only TRUE if the task bar item should be
96 drawn with a flash. */
97 DWORD RenderFlashed
: 1;
100 } TASK_ITEM
, *PTASK_ITEM
;
103 public CWindowImplBaseT
< CToolbar
<TASK_ITEM
>, CControlWinTraits
>
106 INT
UpdateTbButtonSpacing(IN BOOL bHorizontal
, IN BOOL bThemed
, IN UINT uiRows
= 0, IN UINT uiBtnsPerLine
= 0)
110 tbm
.cbSize
= sizeof(tbm
);
111 tbm
.dwMask
= TBMF_BARPAD
| TBMF_BUTTONSPACING
;
113 tbm
.cxBarPad
= tbm
.cyBarPad
= 0;
117 tbm
.cxButtonSpacing
= 0;
118 tbm
.cyButtonSpacing
= 0;
122 if (bHorizontal
|| uiBtnsPerLine
> 1)
123 tbm
.cxButtonSpacing
= (3 * GetSystemMetrics(SM_CXEDGE
) / 2);
125 tbm
.cxButtonSpacing
= 0;
127 if (!bHorizontal
|| uiRows
> 1)
128 tbm
.cyButtonSpacing
= (3 * GetSystemMetrics(SM_CYEDGE
) / 2);
130 tbm
.cyButtonSpacing
= 0;
135 return tbm
.cxButtonSpacing
;
145 SendMessageW(WM_SETREDRAW
, TRUE
);
146 InvalidateRect(NULL
, TRUE
);
149 BOOL
SetButtonCommandId(IN INT iButtonIndex
, IN INT iCommandId
)
153 tbbi
.cbSize
= sizeof(tbbi
);
154 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_COMMAND
;
155 tbbi
.idCommand
= iCommandId
;
157 return SetButtonInfo(iButtonIndex
, &tbbi
) != 0;
160 LRESULT
OnNcHitTestToolbar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
164 /* See if the mouse is on a button */
165 pt
.x
= GET_X_LPARAM(lParam
);
166 pt
.y
= GET_Y_LPARAM(lParam
);
169 INT index
= HitTest(&pt
);
172 /* Make the control appear to be transparent outside of any buttons */
173 return HTTRANSPARENT
;
181 BEGIN_MSG_MAP(CNotifyToolbar
)
182 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTestToolbar
)
185 BOOL
Initialize(HWND hWndParent
)
187 DWORD styles
= WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
|
188 TBSTYLE_TOOLTIPS
| TBSTYLE_WRAPABLE
| TBSTYLE_LIST
| TBSTYLE_TRANSPARENT
|
189 CCS_TOP
| CCS_NORESIZE
| CCS_NODIVIDER
;
191 return SubclassWindow(CToolbar::Create(hWndParent
, styles
));
195 class CTaskSwitchWnd
:
196 public CComCoClass
<CTaskSwitchWnd
>,
197 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
198 public CWindowImpl
< CTaskSwitchWnd
, CWindow
, CControlWinTraits
>,
201 CTaskToolbar m_TaskBar
;
203 CComPtr
<ITrayWindow
> m_Tray
;
207 WORD m_TaskItemCount
;
208 WORD m_AllocatedTaskItems
;
210 PTASK_GROUP m_TaskGroups
;
211 PTASK_ITEM m_TaskItems
;
212 PTASK_ITEM m_ActiveTaskItem
;
215 UINT m_ButtonsPerLine
;
218 HIMAGELIST m_ImageList
;
220 BOOL m_IsGroupingEnabled
;
227 m_ShellHookMsg(NULL
),
229 m_AllocatedTaskItems(0),
232 m_ActiveTaskItem(NULL
),
237 m_IsGroupingEnabled(FALSE
),
238 m_IsDestroying(FALSE
)
240 ZeroMemory(&m_ButtonSize
, sizeof(m_ButtonSize
));
242 virtual ~CTaskSwitchWnd() { }
244 INT
GetWndTextFromTaskItem(IN PTASK_ITEM TaskItem
, LPWSTR szBuf
, DWORD cchBuf
)
246 /* Get the window text without sending a message so we don't hang if an
247 application isn't responding! */
248 return InternalGetWindowText(TaskItem
->hWnd
, szBuf
, cchBuf
);
255 PTASK_GROUP CurrentGroup
;
256 PTASK_ITEM CurrentTaskItem
, LastTaskItem
;
258 TRACE("Tasks dump:\n");
259 if (m_IsGroupingEnabled
)
261 CurrentGroup
= m_TaskGroups
;
262 while (CurrentGroup
!= NULL
)
264 TRACE("- Group PID: 0x%p Tasks: %d Index: %d\n", CurrentGroup
->dwProcessId
, CurrentGroup
->dwTaskCount
, CurrentGroup
->Index
);
266 CurrentTaskItem
= m_TaskItems
;
267 LastTaskItem
= CurrentTaskItem
+ m_TaskItemCount
;
268 while (CurrentTaskItem
!= LastTaskItem
)
270 if (CurrentTaskItem
->Group
== CurrentGroup
)
272 TRACE(" + Task hwnd: 0x%p Index: %d\n", CurrentTaskItem
->hWnd
, CurrentTaskItem
->Index
);
277 CurrentGroup
= CurrentGroup
->Next
;
280 CurrentTaskItem
= m_TaskItems
;
281 LastTaskItem
= CurrentTaskItem
+ m_TaskItemCount
;
282 while (CurrentTaskItem
!= LastTaskItem
)
284 if (CurrentTaskItem
->Group
== NULL
)
286 TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem
->hWnd
, CurrentTaskItem
->Index
);
293 CurrentTaskItem
= m_TaskItems
;
294 LastTaskItem
= CurrentTaskItem
+ m_TaskItemCount
;
295 while (CurrentTaskItem
!= LastTaskItem
)
297 TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem
->hWnd
, CurrentTaskItem
->Index
);
304 VOID
UpdateIndexesAfter(IN INT iIndex
, BOOL bInserted
)
306 PTASK_GROUP CurrentGroup
;
307 PTASK_ITEM CurrentTaskItem
, LastTaskItem
;
310 int offset
= bInserted
? +1 : -1;
312 if (m_IsGroupingEnabled
)
314 /* Update all affected groups */
315 CurrentGroup
= m_TaskGroups
;
316 while (CurrentGroup
!= NULL
)
318 if (CurrentGroup
->IsCollapsed
&&
319 CurrentGroup
->Index
>= iIndex
)
321 /* Update the toolbar buttons */
322 NewIndex
= CurrentGroup
->Index
+ offset
;
323 if (m_TaskBar
.SetButtonCommandId(CurrentGroup
->Index
+ offset
, NewIndex
))
325 CurrentGroup
->Index
= NewIndex
;
328 CurrentGroup
->Index
= -1;
331 CurrentGroup
= CurrentGroup
->Next
;
335 /* Update all affected task items */
336 CurrentTaskItem
= m_TaskItems
;
337 LastTaskItem
= CurrentTaskItem
+ m_TaskItemCount
;
338 while (CurrentTaskItem
!= LastTaskItem
)
340 CurrentGroup
= CurrentTaskItem
->Group
;
341 if (CurrentGroup
!= NULL
)
343 if (!CurrentGroup
->IsCollapsed
&&
344 CurrentTaskItem
->Index
>= iIndex
)
346 goto UpdateTaskItemBtn
;
349 else if (CurrentTaskItem
->Index
>= iIndex
)
352 /* Update the toolbar buttons */
353 NewIndex
= CurrentTaskItem
->Index
+ offset
;
354 if (m_TaskBar
.SetButtonCommandId(CurrentTaskItem
->Index
+ offset
, NewIndex
))
356 CurrentTaskItem
->Index
= NewIndex
;
359 CurrentTaskItem
->Index
= -1;
367 INT
UpdateTaskGroupButton(IN PTASK_GROUP TaskGroup
)
369 ASSERT(TaskGroup
->Index
>= 0);
371 /* FIXME: Implement */
373 return TaskGroup
->Index
;
376 VOID
ExpandTaskGroup(IN PTASK_GROUP TaskGroup
)
378 ASSERT(TaskGroup
->dwTaskCount
> 0);
379 ASSERT(TaskGroup
->IsCollapsed
);
380 ASSERT(TaskGroup
->Index
>= 0);
382 /* FIXME: Implement */
385 HICON
GetWndIcon(HWND hwnd
)
389 SendMessageTimeout(hwnd
, WM_GETICON
, ICON_SMALL2
, 0, SMTO_ABORTIFHUNG
, 1000, (PDWORD_PTR
) &hIcon
);
393 SendMessageTimeout(hwnd
, WM_GETICON
, ICON_SMALL
, 0, SMTO_ABORTIFHUNG
, 1000, (PDWORD_PTR
) &hIcon
);
397 SendMessageTimeout(hwnd
, WM_GETICON
, ICON_BIG
, 0, SMTO_ABORTIFHUNG
, 1000, (PDWORD_PTR
) &hIcon
);
401 hIcon
= (HICON
) GetClassLongPtr(hwnd
, GCL_HICONSM
);
405 hIcon
= (HICON
) GetClassLongPtr(hwnd
, GCL_HICON
);
410 INT
UpdateTaskItemButton(IN PTASK_ITEM TaskItem
)
412 TBBUTTONINFO tbbi
= { 0 };
414 WCHAR windowText
[255];
416 ASSERT(TaskItem
->Index
>= 0);
418 tbbi
.cbSize
= sizeof(tbbi
);
419 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_STATE
| TBIF_TEXT
| TBIF_IMAGE
;
420 tbbi
.fsState
= TBSTATE_ENABLED
;
421 if (m_ActiveTaskItem
== TaskItem
)
422 tbbi
.fsState
|= TBSTATE_CHECKED
;
424 if (TaskItem
->RenderFlashed
)
425 tbbi
.fsState
|= TBSTATE_MARKED
;
427 /* Check if we're updating a button that is the last one in the
428 line. If so, we need to set the TBSTATE_WRAP flag! */
429 if (!m_Tray
->IsHorizontal() || (m_ButtonsPerLine
!= 0 &&
430 (TaskItem
->Index
+ 1) % m_ButtonsPerLine
== 0))
432 tbbi
.fsState
|= TBSTATE_WRAP
;
435 if (GetWndTextFromTaskItem(TaskItem
, windowText
, _countof(windowText
)) > 0)
437 tbbi
.pszText
= windowText
;
440 icon
= GetWndIcon(TaskItem
->hWnd
);
442 icon
= static_cast<HICON
>(LoadImageW(NULL
, MAKEINTRESOURCEW(OIC_SAMPLE
), IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
));
443 TaskItem
->IconIndex
= ImageList_ReplaceIcon(m_ImageList
, TaskItem
->IconIndex
, icon
);
444 tbbi
.iImage
= TaskItem
->IconIndex
;
446 if (!m_TaskBar
.SetButtonInfo(TaskItem
->Index
, &tbbi
))
448 TaskItem
->Index
= -1;
452 TRACE("Updated button %d for hwnd 0x%p\n", TaskItem
->Index
, TaskItem
->hWnd
);
453 return TaskItem
->Index
;
456 VOID
RemoveIcon(IN PTASK_ITEM TaskItem
)
459 PTASK_ITEM currentTaskItem
, LastItem
;
461 if (TaskItem
->IconIndex
== -1)
464 tbbi
.cbSize
= sizeof(tbbi
);
465 tbbi
.dwMask
= TBIF_IMAGE
;
467 currentTaskItem
= m_TaskItems
;
468 LastItem
= currentTaskItem
+ m_TaskItemCount
;
469 while (currentTaskItem
!= LastItem
)
471 if (currentTaskItem
->IconIndex
> TaskItem
->IconIndex
)
473 currentTaskItem
->IconIndex
--;
474 tbbi
.iImage
= currentTaskItem
->IconIndex
;
476 m_TaskBar
.SetButtonInfo(currentTaskItem
->Index
, &tbbi
);
481 ImageList_Remove(m_ImageList
, TaskItem
->IconIndex
);
484 PTASK_ITEM
FindLastTaskItemOfGroup(
485 IN PTASK_GROUP TaskGroup OPTIONAL
,
486 IN PTASK_ITEM NewTaskItem OPTIONAL
)
488 PTASK_ITEM TaskItem
, LastTaskItem
, FoundTaskItem
= NULL
;
491 ASSERT(m_IsGroupingEnabled
);
493 TaskItem
= m_TaskItems
;
494 LastTaskItem
= TaskItem
+ m_TaskItemCount
;
496 dwTaskCount
= (TaskGroup
!= NULL
? TaskGroup
->dwTaskCount
: MAX_TASKS_COUNT
);
498 ASSERT(dwTaskCount
> 0);
500 while (TaskItem
!= LastTaskItem
)
502 if (TaskItem
->Group
== TaskGroup
)
504 if ((NewTaskItem
!= NULL
&& TaskItem
!= NewTaskItem
) || NewTaskItem
== NULL
)
506 FoundTaskItem
= TaskItem
;
509 if (--dwTaskCount
== 0)
511 /* We found the last task item in the group! */
519 return FoundTaskItem
;
522 INT
CalculateTaskItemNewButtonIndex(IN PTASK_ITEM TaskItem
)
524 PTASK_GROUP TaskGroup
;
525 PTASK_ITEM LastTaskItem
;
527 /* NOTE: This routine assumes that the group is *not* collapsed! */
529 TaskGroup
= TaskItem
->Group
;
530 if (m_IsGroupingEnabled
)
532 if (TaskGroup
!= NULL
)
534 ASSERT(TaskGroup
->Index
< 0);
535 ASSERT(!TaskGroup
->IsCollapsed
);
537 if (TaskGroup
->dwTaskCount
> 1)
539 LastTaskItem
= FindLastTaskItemOfGroup(TaskGroup
, TaskItem
);
540 if (LastTaskItem
!= NULL
)
542 /* Since the group is expanded the task items must have an index */
543 ASSERT(LastTaskItem
->Index
>= 0);
545 return LastTaskItem
->Index
+ 1;
551 /* Find the last NULL group button. NULL groups are added at the end of the
552 task item list when grouping is enabled */
553 LastTaskItem
= FindLastTaskItemOfGroup(NULL
, TaskItem
);
554 if (LastTaskItem
!= NULL
)
556 ASSERT(LastTaskItem
->Index
>= 0);
558 return LastTaskItem
->Index
+ 1;
563 return m_ButtonCount
;
566 INT
AddTaskItemButton(IN OUT PTASK_ITEM TaskItem
)
568 WCHAR windowText
[255];
569 TBBUTTON tbBtn
= { 0 };
573 if (TaskItem
->Index
>= 0)
575 return UpdateTaskItemButton(TaskItem
);
578 if (TaskItem
->Group
!= NULL
&&
579 TaskItem
->Group
->IsCollapsed
)
581 /* The task group is collapsed, we only need to update the group button */
582 return UpdateTaskGroupButton(TaskItem
->Group
);
585 icon
= GetWndIcon(TaskItem
->hWnd
);
587 icon
= static_cast<HICON
>(LoadImageW(NULL
, MAKEINTRESOURCEW(OIC_SAMPLE
), IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
));
588 TaskItem
->IconIndex
= ImageList_ReplaceIcon(m_ImageList
, -1, icon
);
590 tbBtn
.iBitmap
= TaskItem
->IconIndex
;
591 tbBtn
.fsState
= TBSTATE_ENABLED
| TBSTATE_ELLIPSES
;
592 tbBtn
.fsStyle
= BTNS_CHECK
| BTNS_NOPREFIX
| BTNS_SHOWTEXT
;
593 tbBtn
.dwData
= TaskItem
->Index
;
595 if (GetWndTextFromTaskItem(TaskItem
, windowText
, _countof(windowText
)) > 0)
597 tbBtn
.iString
= (DWORD_PTR
) windowText
;
600 /* Find out where to insert the new button */
601 iIndex
= CalculateTaskItemNewButtonIndex(TaskItem
);
603 tbBtn
.idCommand
= iIndex
;
605 m_TaskBar
.BeginUpdate();
607 if (m_TaskBar
.InsertButton(iIndex
, &tbBtn
))
609 UpdateIndexesAfter(iIndex
, TRUE
);
611 TRACE("Added button %d for hwnd 0x%p\n", iIndex
, TaskItem
->hWnd
);
613 TaskItem
->Index
= iIndex
;
616 /* Update button sizes and fix the button wrapping */
617 UpdateButtonsSize(TRUE
);
621 m_TaskBar
.EndUpdate();
626 BOOL
DeleteTaskItemButton(IN OUT PTASK_ITEM TaskItem
)
628 PTASK_GROUP TaskGroup
;
631 TaskGroup
= TaskItem
->Group
;
633 if (TaskItem
->Index
>= 0)
635 if ((TaskGroup
!= NULL
&& !TaskGroup
->IsCollapsed
) ||
638 m_TaskBar
.BeginUpdate();
640 RemoveIcon(TaskItem
);
641 iIndex
= TaskItem
->Index
;
642 if (m_TaskBar
.DeleteButton(iIndex
))
644 TaskItem
->Index
= -1;
647 UpdateIndexesAfter(iIndex
, FALSE
);
649 /* Update button sizes and fix the button wrapping */
650 UpdateButtonsSize(TRUE
);
654 m_TaskBar
.EndUpdate();
661 PTASK_GROUP
AddToTaskGroup(IN HWND hWnd
)
664 PTASK_GROUP TaskGroup
, *PrevLink
;
666 if (!GetWindowThreadProcessId(hWnd
,
669 TRACE("Cannot get process id of hwnd 0x%p\n", hWnd
);
673 /* Try to find an existing task group */
674 TaskGroup
= m_TaskGroups
;
675 PrevLink
= &m_TaskGroups
;
676 while (TaskGroup
!= NULL
)
678 if (TaskGroup
->dwProcessId
== dwProcessId
)
680 TaskGroup
->dwTaskCount
++;
684 PrevLink
= &TaskGroup
->Next
;
685 TaskGroup
= TaskGroup
->Next
;
688 /* Allocate a new task group */
689 TaskGroup
= (PTASK_GROUP
) HeapAlloc(hProcessHeap
,
692 if (TaskGroup
!= NULL
)
694 TaskGroup
->dwTaskCount
= 1;
695 TaskGroup
->dwProcessId
= dwProcessId
;
696 TaskGroup
->Index
= -1;
698 /* Add the task group to the list */
699 *PrevLink
= TaskGroup
;
705 VOID
RemoveTaskFromTaskGroup(IN OUT PTASK_ITEM TaskItem
)
707 PTASK_GROUP TaskGroup
, CurrentGroup
, *PrevLink
;
709 TaskGroup
= TaskItem
->Group
;
710 if (TaskGroup
!= NULL
)
712 DWORD dwNewTaskCount
= --TaskGroup
->dwTaskCount
;
713 if (dwNewTaskCount
== 0)
715 /* Find the previous pointer in the chain */
716 CurrentGroup
= m_TaskGroups
;
717 PrevLink
= &m_TaskGroups
;
718 while (CurrentGroup
!= TaskGroup
)
720 PrevLink
= &CurrentGroup
->Next
;
721 CurrentGroup
= CurrentGroup
->Next
;
724 /* Remove the group from the list */
725 ASSERT(TaskGroup
== CurrentGroup
);
726 *PrevLink
= TaskGroup
->Next
;
728 /* Free the task group */
729 HeapFree(hProcessHeap
,
733 else if (TaskGroup
->IsCollapsed
&&
734 TaskGroup
->Index
>= 0)
736 if (dwNewTaskCount
> 1)
738 /* FIXME: Check if we should expand the group */
739 /* Update the task group button */
740 UpdateTaskGroupButton(TaskGroup
);
744 /* Expand the group of one task button to a task button */
745 ExpandTaskGroup(TaskGroup
);
751 PTASK_ITEM
FindTaskItem(IN HWND hWnd
)
753 PTASK_ITEM TaskItem
, LastItem
;
755 TaskItem
= m_TaskItems
;
756 LastItem
= TaskItem
+ m_TaskItemCount
;
757 while (TaskItem
!= LastItem
)
759 if (TaskItem
->hWnd
== hWnd
)
768 PTASK_ITEM
FindOtherTaskItem(IN HWND hWnd
)
770 PTASK_ITEM LastItem
, TaskItem
;
771 PTASK_GROUP TaskGroup
;
774 if (!GetWindowThreadProcessId(hWnd
, &dwProcessId
))
779 /* Try to find another task that belongs to the same
780 process as the given window */
781 TaskItem
= m_TaskItems
;
782 LastItem
= TaskItem
+ m_TaskItemCount
;
783 while (TaskItem
!= LastItem
)
785 TaskGroup
= TaskItem
->Group
;
786 if (TaskGroup
!= NULL
)
788 if (TaskGroup
->dwProcessId
== dwProcessId
)
793 DWORD dwProcessIdTask
;
795 if (GetWindowThreadProcessId(TaskItem
->hWnd
,
797 dwProcessIdTask
== dwProcessId
)
809 PTASK_ITEM
AllocTaskItem()
811 if (m_TaskItemCount
>= MAX_TASKS_COUNT
)
813 /* We need the most significant bit in 16 bit command IDs to indicate whether it
814 is a task group or task item. WM_COMMAND limits command IDs to 16 bits! */
818 ASSERT(m_AllocatedTaskItems
>= m_TaskItemCount
);
820 if (m_TaskItemCount
== 0)
822 m_TaskItems
= (PTASK_ITEM
) HeapAlloc(hProcessHeap
,
824 TASK_ITEM_ARRAY_ALLOC
* sizeof(*m_TaskItems
));
825 if (m_TaskItems
!= NULL
)
827 m_AllocatedTaskItems
= TASK_ITEM_ARRAY_ALLOC
;
832 else if (m_TaskItemCount
>= m_AllocatedTaskItems
)
835 SIZE_T NewArrayLength
, ActiveTaskItemIndex
;
837 NewArrayLength
= m_AllocatedTaskItems
+ TASK_ITEM_ARRAY_ALLOC
;
839 NewArray
= (PTASK_ITEM
) HeapReAlloc(hProcessHeap
,
842 NewArrayLength
* sizeof(*m_TaskItems
));
843 if (NewArray
!= NULL
)
845 if (m_ActiveTaskItem
!= NULL
)
847 /* Fixup the ActiveTaskItem pointer */
848 ActiveTaskItemIndex
= m_ActiveTaskItem
- m_TaskItems
;
849 m_ActiveTaskItem
= NewArray
+ ActiveTaskItemIndex
;
851 m_AllocatedTaskItems
= (WORD
) NewArrayLength
;
852 m_TaskItems
= NewArray
;
858 return m_TaskItems
+ m_TaskItemCount
++;
861 VOID
FreeTaskItem(IN OUT PTASK_ITEM TaskItem
)
865 if (TaskItem
== m_ActiveTaskItem
)
866 m_ActiveTaskItem
= NULL
;
868 wIndex
= (WORD
) (TaskItem
- m_TaskItems
);
869 if (wIndex
+ 1 < m_TaskItemCount
)
873 (m_TaskItemCount
- wIndex
- 1) * sizeof(*TaskItem
));
879 VOID
DeleteTaskItem(IN OUT PTASK_ITEM TaskItem
)
883 /* Delete the task button from the toolbar */
884 DeleteTaskItemButton(TaskItem
);
887 /* Remove the task from it's group */
888 RemoveTaskFromTaskGroup(TaskItem
);
890 /* Free the task item */
891 FreeTaskItem(TaskItem
);
894 VOID
CheckActivateTaskItem(IN OUT PTASK_ITEM TaskItem
)
896 PTASK_ITEM CurrentTaskItem
;
897 PTASK_GROUP TaskGroup
= NULL
;
899 CurrentTaskItem
= m_ActiveTaskItem
;
901 if (TaskItem
!= NULL
)
902 TaskGroup
= TaskItem
->Group
;
904 if (m_IsGroupingEnabled
&&
906 TaskGroup
->IsCollapsed
)
912 if (CurrentTaskItem
!= NULL
)
914 PTASK_GROUP CurrentTaskGroup
;
916 if (CurrentTaskItem
== TaskItem
)
919 CurrentTaskGroup
= CurrentTaskItem
->Group
;
921 if (m_IsGroupingEnabled
&&
922 CurrentTaskGroup
!= NULL
&&
923 CurrentTaskGroup
->IsCollapsed
)
925 if (CurrentTaskGroup
== TaskGroup
)
932 m_ActiveTaskItem
= NULL
;
933 if (CurrentTaskItem
->Index
>= 0)
935 UpdateTaskItemButton(CurrentTaskItem
);
940 m_ActiveTaskItem
= TaskItem
;
942 if (TaskItem
!= NULL
&& TaskItem
->Index
>= 0)
944 UpdateTaskItemButton(TaskItem
);
946 else if (TaskItem
== NULL
)
948 TRACE("Active TaskItem now NULL\n");
952 PTASK_ITEM
FindTaskItemByIndex(IN INT Index
)
954 PTASK_ITEM TaskItem
, LastItem
;
956 TaskItem
= m_TaskItems
;
957 LastItem
= TaskItem
+ m_TaskItemCount
;
958 while (TaskItem
!= LastItem
)
960 if (TaskItem
->Index
== Index
)
969 PTASK_GROUP
FindTaskGroupByIndex(IN INT Index
)
971 PTASK_GROUP CurrentGroup
;
973 CurrentGroup
= m_TaskGroups
;
974 while (CurrentGroup
!= NULL
)
976 if (CurrentGroup
->Index
== Index
)
979 CurrentGroup
= CurrentGroup
->Next
;
985 BOOL
AddTask(IN HWND hWnd
)
989 if (!::IsWindow(hWnd
) || m_Tray
->IsSpecialHWND(hWnd
))
992 TaskItem
= FindTaskItem(hWnd
);
993 if (TaskItem
== NULL
)
995 TRACE("Add window 0x%p\n", hWnd
);
996 TaskItem
= AllocTaskItem();
997 if (TaskItem
!= NULL
)
999 ZeroMemory(TaskItem
, sizeof(*TaskItem
));
1000 TaskItem
->hWnd
= hWnd
;
1001 TaskItem
->Index
= -1;
1002 TaskItem
->Group
= AddToTaskGroup(hWnd
);
1004 if (!m_IsDestroying
)
1006 AddTaskItemButton(TaskItem
);
1011 return TaskItem
!= NULL
;
1014 BOOL
ActivateTaskItem(IN OUT PTASK_ITEM TaskItem OPTIONAL
)
1016 if (TaskItem
!= NULL
)
1018 TRACE("Activate window 0x%p on button %d\n", TaskItem
->hWnd
, TaskItem
->Index
);
1021 CheckActivateTaskItem(TaskItem
);
1026 BOOL
ActivateTask(IN HWND hWnd
)
1028 PTASK_ITEM TaskItem
;
1032 return ActivateTaskItem(NULL
);
1035 TaskItem
= FindTaskItem(hWnd
);
1036 if (TaskItem
== NULL
)
1038 TaskItem
= FindOtherTaskItem(hWnd
);
1041 if (TaskItem
== NULL
)
1043 WARN("Activate window 0x%p, could not find task\n", hWnd
);
1044 RefreshWindowList();
1047 return ActivateTaskItem(TaskItem
);
1050 BOOL
DeleteTask(IN HWND hWnd
)
1052 PTASK_ITEM TaskItem
;
1054 TaskItem
= FindTaskItem(hWnd
);
1055 if (TaskItem
!= NULL
)
1057 TRACE("Delete window 0x%p on button %d\n", hWnd
, TaskItem
->Index
);
1058 DeleteTaskItem(TaskItem
);
1062 //TRACE("Failed to delete window 0x%p\n", hWnd);
1067 VOID
DeleteAllTasks()
1069 PTASK_ITEM CurrentTask
;
1071 if (m_TaskItemCount
> 0)
1073 CurrentTask
= m_TaskItems
+ m_TaskItemCount
;
1076 DeleteTaskItem(--CurrentTask
);
1077 } while (CurrentTask
!= m_TaskItems
);
1081 VOID
FlashTaskItem(IN OUT PTASK_ITEM TaskItem
)
1083 TaskItem
->RenderFlashed
= 1;
1084 UpdateTaskItemButton(TaskItem
);
1087 BOOL
FlashTask(IN HWND hWnd
)
1089 PTASK_ITEM TaskItem
;
1091 TaskItem
= FindTaskItem(hWnd
);
1092 if (TaskItem
!= NULL
)
1094 TRACE("Flashing window 0x%p on button %d\n", hWnd
, TaskItem
->Index
);
1095 FlashTaskItem(TaskItem
);
1102 VOID
RedrawTaskItem(IN OUT PTASK_ITEM TaskItem
)
1104 PTASK_GROUP TaskGroup
;
1106 TaskGroup
= TaskItem
->Group
;
1107 if (m_IsGroupingEnabled
&& TaskGroup
!= NULL
)
1109 if (TaskGroup
->IsCollapsed
&& TaskGroup
->Index
>= 0)
1111 UpdateTaskGroupButton(TaskGroup
);
1113 else if (TaskItem
->Index
>= 0)
1115 goto UpdateTaskItem
;
1118 else if (TaskItem
->Index
>= 0)
1121 TaskItem
->RenderFlashed
= 0;
1122 UpdateTaskItemButton(TaskItem
);
1127 BOOL
RedrawTask(IN HWND hWnd
)
1129 PTASK_ITEM TaskItem
;
1131 TaskItem
= FindTaskItem(hWnd
);
1132 if (TaskItem
!= NULL
)
1134 RedrawTaskItem(TaskItem
);
1141 VOID
UpdateButtonsSize(IN BOOL bRedrawDisabled
)
1144 UINT uiRows
, uiMax
, uiMin
, uiBtnsPerLine
, ui
;
1148 /* Update the size of the image list if needed */
1150 ImageList_GetIconSize(m_ImageList
, &cx
, &cy
);
1151 if (cx
!= GetSystemMetrics(SM_CXSMICON
) || cy
!= GetSystemMetrics(SM_CYSMICON
))
1153 ImageList_SetIconSize(m_ImageList
, GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
));
1155 /* SetIconSize removes all icons so we have to reinsert them */
1156 PTASK_ITEM TaskItem
= m_TaskItems
;
1157 PTASK_ITEM LastTaskItem
= m_TaskItems
+ m_TaskItemCount
;
1158 while (TaskItem
!= LastTaskItem
)
1160 TaskItem
->IconIndex
= -1;
1161 UpdateTaskItemButton(TaskItem
);
1165 m_TaskBar
.SetImageList(m_ImageList
);
1168 if (GetClientRect(&rcClient
) && !IsRectEmpty(&rcClient
))
1170 if (m_ButtonCount
> 0)
1172 Horizontal
= m_Tray
->IsHorizontal();
1176 TBMETRICS tbm
= { 0 };
1177 tbm
.cbSize
= sizeof(tbm
);
1178 tbm
.dwMask
= TBMF_BUTTONSPACING
;
1179 m_TaskBar
.GetMetrics(&tbm
);
1181 if (m_ButtonSize
.cy
+ tbm
.cyButtonSpacing
!= 0)
1182 uiRows
= (rcClient
.bottom
+ tbm
.cyButtonSpacing
) / (m_ButtonSize
.cy
+ tbm
.cyButtonSpacing
);
1189 uiBtnsPerLine
= (m_ButtonCount
+ uiRows
- 1) / uiRows
;
1194 uiRows
= m_ButtonCount
;
1197 if (!bRedrawDisabled
)
1198 m_TaskBar
.BeginUpdate();
1200 /* We might need to update the button spacing */
1201 int cxButtonSpacing
= m_TaskBar
.UpdateTbButtonSpacing(
1202 Horizontal
, m_Theme
!= NULL
,
1203 uiRows
, uiBtnsPerLine
);
1205 /* Determine the minimum and maximum width of a button */
1206 uiMin
= GetSystemMetrics(SM_CXSIZE
) + (2 * GetSystemMetrics(SM_CXEDGE
));
1209 uiMax
= GetSystemMetrics(SM_CXMINIMIZED
);
1211 /* Calculate the ideal width and make sure it's within the allowed range */
1212 NewBtnSize
= (rcClient
.right
- (uiBtnsPerLine
* cxButtonSpacing
)) / uiBtnsPerLine
;
1214 if (NewBtnSize
< (LONG
) uiMin
)
1216 if (NewBtnSize
>(LONG
)uiMax
)
1219 /* Recalculate how many buttons actually fit into one line */
1220 uiBtnsPerLine
= rcClient
.right
/ (NewBtnSize
+ cxButtonSpacing
);
1221 if (uiBtnsPerLine
== 0)
1226 NewBtnSize
= uiMax
= rcClient
.right
;
1229 m_ButtonSize
.cx
= NewBtnSize
;
1231 m_ButtonsPerLine
= uiBtnsPerLine
;
1233 for (ui
= 0; ui
!= m_ButtonCount
; ui
++)
1235 TBBUTTONINFOW tbbi
= { 0 };
1236 tbbi
.cbSize
= sizeof(tbbi
);
1237 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_SIZE
| TBIF_STATE
;
1238 tbbi
.cx
= (INT
) NewBtnSize
;
1239 tbbi
.fsState
= TBSTATE_ENABLED
;
1241 /* Check if we're updating a button that is the last one in the
1242 line. If so, we need to set the TBSTATE_WRAP flag! */
1245 if ((ui
+ 1) % uiBtnsPerLine
== 0)
1246 tbbi
.fsState
|= TBSTATE_WRAP
;
1250 tbbi
.fsState
|= TBSTATE_WRAP
;
1253 if (m_ActiveTaskItem
!= NULL
&&
1254 m_ActiveTaskItem
->Index
== (INT
)ui
)
1256 tbbi
.fsState
|= TBSTATE_CHECKED
;
1259 m_TaskBar
.SetButtonInfo(ui
, &tbbi
);
1264 m_ButtonsPerLine
= 0;
1265 m_ButtonSize
.cx
= 0;
1269 // FIXME: This seems to be enabling redraws prematurely, but moving it to its right place doesn't work!
1270 m_TaskBar
.EndUpdate();
1273 BOOL CALLBACK
EnumWindowsProc(IN HWND hWnd
)
1275 /* Only show windows that still exist and are visible and none of explorer's
1276 special windows (such as the desktop or the tray window) */
1277 if (::IsWindow(hWnd
) && ::IsWindowVisible(hWnd
) &&
1278 !m_Tray
->IsSpecialHWND(hWnd
))
1280 DWORD exStyle
= ::GetWindowLong(hWnd
, GWL_EXSTYLE
);
1281 /* Don't list popup windows and also no tool windows */
1282 if ((::GetWindow(hWnd
, GW_OWNER
) == NULL
|| exStyle
& WS_EX_APPWINDOW
) &&
1283 !(exStyle
& WS_EX_TOOLWINDOW
))
1285 TRACE("Adding task for %p...\n", hWnd
);
1294 static BOOL CALLBACK
s_EnumWindowsProc(IN HWND hWnd
, IN LPARAM lParam
)
1296 CTaskSwitchWnd
* This
= (CTaskSwitchWnd
*) lParam
;
1298 return This
->EnumWindowsProc(hWnd
);
1301 BOOL
RefreshWindowList()
1303 TRACE("Refreshing window list...\n");
1304 /* Add all windows to the toolbar */
1305 return EnumWindows(s_EnumWindowsProc
, (LPARAM
)this);
1308 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1310 TRACE("OmThemeChanged\n");
1313 CloseThemeData(m_Theme
);
1315 if (IsThemeActive())
1316 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBand");
1323 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1325 if (!m_TaskBar
.Initialize(m_hWnd
))
1328 SetWindowTheme(m_TaskBar
.m_hWnd
, L
"TaskBand", NULL
);
1330 m_ImageList
= ImageList_Create(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), ILC_COLOR32
| ILC_MASK
, 0, 1000);
1331 m_TaskBar
.SetImageList(m_ImageList
);
1333 /* Set proper spacing between buttons */
1334 m_TaskBar
.UpdateTbButtonSpacing(m_Tray
->IsHorizontal(), m_Theme
!= NULL
);
1336 /* Register the shell hook */
1337 m_ShellHookMsg
= RegisterWindowMessageW(L
"SHELLHOOK");
1339 TRACE("ShellHookMsg got assigned number %d\n", m_ShellHookMsg
);
1341 RegisterShellHook(m_hWnd
, 3); /* 1 if no NT! We're targeting NT so we don't care! */
1343 RefreshWindowList();
1345 /* Recalculate the button size */
1346 UpdateButtonsSize(FALSE
);
1349 SetTimer(hwnd
, 1, 5000, NULL
);
1354 LRESULT
OnDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1356 m_IsDestroying
= TRUE
;
1358 /* Unregister the shell hook */
1359 RegisterShellHook(m_hWnd
, FALSE
);
1361 CloseThemeData(m_Theme
);
1366 BOOL
HandleAppCommand(IN WPARAM wParam
, IN LPARAM lParam
)
1370 switch (GET_APPCOMMAND_LPARAM(lParam
))
1372 case APPCOMMAND_BROWSER_SEARCH
:
1373 Ret
= SHFindFiles(NULL
,
1377 case APPCOMMAND_BROWSER_HOME
:
1378 case APPCOMMAND_LAUNCH_MAIL
:
1380 TRACE("Shell app command %d unhandled!\n", (INT
) GET_APPCOMMAND_LPARAM(lParam
));
1387 LRESULT
OnShellHook(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1391 /* In case the shell hook wasn't registered properly, ignore WM_NULLs*/
1398 TRACE("Received shell hook message: wParam=%08lx, lParam=%08lx\n", wParam
, lParam
);
1400 switch ((INT
) wParam
)
1402 case HSHELL_APPCOMMAND
:
1403 Ret
= HandleAppCommand(wParam
, lParam
);
1406 case HSHELL_WINDOWCREATED
:
1407 AddTask((HWND
) lParam
);
1410 case HSHELL_WINDOWDESTROYED
:
1411 /* The window still exists! Delay destroying it a bit */
1412 DeleteTask((HWND
) lParam
);
1415 case HSHELL_RUDEAPPACTIVATED
:
1416 case HSHELL_WINDOWACTIVATED
:
1417 ActivateTask((HWND
) lParam
);
1421 FlashTask((HWND
) lParam
);
1425 RedrawTask((HWND
) lParam
);
1428 case HSHELL_TASKMAN
:
1429 ::PostMessage(m_Tray
->GetHWND(), TWM_OPENSTARTMENU
, 0, 0);
1432 case HSHELL_ACTIVATESHELLWINDOW
:
1433 case HSHELL_LANGUAGE
:
1434 case HSHELL_SYSMENU
:
1435 case HSHELL_ENDTASK
:
1436 case HSHELL_ACCESSIBILITYSTATE
:
1437 case HSHELL_WINDOWREPLACED
:
1438 case HSHELL_WINDOWREPLACING
:
1440 case HSHELL_GETMINRECT
:
1443 #if DEBUG_SHELL_HOOK
1445 for (i
= 0, found
= 0; i
!= _countof(hshell_msg
); i
++)
1447 if (hshell_msg
[i
].msg
== (INT
) wParam
)
1449 TRACE("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg
[i
].msg_name
, lParam
);
1457 TRACE("Shell message %d unhandled (lParam = 0x%p)!\n", (INT
) wParam
, lParam
);
1465 VOID
HandleTaskItemClick(IN OUT PTASK_ITEM TaskItem
)
1470 if (::IsWindow(TaskItem
->hWnd
))
1472 bIsMinimized
= ::IsIconic(TaskItem
->hWnd
);
1473 bIsActive
= (TaskItem
== m_ActiveTaskItem
);
1475 TRACE("Active TaskItem %p, selected TaskItem %p\n", m_ActiveTaskItem
, TaskItem
);
1476 if (m_ActiveTaskItem
)
1477 TRACE("Active TaskItem hWnd=%p, TaskItem hWnd %p\n", m_ActiveTaskItem
->hWnd
, TaskItem
->hWnd
);
1479 TRACE("Valid button clicked. HWND=%p, IsMinimized=%s, IsActive=%s...\n",
1480 TaskItem
->hWnd
, bIsMinimized
? "Yes" : "No", bIsActive
? "Yes" : "No");
1482 if (!bIsMinimized
&& bIsActive
)
1484 ::PostMessage(TaskItem
->hWnd
,
1488 TRACE("Valid button clicked. App window Minimized.\n");
1494 ::PostMessage(TaskItem
->hWnd
,
1498 TRACE("Valid button clicked. App window Restored.\n");
1501 SetForegroundWindow(TaskItem
->hWnd
);
1502 TRACE("Valid button clicked. App window Activated.\n");
1507 VOID
HandleTaskGroupClick(IN OUT PTASK_GROUP TaskGroup
)
1509 /* TODO: Show task group menu */
1512 BOOL
HandleButtonClick(IN WORD wIndex
)
1514 PTASK_ITEM TaskItem
;
1515 PTASK_GROUP TaskGroup
;
1517 if (m_IsGroupingEnabled
)
1519 TaskGroup
= FindTaskGroupByIndex((INT
) wIndex
);
1520 if (TaskGroup
!= NULL
&& TaskGroup
->IsCollapsed
)
1522 HandleTaskGroupClick(TaskGroup
);
1527 TaskItem
= FindTaskItemByIndex((INT
) wIndex
);
1528 if (TaskItem
!= NULL
)
1530 HandleTaskItemClick(TaskItem
);
1538 VOID
HandleTaskItemRightClick(IN OUT PTASK_ITEM TaskItem
)
1543 SetForegroundWindow(TaskItem
->hWnd
);
1545 ActivateTask(TaskItem
->hWnd
);
1547 ::SendMessageW(TaskItem
->hWnd
, WM_POPUPSYSTEMMENU
, 0, MAKELPARAM(pt
.x
, pt
.y
));
1550 VOID
HandleTaskGroupRightClick(IN OUT PTASK_GROUP TaskGroup
)
1552 /* TODO: Show task group right click menu */
1555 BOOL
HandleButtonRightClick(IN WORD wIndex
)
1557 PTASK_ITEM TaskItem
;
1558 PTASK_GROUP TaskGroup
;
1559 if (m_IsGroupingEnabled
)
1561 TaskGroup
= FindTaskGroupByIndex((INT
) wIndex
);
1562 if (TaskGroup
!= NULL
&& TaskGroup
->IsCollapsed
)
1564 HandleTaskGroupRightClick(TaskGroup
);
1569 TaskItem
= FindTaskItemByIndex((INT
) wIndex
);
1571 if (TaskItem
!= NULL
)
1573 HandleTaskItemRightClick(TaskItem
);
1581 LRESULT
HandleItemPaint(IN OUT NMTBCUSTOMDRAW
*nmtbcd
)
1583 LRESULT Ret
= CDRF_DODEFAULT
;
1584 PTASK_GROUP TaskGroup
;
1585 PTASK_ITEM TaskItem
;
1587 TaskItem
= FindTaskItemByIndex((INT
) nmtbcd
->nmcd
.dwItemSpec
);
1588 TaskGroup
= FindTaskGroupByIndex((INT
) nmtbcd
->nmcd
.dwItemSpec
);
1589 if (TaskGroup
== NULL
&& TaskItem
!= NULL
)
1591 ASSERT(TaskItem
!= NULL
);
1593 if (TaskItem
!= NULL
&& ::IsWindow(TaskItem
->hWnd
))
1595 /* Make the entire button flashing if necessary */
1596 if (nmtbcd
->nmcd
.uItemState
& CDIS_MARKED
)
1598 Ret
= TBCDRF_NOBACKGROUND
;
1601 SelectObject(nmtbcd
->nmcd
.hdc
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1602 Rectangle(nmtbcd
->nmcd
.hdc
,
1603 nmtbcd
->nmcd
.rc
.left
,
1604 nmtbcd
->nmcd
.rc
.top
,
1605 nmtbcd
->nmcd
.rc
.right
,
1606 nmtbcd
->nmcd
.rc
.bottom
);
1610 DrawThemeBackground(m_Theme
, nmtbcd
->nmcd
.hdc
, TDP_FLASHBUTTON
, 0, &nmtbcd
->nmcd
.rc
, 0);
1612 nmtbcd
->clrText
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
1617 else if (TaskGroup
!= NULL
)
1619 /* FIXME: Implement painting for task groups */
1624 LRESULT
HandleToolbarNotification(IN
const NMHDR
*nmh
)
1632 LPNMTBCUSTOMDRAW nmtbcd
= (LPNMTBCUSTOMDRAW
) nmh
;
1634 switch (nmtbcd
->nmcd
.dwDrawStage
)
1637 case CDDS_ITEMPREPAINT
:
1638 Ret
= HandleItemPaint(nmtbcd
);
1642 Ret
= CDRF_NOTIFYITEMDRAW
;
1646 Ret
= CDRF_DODEFAULT
;
1656 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1658 HDC hdc
= (HDC
) wParam
;
1667 GetClientRect(&rect
);
1668 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1673 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1677 szClient
.cx
= LOWORD(lParam
);
1678 szClient
.cy
= HIWORD(lParam
);
1679 if (m_TaskBar
.m_hWnd
!= NULL
)
1681 m_TaskBar
.SetWindowPos(NULL
, 0, 0, szClient
.cx
, szClient
.cy
, SWP_NOZORDER
);
1683 UpdateButtonsSize(FALSE
);
1688 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1691 /* We want the tray window to be draggable everywhere, so make the control
1692 appear transparent */
1693 Ret
= DefWindowProc(uMsg
, wParam
, lParam
);
1694 if (Ret
!= HTVSCROLL
&& Ret
!= HTHSCROLL
)
1695 Ret
= HTTRANSPARENT
;
1699 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1702 if (lParam
!= 0 && (HWND
) lParam
== m_TaskBar
.m_hWnd
)
1704 HandleButtonClick(LOWORD(wParam
));
1709 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1712 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
1714 if (nmh
->hwndFrom
== m_TaskBar
.m_hWnd
)
1716 Ret
= HandleToolbarNotification(nmh
);
1721 LRESULT
OnEnableGrouping(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1723 LRESULT Ret
= m_IsGroupingEnabled
;
1724 if ((BOOL
)wParam
!= m_IsGroupingEnabled
)
1726 m_IsGroupingEnabled
= (BOOL
)wParam
;
1728 /* Collapse or expand groups if necessary */
1729 UpdateButtonsSize(FALSE
);
1734 LRESULT
OnUpdateTaskbarPos(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1736 /* Update the button spacing */
1737 m_TaskBar
.UpdateTbButtonSpacing(m_Tray
->IsHorizontal(), m_Theme
!= NULL
);
1741 LRESULT
OnTaskbarSettingsChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1743 TaskbarSettings
* newSettings
= (TaskbarSettings
*)lParam
;
1744 if (newSettings
->bGroupButtons
!= g_TaskbarSettings
.bGroupButtons
)
1746 /* TODO: Toggle grouping */
1747 g_TaskbarSettings
.bGroupButtons
= newSettings
->bGroupButtons
;
1753 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1758 if (m_TaskBar
.m_hWnd
!= NULL
)
1762 pt
.x
= GET_X_LPARAM(lParam
);
1763 pt
.y
= GET_Y_LPARAM(lParam
);
1765 ::ScreenToClient(m_TaskBar
.m_hWnd
, &pt
);
1767 iBtn
= m_TaskBar
.HitTest(&pt
);
1770 HandleButtonRightClick(iBtn
);
1775 /* Not on a taskbar button, so forward message to tray */
1776 Ret
= SendMessage(m_Tray
->GetHWND(), uMsg
, wParam
, lParam
);
1781 LRESULT
OnKludgeItemRect(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1783 PTASK_ITEM TaskItem
= FindTaskItem((HWND
) wParam
);
1786 RECT
* prcMinRect
= (RECT
*) lParam
;
1787 RECT rcItem
, rcToolbar
;
1788 m_TaskBar
.GetItemRect(TaskItem
->Index
, &rcItem
);
1789 m_TaskBar
.GetWindowRect(&rcToolbar
);
1791 OffsetRect(&rcItem
, rcToolbar
.left
, rcToolbar
.top
);
1793 *prcMinRect
= rcItem
;
1799 LRESULT
OnMouseActivate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1801 return MA_NOACTIVATE
;
1804 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1817 LRESULT
OnSetFont(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1819 return m_TaskBar
.SendMessageW(uMsg
, wParam
, lParam
);
1822 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1824 if (wParam
== SPI_SETNONCLIENTMETRICS
)
1826 /* Don't update the font, this will be done when we get a WM_SETFONT from our parent */
1827 UpdateButtonsSize(FALSE
);
1833 HRESULT
Initialize(IN HWND hWndParent
, IN OUT ITrayWindow
*tray
)
1836 m_IsGroupingEnabled
= TRUE
; /* FIXME */
1837 Create(hWndParent
, 0, szRunningApps
, WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| WS_TABSTOP
);
1843 HRESULT WINAPI
GetWindow(HWND
* phwnd
)
1846 return E_INVALIDARG
;
1851 HRESULT WINAPI
ContextSensitiveHelp(BOOL fEnterMode
)
1856 DECLARE_WND_CLASS_EX(szTaskSwitchWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
1858 BEGIN_MSG_MAP(CTaskSwitchWnd
)
1859 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
1860 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
1861 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
1862 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
1863 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
1864 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
1865 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
1866 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
1867 MESSAGE_HANDLER(TSWM_ENABLEGROUPING
, OnEnableGrouping
)
1868 MESSAGE_HANDLER(TSWM_UPDATETASKBARPOS
, OnUpdateTaskbarPos
)
1869 MESSAGE_HANDLER(TWM_SETTINGSCHANGED
, OnTaskbarSettingsChanged
)
1870 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
1871 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
1872 MESSAGE_HANDLER(WM_SETFONT
, OnSetFont
)
1873 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
1874 MESSAGE_HANDLER(m_ShellHookMsg
, OnShellHook
)
1875 MESSAGE_HANDLER(WM_MOUSEACTIVATE
, OnMouseActivate
)
1876 MESSAGE_HANDLER(WM_KLUDGEMINRECT
, OnKludgeItemRect
)
1879 DECLARE_NOT_AGGREGATABLE(CTaskSwitchWnd
)
1881 DECLARE_PROTECT_FINAL_CONSTRUCT()
1882 BEGIN_COM_MAP(CTaskSwitchWnd
)
1883 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
1887 HRESULT
CTaskSwitchWnd_CreateInstance(IN HWND hWndParent
, IN OUT ITrayWindow
*Tray
, REFIID riid
, void **ppv
)
1889 return ShellObjectCreatorInit
<CTaskSwitchWnd
>(hWndParent
, Tray
, riid
, ppv
);