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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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_ActivateTask(IN OUT PTASK_SWITCH_WND This
,
1035 PTASK_ITEM TaskItem
;
1037 TaskItem
= TaskSwitchWnd_FindTaskItem(This
,
1039 if (TaskItem
== NULL
)
1041 TaskItem
= TaskSwitchWnd_FindOtherTaskItem(This
,
1045 if (TaskItem
!= NULL
)
1047 DbgPrint("Activate window 0x%p on button %d\n", hWnd
, TaskItem
->Index
);
1051 DbgPrint("Activate window 0x%p, could not find task\n", hWnd
);
1054 TaskSwitchWnd_CheckActivateTaskItem(This
,
1061 TaskSwitchWnd_DeleteTask(IN OUT PTASK_SWITCH_WND This
,
1064 PTASK_ITEM TaskItem
;
1066 TaskItem
= TaskSwitchWnd_FindTaskItem(This
,
1068 if (TaskItem
!= NULL
)
1070 DbgPrint("Delete window 0x%p on button %d\n", hWnd
, TaskItem
->Index
);
1071 TaskSwitchWnd_DeleteTaskItem(This
,
1076 //DbgPrint("Failed to delete window 0x%p\n", hWnd);
1082 TaskSwitchWnd_DeleteAllTasks(IN OUT PTASK_SWITCH_WND This
)
1084 PTASK_ITEM CurrentTask
;
1086 if (This
->TaskItemCount
> 0)
1088 CurrentTask
= This
->TaskItems
+ This
->TaskItemCount
;
1091 TaskSwitchWnd_DeleteTaskItem(This
,
1093 } while (CurrentTask
!= This
->TaskItems
);
1098 TaskSwitchWnd_FlashTaskItem(IN OUT PTASK_SWITCH_WND This
,
1099 IN OUT PTASK_ITEM TaskItem
)
1101 /* FIXME: Implement */
1105 TaskSwitchWnd_FlashTask(IN OUT PTASK_SWITCH_WND This
,
1108 PTASK_ITEM TaskItem
;
1110 TaskItem
= TaskSwitchWnd_FindTaskItem(This
,
1112 if (TaskItem
!= NULL
)
1114 DbgPrint("Flashing window 0x%p on button %d\n", hWnd
, TaskItem
->Index
);
1115 TaskSwitchWnd_FlashTaskItem(This
,
1124 TaskSwitchWnd_RedrawTaskItem(IN OUT PTASK_SWITCH_WND This
,
1125 IN OUT PTASK_ITEM TaskItem
)
1127 PTASK_GROUP TaskGroup
;
1129 TaskGroup
= TaskItem
->Group
;
1130 if (This
->IsGroupingEnabled
&& TaskGroup
!= NULL
)
1132 if (TaskGroup
->IsCollapsed
&& TaskGroup
->Index
>= 0)
1134 TaskSwitchWnd_UpdateTaskGroupButton(This
,
1137 else if (TaskItem
->Index
>= 0)
1139 goto UpdateTaskItem
;
1142 else if (TaskItem
->Index
>= 0)
1145 TaskSwitchWnd_UpdateTaskItemButton(This
,
1152 TaskSwitchWnd_RedrawTask(IN OUT PTASK_SWITCH_WND This
,
1155 PTASK_ITEM TaskItem
;
1157 TaskItem
= TaskSwitchWnd_FindTaskItem(This
,
1159 if (TaskItem
!= NULL
)
1161 TaskSwitchWnd_RedrawTaskItem(This
,
1170 TaskSwitchWnd_UpdateTbButtonSpacing(IN OUT PTASK_SWITCH_WND This
,
1171 IN BOOL bHorizontal
,
1173 IN UINT uiBtnsPerLine
)
1177 tbm
.cbSize
= sizeof(tbm
);
1178 tbm
.dwMask
= TBMF_BARPAD
| TBMF_BUTTONSPACING
;
1180 tbm
.cxBarPad
= tbm
.cyBarPad
= 0;
1182 if (bHorizontal
|| uiBtnsPerLine
> 1)
1183 tbm
.cxButtonSpacing
= (3 * GetSystemMetrics(SM_CXEDGE
) / 2);
1185 tbm
.cxButtonSpacing
= 0;
1187 if (!bHorizontal
|| uiRows
> 1)
1188 tbm
.cyButtonSpacing
= (3 * GetSystemMetrics(SM_CYEDGE
) / 2);
1190 tbm
.cyButtonSpacing
= 0;
1192 SendMessage(This
->hWndToolbar
,
1197 return tbm
.cxButtonSpacing
;
1202 TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This
,
1203 IN BOOL bRedrawDisabled
)
1206 UINT uiRows
, uiMax
, uiMin
, uiBtnsPerLine
, ui
;
1212 if (GetClientRect(This
->hWnd
,
1214 !IsRectEmpty(&rcClient
))
1216 if (This
->ToolbarBtnCount
> 0)
1218 ZeroMemory (&tbm
, sizeof (tbm
));
1219 tbm
.cbSize
= sizeof(tbm
);
1220 tbm
.dwMask
= TBMF_BUTTONSPACING
;
1221 SendMessage(This
->hWndToolbar
,
1226 uiRows
= (rcClient
.bottom
+ tbm
.cyButtonSpacing
) / (This
->ButtonSize
.cy
+ tbm
.cyButtonSpacing
);
1230 uiBtnsPerLine
= (This
->ToolbarBtnCount
+ uiRows
- 1) / uiRows
;
1232 Horizontal
= ITrayWindow_IsHorizontal(This
->Tray
);
1234 if (!bRedrawDisabled
)
1235 TaskSwitchWnd_BeginUpdate(This
);
1237 /* We might need to update the button spacing */
1238 tbm
.cxButtonSpacing
= TaskSwitchWnd_UpdateTbButtonSpacing(This
,
1243 /* Calculate the ideal width and make sure it's within the allowed range */
1244 NewBtnSize
= (rcClient
.right
- (uiBtnsPerLine
* tbm
.cxButtonSpacing
)) / uiBtnsPerLine
;
1246 /* Determine the minimum and maximum width of a button */
1248 uiMax
= GetSystemMetrics(SM_CXMINIMIZED
);
1250 uiMax
= rcClient
.right
;
1252 uiMin
= GetSystemMetrics(SM_CXSIZE
) + (2 * GetSystemMetrics(SM_CXEDGE
));
1254 if (NewBtnSize
< (LONG
)uiMin
)
1256 if (NewBtnSize
> (LONG
)uiMax
)
1259 This
->ButtonSize
.cx
= NewBtnSize
;
1261 /* Recalculate how many buttons actually fit into one line */
1262 uiBtnsPerLine
= rcClient
.right
/ (NewBtnSize
+ tbm
.cxButtonSpacing
);
1263 if (uiBtnsPerLine
== 0)
1265 This
->TbButtonsPerLine
= uiBtnsPerLine
;
1267 tbbi
.cbSize
= sizeof(tbbi
);
1268 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_SIZE
| TBIF_STATE
;
1269 tbbi
.cx
= (INT
)NewBtnSize
;
1271 for (ui
= 0; ui
!= This
->ToolbarBtnCount
; ui
++)
1273 tbbi
.fsState
= TBSTATE_ENABLED
;
1275 /* Check if we're updating a button that is the last one in the
1276 line. If so, we need to set the TBSTATE_WRAP flag! */
1277 if ((ui
+ 1) % uiBtnsPerLine
== 0)
1278 tbbi
.fsState
|= TBSTATE_WRAP
;
1280 if (This
->ActiveTaskItem
!= NULL
&&
1281 This
->ActiveTaskItem
->Index
== ui
)
1283 tbbi
.fsState
|= TBSTATE_CHECKED
;
1286 SendMessage(This
->hWndToolbar
,
1293 /* FIXME: Force the window to the correct position in case some idiot
1294 did something to us */
1295 SetWindowPos(This
->hWndToolbar
,
1299 rcClient
.right
, /* FIXME */
1300 rcClient
.bottom
, /* FIXME */
1301 SWP_NOACTIVATE
| SWP_NOZORDER
);
1306 This
->TbButtonsPerLine
= 0;
1307 This
->ButtonSize
.cx
= 0;
1311 TaskSwitchWnd_EndUpdate(This
);
1314 static BOOL CALLBACK
1315 TaskSwitchWnd_EnumWindowsProc(IN HWND hWnd
,
1318 PTASK_SWITCH_WND This
= (PTASK_SWITCH_WND
)lParam
;
1320 /* Only show windows that still exist and are visible and none of explorer's
1321 special windows (such as the desktop or the tray window) */
1322 if (IsWindow(hWnd
) && IsWindowVisible(hWnd
) &&
1323 !ITrayWindow_IsSpecialHWND(This
->Tray
,
1326 /* Don't list popup windows and also no tool windows */
1328 GW_OWNER
) == NULL
&&
1329 !(GetWindowLong(hWnd
,
1330 GWL_EXSTYLE
) & WS_EX_TOOLWINDOW
))
1332 TaskSwitchWnd_AddTask(This
,
1340 static LRESULT CALLBACK
1341 TaskSwichWnd_ToolbarSubclassedProc(IN HWND hWnd
,
1345 IN UINT_PTR uIdSubclass
,
1346 IN DWORD_PTR dwRefData
)
1350 Ret
= DefSubclassProc(hWnd
,
1355 if (msg
== WM_NCHITTEST
&& Ret
== HTCLIENT
)
1359 /* See if the mouse is on a button */
1360 pt
.x
= (SHORT
)LOWORD(lParam
);
1361 pt
.y
= (SHORT
)HIWORD(lParam
);
1363 if (MapWindowPoints(HWND_DESKTOP
,
1367 (INT
)SendMessage(hWnd
,
1372 /* Make the control appear to be transparent outside of any buttons */
1373 Ret
= HTTRANSPARENT
;
1381 TaskSwitchWnd_Create(IN OUT PTASK_SWITCH_WND This
)
1383 This
->hWndToolbar
= CreateWindowEx(0,
1386 WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
|
1387 TBSTYLE_TOOLTIPS
| TBSTYLE_WRAPABLE
| TBSTYLE_LIST
|
1388 TBSTYLE_TRANSPARENT
|
1389 CCS_TOP
| CCS_NORESIZE
| CCS_NODIVIDER
,
1399 if (This
->hWndToolbar
!= NULL
)
1404 /* Identify the version we're using */
1405 SendMessage(This
->hWndToolbar
,
1406 TB_BUTTONSTRUCTSIZE
,
1410 /* Calculate the default button size. Don't save this in This->ButtonSize.cx so that
1411 the actual button width gets updated correctly on the first recalculation */
1412 BtnSize
.cx
= GetSystemMetrics(SM_CXMINIMIZED
);
1413 This
->ButtonSize
.cy
= BtnSize
.cy
= GetSystemMetrics(SM_CYSIZE
) + (2 * GetSystemMetrics(SM_CYEDGE
));
1414 SendMessage(This
->hWndToolbar
,
1417 (LPARAM
)MAKELONG(BtnSize
.cx
,
1420 /* We don't want to see partially clipped buttons...not that we could see them... */
1422 SendMessage(This
->hWndToolbar
,
1423 TB_SETEXTENDEDSTYLE
,
1425 TBSTYLE_EX_HIDECLIPPEDBUTTONS
);
1428 /* Set proper spacing between buttons */
1429 TaskSwitchWnd_UpdateTbButtonSpacing(This
,
1430 ITrayWindow_IsHorizontal(This
->Tray
),
1434 /* Register the shell hook */
1435 This
->ShellHookMsg
= RegisterWindowMessage(TEXT("SHELLHOOK"));
1436 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
1437 if (hShell32
!= NULL
)
1439 REGSHELLHOOK RegShellHook
;
1441 /* RegisterShellHook */
1442 RegShellHook
= (REGSHELLHOOK
)GetProcAddress(hShell32
,
1443 (LPCSTR
)((LONG
)181));
1444 if (RegShellHook
!= NULL
)
1446 RegShellHook(This
->hWnd
,
1447 3); /* 1 if no NT! We're targeting NT so we don't care! */
1451 /* Add all windows to the toolbar */
1452 EnumWindows(TaskSwitchWnd_EnumWindowsProc
,
1455 /* Recalculate the button size */
1456 TaskSwitchWnd_UpdateButtonsSize(This
,
1459 /* Subclass the toolbar control because it doesn't provide a
1460 NM_NCHITTEST notification */
1461 This
->IsToolbarSubclassed
= SetWindowSubclass(This
->hWndToolbar
,
1462 TaskSwichWnd_ToolbarSubclassedProc
,
1463 TSW_TOOLBAR_SUBCLASS_ID
,
1469 TaskSwitchWnd_NCDestroy(IN OUT PTASK_SWITCH_WND This
)
1473 This
->IsDestroying
= TRUE
;
1475 /* Unregister the shell hook */
1476 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
1477 if (hShell32
!= NULL
)
1479 REGSHELLHOOK RegShellHook
;
1481 /* RegisterShellHook */
1482 RegShellHook
= (REGSHELLHOOK
)GetProcAddress(hShell32
,
1483 (LPCSTR
)((LONG
)181));
1484 if (RegShellHook
!= NULL
)
1486 RegShellHook(This
->hWnd
,
1491 TaskSwitchWnd_DeleteAllTasks(This
);
1495 TaskSwitchWnd_HandleAppCommand(IN OUT PTASK_SWITCH_WND This
,
1501 switch (GET_APPCOMMAND_LPARAM(lParam
))
1503 case APPCOMMAND_BROWSER_SEARCH
:
1504 Ret
= SHFindFiles(NULL
,
1508 case APPCOMMAND_BROWSER_HOME
:
1509 case APPCOMMAND_LAUNCH_MAIL
:
1511 DbgPrint("Shell app command %d unhandled!\n", (INT
)GET_APPCOMMAND_LPARAM(lParam
));
1520 TaskSwitchWnd_HandleShellHookMsg(IN OUT PTASK_SWITCH_WND This
,
1526 switch ((INT
)wParam
)
1528 case HSHELL_APPCOMMAND
:
1529 TaskSwitchWnd_HandleAppCommand(This
,
1535 case HSHELL_WINDOWCREATED
:
1536 TaskSwitchWnd_AddTask(This
,
1541 case HSHELL_WINDOWDESTROYED
:
1542 /* The window still exists! Delay destroying it a bit */
1543 TaskSwitchWnd_DeleteTask(This
,
1548 case HSHELL_ACTIVATESHELLWINDOW
:
1549 goto UnhandledShellMessage
;
1551 case HSHELL_RUDEAPPACTIVATED
:
1552 goto UnhandledShellMessage
;
1554 case HSHELL_WINDOWACTIVATED
:
1555 TaskSwitchWnd_ActivateTask(This
,
1560 case HSHELL_GETMINRECT
:
1561 goto UnhandledShellMessage
;
1564 TaskSwitchWnd_FlashTask(This
,
1570 TaskSwitchWnd_RedrawTask(This
,
1575 case HSHELL_TASKMAN
:
1576 case HSHELL_LANGUAGE
:
1577 case HSHELL_SYSMENU
:
1578 case HSHELL_ENDTASK
:
1579 case HSHELL_ACCESSIBILITYSTATE
:
1580 case HSHELL_WINDOWREPLACED
:
1581 case HSHELL_WINDOWREPLACING
:
1584 static const struct {
1588 {HSHELL_WINDOWCREATED
, L
"HSHELL_WINDOWCREATED"},
1589 {HSHELL_WINDOWDESTROYED
, L
"HSHELL_WINDOWDESTROYED"},
1590 {HSHELL_ACTIVATESHELLWINDOW
, L
"HSHELL_ACTIVATESHELLWINDOW"},
1591 {HSHELL_WINDOWACTIVATED
, L
"HSHELL_WINDOWACTIVATED"},
1592 {HSHELL_GETMINRECT
, L
"HSHELL_GETMINRECT"},
1593 {HSHELL_REDRAW
, L
"HSHELL_REDRAW"},
1594 {HSHELL_TASKMAN
, L
"HSHELL_TASKMAN"},
1595 {HSHELL_LANGUAGE
, L
"HSHELL_LANGUAGE"},
1596 {HSHELL_SYSMENU
, L
"HSHELL_SYSMENU"},
1597 {HSHELL_ENDTASK
, L
"HSHELL_ENDTASK"},
1598 {HSHELL_ACCESSIBILITYSTATE
, L
"HSHELL_ACCESSIBILITYSTATE"},
1599 {HSHELL_APPCOMMAND
, L
"HSHELL_APPCOMMAND"},
1600 {HSHELL_WINDOWREPLACED
, L
"HSHELL_WINDOWREPLACED"},
1601 {HSHELL_WINDOWREPLACING
, L
"HSHELL_WINDOWREPLACING"},
1602 {HSHELL_RUDEAPPACTIVATED
, L
"HSHELL_RUDEAPPACTIVATED"},
1605 UnhandledShellMessage
:
1606 for (i
= 0, found
= 0; i
!= sizeof(hshell_msg
) / sizeof(hshell_msg
[0]); i
++)
1608 if (hshell_msg
[i
].msg
== (INT
)wParam
)
1610 DbgPrint("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg
[i
].msg_name
, lParam
);
1617 DbgPrint("Shell message %d unhandled (lParam = 0x%p)!\n", (INT
)wParam
, lParam
);
1627 TaskSwitchWnd_EnableGrouping(IN OUT PTASK_SWITCH_WND This
,
1630 This
->IsGroupingEnabled
= bEnable
;
1632 /* Collapse or expand groups if neccessary */
1633 TaskSwitchWnd_UpdateButtonsSize(This
,
1638 TaskSwichWnd_HandleItemPaint(IN OUT PTASK_SWITCH_WND This
,
1639 IN OUT NMTBCUSTOMDRAW
*nmtbcd
)
1641 HFONT hCaptionFont
, hBoldCaptionFont
;
1642 LRESULT Ret
= CDRF_DODEFAULT
;
1643 PTASK_GROUP TaskGroup
;
1644 PTASK_ITEM TaskItem
;
1646 #if TASK_USE_DRAWCAPTIONTEMP != 0
1648 UINT uidctFlags
= DC_TEXT
| DC_ICON
| DC_NOSENDMSG
;
1651 TaskItem
= FindTaskItemByIndex(This
,
1652 (INT
)nmtbcd
->nmcd
.dwItemSpec
);
1653 TaskGroup
= FindTaskGroupByIndex(This
,
1654 (INT
)nmtbcd
->nmcd
.dwItemSpec
);
1655 if (TaskGroup
== NULL
&& TaskItem
!= NULL
)
1657 ASSERT(TaskItem
!= NULL
);
1659 if (TaskItem
!= NULL
&& IsWindow(TaskItem
->hWnd
))
1661 hCaptionFont
= ITrayWindow_GetCaptionFonts(This
->Tray
,
1663 if (nmtbcd
->nmcd
.uItemState
& CDIS_CHECKED
)
1664 hCaptionFont
= hBoldCaptionFont
;
1666 #if TASK_USE_DRAWCAPTIONTEMP != 0
1668 /* Make sure we don't draw on the button edges */
1669 InflateRect(&nmtbcd
->nmcd
.rc
,
1670 -GetSystemMetrics(SM_CXEDGE
),
1671 -GetSystemMetrics(SM_CYEDGE
));
1673 if ((nmtbcd
->nmcd
.uItemState
& CDIS_MARKED
) && TaskItem
->RenderFlashed
)
1675 /* This is a slight glitch. We have to move the rectangle so that
1676 the button content appears to be pressed. However, when flashing
1677 is enabled, we can see a light line at the top and left inner
1678 border. We need to fill that area with the flashing color. Note
1679 that since we're using DrawCaptionTemp() the flashing color is
1680 COLOR_ACTIVECAPTION, not COLOR_HIGHLIGHT! */
1681 FillRect(nmtbcd
->nmcd
.hdc
,
1683 (HBRUSH
)(COLOR_ACTIVECAPTION
+ 1));
1685 /* Make the button content appear pressed. This however draws a bit
1686 into the right and bottom border of the button edge, making it
1687 look a bit odd. However, selecting a clipping region to prevent
1688 that from happening causes problems with DrawCaptionTemp()! */
1689 OffsetRect(&nmtbcd
->nmcd
.rc
,
1693 /* Render flashed */
1694 uidctFlags
|= DC_ACTIVE
;
1698 uidctFlags
|= DC_INBUTTON
;
1699 if (nmtbcd
->nmcd
.uItemState
& CDIS_CHECKED
)
1700 uidctFlags
|= DC_ACTIVE
;
1703 if (DrawCapTemp
!= NULL
)
1705 /* Draw the button content */
1706 TaskItem
->DisplayTooltip
= !DrawCapTemp(TaskItem
->hWnd
,
1715 return CDRF_SKIPDEFAULT
;
1717 #else /* !TASK_USE_DRAWCAPTIONTEMP */
1719 /* Make the entire button flashing if neccessary */
1720 if (nmtbcd
->nmcd
.uItemState
& CDIS_MARKED
)
1722 if (TaskItem
->RenderFlashed
)
1724 nmtbcd
->hbrMonoDither
= GetSysColorBrush(COLOR_HIGHLIGHT
);
1725 nmtbcd
->clrTextHighlight
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
1726 nmtbcd
->nHLStringBkMode
= TRANSPARENT
;
1728 /* We don't really need to set clrMark because we set the
1729 background mode to TRANSPARENT! */
1730 nmtbcd
->clrMark
= GetSysColor(COLOR_HIGHLIGHT
);
1732 Ret
|= TBCDRF_USECDCOLORS
;
1735 Ret
|= TBCDRF_NOMARK
;
1738 /* Select the font we want to use */
1739 SelectObject(nmtbcd
->nmcd
.hdc
,
1741 return Ret
| CDRF_NEWFONT
;
1747 else if (TaskGroup
!= NULL
)
1749 /* FIXME: Implement painting for task groups */
1756 TaskSwitchWnd_HandleToolbarNotification(IN OUT PTASK_SWITCH_WND This
,
1757 IN
const NMHDR
*nmh
)
1765 LPNMTBCUSTOMDRAW nmtbcd
= (LPNMTBCUSTOMDRAW
)nmh
;
1767 switch (nmtbcd
->nmcd
.dwDrawStage
)
1770 #if TASK_USE_DRAWCAPTIONTEMP != 0
1772 case CDDS_ITEMPREPAINT
:
1773 /* We handle drawing in the post-paint stage so that we
1774 don't have to draw the button edges, etc */
1775 Ret
= CDRF_NOTIFYPOSTPAINT
;
1778 case CDDS_ITEMPOSTPAINT
:
1780 #else /* !TASK_USE_DRAWCAPTIONTEMP */
1782 case CDDS_ITEMPREPAINT
:
1786 Ret
= TaskSwichWnd_HandleItemPaint(This
,
1791 Ret
= CDRF_NOTIFYITEMDRAW
;
1795 Ret
= CDRF_DODEFAULT
;
1805 static LRESULT CALLBACK
1806 TaskSwitchWndProc(IN HWND hwnd
,
1811 PTASK_SWITCH_WND This
= NULL
;
1812 LRESULT Ret
= FALSE
;
1814 if (uMsg
!= WM_NCCREATE
)
1816 This
= (PTASK_SWITCH_WND
)GetWindowLongPtr(hwnd
,
1820 if (This
!= NULL
|| uMsg
== WM_NCCREATE
)
1828 szClient
.cx
= LOWORD(lParam
);
1829 szClient
.cy
= HIWORD(lParam
);
1830 if (This
->hWndToolbar
!= NULL
)
1832 SetWindowPos(This
->hWndToolbar
,
1840 TaskSwitchWnd_UpdateButtonsSize(This
,
1848 /* We want the tray window to be draggable everywhere, so make the control
1849 appear transparent */
1850 Ret
= DefWindowProc(hwnd
,
1854 if (Ret
!= HTVSCROLL
&& Ret
!= HTHSCROLL
)
1855 Ret
= HTTRANSPARENT
;
1861 if (lParam
!= 0 && (HWND
)lParam
== This
->hWndToolbar
)
1863 DbgPrint("WM_COMMAND %u:%u (%u)\n", (UINT
)LOWORD(wParam
), (UINT
)HIWORD(wParam
), (UINT
)wParam
);
1870 const NMHDR
*nmh
= (const NMHDR
*)lParam
;
1872 if (nmh
->hwndFrom
== This
->hWndToolbar
)
1874 Ret
= TaskSwitchWnd_HandleToolbarNotification(This
,
1880 case TSWM_ENABLEGROUPING
:
1882 Ret
= This
->IsGroupingEnabled
;
1883 if (wParam
!= This
->IsGroupingEnabled
)
1885 TaskSwitchWnd_EnableGrouping(This
,
1891 case TSWM_UPDATETASKBARPOS
:
1893 /* Update the button spacing */
1894 TaskSwitchWnd_UpdateTbButtonSpacing(This
,
1895 ITrayWindow_IsHorizontal(This
->Tray
),
1901 case WM_CONTEXTMENU
:
1903 if (This
->hWndToolbar
!= NULL
)
1908 pt
.x
= (LONG
)LOWORD(lParam
);
1909 pt
.y
= (LONG
)HIWORD(lParam
);
1911 MapWindowPoints(NULL
,
1916 iBtn
= (INT_PTR
)SendMessage(This
->hWndToolbar
,
1922 /* FIXME: Display the system menu of the window */
1925 goto ForwardContextMenuMsg
;
1929 ForwardContextMenuMsg
:
1930 /* Forward message */
1931 Ret
= SendMessage(ITrayWindow_GetHWND(This
->Tray
),
1941 LPCREATESTRUCT CreateStruct
= (LPCREATESTRUCT
)lParam
;
1942 This
= (PTASK_SWITCH_WND
)HeapAlloc(hProcessHeap
,
1951 This
->hWndNotify
= CreateStruct
->hwndParent
;
1952 This
->Tray
= (ITrayWindow
*)CreateStruct
->lpCreateParams
;
1953 This
->IsGroupingEnabled
= TRUE
; /* FIXME */
1954 SetWindowLongPtr(hwnd
,
1962 TaskSwitchWnd_Create(This
);
1974 if (This
->IsToolbarSubclassed
)
1976 if (RemoveWindowSubclass(This
->hWndToolbar
,
1977 TaskSwichWnd_ToolbarSubclassedProc
,
1978 TSW_TOOLBAR_SUBCLASS_ID
))
1980 This
->IsToolbarSubclassed
= FALSE
;
1986 TaskSwitchWnd_NCDestroy(This
);
1987 HeapFree(hProcessHeap
,
1990 SetWindowLongPtr(hwnd
,
2000 TaskSwitchWnd_DumpTasks(This
);
2007 /* HandleDefaultMessage: */
2008 if (uMsg
== This
->ShellHookMsg
&& This
->ShellHookMsg
!= 0)
2010 /* Process shell messages */
2011 Ret
= (LRESULT
)TaskSwitchWnd_HandleShellHookMsg(This
,
2017 Ret
= DefWindowProc(hwnd
,
2026 Ret
= DefWindowProc(hwnd
,
2037 CreateTaskSwitchWnd(IN HWND hWndParent
,
2038 IN OUT ITrayWindow
*Tray
)
2042 hwndTaskBar
= CreateWindowEx(0,
2043 szTaskSwitchWndClass
,
2045 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| WS_TABSTOP
,
2059 RegisterTaskSwitchWndClass(VOID
)
2063 wc
.style
= CS_DBLCLKS
;
2064 wc
.lpfnWndProc
= TaskSwitchWndProc
;
2066 wc
.cbWndExtra
= sizeof(PTASK_SWITCH_WND
);
2067 wc
.hInstance
= hExplorerInstance
;
2069 wc
.hCursor
= LoadCursor(NULL
,
2071 wc
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+ 1);
2072 wc
.lpszMenuName
= NULL
;
2073 wc
.lpszClassName
= szTaskSwitchWndClass
;
2075 return RegisterClass(&wc
) != 0;
2079 UnregisterTaskSwitchWndClass(VOID
)
2081 UnregisterClass(szTaskSwitchWndClass
,