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 #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
25 #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
27 /* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every
30 #define DEBUG_SHELL_HOOK 0
32 #define MAX_TASKS_COUNT (0x7FFF)
33 #define TASK_ITEM_ARRAY_ALLOC 64
35 const WCHAR szTaskSwitchWndClass
[] = TEXT("MSTaskSwWClass");
36 const WCHAR szRunningApps
[] = TEXT("Running Applications");
43 { HSHELL_WINDOWCREATED
, L
"HSHELL_WINDOWCREATED" },
44 { HSHELL_WINDOWDESTROYED
, L
"HSHELL_WINDOWDESTROYED" },
45 { HSHELL_ACTIVATESHELLWINDOW
, L
"HSHELL_ACTIVATESHELLWINDOW" },
46 { HSHELL_WINDOWACTIVATED
, L
"HSHELL_WINDOWACTIVATED" },
47 { HSHELL_GETMINRECT
, L
"HSHELL_GETMINRECT" },
48 { HSHELL_REDRAW
, L
"HSHELL_REDRAW" },
49 { HSHELL_TASKMAN
, L
"HSHELL_TASKMAN" },
50 { HSHELL_LANGUAGE
, L
"HSHELL_LANGUAGE" },
51 { HSHELL_SYSMENU
, L
"HSHELL_SYSMENU" },
52 { HSHELL_ENDTASK
, L
"HSHELL_ENDTASK" },
53 { HSHELL_ACCESSIBILITYSTATE
, L
"HSHELL_ACCESSIBILITYSTATE" },
54 { HSHELL_APPCOMMAND
, L
"HSHELL_APPCOMMAND" },
55 { HSHELL_WINDOWREPLACED
, L
"HSHELL_WINDOWREPLACED" },
56 { HSHELL_WINDOWREPLACING
, L
"HSHELL_WINDOWREPLACING" },
57 { HSHELL_RUDEAPPACTIVATED
, L
"HSHELL_RUDEAPPACTIVATED" },
61 typedef struct _TASK_GROUP
63 /* We have to use a linked list instead of an array so we don't have to
64 update all pointers to groups in the task item array when removing
66 struct _TASK_GROUP
*Next
;
77 DWORD IsCollapsed
: 1;
80 } TASK_GROUP
, *PTASK_GROUP
;
82 typedef struct _TASK_ITEM
95 /* IsFlashing is TRUE when the task bar item should be flashing. */
98 /* RenderFlashed is only TRUE if the task bar item should be
99 drawn with a flash. */
100 DWORD RenderFlashed
: 1;
103 } TASK_ITEM
, *PTASK_ITEM
;
106 public CWindowImplBaseT
< CToolbar
<TASK_ITEM
>, CControlWinTraits
>
109 INT
UpdateTbButtonSpacing(IN BOOL bHorizontal
, IN BOOL bThemed
, IN UINT uiRows
= 0, IN UINT uiBtnsPerLine
= 0)
113 tbm
.cbSize
= sizeof(tbm
);
114 tbm
.dwMask
= TBMF_BARPAD
| TBMF_BUTTONSPACING
;
116 tbm
.cxBarPad
= tbm
.cyBarPad
= 0;
120 tbm
.cxButtonSpacing
= 0;
121 tbm
.cyButtonSpacing
= 0;
125 if (bHorizontal
|| uiBtnsPerLine
> 1)
126 tbm
.cxButtonSpacing
= (3 * GetSystemMetrics(SM_CXEDGE
) / 2);
128 tbm
.cxButtonSpacing
= 0;
130 if (!bHorizontal
|| uiRows
> 1)
131 tbm
.cyButtonSpacing
= (3 * GetSystemMetrics(SM_CYEDGE
) / 2);
133 tbm
.cyButtonSpacing
= 0;
138 return tbm
.cxButtonSpacing
;
148 SendMessageW(WM_SETREDRAW
, TRUE
);
149 InvalidateRect(NULL
, TRUE
);
152 BOOL
SetButtonCommandId(IN INT iButtonIndex
, IN INT iCommandId
)
156 tbbi
.cbSize
= sizeof(tbbi
);
157 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_COMMAND
;
158 tbbi
.idCommand
= iCommandId
;
160 return SetButtonInfo(iButtonIndex
, &tbbi
) != 0;
164 BEGIN_MSG_MAP(CNotifyToolbar
)
167 BOOL
Initialize(HWND hWndParent
)
169 DWORD styles
= WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
|
170 TBSTYLE_TOOLTIPS
| TBSTYLE_WRAPABLE
| TBSTYLE_LIST
| TBSTYLE_TRANSPARENT
|
171 CCS_TOP
| CCS_NORESIZE
| CCS_NODIVIDER
;
173 return SubclassWindow(CToolbar::Create(hWndParent
, styles
));
177 class CTaskSwitchWnd
:
178 public CWindowImpl
< CTaskSwitchWnd
, CWindow
, CControlWinTraits
>
180 CTaskToolbar m_TaskBar
;
182 CComPtr
<ITrayWindow
> m_Tray
;
186 WORD m_TaskItemCount
;
187 WORD m_AllocatedTaskItems
;
189 PTASK_GROUP m_TaskGroups
;
190 PTASK_ITEM m_TaskItems
;
191 PTASK_ITEM m_ActiveTaskItem
;
194 UINT m_ButtonsPerLine
;
197 HIMAGELIST m_ImageList
;
199 BOOL m_IsGroupingEnabled
;
206 m_ShellHookMsg(NULL
),
208 m_AllocatedTaskItems(0),
211 m_ActiveTaskItem(NULL
),
216 m_IsGroupingEnabled(FALSE
),
217 m_IsDestroying(FALSE
)
219 ZeroMemory(&m_ButtonSize
, sizeof(m_ButtonSize
));
221 virtual ~CTaskSwitchWnd() { }
223 VOID
TaskSwitchWnd_UpdateButtonsSize(IN BOOL bRedrawDisabled
);
225 INT
GetWndTextFromTaskItem(IN PTASK_ITEM TaskItem
, LPWSTR szBuf
, DWORD cchBuf
)
227 /* Get the window text without sending a message so we don't hang if an
228 application isn't responding! */
229 return InternalGetWindowText(TaskItem
->hWnd
, szBuf
, cchBuf
);
236 PTASK_GROUP CurrentGroup
;
237 PTASK_ITEM CurrentTaskItem
, LastTaskItem
;
239 TRACE("Tasks dump:\n");
240 if (m_IsGroupingEnabled
)
242 CurrentGroup
= m_TaskGroups
;
243 while (CurrentGroup
!= NULL
)
245 TRACE("- Group PID: 0x%p Tasks: %d Index: %d\n", CurrentGroup
->dwProcessId
, CurrentGroup
->dwTaskCount
, CurrentGroup
->Index
);
247 CurrentTaskItem
= m_TaskItems
;
248 LastTaskItem
= CurrentTaskItem
+ m_TaskItemCount
;
249 while (CurrentTaskItem
!= LastTaskItem
)
251 if (CurrentTaskItem
->Group
== CurrentGroup
)
253 TRACE(" + Task hwnd: 0x%p Index: %d\n", CurrentTaskItem
->hWnd
, CurrentTaskItem
->Index
);
258 CurrentGroup
= CurrentGroup
->Next
;
261 CurrentTaskItem
= m_TaskItems
;
262 LastTaskItem
= CurrentTaskItem
+ m_TaskItemCount
;
263 while (CurrentTaskItem
!= LastTaskItem
)
265 if (CurrentTaskItem
->Group
== NULL
)
267 TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem
->hWnd
, CurrentTaskItem
->Index
);
274 CurrentTaskItem
= m_TaskItems
;
275 LastTaskItem
= CurrentTaskItem
+ m_TaskItemCount
;
276 while (CurrentTaskItem
!= LastTaskItem
)
278 TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem
->hWnd
, CurrentTaskItem
->Index
);
285 VOID
UpdateIndexesAfter(IN INT iIndex
, BOOL bInserted
)
287 PTASK_GROUP CurrentGroup
;
288 PTASK_ITEM CurrentTaskItem
, LastTaskItem
;
291 int offset
= bInserted
? +1 : -1;
293 if (m_IsGroupingEnabled
)
295 /* Update all affected groups */
296 CurrentGroup
= m_TaskGroups
;
297 while (CurrentGroup
!= NULL
)
299 if (CurrentGroup
->IsCollapsed
&&
300 CurrentGroup
->Index
>= iIndex
)
302 /* Update the toolbar buttons */
303 NewIndex
= CurrentGroup
->Index
+ offset
;
304 if (m_TaskBar
.SetButtonCommandId(CurrentGroup
->Index
+ offset
, NewIndex
))
306 CurrentGroup
->Index
= NewIndex
;
309 CurrentGroup
->Index
= -1;
312 CurrentGroup
= CurrentGroup
->Next
;
316 /* Update all affected task items */
317 CurrentTaskItem
= m_TaskItems
;
318 LastTaskItem
= CurrentTaskItem
+ m_TaskItemCount
;
319 while (CurrentTaskItem
!= LastTaskItem
)
321 CurrentGroup
= CurrentTaskItem
->Group
;
322 if (CurrentGroup
!= NULL
)
324 if (!CurrentGroup
->IsCollapsed
&&
325 CurrentTaskItem
->Index
>= iIndex
)
327 goto UpdateTaskItemBtn
;
330 else if (CurrentTaskItem
->Index
>= iIndex
)
333 /* Update the toolbar buttons */
334 NewIndex
= CurrentTaskItem
->Index
+ offset
;
335 if (m_TaskBar
.SetButtonCommandId(CurrentTaskItem
->Index
+ offset
, NewIndex
))
337 CurrentTaskItem
->Index
= NewIndex
;
340 CurrentTaskItem
->Index
= -1;
348 INT
UpdateTaskGroupButton(IN PTASK_GROUP TaskGroup
)
350 ASSERT(TaskGroup
->Index
>= 0);
352 /* FIXME: Implement */
354 return TaskGroup
->Index
;
357 VOID
ExpandTaskGroup(IN PTASK_GROUP TaskGroup
)
359 ASSERT(TaskGroup
->dwTaskCount
> 0);
360 ASSERT(TaskGroup
->IsCollapsed
);
361 ASSERT(TaskGroup
->Index
>= 0);
363 /* FIXME: Implement */
366 HICON
GetWndIcon(HWND hwnd
)
370 SendMessageTimeout(hwnd
, WM_GETICON
, ICON_SMALL2
, 0, SMTO_ABORTIFHUNG
, 1000, (PDWORD_PTR
) &hIcon
);
374 SendMessageTimeout(hwnd
, WM_GETICON
, ICON_SMALL
, 0, SMTO_ABORTIFHUNG
, 1000, (PDWORD_PTR
) &hIcon
);
378 SendMessageTimeout(hwnd
, WM_GETICON
, ICON_BIG
, 0, SMTO_ABORTIFHUNG
, 1000, (PDWORD_PTR
) &hIcon
);
382 hIcon
= (HICON
) GetClassLongPtr(hwnd
, GCL_HICONSM
);
386 hIcon
= (HICON
) GetClassLongPtr(hwnd
, GCL_HICON
);
391 INT
UpdateTaskItemButton(IN PTASK_ITEM TaskItem
)
393 TBBUTTONINFO tbbi
= { 0 };
395 WCHAR windowText
[255];
397 ASSERT(TaskItem
->Index
>= 0);
399 tbbi
.cbSize
= sizeof(tbbi
);
400 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_STATE
| TBIF_TEXT
| TBIF_IMAGE
;
401 tbbi
.fsState
= TBSTATE_ENABLED
;
402 if (m_ActiveTaskItem
== TaskItem
)
403 tbbi
.fsState
|= TBSTATE_CHECKED
;
405 if (TaskItem
->RenderFlashed
)
406 tbbi
.fsState
|= TBSTATE_MARKED
;
408 /* Check if we're updating a button that is the last one in the
409 line. If so, we need to set the TBSTATE_WRAP flag! */
410 if (!m_Tray
->IsHorizontal() || (m_ButtonsPerLine
!= 0 &&
411 (TaskItem
->Index
+ 1) % m_ButtonsPerLine
== 0))
413 tbbi
.fsState
|= TBSTATE_WRAP
;
416 if (GetWndTextFromTaskItem(TaskItem
, windowText
, _countof(windowText
)) > 0)
418 tbbi
.pszText
= windowText
;
421 icon
= GetWndIcon(TaskItem
->hWnd
);
423 icon
= static_cast<HICON
>(LoadImage(NULL
, MAKEINTRESOURCE(OIC_SAMPLE
), IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
));
424 TaskItem
->IconIndex
= ImageList_ReplaceIcon(m_ImageList
, TaskItem
->IconIndex
, icon
);
425 tbbi
.iImage
= TaskItem
->IconIndex
;
427 if (!m_TaskBar
.SetButtonInfo(TaskItem
->Index
, &tbbi
))
429 TaskItem
->Index
= -1;
433 TRACE("Updated button %d for hwnd 0x%p\n", TaskItem
->Index
, TaskItem
->hWnd
);
434 return TaskItem
->Index
;
437 VOID
RemoveIcon(IN PTASK_ITEM TaskItem
)
440 PTASK_ITEM currentTaskItem
, LastItem
;
442 if (TaskItem
->IconIndex
== -1)
445 tbbi
.cbSize
= sizeof(tbbi
);
446 tbbi
.dwMask
= TBIF_IMAGE
;
448 currentTaskItem
= m_TaskItems
;
449 LastItem
= currentTaskItem
+ m_TaskItemCount
;
450 while (currentTaskItem
!= LastItem
)
452 if (currentTaskItem
->IconIndex
> TaskItem
->IconIndex
)
454 currentTaskItem
->IconIndex
--;
455 tbbi
.iImage
= currentTaskItem
->IconIndex
;
457 m_TaskBar
.SetButtonInfo(currentTaskItem
->Index
, &tbbi
);
462 ImageList_Remove(m_ImageList
, TaskItem
->IconIndex
);
465 PTASK_ITEM
FindLastTaskItemOfGroup(
466 IN PTASK_GROUP TaskGroup OPTIONAL
,
467 IN PTASK_ITEM NewTaskItem OPTIONAL
)
469 PTASK_ITEM TaskItem
, LastTaskItem
, FoundTaskItem
= NULL
;
472 ASSERT(m_IsGroupingEnabled
);
474 TaskItem
= m_TaskItems
;
475 LastTaskItem
= TaskItem
+ m_TaskItemCount
;
477 dwTaskCount
= (TaskGroup
!= NULL
? TaskGroup
->dwTaskCount
: MAX_TASKS_COUNT
);
479 ASSERT(dwTaskCount
> 0);
481 while (TaskItem
!= LastTaskItem
)
483 if (TaskItem
->Group
== TaskGroup
)
485 if ((NewTaskItem
!= NULL
&& TaskItem
!= NewTaskItem
) || NewTaskItem
== NULL
)
487 FoundTaskItem
= TaskItem
;
490 if (--dwTaskCount
== 0)
492 /* We found the last task item in the group! */
500 return FoundTaskItem
;
503 INT
CalculateTaskItemNewButtonIndex(IN PTASK_ITEM TaskItem
)
505 PTASK_GROUP TaskGroup
;
506 PTASK_ITEM LastTaskItem
;
508 /* NOTE: This routine assumes that the group is *not* collapsed! */
510 TaskGroup
= TaskItem
->Group
;
511 if (m_IsGroupingEnabled
)
513 if (TaskGroup
!= NULL
)
515 ASSERT(TaskGroup
->Index
< 0);
516 ASSERT(!TaskGroup
->IsCollapsed
);
518 if (TaskGroup
->dwTaskCount
> 1)
520 LastTaskItem
= FindLastTaskItemOfGroup(TaskGroup
, TaskItem
);
521 if (LastTaskItem
!= NULL
)
523 /* Since the group is expanded the task items must have an index */
524 ASSERT(LastTaskItem
->Index
>= 0);
526 return LastTaskItem
->Index
+ 1;
532 /* Find the last NULL group button. NULL groups are added at the end of the
533 task item list when grouping is enabled */
534 LastTaskItem
= FindLastTaskItemOfGroup(NULL
, TaskItem
);
535 if (LastTaskItem
!= NULL
)
537 ASSERT(LastTaskItem
->Index
>= 0);
539 return LastTaskItem
->Index
+ 1;
544 return m_ButtonCount
;
547 INT
AddTaskItemButton(IN OUT PTASK_ITEM TaskItem
)
549 WCHAR windowText
[255];
550 TBBUTTON tbBtn
= { 0 };
554 if (TaskItem
->Index
>= 0)
556 return UpdateTaskItemButton(TaskItem
);
559 if (TaskItem
->Group
!= NULL
&&
560 TaskItem
->Group
->IsCollapsed
)
562 /* The task group is collapsed, we only need to update the group button */
563 return UpdateTaskGroupButton(TaskItem
->Group
);
566 icon
= GetWndIcon(TaskItem
->hWnd
);
568 icon
= static_cast<HICON
>(LoadImage(NULL
, MAKEINTRESOURCE(OIC_SAMPLE
), IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
));
569 TaskItem
->IconIndex
= ImageList_ReplaceIcon(m_ImageList
, -1, icon
);
571 tbBtn
.iBitmap
= TaskItem
->IconIndex
;
572 tbBtn
.fsState
= TBSTATE_ENABLED
| TBSTATE_ELLIPSES
;
573 tbBtn
.fsStyle
= BTNS_CHECK
| BTNS_NOPREFIX
| BTNS_SHOWTEXT
;
574 tbBtn
.dwData
= TaskItem
->Index
;
576 if (GetWndTextFromTaskItem(TaskItem
, windowText
, _countof(windowText
)) > 0)
578 tbBtn
.iString
= (DWORD_PTR
) windowText
;
581 /* Find out where to insert the new button */
582 iIndex
= CalculateTaskItemNewButtonIndex(TaskItem
);
584 tbBtn
.idCommand
= iIndex
;
586 m_TaskBar
.BeginUpdate();
588 if (m_TaskBar
.InsertButton(iIndex
, &tbBtn
))
590 UpdateIndexesAfter(iIndex
, TRUE
);
592 TRACE("Added button %d for hwnd 0x%p\n", iIndex
, TaskItem
->hWnd
);
594 TaskItem
->Index
= iIndex
;
597 /* Update button sizes and fix the button wrapping */
598 UpdateButtonsSize(TRUE
);
602 m_TaskBar
.EndUpdate();
607 BOOL
DeleteTaskItemButton(IN OUT PTASK_ITEM TaskItem
)
609 PTASK_GROUP TaskGroup
;
612 TaskGroup
= TaskItem
->Group
;
614 if (TaskItem
->Index
>= 0)
616 if ((TaskGroup
!= NULL
&& !TaskGroup
->IsCollapsed
) ||
619 m_TaskBar
.BeginUpdate();
621 RemoveIcon(TaskItem
);
622 iIndex
= TaskItem
->Index
;
623 if (m_TaskBar
.DeleteButton(iIndex
))
625 TaskItem
->Index
= -1;
628 UpdateIndexesAfter(iIndex
, FALSE
);
630 /* Update button sizes and fix the button wrapping */
631 UpdateButtonsSize(TRUE
);
635 m_TaskBar
.EndUpdate();
642 PTASK_GROUP
AddToTaskGroup(IN HWND hWnd
)
645 PTASK_GROUP TaskGroup
, *PrevLink
;
647 if (!GetWindowThreadProcessId(hWnd
,
650 TRACE("Cannot get process id of hwnd 0x%p\n", hWnd
);
654 /* Try to find an existing task group */
655 TaskGroup
= m_TaskGroups
;
656 PrevLink
= &m_TaskGroups
;
657 while (TaskGroup
!= NULL
)
659 if (TaskGroup
->dwProcessId
== dwProcessId
)
661 TaskGroup
->dwTaskCount
++;
665 PrevLink
= &TaskGroup
->Next
;
666 TaskGroup
= TaskGroup
->Next
;
669 /* Allocate a new task group */
670 TaskGroup
= (PTASK_GROUP
) HeapAlloc(hProcessHeap
,
673 if (TaskGroup
!= NULL
)
675 TaskGroup
->dwTaskCount
= 1;
676 TaskGroup
->dwProcessId
= dwProcessId
;
677 TaskGroup
->Index
= -1;
679 /* Add the task group to the list */
680 *PrevLink
= TaskGroup
;
686 VOID
RemoveTaskFromTaskGroup(IN OUT PTASK_ITEM TaskItem
)
688 PTASK_GROUP TaskGroup
, CurrentGroup
, *PrevLink
;
690 TaskGroup
= TaskItem
->Group
;
691 if (TaskGroup
!= NULL
)
693 DWORD dwNewTaskCount
= --TaskGroup
->dwTaskCount
;
694 if (dwNewTaskCount
== 0)
696 /* Find the previous pointer in the chain */
697 CurrentGroup
= m_TaskGroups
;
698 PrevLink
= &m_TaskGroups
;
699 while (CurrentGroup
!= TaskGroup
)
701 PrevLink
= &CurrentGroup
->Next
;
702 CurrentGroup
= CurrentGroup
->Next
;
705 /* Remove the group from the list */
706 ASSERT(TaskGroup
== CurrentGroup
);
707 *PrevLink
= TaskGroup
->Next
;
709 /* Free the task group */
710 HeapFree(hProcessHeap
,
714 else if (TaskGroup
->IsCollapsed
&&
715 TaskGroup
->Index
>= 0)
717 if (dwNewTaskCount
> 1)
719 /* FIXME: Check if we should expand the group */
720 /* Update the task group button */
721 UpdateTaskGroupButton(TaskGroup
);
725 /* Expand the group of one task button to a task button */
726 ExpandTaskGroup(TaskGroup
);
732 PTASK_ITEM
FindTaskItem(IN HWND hWnd
)
734 PTASK_ITEM TaskItem
, LastItem
;
736 TaskItem
= m_TaskItems
;
737 LastItem
= TaskItem
+ m_TaskItemCount
;
738 while (TaskItem
!= LastItem
)
740 if (TaskItem
->hWnd
== hWnd
)
749 PTASK_ITEM
FindOtherTaskItem(IN HWND hWnd
)
751 PTASK_ITEM LastItem
, TaskItem
;
752 PTASK_GROUP TaskGroup
;
755 if (!GetWindowThreadProcessId(hWnd
, &dwProcessId
))
760 /* Try to find another task that belongs to the same
761 process as the given window */
762 TaskItem
= m_TaskItems
;
763 LastItem
= TaskItem
+ m_TaskItemCount
;
764 while (TaskItem
!= LastItem
)
766 TaskGroup
= TaskItem
->Group
;
767 if (TaskGroup
!= NULL
)
769 if (TaskGroup
->dwProcessId
== dwProcessId
)
774 DWORD dwProcessIdTask
;
776 if (GetWindowThreadProcessId(TaskItem
->hWnd
,
778 dwProcessIdTask
== dwProcessId
)
790 PTASK_ITEM
AllocTaskItem()
792 if (m_TaskItemCount
>= MAX_TASKS_COUNT
)
794 /* We need the most significant bit in 16 bit command IDs to indicate whether it
795 is a task group or task item. WM_COMMAND limits command IDs to 16 bits! */
799 ASSERT(m_AllocatedTaskItems
>= m_TaskItemCount
);
801 if (m_TaskItemCount
== 0)
803 m_TaskItems
= (PTASK_ITEM
) HeapAlloc(hProcessHeap
,
805 TASK_ITEM_ARRAY_ALLOC
* sizeof(*m_TaskItems
));
806 if (m_TaskItems
!= NULL
)
808 m_AllocatedTaskItems
= TASK_ITEM_ARRAY_ALLOC
;
813 else if (m_TaskItemCount
>= m_AllocatedTaskItems
)
816 SIZE_T NewArrayLength
, ActiveTaskItemIndex
;
818 NewArrayLength
= m_AllocatedTaskItems
+ TASK_ITEM_ARRAY_ALLOC
;
820 NewArray
= (PTASK_ITEM
) HeapReAlloc(hProcessHeap
,
823 NewArrayLength
* sizeof(*m_TaskItems
));
824 if (NewArray
!= NULL
)
826 if (m_ActiveTaskItem
!= NULL
)
828 /* Fixup the ActiveTaskItem pointer */
829 ActiveTaskItemIndex
= m_ActiveTaskItem
- m_TaskItems
;
830 m_ActiveTaskItem
= NewArray
+ ActiveTaskItemIndex
;
832 m_AllocatedTaskItems
= (WORD
) NewArrayLength
;
833 m_TaskItems
= NewArray
;
839 return m_TaskItems
+ m_TaskItemCount
++;
842 VOID
FreeTaskItem(IN OUT PTASK_ITEM TaskItem
)
846 if (TaskItem
== m_ActiveTaskItem
)
847 m_ActiveTaskItem
= NULL
;
849 wIndex
= (WORD
) (TaskItem
- m_TaskItems
);
850 if (wIndex
+ 1 < m_TaskItemCount
)
854 (m_TaskItemCount
- wIndex
- 1) * sizeof(*TaskItem
));
860 VOID
DeleteTaskItem(IN OUT PTASK_ITEM TaskItem
)
864 /* Delete the task button from the toolbar */
865 DeleteTaskItemButton(TaskItem
);
868 /* Remove the task from it's group */
869 RemoveTaskFromTaskGroup(TaskItem
);
871 /* Free the task item */
872 FreeTaskItem(TaskItem
);
875 VOID
CheckActivateTaskItem(IN OUT PTASK_ITEM TaskItem
)
877 PTASK_ITEM CurrentTaskItem
;
878 PTASK_GROUP TaskGroup
= NULL
;
880 CurrentTaskItem
= m_ActiveTaskItem
;
882 if (TaskItem
!= NULL
)
883 TaskGroup
= TaskItem
->Group
;
885 if (m_IsGroupingEnabled
&&
887 TaskGroup
->IsCollapsed
)
893 if (CurrentTaskItem
!= NULL
)
895 PTASK_GROUP CurrentTaskGroup
;
897 if (CurrentTaskItem
== TaskItem
)
900 CurrentTaskGroup
= CurrentTaskItem
->Group
;
902 if (m_IsGroupingEnabled
&&
903 CurrentTaskGroup
!= NULL
&&
904 CurrentTaskGroup
->IsCollapsed
)
906 if (CurrentTaskGroup
== TaskGroup
)
913 m_ActiveTaskItem
= NULL
;
914 if (CurrentTaskItem
->Index
>= 0)
916 UpdateTaskItemButton(CurrentTaskItem
);
921 m_ActiveTaskItem
= TaskItem
;
923 if (TaskItem
!= NULL
&& TaskItem
->Index
>= 0)
925 UpdateTaskItemButton(TaskItem
);
927 else if (TaskItem
== NULL
)
929 TRACE("Active TaskItem now NULL\n");
933 PTASK_ITEM
FindTaskItemByIndex(IN INT Index
)
935 PTASK_ITEM TaskItem
, LastItem
;
937 TaskItem
= m_TaskItems
;
938 LastItem
= TaskItem
+ m_TaskItemCount
;
939 while (TaskItem
!= LastItem
)
941 if (TaskItem
->Index
== Index
)
950 PTASK_GROUP
FindTaskGroupByIndex(IN INT Index
)
952 PTASK_GROUP CurrentGroup
;
954 CurrentGroup
= m_TaskGroups
;
955 while (CurrentGroup
!= NULL
)
957 if (CurrentGroup
->Index
== Index
)
960 CurrentGroup
= CurrentGroup
->Next
;
966 BOOL
AddTask(IN HWND hWnd
)
970 if (!::IsWindow(hWnd
) || m_Tray
->IsSpecialHWND(hWnd
))
973 TaskItem
= FindTaskItem(hWnd
);
974 if (TaskItem
== NULL
)
976 TRACE("Add window 0x%p\n", hWnd
);
977 TaskItem
= AllocTaskItem();
978 if (TaskItem
!= NULL
)
982 TaskItem
->hWnd
= hWnd
;
983 TaskItem
->Index
= -1;
984 TaskItem
->Group
= AddToTaskGroup(hWnd
);
988 AddTaskItemButton(TaskItem
);
993 return TaskItem
!= NULL
;
996 BOOL
ActivateTaskItem(IN OUT PTASK_ITEM TaskItem OPTIONAL
)
998 if (TaskItem
!= NULL
)
1000 TRACE("Activate window 0x%p on button %d\n", TaskItem
->hWnd
, TaskItem
->Index
);
1003 CheckActivateTaskItem(TaskItem
);
1008 BOOL
ActivateTask(IN HWND hWnd
)
1010 PTASK_ITEM TaskItem
;
1014 return ActivateTaskItem(NULL
);
1017 TaskItem
= FindTaskItem(hWnd
);
1018 if (TaskItem
== NULL
)
1020 TaskItem
= FindOtherTaskItem(hWnd
);
1023 if (TaskItem
== NULL
)
1025 WARN("Activate window 0x%p, could not find task\n", hWnd
);
1026 RefreshWindowList();
1029 return ActivateTaskItem(TaskItem
);
1032 BOOL
DeleteTask(IN HWND hWnd
)
1034 PTASK_ITEM TaskItem
;
1036 TaskItem
= FindTaskItem(hWnd
);
1037 if (TaskItem
!= NULL
)
1039 TRACE("Delete window 0x%p on button %d\n", hWnd
, TaskItem
->Index
);
1040 DeleteTaskItem(TaskItem
);
1044 //TRACE("Failed to delete window 0x%p\n", hWnd);
1049 VOID
DeleteAllTasks()
1051 PTASK_ITEM CurrentTask
;
1053 if (m_TaskItemCount
> 0)
1055 CurrentTask
= m_TaskItems
+ m_TaskItemCount
;
1058 DeleteTaskItem(--CurrentTask
);
1059 } while (CurrentTask
!= m_TaskItems
);
1063 VOID
FlashTaskItem(IN OUT PTASK_ITEM TaskItem
)
1065 TaskItem
->RenderFlashed
= 1;
1066 UpdateTaskItemButton(TaskItem
);
1069 BOOL
FlashTask(IN HWND hWnd
)
1071 PTASK_ITEM TaskItem
;
1073 TaskItem
= FindTaskItem(hWnd
);
1074 if (TaskItem
!= NULL
)
1076 TRACE("Flashing window 0x%p on button %d\n", hWnd
, TaskItem
->Index
);
1077 FlashTaskItem(TaskItem
);
1084 VOID
RedrawTaskItem(IN OUT PTASK_ITEM TaskItem
)
1086 PTASK_GROUP TaskGroup
;
1088 TaskGroup
= TaskItem
->Group
;
1089 if (m_IsGroupingEnabled
&& TaskGroup
!= NULL
)
1091 if (TaskGroup
->IsCollapsed
&& TaskGroup
->Index
>= 0)
1093 UpdateTaskGroupButton(TaskGroup
);
1095 else if (TaskItem
->Index
>= 0)
1097 goto UpdateTaskItem
;
1100 else if (TaskItem
->Index
>= 0)
1103 TaskItem
->RenderFlashed
= 0;
1104 UpdateTaskItemButton(TaskItem
);
1109 BOOL
RedrawTask(IN HWND hWnd
)
1111 PTASK_ITEM TaskItem
;
1113 TaskItem
= FindTaskItem(hWnd
);
1114 if (TaskItem
!= NULL
)
1116 RedrawTaskItem(TaskItem
);
1123 VOID
UpdateButtonsSize(IN BOOL bRedrawDisabled
)
1126 UINT uiRows
, uiMax
, uiMin
, uiBtnsPerLine
, ui
;
1130 if (GetClientRect(&rcClient
) && !IsRectEmpty(&rcClient
))
1132 if (m_ButtonCount
> 0)
1134 Horizontal
= m_Tray
->IsHorizontal();
1138 TBMETRICS tbm
= { 0 };
1139 tbm
.cbSize
= sizeof(tbm
);
1140 tbm
.dwMask
= TBMF_BUTTONSPACING
;
1141 m_TaskBar
.GetMetrics(&tbm
);
1143 uiRows
= (rcClient
.bottom
+ tbm
.cyButtonSpacing
) / (m_ButtonSize
.cy
+ tbm
.cyButtonSpacing
);
1147 uiBtnsPerLine
= (m_ButtonCount
+ uiRows
- 1) / uiRows
;
1152 uiRows
= m_ButtonCount
;
1155 if (!bRedrawDisabled
)
1156 m_TaskBar
.BeginUpdate();
1158 /* We might need to update the button spacing */
1159 int cxButtonSpacing
= m_TaskBar
.UpdateTbButtonSpacing(
1160 Horizontal
, m_Theme
!= NULL
,
1161 uiRows
, uiBtnsPerLine
);
1163 /* Determine the minimum and maximum width of a button */
1164 uiMin
= GetSystemMetrics(SM_CXSIZE
) + (2 * GetSystemMetrics(SM_CXEDGE
));
1167 uiMax
= GetSystemMetrics(SM_CXMINIMIZED
);
1169 /* Calculate the ideal width and make sure it's within the allowed range */
1170 NewBtnSize
= (rcClient
.right
- (uiBtnsPerLine
* cxButtonSpacing
)) / uiBtnsPerLine
;
1172 if (NewBtnSize
< (LONG
) uiMin
)
1174 if (NewBtnSize
>(LONG
)uiMax
)
1177 /* Recalculate how many buttons actually fit into one line */
1178 uiBtnsPerLine
= rcClient
.right
/ (NewBtnSize
+ cxButtonSpacing
);
1179 if (uiBtnsPerLine
== 0)
1184 NewBtnSize
= uiMax
= rcClient
.right
;
1187 m_ButtonSize
.cx
= NewBtnSize
;
1189 m_ButtonsPerLine
= uiBtnsPerLine
;
1191 for (ui
= 0; ui
!= m_ButtonCount
; ui
++)
1193 TBBUTTONINFOW tbbi
= { 0 };
1194 tbbi
.cbSize
= sizeof(tbbi
);
1195 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_SIZE
| TBIF_STATE
;
1196 tbbi
.cx
= (INT
) NewBtnSize
;
1197 tbbi
.fsState
= TBSTATE_ENABLED
;
1199 /* Check if we're updating a button that is the last one in the
1200 line. If so, we need to set the TBSTATE_WRAP flag! */
1203 if ((ui
+ 1) % uiBtnsPerLine
== 0)
1204 tbbi
.fsState
|= TBSTATE_WRAP
;
1208 tbbi
.fsState
|= TBSTATE_WRAP
;
1211 if (m_ActiveTaskItem
!= NULL
&&
1212 m_ActiveTaskItem
->Index
== (INT
)ui
)
1214 tbbi
.fsState
|= TBSTATE_CHECKED
;
1217 m_TaskBar
.SetButtonInfo(ui
, &tbbi
);
1222 m_ButtonsPerLine
= 0;
1223 m_ButtonSize
.cx
= 0;
1227 // FIXME: This seems to be enabling redraws prematurely, but moving it to its right place doesn't work!
1228 m_TaskBar
.EndUpdate();
1231 BOOL CALLBACK
EnumWindowsProc(IN HWND hWnd
)
1233 /* Only show windows that still exist and are visible and none of explorer's
1234 special windows (such as the desktop or the tray window) */
1235 if (::IsWindow(hWnd
) && ::IsWindowVisible(hWnd
) &&
1236 !m_Tray
->IsSpecialHWND(hWnd
))
1238 DWORD exStyle
= ::GetWindowLong(hWnd
, GWL_EXSTYLE
);
1239 /* Don't list popup windows and also no tool windows */
1240 if ((::GetWindow(hWnd
, GW_OWNER
) == NULL
|| exStyle
& WS_EX_APPWINDOW
) &&
1241 !(exStyle
& WS_EX_TOOLWINDOW
))
1243 TRACE("Adding task for %p...\n", hWnd
);
1252 static BOOL CALLBACK
s_EnumWindowsProc(IN HWND hWnd
, IN LPARAM lParam
)
1254 CTaskSwitchWnd
* This
= (CTaskSwitchWnd
*) lParam
;
1256 return This
->EnumWindowsProc(hWnd
);
1259 BOOL
RefreshWindowList()
1261 TRACE("Refreshing window list...\n");
1262 /* Add all windows to the toolbar */
1263 return EnumWindows(s_EnumWindowsProc
, (LPARAM
)this);
1266 LRESULT
OnThemeChanged()
1268 TRACE("OmThemeChanged\n");
1271 CloseThemeData(m_Theme
);
1273 if (IsThemeActive())
1274 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBand");
1281 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1283 return OnThemeChanged();
1286 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1288 if (!m_TaskBar
.Initialize(m_hWnd
))
1291 SetWindowTheme(m_TaskBar
.m_hWnd
, L
"TaskBand", NULL
);
1294 m_ImageList
= ImageList_Create(16, 16, ILC_COLOR32
| ILC_MASK
, 0, 1000);
1295 m_TaskBar
.SetImageList(m_ImageList
);
1297 /* Calculate the default button size. Don't save this in m_ButtonSize.cx so that
1298 the actual button width gets updated correctly on the first recalculation */
1299 int cx
= GetSystemMetrics(SM_CXMINIMIZED
);
1300 int cy
= m_ButtonSize
.cy
= GetSystemMetrics(SM_CYSIZE
) + (2 * GetSystemMetrics(SM_CYEDGE
));
1301 m_TaskBar
.SetButtonSize(cx
, cy
);
1303 /* Set proper spacing between buttons */
1304 m_TaskBar
.UpdateTbButtonSpacing(m_Tray
->IsHorizontal(), m_Theme
!= NULL
);
1306 /* Register the shell hook */
1307 m_ShellHookMsg
= RegisterWindowMessage(TEXT("SHELLHOOK"));
1309 TRACE("ShellHookMsg got assigned number %d\n", m_ShellHookMsg
);
1311 RegisterShellHook(m_hWnd
, 3); /* 1 if no NT! We're targeting NT so we don't care! */
1313 RefreshWindowList();
1315 /* Recalculate the button size */
1316 UpdateButtonsSize(FALSE
);
1319 SetTimer(hwnd
, 1, 5000, NULL
);
1324 LRESULT
OnDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1326 m_IsDestroying
= TRUE
;
1328 /* Unregister the shell hook */
1329 RegisterShellHook(m_hWnd
, FALSE
);
1331 CloseThemeData(m_Theme
);
1336 BOOL
HandleAppCommand(IN WPARAM wParam
, IN LPARAM lParam
)
1340 switch (GET_APPCOMMAND_LPARAM(lParam
))
1342 case APPCOMMAND_BROWSER_SEARCH
:
1343 Ret
= SHFindFiles(NULL
,
1347 case APPCOMMAND_BROWSER_HOME
:
1348 case APPCOMMAND_LAUNCH_MAIL
:
1350 TRACE("Shell app command %d unhandled!\n", (INT
) GET_APPCOMMAND_LPARAM(lParam
));
1357 LRESULT
HandleShellHookMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1361 /* In case the shell hook wasn't registered properly, ignore WM_NULLs*/
1368 TRACE("Received shell hook message: wParam=%08lx, lParam=%08lx\n", wParam
, lParam
);
1370 switch ((INT
) wParam
)
1372 case HSHELL_APPCOMMAND
:
1373 HandleAppCommand(wParam
, lParam
);
1377 case HSHELL_WINDOWCREATED
:
1378 Ret
= AddTask((HWND
) lParam
);
1381 case HSHELL_WINDOWDESTROYED
:
1382 /* The window still exists! Delay destroying it a bit */
1383 DeleteTask((HWND
) lParam
);
1387 case HSHELL_RUDEAPPACTIVATED
:
1388 case HSHELL_WINDOWACTIVATED
:
1391 ActivateTask((HWND
) lParam
);
1397 FlashTask((HWND
) lParam
);
1402 RedrawTask((HWND
) lParam
);
1406 case HSHELL_TASKMAN
:
1407 ::PostMessage(m_Tray
->GetHWND(), TWM_OPENSTARTMENU
, 0, 0);
1410 case HSHELL_ACTIVATESHELLWINDOW
:
1411 case HSHELL_LANGUAGE
:
1412 case HSHELL_SYSMENU
:
1413 case HSHELL_ENDTASK
:
1414 case HSHELL_ACCESSIBILITYSTATE
:
1415 case HSHELL_WINDOWREPLACED
:
1416 case HSHELL_WINDOWREPLACING
:
1418 case HSHELL_GETMINRECT
:
1421 #if DEBUG_SHELL_HOOK
1423 for (i
= 0, found
= 0; i
!= sizeof(hshell_msg
) / sizeof(hshell_msg
[0]); i
++)
1425 if (hshell_msg
[i
].msg
== (INT
) wParam
)
1427 TRACE("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg
[i
].msg_name
, lParam
);
1435 TRACE("Shell message %d unhandled (lParam = 0x%p)!\n", (INT
) wParam
, lParam
);
1443 VOID
EnableGrouping(IN BOOL bEnable
)
1445 m_IsGroupingEnabled
= bEnable
;
1447 /* Collapse or expand groups if neccessary */
1448 UpdateButtonsSize(FALSE
);
1451 VOID
HandleTaskItemClick(IN OUT PTASK_ITEM TaskItem
)
1456 if (::IsWindow(TaskItem
->hWnd
))
1458 bIsMinimized
= ::IsIconic(TaskItem
->hWnd
);
1459 bIsActive
= (TaskItem
== m_ActiveTaskItem
);
1461 TRACE("Active TaskItem %p, selected TaskItem %p\n", m_ActiveTaskItem
, TaskItem
);
1462 if (m_ActiveTaskItem
)
1463 TRACE("Active TaskItem hWnd=%p, TaskItem hWnd %p\n", m_ActiveTaskItem
->hWnd
, TaskItem
->hWnd
);
1465 TRACE("Valid button clicked. HWND=%p, IsMinimized=%s, IsActive=%s...\n",
1466 TaskItem
->hWnd
, bIsMinimized
? "Yes" : "No", bIsActive
? "Yes" : "No");
1468 if (!bIsMinimized
&& bIsActive
)
1470 ::PostMessage(TaskItem
->hWnd
,
1474 TRACE("Valid button clicked. App window Minimized.\n");
1480 ::PostMessage(TaskItem
->hWnd
,
1484 TRACE("Valid button clicked. App window Restored.\n");
1487 SetForegroundWindow(TaskItem
->hWnd
);
1488 TRACE("Valid button clicked. App window Activated.\n");
1493 VOID
HandleTaskGroupClick(IN OUT PTASK_GROUP TaskGroup
)
1495 /* TODO: Show task group menu */
1498 BOOL
HandleButtonClick(IN WORD wIndex
)
1500 PTASK_ITEM TaskItem
;
1501 PTASK_GROUP TaskGroup
;
1503 if (m_IsGroupingEnabled
)
1505 TaskGroup
= FindTaskGroupByIndex((INT
) wIndex
);
1506 if (TaskGroup
!= NULL
&& TaskGroup
->IsCollapsed
)
1508 HandleTaskGroupClick(TaskGroup
);
1513 TaskItem
= FindTaskItemByIndex((INT
) wIndex
);
1514 if (TaskItem
!= NULL
)
1516 HandleTaskItemClick(TaskItem
);
1524 VOID
HandleTaskItemRightClick(IN OUT PTASK_ITEM TaskItem
)
1527 HMENU hmenu
= ::GetSystemMenu(TaskItem
->hWnd
, FALSE
);
1534 cmd
= TrackPopupMenu(hmenu
, TPM_LEFTBUTTON
| TPM_RIGHTBUTTON
| TPM_RETURNCMD
, pt
.x
, pt
.y
, 0, m_TaskBar
.m_hWnd
, NULL
);
1537 SetForegroundWindow(TaskItem
->hWnd
); // reactivate window after the context menu has closed
1538 ::PostMessage(TaskItem
->hWnd
, WM_SYSCOMMAND
, cmd
, 0);
1543 VOID
HandleTaskGroupRightClick(IN OUT PTASK_GROUP TaskGroup
)
1545 /* TODO: Show task group right click menu */
1548 BOOL
HandleButtonRightClick(IN WORD wIndex
)
1550 PTASK_ITEM TaskItem
;
1551 PTASK_GROUP TaskGroup
;
1552 if (m_IsGroupingEnabled
)
1554 TaskGroup
= FindTaskGroupByIndex((INT
) wIndex
);
1555 if (TaskGroup
!= NULL
&& TaskGroup
->IsCollapsed
)
1557 HandleTaskGroupRightClick(TaskGroup
);
1562 TaskItem
= FindTaskItemByIndex((INT
) wIndex
);
1564 if (TaskItem
!= NULL
)
1566 HandleTaskItemRightClick(TaskItem
);
1574 LRESULT
HandleItemPaint(IN OUT NMTBCUSTOMDRAW
*nmtbcd
)
1576 LRESULT Ret
= CDRF_DODEFAULT
;
1577 PTASK_GROUP TaskGroup
;
1578 PTASK_ITEM TaskItem
;
1580 TaskItem
= FindTaskItemByIndex((INT
) nmtbcd
->nmcd
.dwItemSpec
);
1581 TaskGroup
= FindTaskGroupByIndex((INT
) nmtbcd
->nmcd
.dwItemSpec
);
1582 if (TaskGroup
== NULL
&& TaskItem
!= NULL
)
1584 ASSERT(TaskItem
!= NULL
);
1586 if (TaskItem
!= NULL
&& ::IsWindow(TaskItem
->hWnd
))
1588 /* Make the entire button flashing if neccessary */
1589 if (nmtbcd
->nmcd
.uItemState
& CDIS_MARKED
)
1591 Ret
= TBCDRF_NOBACKGROUND
;
1594 SelectObject(nmtbcd
->nmcd
.hdc
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1595 Rectangle(nmtbcd
->nmcd
.hdc
,
1596 nmtbcd
->nmcd
.rc
.left
,
1597 nmtbcd
->nmcd
.rc
.top
,
1598 nmtbcd
->nmcd
.rc
.right
,
1599 nmtbcd
->nmcd
.rc
.bottom
);
1603 DrawThemeBackground(m_Theme
, nmtbcd
->nmcd
.hdc
, TDP_FLASHBUTTON
, 0, &nmtbcd
->nmcd
.rc
, 0);
1605 nmtbcd
->clrText
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
1610 else if (TaskGroup
!= NULL
)
1612 /* FIXME: Implement painting for task groups */
1617 LRESULT
HandleToolbarNotification(IN
const NMHDR
*nmh
)
1625 LPNMTBCUSTOMDRAW nmtbcd
= (LPNMTBCUSTOMDRAW
) nmh
;
1627 switch (nmtbcd
->nmcd
.dwDrawStage
)
1630 case CDDS_ITEMPREPAINT
:
1631 Ret
= HandleItemPaint(nmtbcd
);
1635 Ret
= CDRF_NOTIFYITEMDRAW
;
1639 Ret
= CDRF_DODEFAULT
;
1649 LRESULT
DrawBackground(HDC hdc
)
1653 GetClientRect(&rect
);
1654 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1659 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1661 HDC hdc
= (HDC
) wParam
;
1669 return DrawBackground(hdc
);
1672 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1676 szClient
.cx
= LOWORD(lParam
);
1677 szClient
.cy
= HIWORD(lParam
);
1678 if (m_TaskBar
.m_hWnd
!= NULL
)
1680 m_TaskBar
.SetWindowPos(NULL
, 0, 0, szClient
.cx
, szClient
.cy
, SWP_NOZORDER
);
1682 UpdateButtonsSize(FALSE
);
1687 LRESULT
OnNcHitTestToolbar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1691 /* See if the mouse is on a button */
1692 pt
.x
= GET_X_LPARAM(lParam
);
1693 pt
.y
= GET_Y_LPARAM(lParam
);
1694 ScreenToClient(&pt
);
1696 INT index
= m_TaskBar
.HitTest(&pt
);
1699 /* Make the control appear to be transparent outside of any buttons */
1700 return HTTRANSPARENT
;
1707 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1710 /* We want the tray window to be draggable everywhere, so make the control
1711 appear transparent */
1712 Ret
= DefWindowProc(uMsg
, wParam
, lParam
);
1713 if (Ret
!= HTVSCROLL
&& Ret
!= HTHSCROLL
)
1714 Ret
= HTTRANSPARENT
;
1718 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1721 if (lParam
!= 0 && (HWND
) lParam
== m_TaskBar
.m_hWnd
)
1723 HandleButtonClick(LOWORD(wParam
));
1728 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1731 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
1733 if (nmh
->hwndFrom
== m_TaskBar
.m_hWnd
)
1735 Ret
= HandleToolbarNotification(nmh
);
1740 LRESULT
OnEnableGrouping(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1742 LRESULT Ret
= m_IsGroupingEnabled
;
1743 if ((BOOL
)wParam
!= m_IsGroupingEnabled
)
1745 EnableGrouping((BOOL
) wParam
);
1750 LRESULT
OnUpdateTaskbarPos(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1752 /* Update the button spacing */
1753 m_TaskBar
.UpdateTbButtonSpacing(m_Tray
->IsHorizontal(), m_Theme
!= NULL
);
1757 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1762 if (m_TaskBar
.m_hWnd
!= NULL
)
1766 pt
.x
= GET_X_LPARAM(lParam
);
1767 pt
.y
= GET_Y_LPARAM(lParam
);
1769 ::ScreenToClient(m_TaskBar
.m_hWnd
, &pt
);
1771 iBtn
= m_TaskBar
.HitTest(&pt
);
1774 HandleButtonRightClick(iBtn
);
1779 /* Not on a taskbar button, so forward message to tray */
1780 Ret
= SendMessage(m_Tray
->GetHWND(), uMsg
, wParam
, lParam
);
1785 LRESULT
OnKludgeItemRect(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1787 PTASK_ITEM TaskItem
= FindTaskItem((HWND
) wParam
);
1790 RECT
* prcMinRect
= (RECT
*) lParam
;
1791 RECT rcItem
, rcToolbar
;
1792 m_TaskBar
.GetItemRect(TaskItem
->Index
, &rcItem
);
1793 m_TaskBar
.GetWindowRect(&rcToolbar
);
1795 OffsetRect(&rcItem
, rcToolbar
.left
, rcToolbar
.top
);
1797 *prcMinRect
= rcItem
;
1803 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1816 DECLARE_WND_CLASS_EX(szTaskSwitchWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
1818 BEGIN_MSG_MAP(CTaskSwitchWnd
)
1819 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
1820 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
1821 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
1822 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
1823 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
1824 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
1825 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
1826 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
1827 MESSAGE_HANDLER(TSWM_ENABLEGROUPING
, OnEnableGrouping
)
1828 MESSAGE_HANDLER(TSWM_UPDATETASKBARPOS
, OnUpdateTaskbarPos
)
1829 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
1830 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
1831 MESSAGE_HANDLER(m_ShellHookMsg
, HandleShellHookMsg
)
1833 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTestToolbar
)
1836 HWND
_Init(IN HWND hWndParent
, IN OUT ITrayWindow
*tray
)
1839 m_IsGroupingEnabled
= TRUE
; /* FIXME */
1840 return Create(hWndParent
, 0, szRunningApps
, WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| WS_TABSTOP
);
1845 CreateTaskSwitchWnd(IN HWND hWndParent
, IN OUT ITrayWindow
*Tray
)
1847 CTaskSwitchWnd
* instance
;
1849 // TODO: Destroy after the window is destroyed
1850 instance
= new CTaskSwitchWnd();
1852 return instance
->_Init(hWndParent
, Tray
);