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
23 /* By default we don't use DrawCaptionTemp() because it causes some minimal
24 drawing glitches with the toolbar custom painting code */
25 #define TASK_USE_DRAWCAPTIONTEMP 1
27 /* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every
31 static const TCHAR szTaskSwitchWndClass
[] = TEXT("MSTaskSwWClass");
32 static const TCHAR szRunningApps
[] = TEXT("Running Applications");
34 typedef struct _TASK_GROUP
36 /* We have to use a linked list instead of an array so we don't have to
37 update all pointers to groups in the task item array when removing
39 struct _TASK_GROUP
*Next
;
50 #if TASK_USE_DRAWCAPTIONTEMP != 0
52 /* DisplayTooltip is TRUE when the group button text didn't fit into
54 DWORD DisplayTooltip
: 1;
58 DWORD IsCollapsed
: 1;
61 } TASK_GROUP
, *PTASK_GROUP
;
63 typedef struct _TASK_ITEM
69 #if !(TASK_USE_DRAWCAPTIONTEMP != 0)
81 #if TASK_USE_DRAWCAPTIONTEMP != 0
83 /* DisplayTooltip is TRUE when the window text didn't fit into the
85 DWORD DisplayTooltip
: 1;
89 /* IsFlashing is TRUE when the task bar item should be flashing. */
92 /* RenderFlashed is only TRUE if the task bar item should be
93 drawn with a flash. */
94 DWORD RenderFlashed
: 1;
97 } TASK_ITEM
, *PTASK_ITEM
;
99 #define TASK_ITEM_ARRAY_ALLOC 64
101 typedef struct _TASK_SWITCH_WND
109 PTASK_GROUP TaskGroups
;
112 WORD AllocatedTaskItems
;
113 PTASK_ITEM TaskItems
;
114 PTASK_ITEM ActiveTaskItem
;
117 UINT TbButtonsPerLine
;
118 WORD ToolbarBtnCount
;
125 DWORD IsGroupingEnabled
: 1;
126 DWORD IsDestroying
: 1;
127 DWORD IsToolbarSubclassed
: 1;
133 } TASK_SWITCH_WND
, *PTASK_SWITCH_WND
;
135 #define TSW_TOOLBAR_SUBCLASS_ID 1
137 #define MAX_TASKS_COUNT (0x7FFF)
139 static VOID
TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This
,
140 IN BOOL bRedrawDisabled
);
142 #if TASK_USE_DRAWCAPTIONTEMP != 0
144 #define TaskSwitchWnd_GetWndTextFromTaskItem(a,b) NULL
146 #else /* !TASK_USE_DRAWCAPTIONTEMP */
149 TaskSwitchWnd_GetWndTextFromTaskItem(IN OUT PTASK_SWITCH_WND This
,
150 IN PTASK_ITEM TaskItem
)
152 /* Get the window text without sending a message so we don't hang if an
153 application isn't responding! */
154 if (InternalGetWindowText(TaskItem
->hWnd
,
156 sizeof(This
->szBuf
) / sizeof(This
->szBuf
[0])) > 0)
168 TaskSwitchWnd_DumpTasks(IN OUT PTASK_SWITCH_WND This
)
170 PTASK_GROUP CurrentGroup
;
171 PTASK_ITEM CurrentTaskItem
, LastTaskItem
;
173 DbgPrint("Tasks dump:\n");
174 if (This
->IsGroupingEnabled
)
176 CurrentGroup
= This
->TaskGroups
;
177 while (CurrentGroup
!= NULL
)
179 DbgPrint("- Group PID: 0x%p Tasks: %d Index: %d\n", CurrentGroup
->dwProcessId
, CurrentGroup
->dwTaskCount
, CurrentGroup
->Index
);
181 CurrentTaskItem
= This
->TaskItems
;
182 LastTaskItem
= CurrentTaskItem
+ This
->TaskItemCount
;
183 while (CurrentTaskItem
!= LastTaskItem
)
185 if (CurrentTaskItem
->Group
== CurrentGroup
)
187 DbgPrint(" + Task hwnd: 0x%p Index: %d\n", CurrentTaskItem
->hWnd
, CurrentTaskItem
->Index
);
192 CurrentGroup
= CurrentGroup
->Next
;
195 CurrentTaskItem
= This
->TaskItems
;
196 LastTaskItem
= CurrentTaskItem
+ This
->TaskItemCount
;
197 while (CurrentTaskItem
!= LastTaskItem
)
199 if (CurrentTaskItem
->Group
== NULL
)
201 DbgPrint("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem
->hWnd
, CurrentTaskItem
->Index
);
208 CurrentTaskItem
= This
->TaskItems
;
209 LastTaskItem
= CurrentTaskItem
+ This
->TaskItemCount
;
210 while (CurrentTaskItem
!= LastTaskItem
)
212 DbgPrint("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem
->hWnd
, CurrentTaskItem
->Index
);
220 TaskSwitchWnd_BeginUpdate(IN OUT PTASK_SWITCH_WND This
)
222 SendMessage(This
->hWndToolbar
,
229 TaskSwitchWnd_EndUpdate(IN OUT PTASK_SWITCH_WND This
)
231 SendMessage(This
->hWndToolbar
,
235 InvalidateRect(This
->hWndToolbar
,
241 TaskSwitchWnd_SetToolbarButtonCommandId(IN OUT PTASK_SWITCH_WND This
,
247 tbbi
.cbSize
= sizeof(tbbi
);
248 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_COMMAND
;
249 tbbi
.idCommand
= iCommandId
;
251 return SendMessage(This
->hWndToolbar
,
253 (WPARAM
)iButtonIndex
,
258 TaskSwitchWnd_UpdateIndexesAfterButtonInserted(IN OUT PTASK_SWITCH_WND This
,
261 PTASK_GROUP CurrentGroup
;
262 PTASK_ITEM CurrentTaskItem
, LastTaskItem
;
265 if (This
->IsGroupingEnabled
)
267 /* Update all affected groups */
268 CurrentGroup
= This
->TaskGroups
;
269 while (CurrentGroup
!= NULL
)
271 if (CurrentGroup
->IsCollapsed
&&
272 CurrentGroup
->Index
>= iIndex
)
274 /* Update the toolbar buttons */
275 NewIndex
= CurrentGroup
->Index
+ 1;
276 if (TaskSwitchWnd_SetToolbarButtonCommandId(This
,
277 CurrentGroup
->Index
+ 1,
280 CurrentGroup
->Index
= NewIndex
;
283 CurrentGroup
->Index
= -1;
286 CurrentGroup
= CurrentGroup
->Next
;
290 /* Update all affected task items */
291 CurrentTaskItem
= This
->TaskItems
;
292 LastTaskItem
= CurrentTaskItem
+ This
->TaskItemCount
;
293 while (CurrentTaskItem
!= LastTaskItem
)
295 CurrentGroup
= CurrentTaskItem
->Group
;
296 if (CurrentGroup
!= NULL
)
298 if (!CurrentGroup
->IsCollapsed
&&
299 CurrentTaskItem
->Index
>= iIndex
)
301 goto UpdateTaskItemBtn
;
304 else if (CurrentTaskItem
->Index
>= iIndex
)
307 /* Update the toolbar buttons */
308 NewIndex
= CurrentTaskItem
->Index
+ 1;
309 if (TaskSwitchWnd_SetToolbarButtonCommandId(This
,
310 CurrentTaskItem
->Index
+ 1,
313 CurrentTaskItem
->Index
= NewIndex
;
316 CurrentTaskItem
->Index
= -1;
324 TaskSwitchWnd_UpdateIndexesAfterButtonDeleted(IN OUT PTASK_SWITCH_WND This
,
327 PTASK_GROUP CurrentGroup
;
328 PTASK_ITEM CurrentTaskItem
, LastTaskItem
;
331 if (This
->IsGroupingEnabled
)
333 /* Update all affected groups */
334 CurrentGroup
= This
->TaskGroups
;
335 while (CurrentGroup
!= NULL
)
337 if (CurrentGroup
->IsCollapsed
&&
338 CurrentGroup
->Index
> iIndex
)
340 /* Update the toolbar buttons */
341 NewIndex
= CurrentGroup
->Index
- 1;
342 if (TaskSwitchWnd_SetToolbarButtonCommandId(This
,
343 CurrentGroup
->Index
- 1,
346 CurrentGroup
->Index
= NewIndex
;
349 CurrentGroup
->Index
= -1;
352 CurrentGroup
= CurrentGroup
->Next
;
356 /* Update all affected task items */
357 CurrentTaskItem
= This
->TaskItems
;
358 LastTaskItem
= CurrentTaskItem
+ This
->TaskItemCount
;
359 while (CurrentTaskItem
!= LastTaskItem
)
361 CurrentGroup
= CurrentTaskItem
->Group
;
362 if (CurrentGroup
!= NULL
)
364 if (!CurrentGroup
->IsCollapsed
&&
365 CurrentTaskItem
->Index
> iIndex
)
367 goto UpdateTaskItemBtn
;
370 else if (CurrentTaskItem
->Index
> iIndex
)
373 /* Update the toolbar buttons */
374 NewIndex
= CurrentTaskItem
->Index
- 1;
375 if (TaskSwitchWnd_SetToolbarButtonCommandId(This
,
376 CurrentTaskItem
->Index
- 1,
379 CurrentTaskItem
->Index
= NewIndex
;
382 CurrentTaskItem
->Index
= -1;
390 TaskSwitchWnd_UpdateTaskGroupButton(IN OUT PTASK_SWITCH_WND This
,
391 IN PTASK_GROUP TaskGroup
)
393 ASSERT(TaskGroup
->Index
>= 0);
395 /* FIXME: Implement */
397 return TaskGroup
->Index
;
401 TaskSwitchWnd_ExpandTaskGroup(IN OUT PTASK_SWITCH_WND This
,
402 IN PTASK_GROUP TaskGroup
)
404 ASSERT(TaskGroup
->dwTaskCount
> 0);
405 ASSERT(TaskGroup
->IsCollapsed
);
406 ASSERT(TaskGroup
->Index
>= 0);
408 /* FIXME: Implement */
412 TaskSwitchWnd_UpdateTaskItemButton(IN OUT PTASK_SWITCH_WND This
,
413 IN PTASK_ITEM TaskItem
)
417 ASSERT(TaskItem
->Index
>= 0);
419 tbbi
.cbSize
= sizeof(tbbi
);
420 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_STATE
| TBIF_TEXT
;
421 tbbi
.fsState
= TBSTATE_ENABLED
;
422 if (This
->ActiveTaskItem
== TaskItem
)
423 tbbi
.fsState
|= TBSTATE_CHECKED
;
425 /* Check if we're updating a button that is the last one in the
426 line. If so, we need to set the TBSTATE_WRAP flag! */
427 if (This
->TbButtonsPerLine
!= 0 &&
428 (TaskItem
->Index
+ 1) % This
->TbButtonsPerLine
== 0)
430 tbbi
.fsState
|= TBSTATE_WRAP
;
433 tbbi
.pszText
= TaskSwitchWnd_GetWndTextFromTaskItem(This
,
436 if (!SendMessage(This
->hWndToolbar
,
438 (WPARAM
)TaskItem
->Index
,
441 TaskItem
->Index
= -1;
445 DbgPrint("Updated button %d for hwnd 0x%p\n", TaskItem
->Index
, TaskItem
->hWnd
);
446 return TaskItem
->Index
;
450 TaskSwitchWnd_FindLastTaskItemOfGroup(IN OUT PTASK_SWITCH_WND This
,
451 IN PTASK_GROUP TaskGroup OPTIONAL
,
452 IN PTASK_ITEM NewTaskItem OPTIONAL
)
454 PTASK_ITEM TaskItem
, LastTaskItem
, FoundTaskItem
= NULL
;
457 ASSERT(This
->IsGroupingEnabled
);
459 TaskItem
= This
->TaskItems
;
460 LastTaskItem
= TaskItem
+ This
->TaskItemCount
;
462 dwTaskCount
= (TaskGroup
!= NULL
? TaskGroup
->dwTaskCount
: MAX_TASKS_COUNT
);
464 ASSERT(dwTaskCount
> 0);
466 while (TaskItem
!= LastTaskItem
)
468 if (TaskItem
->Group
== TaskGroup
)
470 if ((NewTaskItem
!= NULL
&& TaskItem
!= NewTaskItem
) || NewTaskItem
== NULL
)
472 FoundTaskItem
= TaskItem
;
475 if (--dwTaskCount
== 0)
477 /* We found the last task item in the group! */
485 return FoundTaskItem
;
489 TaskSwitchWnd_CalculateTaskItemNewButtonIndex(IN OUT PTASK_SWITCH_WND This
,
490 IN PTASK_ITEM TaskItem
)
492 PTASK_GROUP TaskGroup
;
493 PTASK_ITEM LastTaskItem
;
495 /* NOTE: This routine assumes that the group is *not* collapsed! */
497 TaskGroup
= TaskItem
->Group
;
498 if (This
->IsGroupingEnabled
)
500 if (TaskGroup
!= NULL
)
502 ASSERT(TaskGroup
->Index
< 0);
503 ASSERT(!TaskGroup
->IsCollapsed
);
505 if (TaskGroup
->dwTaskCount
> 1)
507 LastTaskItem
= TaskSwitchWnd_FindLastTaskItemOfGroup(This
,
510 if (LastTaskItem
!= NULL
)
512 /* Since the group is expanded the task items must have an index */
513 ASSERT(LastTaskItem
->Index
>= 0);
515 return LastTaskItem
->Index
+ 1;
521 /* Find the last NULL group button. NULL groups are added at the end of the
522 task item list when grouping is enabled */
523 LastTaskItem
= TaskSwitchWnd_FindLastTaskItemOfGroup(This
,
526 if (LastTaskItem
!= NULL
)
528 ASSERT(LastTaskItem
->Index
>= 0);
530 return LastTaskItem
->Index
+ 1;
535 return This
->ToolbarBtnCount
;
539 TaskSwitchWnd_AddTaskItemButton(IN OUT PTASK_SWITCH_WND This
,
540 IN OUT PTASK_ITEM TaskItem
)
545 if (TaskItem
->Index
>= 0)
547 return TaskSwitchWnd_UpdateTaskItemButton(This
,
551 if (TaskItem
->Group
!= NULL
&&
552 TaskItem
->Group
->IsCollapsed
)
554 /* The task group is collapsed, we only need to update the group button */
555 return TaskSwitchWnd_UpdateTaskGroupButton(This
,
560 tbBtn
.fsState
= TBSTATE_ENABLED
| TBSTATE_ELLIPSES
;
561 tbBtn
.fsStyle
= BTNS_CHECK
| BTNS_NOPREFIX
| BTNS_SHOWTEXT
;
562 tbBtn
.dwData
= TaskItem
->Index
;
564 tbBtn
.iString
= (DWORD_PTR
)TaskSwitchWnd_GetWndTextFromTaskItem(This
,
567 /* Find out where to insert the new button */
568 iIndex
= TaskSwitchWnd_CalculateTaskItemNewButtonIndex(This
,
571 tbBtn
.idCommand
= iIndex
;
573 TaskSwitchWnd_BeginUpdate(This
);
575 if (SendMessage(This
->hWndToolbar
,
580 TaskSwitchWnd_UpdateIndexesAfterButtonInserted(This
,
583 DbgPrint("Added button %d for hwnd 0x%p\n", iIndex
, TaskItem
->hWnd
);
585 TaskItem
->Index
= iIndex
;
586 This
->ToolbarBtnCount
++;
588 /* Update button sizes and fix the button wrapping */
589 TaskSwitchWnd_UpdateButtonsSize(This
,
594 TaskSwitchWnd_EndUpdate(This
);
600 TaskSwitchWnd_DeleteTaskItemButton(IN OUT PTASK_SWITCH_WND This
,
601 IN OUT PTASK_ITEM TaskItem
)
603 PTASK_GROUP TaskGroup
;
606 TaskGroup
= TaskItem
->Group
;
608 if (TaskItem
->Index
>= 0)
610 if ((TaskGroup
!= NULL
&& !TaskGroup
->IsCollapsed
) ||
613 TaskSwitchWnd_BeginUpdate(This
);
615 iIndex
= TaskItem
->Index
;
616 if (SendMessage(This
->hWndToolbar
,
621 TaskItem
->Index
= -1;
622 This
->ToolbarBtnCount
--;
624 TaskSwitchWnd_UpdateIndexesAfterButtonDeleted(This
,
627 /* Update button sizes and fix the button wrapping */
628 TaskSwitchWnd_UpdateButtonsSize(This
,
633 TaskSwitchWnd_EndUpdate(This
);
641 TaskSwitchWnd_AddToTaskGroup(IN OUT PTASK_SWITCH_WND This
,
645 PTASK_GROUP TaskGroup
, *PrevLink
;
647 if (!GetWindowThreadProcessId(hWnd
,
650 DbgPrint("Cannot get process id of hwnd 0x%p\n", hWnd
);
654 /* Try to find an existing task group */
655 TaskGroup
= This
->TaskGroups
;
656 PrevLink
= &This
->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
= HeapAlloc(hProcessHeap
,
673 if (TaskGroup
!= NULL
)
675 ZeroMemory(TaskGroup
,
678 TaskGroup
->dwTaskCount
= 1;
679 TaskGroup
->dwProcessId
= dwProcessId
;
680 TaskGroup
->Index
= -1;
682 /* Add the task group to the list */
683 *PrevLink
= TaskGroup
;
690 TaskSwitchWnd_RemoveTaskFromTaskGroup(IN OUT PTASK_SWITCH_WND This
,
691 IN OUT PTASK_ITEM TaskItem
)
693 PTASK_GROUP TaskGroup
, CurrentGroup
, *PrevLink
;
695 TaskGroup
= TaskItem
->Group
;
696 if (TaskGroup
!= NULL
)
698 DWORD dwNewTaskCount
= --TaskGroup
->dwTaskCount
;
699 if (dwNewTaskCount
== 0)
701 /* Find the previous pointer in the chain */
702 CurrentGroup
= This
->TaskGroups
;
703 PrevLink
= &This
->TaskGroups
;
704 while (CurrentGroup
!= TaskGroup
)
706 PrevLink
= &CurrentGroup
->Next
;
707 CurrentGroup
= CurrentGroup
->Next
;
710 /* Remove the group from the list */
711 ASSERT(TaskGroup
== CurrentGroup
);
712 *PrevLink
= TaskGroup
->Next
;
714 /* Free the task group */
715 HeapFree(hProcessHeap
,
719 else if (TaskGroup
->IsCollapsed
&&
720 TaskGroup
->Index
>= 0)
722 if (dwNewTaskCount
> 1)
724 /* FIXME: Check if we should expand the group */
725 /* Update the task group button */
726 TaskSwitchWnd_UpdateTaskGroupButton(This
,
731 /* Expand the group of one task button to a task button */
732 TaskSwitchWnd_ExpandTaskGroup(This
,
740 TaskSwitchWnd_FindTaskItem(IN OUT PTASK_SWITCH_WND This
,
743 PTASK_ITEM TaskItem
, LastItem
;
745 TaskItem
= This
->TaskItems
;
746 LastItem
= TaskItem
+ This
->TaskItemCount
;
747 while (TaskItem
!= LastItem
)
749 if (TaskItem
->hWnd
== hWnd
)
759 TaskSwitchWnd_FindOtherTaskItem(IN OUT PTASK_SWITCH_WND This
,
762 PTASK_ITEM LastItem
, TaskItem
;
763 PTASK_GROUP TaskGroup
;
766 if (!GetWindowThreadProcessId(hWnd
,
772 /* Try to find another task that belongs to the same
773 process as the given window */
774 TaskItem
= This
->TaskItems
;
775 LastItem
= TaskItem
+ This
->TaskItemCount
;
776 while (TaskItem
!= LastItem
)
778 TaskGroup
= TaskItem
->Group
;
779 if (TaskGroup
!= NULL
)
781 if (TaskGroup
->dwProcessId
== dwProcessId
)
786 DWORD dwProcessIdTask
;
788 if (GetWindowThreadProcessId(TaskItem
->hWnd
,
790 dwProcessIdTask
== dwProcessId
)
803 TaskSwitchWnd_AllocTaskItem(IN OUT PTASK_SWITCH_WND This
)
805 if (This
->TaskItemCount
>= MAX_TASKS_COUNT
)
807 /* We need the most significant bit in 16 bit command IDs to indicate whether it
808 is a task group or task item. WM_COMMAND limits command IDs to 16 bits! */
812 ASSERT(This
->AllocatedTaskItems
>= This
->TaskItemCount
);
814 if (This
->TaskItemCount
!= 0)
817 SIZE_T NewArrayLength
, ActiveTaskItemIndex
;
819 NewArrayLength
= This
->AllocatedTaskItems
+ TASK_ITEM_ARRAY_ALLOC
;
821 NewArray
= HeapReAlloc(hProcessHeap
,
824 NewArrayLength
* sizeof(*This
->TaskItems
));
825 if (NewArray
!= NULL
)
827 if (This
->ActiveTaskItem
!= NULL
)
829 /* Fixup the ActiveTaskItem pointer */
830 ActiveTaskItemIndex
= This
->ActiveTaskItem
- This
->TaskItems
;
831 This
->ActiveTaskItem
= NewArray
+ ActiveTaskItemIndex
;
833 This
->AllocatedTaskItems
= (WORD
)NewArrayLength
;
834 This
->TaskItems
= NewArray
;
841 This
->TaskItems
= HeapAlloc(hProcessHeap
,
843 TASK_ITEM_ARRAY_ALLOC
* sizeof(*This
->TaskItems
));
844 if (This
->TaskItems
!= NULL
)
846 This
->AllocatedTaskItems
= TASK_ITEM_ARRAY_ALLOC
;
852 return This
->TaskItems
+ This
->TaskItemCount
++;
856 TaskSwitchWnd_FreeTaskItem(IN OUT PTASK_SWITCH_WND This
,
857 IN OUT PTASK_ITEM TaskItem
)
861 if (TaskItem
== This
->ActiveTaskItem
)
862 This
->ActiveTaskItem
= NULL
;
864 wIndex
= (WORD
)(TaskItem
- This
->TaskItems
);
865 if (wIndex
+ 1 < This
->TaskItemCount
)
869 (This
->TaskItemCount
- wIndex
- 1) * sizeof(*TaskItem
));
872 This
->TaskItemCount
--;
876 TaskSwitchWnd_DeleteTaskItem(IN OUT PTASK_SWITCH_WND This
,
877 IN OUT PTASK_ITEM TaskItem
)
879 if (!This
->IsDestroying
)
881 /* Delete the task button from the toolbar */
882 TaskSwitchWnd_DeleteTaskItemButton(This
,
886 /* Remove the task from it's group */
887 TaskSwitchWnd_RemoveTaskFromTaskGroup(This
,
890 /* Free the task item */
891 TaskSwitchWnd_FreeTaskItem(This
,
896 TaskSwitchWnd_CheckActivateTaskItem(IN OUT PTASK_SWITCH_WND This
,
897 IN OUT PTASK_ITEM TaskItem
)
899 PTASK_ITEM ActiveTaskItem
;
900 PTASK_GROUP TaskGroup
= NULL
;
902 ActiveTaskItem
= This
->ActiveTaskItem
;
904 if (TaskItem
!= NULL
)
905 TaskGroup
= TaskItem
->Group
;
907 if (This
->IsGroupingEnabled
&& TaskGroup
!= NULL
)
909 if (TaskGroup
->IsCollapsed
)
914 goto ChangeTaskItemButton
;
918 ChangeTaskItemButton
:
919 if (ActiveTaskItem
!= NULL
)
921 PTASK_GROUP ActiveTaskGroup
;
923 if (ActiveTaskItem
== TaskItem
)
926 ActiveTaskGroup
= ActiveTaskItem
->Group
;
928 if (This
->IsGroupingEnabled
&& ActiveTaskGroup
!= NULL
)
930 if (ActiveTaskGroup
->IsCollapsed
)
932 if (ActiveTaskGroup
== TaskGroup
)
938 goto ChangeActiveTaskItemButton
;
942 ChangeActiveTaskItemButton
:
943 This
->ActiveTaskItem
= NULL
;
944 if (ActiveTaskItem
->Index
>= 0)
946 TaskSwitchWnd_UpdateTaskItemButton(This
,
952 This
->ActiveTaskItem
= TaskItem
;
954 if (TaskItem
!= NULL
&& TaskItem
->Index
>= 0)
956 TaskSwitchWnd_UpdateTaskItemButton(This
,
963 FindTaskItemByIndex(IN OUT PTASK_SWITCH_WND This
,
966 PTASK_ITEM TaskItem
, LastItem
;
968 TaskItem
= This
->TaskItems
;
969 LastItem
= TaskItem
+ This
->TaskItemCount
;
970 while (TaskItem
!= LastItem
)
972 if (TaskItem
->Index
== Index
)
982 FindTaskGroupByIndex(IN OUT PTASK_SWITCH_WND This
,
985 PTASK_GROUP CurrentGroup
;
987 CurrentGroup
= This
->TaskGroups
;
988 while (CurrentGroup
!= NULL
)
990 if (CurrentGroup
->Index
== Index
)
993 CurrentGroup
= CurrentGroup
->Next
;
1000 TaskSwitchWnd_AddTask(IN OUT PTASK_SWITCH_WND This
,
1003 PTASK_ITEM TaskItem
;
1005 TaskItem
= TaskSwitchWnd_FindTaskItem(This
,
1007 if (TaskItem
== NULL
)
1009 DbgPrint("Add window 0x%p\n", hWnd
);
1010 TaskItem
= TaskSwitchWnd_AllocTaskItem(This
);
1011 if (TaskItem
!= NULL
)
1013 ZeroMemory(TaskItem
,
1015 TaskItem
->hWnd
= hWnd
;
1016 TaskItem
->Index
= -1;
1017 TaskItem
->Group
= TaskSwitchWnd_AddToTaskGroup(This
,
1020 if (!This
->IsDestroying
)
1022 TaskSwitchWnd_AddTaskItemButton(This
,
1028 return TaskItem
!= NULL
;
1032 TaskSwitchWnd_ActivateTaskItem(IN OUT PTASK_SWITCH_WND This
,
1033 IN OUT PTASK_ITEM TaskItem OPTIONAL
)
1035 if (TaskItem
!= NULL
)
1037 DbgPrint("Activate window 0x%p on button %d\n", TaskItem
->hWnd
, TaskItem
->Index
);
1040 TaskSwitchWnd_CheckActivateTaskItem(This
,
1047 TaskSwitchWnd_ActivateTask(IN OUT PTASK_SWITCH_WND This
,
1050 PTASK_ITEM TaskItem
;
1052 TaskItem
= TaskSwitchWnd_FindTaskItem(This
,
1054 if (TaskItem
== NULL
)
1056 TaskItem
= TaskSwitchWnd_FindOtherTaskItem(This
,
1060 if (TaskItem
== NULL
)
1062 DbgPrint("Activate window 0x%p, could not find task\n", hWnd
);
1065 return TaskSwitchWnd_ActivateTaskItem(This
,
1070 TaskSwitchWnd_DeleteTask(IN OUT PTASK_SWITCH_WND This
,
1073 PTASK_ITEM TaskItem
;
1075 TaskItem
= TaskSwitchWnd_FindTaskItem(This
,
1077 if (TaskItem
!= NULL
)
1079 DbgPrint("Delete window 0x%p on button %d\n", hWnd
, TaskItem
->Index
);
1080 TaskSwitchWnd_DeleteTaskItem(This
,
1085 //DbgPrint("Failed to delete window 0x%p\n", hWnd);
1091 TaskSwitchWnd_DeleteAllTasks(IN OUT PTASK_SWITCH_WND This
)
1093 PTASK_ITEM CurrentTask
;
1095 if (This
->TaskItemCount
> 0)
1097 CurrentTask
= This
->TaskItems
+ This
->TaskItemCount
;
1100 TaskSwitchWnd_DeleteTaskItem(This
,
1102 } while (CurrentTask
!= This
->TaskItems
);
1107 TaskSwitchWnd_FlashTaskItem(IN OUT PTASK_SWITCH_WND This
,
1108 IN OUT PTASK_ITEM TaskItem
)
1110 /* FIXME: Implement */
1114 TaskSwitchWnd_FlashTask(IN OUT PTASK_SWITCH_WND This
,
1117 PTASK_ITEM TaskItem
;
1119 TaskItem
= TaskSwitchWnd_FindTaskItem(This
,
1121 if (TaskItem
!= NULL
)
1123 DbgPrint("Flashing window 0x%p on button %d\n", hWnd
, TaskItem
->Index
);
1124 TaskSwitchWnd_FlashTaskItem(This
,
1133 TaskSwitchWnd_RedrawTaskItem(IN OUT PTASK_SWITCH_WND This
,
1134 IN OUT PTASK_ITEM TaskItem
)
1136 PTASK_GROUP TaskGroup
;
1138 TaskGroup
= TaskItem
->Group
;
1139 if (This
->IsGroupingEnabled
&& TaskGroup
!= NULL
)
1141 if (TaskGroup
->IsCollapsed
&& TaskGroup
->Index
>= 0)
1143 TaskSwitchWnd_UpdateTaskGroupButton(This
,
1146 else if (TaskItem
->Index
>= 0)
1148 goto UpdateTaskItem
;
1151 else if (TaskItem
->Index
>= 0)
1154 TaskSwitchWnd_UpdateTaskItemButton(This
,
1161 TaskSwitchWnd_RedrawTask(IN OUT PTASK_SWITCH_WND This
,
1164 PTASK_ITEM TaskItem
;
1166 TaskItem
= TaskSwitchWnd_FindTaskItem(This
,
1168 if (TaskItem
!= NULL
)
1170 TaskSwitchWnd_RedrawTaskItem(This
,
1179 TaskSwitchWnd_UpdateTbButtonSpacing(IN OUT PTASK_SWITCH_WND This
,
1180 IN BOOL bHorizontal
,
1182 IN UINT uiBtnsPerLine
)
1186 tbm
.cbSize
= sizeof(tbm
);
1187 tbm
.dwMask
= TBMF_BARPAD
| TBMF_BUTTONSPACING
;
1189 tbm
.cxBarPad
= tbm
.cyBarPad
= 0;
1191 if (bHorizontal
|| uiBtnsPerLine
> 1)
1192 tbm
.cxButtonSpacing
= (3 * GetSystemMetrics(SM_CXEDGE
) / 2);
1194 tbm
.cxButtonSpacing
= 0;
1196 if (!bHorizontal
|| uiRows
> 1)
1197 tbm
.cyButtonSpacing
= (3 * GetSystemMetrics(SM_CYEDGE
) / 2);
1199 tbm
.cyButtonSpacing
= 0;
1201 SendMessage(This
->hWndToolbar
,
1206 return tbm
.cxButtonSpacing
;
1211 TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This
,
1212 IN BOOL bRedrawDisabled
)
1215 UINT uiRows
, uiMax
, uiMin
, uiBtnsPerLine
, ui
;
1221 if (GetClientRect(This
->hWnd
,
1223 !IsRectEmpty(&rcClient
))
1225 if (This
->ToolbarBtnCount
> 0)
1227 ZeroMemory (&tbm
, sizeof (tbm
));
1228 tbm
.cbSize
= sizeof(tbm
);
1229 tbm
.dwMask
= TBMF_BUTTONSPACING
;
1230 SendMessage(This
->hWndToolbar
,
1235 uiRows
= (rcClient
.bottom
+ tbm
.cyButtonSpacing
) / (This
->ButtonSize
.cy
+ tbm
.cyButtonSpacing
);
1239 uiBtnsPerLine
= (This
->ToolbarBtnCount
+ uiRows
- 1) / uiRows
;
1241 Horizontal
= ITrayWindow_IsHorizontal(This
->Tray
);
1243 if (!bRedrawDisabled
)
1244 TaskSwitchWnd_BeginUpdate(This
);
1246 /* We might need to update the button spacing */
1247 tbm
.cxButtonSpacing
= TaskSwitchWnd_UpdateTbButtonSpacing(This
,
1252 /* Calculate the ideal width and make sure it's within the allowed range */
1253 NewBtnSize
= (rcClient
.right
- (uiBtnsPerLine
* tbm
.cxButtonSpacing
)) / uiBtnsPerLine
;
1255 /* Determine the minimum and maximum width of a button */
1257 uiMax
= GetSystemMetrics(SM_CXMINIMIZED
);
1259 uiMax
= rcClient
.right
;
1261 uiMin
= GetSystemMetrics(SM_CXSIZE
) + (2 * GetSystemMetrics(SM_CXEDGE
));
1263 if (NewBtnSize
< (LONG
)uiMin
)
1265 if (NewBtnSize
> (LONG
)uiMax
)
1268 This
->ButtonSize
.cx
= NewBtnSize
;
1270 /* Recalculate how many buttons actually fit into one line */
1271 uiBtnsPerLine
= rcClient
.right
/ (NewBtnSize
+ tbm
.cxButtonSpacing
);
1272 if (uiBtnsPerLine
== 0)
1274 This
->TbButtonsPerLine
= uiBtnsPerLine
;
1276 tbbi
.cbSize
= sizeof(tbbi
);
1277 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_SIZE
| TBIF_STATE
;
1278 tbbi
.cx
= (INT
)NewBtnSize
;
1280 for (ui
= 0; ui
!= This
->ToolbarBtnCount
; ui
++)
1282 tbbi
.fsState
= TBSTATE_ENABLED
;
1284 /* Check if we're updating a button that is the last one in the
1285 line. If so, we need to set the TBSTATE_WRAP flag! */
1286 if ((ui
+ 1) % uiBtnsPerLine
== 0)
1287 tbbi
.fsState
|= TBSTATE_WRAP
;
1289 if (This
->ActiveTaskItem
!= NULL
&&
1290 This
->ActiveTaskItem
->Index
== ui
)
1292 tbbi
.fsState
|= TBSTATE_CHECKED
;
1295 SendMessage(This
->hWndToolbar
,
1302 /* FIXME: Force the window to the correct position in case some idiot
1303 did something to us */
1304 SetWindowPos(This
->hWndToolbar
,
1308 rcClient
.right
, /* FIXME */
1309 rcClient
.bottom
, /* FIXME */
1310 SWP_NOACTIVATE
| SWP_NOZORDER
);
1315 This
->TbButtonsPerLine
= 0;
1316 This
->ButtonSize
.cx
= 0;
1320 TaskSwitchWnd_EndUpdate(This
);
1323 static BOOL CALLBACK
1324 TaskSwitchWnd_EnumWindowsProc(IN HWND hWnd
,
1327 PTASK_SWITCH_WND This
= (PTASK_SWITCH_WND
)lParam
;
1329 /* Only show windows that still exist and are visible and none of explorer's
1330 special windows (such as the desktop or the tray window) */
1331 if (IsWindow(hWnd
) && IsWindowVisible(hWnd
) &&
1332 !ITrayWindow_IsSpecialHWND(This
->Tray
,
1335 /* Don't list popup windows and also no tool windows */
1337 GW_OWNER
) == NULL
&&
1338 !(GetWindowLongPtr(hWnd
,
1339 GWL_EXSTYLE
) & WS_EX_TOOLWINDOW
))
1341 TaskSwitchWnd_AddTask(This
,
1349 static LRESULT CALLBACK
1350 TaskSwichWnd_ToolbarSubclassedProc(IN HWND hWnd
,
1354 IN UINT_PTR uIdSubclass
,
1355 IN DWORD_PTR dwRefData
)
1359 Ret
= DefSubclassProc(hWnd
,
1364 if (msg
== WM_NCHITTEST
&& Ret
== HTCLIENT
)
1368 /* See if the mouse is on a button */
1369 pt
.x
= (SHORT
)LOWORD(lParam
);
1370 pt
.y
= (SHORT
)HIWORD(lParam
);
1372 if (MapWindowPoints(HWND_DESKTOP
,
1376 (INT
)SendMessage(hWnd
,
1381 /* Make the control appear to be transparent outside of any buttons */
1382 Ret
= HTTRANSPARENT
;
1390 TaskSwitchWnd_Create(IN OUT PTASK_SWITCH_WND This
)
1392 This
->hWndToolbar
= CreateWindowEx(0,
1395 WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
|
1396 TBSTYLE_TOOLTIPS
| TBSTYLE_WRAPABLE
| TBSTYLE_LIST
|
1397 TBSTYLE_TRANSPARENT
|
1398 CCS_TOP
| CCS_NORESIZE
| CCS_NODIVIDER
,
1408 if (This
->hWndToolbar
!= NULL
)
1413 /* Identify the version we're using */
1414 SendMessage(This
->hWndToolbar
,
1415 TB_BUTTONSTRUCTSIZE
,
1419 /* Calculate the default button size. Don't save this in This->ButtonSize.cx so that
1420 the actual button width gets updated correctly on the first recalculation */
1421 BtnSize
.cx
= GetSystemMetrics(SM_CXMINIMIZED
);
1422 This
->ButtonSize
.cy
= BtnSize
.cy
= GetSystemMetrics(SM_CYSIZE
) + (2 * GetSystemMetrics(SM_CYEDGE
));
1423 SendMessage(This
->hWndToolbar
,
1426 (LPARAM
)MAKELONG(BtnSize
.cx
,
1429 /* We don't want to see partially clipped buttons...not that we could see them... */
1431 SendMessage(This
->hWndToolbar
,
1432 TB_SETEXTENDEDSTYLE
,
1434 TBSTYLE_EX_HIDECLIPPEDBUTTONS
);
1437 /* Set proper spacing between buttons */
1438 TaskSwitchWnd_UpdateTbButtonSpacing(This
,
1439 ITrayWindow_IsHorizontal(This
->Tray
),
1443 /* Register the shell hook */
1444 This
->ShellHookMsg
= RegisterWindowMessage(TEXT("SHELLHOOK"));
1445 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
1446 if (hShell32
!= NULL
)
1448 REGSHELLHOOK RegShellHook
;
1450 /* RegisterShellHook */
1451 RegShellHook
= (REGSHELLHOOK
)GetProcAddress(hShell32
,
1452 (LPCSTR
)((LONG
)181));
1453 if (RegShellHook
!= NULL
)
1455 RegShellHook(This
->hWnd
,
1456 3); /* 1 if no NT! We're targeting NT so we don't care! */
1460 /* Add all windows to the toolbar */
1461 EnumWindows(TaskSwitchWnd_EnumWindowsProc
,
1464 /* Recalculate the button size */
1465 TaskSwitchWnd_UpdateButtonsSize(This
,
1468 /* Subclass the toolbar control because it doesn't provide a
1469 NM_NCHITTEST notification */
1470 This
->IsToolbarSubclassed
= SetWindowSubclass(This
->hWndToolbar
,
1471 TaskSwichWnd_ToolbarSubclassedProc
,
1472 TSW_TOOLBAR_SUBCLASS_ID
,
1478 TaskSwitchWnd_NCDestroy(IN OUT PTASK_SWITCH_WND This
)
1482 This
->IsDestroying
= TRUE
;
1484 /* Unregister the shell hook */
1485 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
1486 if (hShell32
!= NULL
)
1488 REGSHELLHOOK RegShellHook
;
1490 /* RegisterShellHook */
1491 RegShellHook
= (REGSHELLHOOK
)GetProcAddress(hShell32
,
1492 (LPCSTR
)((LONG
)181));
1493 if (RegShellHook
!= NULL
)
1495 RegShellHook(This
->hWnd
,
1500 TaskSwitchWnd_DeleteAllTasks(This
);
1504 TaskSwitchWnd_HandleAppCommand(IN OUT PTASK_SWITCH_WND This
,
1510 switch (GET_APPCOMMAND_LPARAM(lParam
))
1512 case APPCOMMAND_BROWSER_SEARCH
:
1513 Ret
= SHFindFiles(NULL
,
1517 case APPCOMMAND_BROWSER_HOME
:
1518 case APPCOMMAND_LAUNCH_MAIL
:
1520 DbgPrint("Shell app command %d unhandled!\n", (INT
)GET_APPCOMMAND_LPARAM(lParam
));
1529 TaskSwitchWnd_HandleShellHookMsg(IN OUT PTASK_SWITCH_WND This
,
1535 switch ((INT
)wParam
)
1537 case HSHELL_APPCOMMAND
:
1538 TaskSwitchWnd_HandleAppCommand(This
,
1544 case HSHELL_WINDOWCREATED
:
1545 TaskSwitchWnd_AddTask(This
,
1550 case HSHELL_WINDOWDESTROYED
:
1551 /* The window still exists! Delay destroying it a bit */
1552 TaskSwitchWnd_DeleteTask(This
,
1557 case HSHELL_ACTIVATESHELLWINDOW
:
1558 goto UnhandledShellMessage
;
1560 case HSHELL_RUDEAPPACTIVATED
:
1561 goto UnhandledShellMessage
;
1563 case HSHELL_WINDOWACTIVATED
:
1564 TaskSwitchWnd_ActivateTask(This
,
1569 case HSHELL_GETMINRECT
:
1570 goto UnhandledShellMessage
;
1573 TaskSwitchWnd_FlashTask(This
,
1579 TaskSwitchWnd_RedrawTask(This
,
1584 case HSHELL_TASKMAN
:
1585 case HSHELL_LANGUAGE
:
1586 case HSHELL_SYSMENU
:
1587 case HSHELL_ENDTASK
:
1588 case HSHELL_ACCESSIBILITYSTATE
:
1589 case HSHELL_WINDOWREPLACED
:
1590 case HSHELL_WINDOWREPLACING
:
1593 static const struct {
1597 {HSHELL_WINDOWCREATED
, L
"HSHELL_WINDOWCREATED"},
1598 {HSHELL_WINDOWDESTROYED
, L
"HSHELL_WINDOWDESTROYED"},
1599 {HSHELL_ACTIVATESHELLWINDOW
, L
"HSHELL_ACTIVATESHELLWINDOW"},
1600 {HSHELL_WINDOWACTIVATED
, L
"HSHELL_WINDOWACTIVATED"},
1601 {HSHELL_GETMINRECT
, L
"HSHELL_GETMINRECT"},
1602 {HSHELL_REDRAW
, L
"HSHELL_REDRAW"},
1603 {HSHELL_TASKMAN
, L
"HSHELL_TASKMAN"},
1604 {HSHELL_LANGUAGE
, L
"HSHELL_LANGUAGE"},
1605 {HSHELL_SYSMENU
, L
"HSHELL_SYSMENU"},
1606 {HSHELL_ENDTASK
, L
"HSHELL_ENDTASK"},
1607 {HSHELL_ACCESSIBILITYSTATE
, L
"HSHELL_ACCESSIBILITYSTATE"},
1608 {HSHELL_APPCOMMAND
, L
"HSHELL_APPCOMMAND"},
1609 {HSHELL_WINDOWREPLACED
, L
"HSHELL_WINDOWREPLACED"},
1610 {HSHELL_WINDOWREPLACING
, L
"HSHELL_WINDOWREPLACING"},
1611 {HSHELL_RUDEAPPACTIVATED
, L
"HSHELL_RUDEAPPACTIVATED"},
1614 UnhandledShellMessage
:
1615 for (i
= 0, found
= 0; i
!= sizeof(hshell_msg
) / sizeof(hshell_msg
[0]); i
++)
1617 if (hshell_msg
[i
].msg
== (INT
)wParam
)
1619 DbgPrint("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg
[i
].msg_name
, lParam
);
1626 DbgPrint("Shell message %d unhandled (lParam = 0x%p)!\n", (INT
)wParam
, lParam
);
1636 TaskSwitchWnd_EnableGrouping(IN OUT PTASK_SWITCH_WND This
,
1639 This
->IsGroupingEnabled
= bEnable
;
1641 /* Collapse or expand groups if neccessary */
1642 TaskSwitchWnd_UpdateButtonsSize(This
,
1647 TaskSwitchWnd_HandleTaskItemClick(IN OUT PTASK_SWITCH_WND This
,
1648 IN OUT PTASK_ITEM TaskItem
)
1653 if (IsWindow(TaskItem
->hWnd
))
1655 bIsMinimized
= IsIconic(TaskItem
->hWnd
);
1656 bIsActive
= (TaskItem
== This
->ActiveTaskItem
);
1658 if (!bIsMinimized
&& bIsActive
)
1660 PostMessage(TaskItem
->hWnd
,
1669 PostMessage(TaskItem
->hWnd
,
1675 SetForegroundWindow(TaskItem
->hWnd
);
1681 TaskSwitchWnd_HandleTaskGroupClick(IN OUT PTASK_SWITCH_WND This
,
1682 IN OUT PTASK_GROUP TaskGroup
)
1684 /* TODO: Show task group menu */
1688 TaskSwitchWnd_HandleButtonClick(IN OUT PTASK_SWITCH_WND This
,
1691 PTASK_ITEM TaskItem
;
1692 PTASK_GROUP TaskGroup
;
1694 if (This
->IsGroupingEnabled
)
1696 TaskGroup
= FindTaskGroupByIndex(This
,
1698 if (TaskGroup
!= NULL
&& TaskGroup
->IsCollapsed
)
1700 TaskSwitchWnd_HandleTaskGroupClick(This
,
1706 TaskItem
= FindTaskItemByIndex(This
,
1708 if (TaskItem
!= NULL
)
1710 TaskSwitchWnd_HandleTaskItemClick(This
,
1719 TaskSwichWnd_HandleItemPaint(IN OUT PTASK_SWITCH_WND This
,
1720 IN OUT NMTBCUSTOMDRAW
*nmtbcd
)
1722 HFONT hCaptionFont
, hBoldCaptionFont
;
1723 LRESULT Ret
= CDRF_DODEFAULT
;
1724 PTASK_GROUP TaskGroup
;
1725 PTASK_ITEM TaskItem
;
1727 #if TASK_USE_DRAWCAPTIONTEMP != 0
1729 UINT uidctFlags
= DC_TEXT
| DC_ICON
| DC_NOSENDMSG
;
1732 TaskItem
= FindTaskItemByIndex(This
,
1733 (INT
)nmtbcd
->nmcd
.dwItemSpec
);
1734 TaskGroup
= FindTaskGroupByIndex(This
,
1735 (INT
)nmtbcd
->nmcd
.dwItemSpec
);
1736 if (TaskGroup
== NULL
&& TaskItem
!= NULL
)
1738 ASSERT(TaskItem
!= NULL
);
1740 if (TaskItem
!= NULL
&& IsWindow(TaskItem
->hWnd
))
1742 hCaptionFont
= ITrayWindow_GetCaptionFonts(This
->Tray
,
1744 if (nmtbcd
->nmcd
.uItemState
& CDIS_CHECKED
)
1745 hCaptionFont
= hBoldCaptionFont
;
1747 #if TASK_USE_DRAWCAPTIONTEMP != 0
1749 /* Make sure we don't draw on the button edges */
1750 InflateRect(&nmtbcd
->nmcd
.rc
,
1751 -GetSystemMetrics(SM_CXEDGE
),
1752 -GetSystemMetrics(SM_CYEDGE
));
1754 if ((nmtbcd
->nmcd
.uItemState
& CDIS_MARKED
) && TaskItem
->RenderFlashed
)
1756 /* This is a slight glitch. We have to move the rectangle so that
1757 the button content appears to be pressed. However, when flashing
1758 is enabled, we can see a light line at the top and left inner
1759 border. We need to fill that area with the flashing color. Note
1760 that since we're using DrawCaptionTemp() the flashing color is
1761 COLOR_ACTIVECAPTION, not COLOR_HIGHLIGHT! */
1762 FillRect(nmtbcd
->nmcd
.hdc
,
1764 (HBRUSH
)(COLOR_ACTIVECAPTION
+ 1));
1766 /* Make the button content appear pressed. This however draws a bit
1767 into the right and bottom border of the button edge, making it
1768 look a bit odd. However, selecting a clipping region to prevent
1769 that from happening causes problems with DrawCaptionTemp()! */
1770 OffsetRect(&nmtbcd
->nmcd
.rc
,
1774 /* Render flashed */
1775 uidctFlags
|= DC_ACTIVE
;
1779 uidctFlags
|= DC_INBUTTON
;
1780 if (nmtbcd
->nmcd
.uItemState
& CDIS_CHECKED
)
1781 uidctFlags
|= DC_ACTIVE
;
1784 if (DrawCapTemp
!= NULL
)
1786 /* Draw the button content */
1787 TaskItem
->DisplayTooltip
= !DrawCapTemp(TaskItem
->hWnd
,
1796 return CDRF_SKIPDEFAULT
;
1798 #else /* !TASK_USE_DRAWCAPTIONTEMP */
1800 /* Make the entire button flashing if neccessary */
1801 if (nmtbcd
->nmcd
.uItemState
& CDIS_MARKED
)
1803 if (TaskItem
->RenderFlashed
)
1805 nmtbcd
->hbrMonoDither
= GetSysColorBrush(COLOR_HIGHLIGHT
);
1806 nmtbcd
->clrTextHighlight
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
1807 nmtbcd
->nHLStringBkMode
= TRANSPARENT
;
1809 /* We don't really need to set clrMark because we set the
1810 background mode to TRANSPARENT! */
1811 nmtbcd
->clrMark
= GetSysColor(COLOR_HIGHLIGHT
);
1813 Ret
|= TBCDRF_USECDCOLORS
;
1816 Ret
|= TBCDRF_NOMARK
;
1819 /* Select the font we want to use */
1820 SelectObject(nmtbcd
->nmcd
.hdc
,
1822 return Ret
| CDRF_NEWFONT
;
1828 else if (TaskGroup
!= NULL
)
1830 /* FIXME: Implement painting for task groups */
1837 TaskSwitchWnd_HandleToolbarNotification(IN OUT PTASK_SWITCH_WND This
,
1838 IN
const NMHDR
*nmh
)
1846 LPNMTBCUSTOMDRAW nmtbcd
= (LPNMTBCUSTOMDRAW
)nmh
;
1848 switch (nmtbcd
->nmcd
.dwDrawStage
)
1851 #if TASK_USE_DRAWCAPTIONTEMP != 0
1853 case CDDS_ITEMPREPAINT
:
1854 /* We handle drawing in the post-paint stage so that we
1855 don't have to draw the button edges, etc */
1856 Ret
= CDRF_NOTIFYPOSTPAINT
;
1859 case CDDS_ITEMPOSTPAINT
:
1861 #else /* !TASK_USE_DRAWCAPTIONTEMP */
1863 case CDDS_ITEMPREPAINT
:
1867 Ret
= TaskSwichWnd_HandleItemPaint(This
,
1872 Ret
= CDRF_NOTIFYITEMDRAW
;
1876 Ret
= CDRF_DODEFAULT
;
1886 static LRESULT CALLBACK
1887 TaskSwitchWndProc(IN HWND hwnd
,
1892 PTASK_SWITCH_WND This
= NULL
;
1893 LRESULT Ret
= FALSE
;
1895 if (uMsg
!= WM_NCCREATE
)
1897 This
= (PTASK_SWITCH_WND
)GetWindowLongPtr(hwnd
,
1901 if (This
!= NULL
|| uMsg
== WM_NCCREATE
)
1909 szClient
.cx
= LOWORD(lParam
);
1910 szClient
.cy
= HIWORD(lParam
);
1911 if (This
->hWndToolbar
!= NULL
)
1913 SetWindowPos(This
->hWndToolbar
,
1921 TaskSwitchWnd_UpdateButtonsSize(This
,
1929 /* We want the tray window to be draggable everywhere, so make the control
1930 appear transparent */
1931 Ret
= DefWindowProc(hwnd
,
1935 if (Ret
!= HTVSCROLL
&& Ret
!= HTHSCROLL
)
1936 Ret
= HTTRANSPARENT
;
1942 if (lParam
!= 0 && (HWND
)lParam
== This
->hWndToolbar
)
1944 TaskSwitchWnd_HandleButtonClick(This
,
1952 const NMHDR
*nmh
= (const NMHDR
*)lParam
;
1954 if (nmh
->hwndFrom
== This
->hWndToolbar
)
1956 Ret
= TaskSwitchWnd_HandleToolbarNotification(This
,
1962 case TSWM_ENABLEGROUPING
:
1964 Ret
= This
->IsGroupingEnabled
;
1965 if (wParam
!= This
->IsGroupingEnabled
)
1967 TaskSwitchWnd_EnableGrouping(This
,
1973 case TSWM_UPDATETASKBARPOS
:
1975 /* Update the button spacing */
1976 TaskSwitchWnd_UpdateTbButtonSpacing(This
,
1977 ITrayWindow_IsHorizontal(This
->Tray
),
1983 case WM_CONTEXTMENU
:
1985 if (This
->hWndToolbar
!= NULL
)
1990 pt
.x
= (LONG
)LOWORD(lParam
);
1991 pt
.y
= (LONG
)HIWORD(lParam
);
1993 MapWindowPoints(NULL
,
1998 iBtn
= (INT_PTR
)SendMessage(This
->hWndToolbar
,
2004 /* FIXME: Display the system menu of the window */
2007 goto ForwardContextMenuMsg
;
2011 ForwardContextMenuMsg
:
2012 /* Forward message */
2013 Ret
= SendMessage(ITrayWindow_GetHWND(This
->Tray
),
2023 LPCREATESTRUCT CreateStruct
= (LPCREATESTRUCT
)lParam
;
2024 This
= (PTASK_SWITCH_WND
)HeapAlloc(hProcessHeap
,
2033 This
->hWndNotify
= CreateStruct
->hwndParent
;
2034 This
->Tray
= (ITrayWindow
*)CreateStruct
->lpCreateParams
;
2035 This
->IsGroupingEnabled
= TRUE
; /* FIXME */
2036 SetWindowLongPtr(hwnd
,
2044 TaskSwitchWnd_Create(This
);
2056 if (This
->IsToolbarSubclassed
)
2058 if (RemoveWindowSubclass(This
->hWndToolbar
,
2059 TaskSwichWnd_ToolbarSubclassedProc
,
2060 TSW_TOOLBAR_SUBCLASS_ID
))
2062 This
->IsToolbarSubclassed
= FALSE
;
2068 TaskSwitchWnd_NCDestroy(This
);
2069 HeapFree(hProcessHeap
,
2072 SetWindowLongPtr(hwnd
,
2082 TaskSwitchWnd_DumpTasks(This
);
2089 /* HandleDefaultMessage: */
2090 if (uMsg
== This
->ShellHookMsg
&& This
->ShellHookMsg
!= 0)
2092 /* Process shell messages */
2093 Ret
= (LRESULT
)TaskSwitchWnd_HandleShellHookMsg(This
,
2099 Ret
= DefWindowProc(hwnd
,
2108 Ret
= DefWindowProc(hwnd
,
2119 CreateTaskSwitchWnd(IN HWND hWndParent
,
2120 IN OUT ITrayWindow
*Tray
)
2124 hwndTaskBar
= CreateWindowEx(0,
2125 szTaskSwitchWndClass
,
2127 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| WS_TABSTOP
,
2141 RegisterTaskSwitchWndClass(VOID
)
2145 wc
.style
= CS_DBLCLKS
;
2146 wc
.lpfnWndProc
= TaskSwitchWndProc
;
2148 wc
.cbWndExtra
= sizeof(PTASK_SWITCH_WND
);
2149 wc
.hInstance
= hExplorerInstance
;
2151 wc
.hCursor
= LoadCursor(NULL
,
2153 wc
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+ 1);
2154 wc
.lpszMenuName
= NULL
;
2155 wc
.lpszClassName
= szTaskSwitchWndClass
;
2157 return RegisterClass(&wc
) != 0;
2161 UnregisterTaskSwitchWndClass(VOID
)
2163 UnregisterClass(szTaskSwitchWndClass
,