1 /*
2 * ReactOS Explorer
3 *
4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "precomp.h"
22 #include <commoncontrols.h>
23
24 /* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every
25 5 seconds */
26 #define DUMP_TASKS 0
27 #define DEBUG_SHELL_HOOK 0
28
29 #define MAX_TASKS_COUNT (0x7FFF)
30 #define TASK_ITEM_ARRAY_ALLOC 64
31
32 const WCHAR szTaskSwitchWndClass[] = L"MSTaskSwWClass";
33 const WCHAR szRunningApps[] = L"Running Applications";
34
35 #if DEBUG_SHELL_HOOK
36 const struct {
37 INT msg;
38 LPCWSTR msg_name;
39 } hshell_msg [] = {
40 { HSHELL_WINDOWCREATED, L"HSHELL_WINDOWCREATED" },
41 { HSHELL_WINDOWDESTROYED, L"HSHELL_WINDOWDESTROYED" },
42 { HSHELL_ACTIVATESHELLWINDOW, L"HSHELL_ACTIVATESHELLWINDOW" },
43 { HSHELL_WINDOWACTIVATED, L"HSHELL_WINDOWACTIVATED" },
44 { HSHELL_GETMINRECT, L"HSHELL_GETMINRECT" },
45 { HSHELL_REDRAW, L"HSHELL_REDRAW" },
46 { HSHELL_TASKMAN, L"HSHELL_TASKMAN" },
47 { HSHELL_LANGUAGE, L"HSHELL_LANGUAGE" },
48 { HSHELL_SYSMENU, L"HSHELL_SYSMENU" },
49 { HSHELL_ENDTASK, L"HSHELL_ENDTASK" },
50 { HSHELL_ACCESSIBILITYSTATE, L"HSHELL_ACCESSIBILITYSTATE" },
51 { HSHELL_APPCOMMAND, L"HSHELL_APPCOMMAND" },
52 { HSHELL_WINDOWREPLACED, L"HSHELL_WINDOWREPLACED" },
53 { HSHELL_WINDOWREPLACING, L"HSHELL_WINDOWREPLACING" },
54 { HSHELL_RUDEAPPACTIVATED, L"HSHELL_RUDEAPPACTIVATED" },
55 };
56 #endif
57
58 typedef struct _TASK_GROUP
59 {
60 /* We have to use a linked list instead of an array so we don't have to
61 update all pointers to groups in the task item array when removing
62 groups. */
63 struct _TASK_GROUP *Next;
64
65 DWORD dwTaskCount;
66 DWORD dwProcessId;
67 INT Index;
68 union
69 {
70 DWORD dwFlags;
71 struct
72 {
73
74 DWORD IsCollapsed : 1;
75 };
76 };
77 } TASK_GROUP, *PTASK_GROUP;
78
79 typedef struct _TASK_ITEM
80 {
81 HWND hWnd;
82 PTASK_GROUP Group;
83 INT Index;
84 INT IconIndex;
85
86 union
87 {
88 DWORD dwFlags;
89 struct
90 {
91
92 /* IsFlashing is TRUE when the task bar item should be flashing. */
93 DWORD IsFlashing : 1;
94
95 /* RenderFlashed is only TRUE if the task bar item should be
96 drawn with a flash. */
97 DWORD RenderFlashed : 1;
98 };
99 };
100 } TASK_ITEM, *PTASK_ITEM;
101
102
103 class CHardErrorThread
104 {
105 DWORD m_ThreadId;
106 HANDLE m_hThread;
107 LONG m_bThreadRunning;
108 DWORD m_Status;
109 DWORD m_dwType;
110 CStringW m_Title;
111 CStringW m_Text;
112 public:
113
CHardErrorThread()114 CHardErrorThread():
115 m_ThreadId(0),
116 m_hThread(NULL),
117 m_bThreadRunning(FALSE),
118 m_Status(NULL),
119 m_dwType(NULL)
120 {
121 }
122
~CHardErrorThread()123 ~CHardErrorThread()
124 {
125 if (m_bThreadRunning)
126 {
127 /* Try to unstuck Show */
128 PostThreadMessage(m_ThreadId, WM_QUIT, 0, 0);
129 DWORD ret = WaitForSingleObject(m_hThread, 3*1000);
130 if (ret == WAIT_TIMEOUT)
131 TerminateThread(m_hThread, 0);
132 CloseHandle(m_hThread);
133 }
134 }
135
ThreadProc()136 HRESULT ThreadProc()
137 {
138 HRESULT hr;
139 CComPtr<IUserNotification> pnotification;
140
141 hr = OleInitialize(NULL);
142 if (FAILED_UNEXPECTEDLY(hr))
143 return hr;
144
145 hr = CoCreateInstance(CLSID_UserNotification,
146 NULL,
147 CLSCTX_INPROC_SERVER,
148 IID_PPV_ARG(IUserNotification, &pnotification));
149 if (FAILED_UNEXPECTEDLY(hr))
150 return hr;
151
152 hr = pnotification->SetBalloonInfo(m_Title, m_Text, NIIF_WARNING);
153 if (FAILED_UNEXPECTEDLY(hr))
154 return hr;
155
156 hr = pnotification->SetIconInfo(NULL, NULL);
157 if (FAILED_UNEXPECTEDLY(hr))
158 return hr;
159
160 /* Show will block until the balloon closes */
161 hr = pnotification->Show(NULL, 0);
162 if (FAILED_UNEXPECTEDLY(hr))
163 return hr;
164
165 return S_OK;
166 }
167
s_HardErrorThreadProc(IN OUT LPVOID lpParameter)168 static DWORD CALLBACK s_HardErrorThreadProc(IN OUT LPVOID lpParameter)
169 {
170 CHardErrorThread* pThis = reinterpret_cast<CHardErrorThread*>(lpParameter);
171 pThis->ThreadProc();
172 CloseHandle(pThis->m_hThread);
173 OleUninitialize();
174 InterlockedExchange(&pThis->m_bThreadRunning, FALSE);
175 return 0;
176 }
177
StartThread(PBALLOON_HARD_ERROR_DATA pData)178 void StartThread(PBALLOON_HARD_ERROR_DATA pData)
179 {
180 BOOL bIsRunning = InterlockedExchange(&m_bThreadRunning, TRUE);
181
182 /* Ignore the new message if we are already showing one */
183 if (bIsRunning)
184 return;
185
186 m_Status = pData->Status;
187 m_dwType = pData->dwType;
188 m_Title = (PWCHAR)((ULONG_PTR)pData + pData->TitleOffset);
189 m_Text = (PWCHAR)((ULONG_PTR)pData + pData->MessageOffset);
190 m_hThread = CreateThread(NULL, 0, s_HardErrorThreadProc, this, 0, &m_ThreadId);
191 if (!m_hThread)
192 {
193 m_bThreadRunning = FALSE;
194 CloseHandle(m_hThread);
195 }
196 }
197 };
198
199 class CTaskToolbar :
200 public CWindowImplBaseT< CToolbar<TASK_ITEM>, CControlWinTraits >
201 {
202 public:
UpdateTbButtonSpacing(IN BOOL bHorizontal,IN BOOL bThemed,IN UINT uiRows=0,IN UINT uiBtnsPerLine=0)203 INT UpdateTbButtonSpacing(IN BOOL bHorizontal, IN BOOL bThemed, IN UINT uiRows = 0, IN UINT uiBtnsPerLine = 0)
204 {
205 TBMETRICS tbm;
206
207 tbm.cbSize = sizeof(tbm);
208 tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING;
209
210 tbm.cxBarPad = tbm.cyBarPad = 0;
211
212 if (bThemed)
213 {
214 tbm.cxButtonSpacing = 0;
215 tbm.cyButtonSpacing = 0;
216 }
217 else
218 {
219 if (bHorizontal || uiBtnsPerLine > 1)
220 tbm.cxButtonSpacing = (3 * GetSystemMetrics(SM_CXEDGE) / 2);
221 else
222 tbm.cxButtonSpacing = 0;
223
224 if (!bHorizontal || uiRows > 1)
225 tbm.cyButtonSpacing = (3 * GetSystemMetrics(SM_CYEDGE) / 2);
226 else
227 tbm.cyButtonSpacing = 0;
228 }
229
230 SetMetrics(&tbm);
231
232 return tbm.cxButtonSpacing;
233 }
234
BeginUpdate()235 VOID BeginUpdate()
236 {
237 SetRedraw(FALSE);
238 }
239
EndUpdate()240 VOID EndUpdate()
241 {
242 SendMessageW(WM_SETREDRAW, TRUE);
243 InvalidateRect(NULL, TRUE);
244 }
245
SetButtonCommandId(IN INT iButtonIndex,IN INT iCommandId)246 BOOL SetButtonCommandId(IN INT iButtonIndex, IN INT iCommandId)
247 {
248 TBBUTTONINFO tbbi;
249
250 tbbi.cbSize = sizeof(tbbi);
251 tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
252 tbbi.idCommand = iCommandId;
253
254 return SetButtonInfo(iButtonIndex, &tbbi) != 0;
255 }
256
OnNcHitTestToolbar(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)257 LRESULT OnNcHitTestToolbar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
258 {
259 POINT pt;
260
261 /* See if the mouse is on a button */
262 pt.x = GET_X_LPARAM(lParam);
263 pt.y = GET_Y_LPARAM(lParam);
264 ScreenToClient(&pt);
265
266 INT index = HitTest(&pt);
267 if (index < 0)
268 {
269 /* Make the control appear to be transparent outside of any buttons */
270 return HTTRANSPARENT;
271 }
272
273 bHandled = FALSE;
274 return 0;
275 }
276
277 public:
278 BEGIN_MSG_MAP(CNotifyToolbar)
MESSAGE_HANDLER(WM_NCHITTEST,OnNcHitTestToolbar)279 MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTestToolbar)
280 END_MSG_MAP()
281
282 BOOL Initialize(HWND hWndParent)
283 {
284 DWORD styles = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
285 TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_LIST | TBSTYLE_TRANSPARENT |
286 CCS_TOP | CCS_NORESIZE | CCS_NODIVIDER;
287
288 // HACK & FIXME: CORE-18016
289 HWND toolbar = CToolbar::Create(hWndParent, styles);
290 m_hWnd = NULL;
291 return SubclassWindow(toolbar);
292 }
293 };
294
295 class CTaskSwitchWnd :
296 public CComCoClass<CTaskSwitchWnd>,
297 public CComObjectRootEx<CComMultiThreadModelNoCS>,
298 public CWindowImpl < CTaskSwitchWnd, CWindow, CControlWinTraits >,
299 public IOleWindow
300 {
301 CTaskToolbar m_TaskBar;
302
303 CComPtr<ITrayWindow> m_Tray;
304
305 UINT m_ShellHookMsg;
306
307 WORD m_TaskItemCount;
308 WORD m_AllocatedTaskItems;
309
310 PTASK_GROUP m_TaskGroups;
311 PTASK_ITEM m_TaskItems;
312 PTASK_ITEM m_ActiveTaskItem;
313
314 HTHEME m_Theme;
315 UINT m_ButtonsPerLine;
316 WORD m_ButtonCount;
317
318 HIMAGELIST m_ImageList;
319
320 BOOL m_IsGroupingEnabled;
321 BOOL m_IsDestroying;
322
323 SIZE m_ButtonSize;
324
325 UINT m_uHardErrorMsg;
326 CHardErrorThread m_HardErrorThread;
327
328 public:
CTaskSwitchWnd()329 CTaskSwitchWnd() :
330 m_ShellHookMsg(NULL),
331 m_TaskItemCount(0),
332 m_AllocatedTaskItems(0),
333 m_TaskGroups(NULL),
334 m_TaskItems(NULL),
335 m_ActiveTaskItem(NULL),
336 m_Theme(NULL),
337 m_ButtonsPerLine(0),
338 m_ButtonCount(0),
339 m_ImageList(NULL),
340 m_IsGroupingEnabled(FALSE),
341 m_IsDestroying(FALSE)
342 {
343 ZeroMemory(&m_ButtonSize, sizeof(m_ButtonSize));
344 m_uHardErrorMsg = RegisterWindowMessageW(L"HardError");
345 }
~CTaskSwitchWnd()346 virtual ~CTaskSwitchWnd() { }
347
GetWndTextFromTaskItem(IN PTASK_ITEM TaskItem,LPWSTR szBuf,DWORD cchBuf)348 INT GetWndTextFromTaskItem(IN PTASK_ITEM TaskItem, LPWSTR szBuf, DWORD cchBuf)
349 {
350 /* Get the window text without sending a message so we don't hang if an
351 application isn't responding! */
352 return InternalGetWindowText(TaskItem->hWnd, szBuf, cchBuf);
353 }
354
355
356 #if DUMP_TASKS != 0
DumpTasks()357 VOID DumpTasks()
358 {
359 PTASK_GROUP CurrentGroup;
360 PTASK_ITEM CurrentTaskItem, LastTaskItem;
361
362 TRACE("Tasks dump:\n");
363 if (m_IsGroupingEnabled)
364 {
365 CurrentGroup = m_TaskGroups;
366 while (CurrentGroup != NULL)
367 {
368 TRACE("- Group PID: 0x%p Tasks: %d Index: %d\n", CurrentGroup->dwProcessId, CurrentGroup->dwTaskCount, CurrentGroup->Index);
369
370 CurrentTaskItem = m_TaskItems;
371 LastTaskItem = CurrentTaskItem + m_TaskItemCount;
372 while (CurrentTaskItem != LastTaskItem)
373 {
374 if (CurrentTaskItem->Group == CurrentGroup)
375 {
376 TRACE(" + Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index);
377 }
378 CurrentTaskItem++;
379 }
380
381 CurrentGroup = CurrentGroup->Next;
382 }
383
384 CurrentTaskItem = m_TaskItems;
385 LastTaskItem = CurrentTaskItem + m_TaskItemCount;
386 while (CurrentTaskItem != LastTaskItem)
387 {
388 if (CurrentTaskItem->Group == NULL)
389 {
390 TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index);
391 }
392 CurrentTaskItem++;
393 }
394 }
395 else
396 {
397 CurrentTaskItem = m_TaskItems;
398 LastTaskItem = CurrentTaskItem + m_TaskItemCount;
399 while (CurrentTaskItem != LastTaskItem)
400 {
401 TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index);
402 CurrentTaskItem++;
403 }
404 }
405 }
406 #endif
407
UpdateIndexesAfter(IN INT iIndex,BOOL bInserted)408 VOID UpdateIndexesAfter(IN INT iIndex, BOOL bInserted)
409 {
410 PTASK_GROUP CurrentGroup;
411 PTASK_ITEM CurrentTaskItem, LastTaskItem;
412 INT NewIndex;
413
414 int offset = bInserted ? +1 : -1;
415
416 if (m_IsGroupingEnabled)
417 {
418 /* Update all affected groups */
419 CurrentGroup = m_TaskGroups;
420 while (CurrentGroup != NULL)
421 {
422 if (CurrentGroup->IsCollapsed &&
423 CurrentGroup->Index >= iIndex)
424 {
425 /* Update the toolbar buttons */
426 NewIndex = CurrentGroup->Index + offset;
427 if (m_TaskBar.SetButtonCommandId(CurrentGroup->Index + offset, NewIndex))
428 {
429 CurrentGroup->Index = NewIndex;
430 }
431 else
432 CurrentGroup->Index = -1;
433 }
434
435 CurrentGroup = CurrentGroup->Next;
436 }
437 }
438
439 /* Update all affected task items */
440 CurrentTaskItem = m_TaskItems;
441 LastTaskItem = CurrentTaskItem + m_TaskItemCount;
442 while (CurrentTaskItem != LastTaskItem)
443 {
444 CurrentGroup = CurrentTaskItem->Group;
445 if (CurrentGroup != NULL)
446 {
447 if (!CurrentGroup->IsCollapsed &&
448 CurrentTaskItem->Index >= iIndex)
449 {
450 goto UpdateTaskItemBtn;
451 }
452 }
453 else if (CurrentTaskItem->Index >= iIndex)
454 {
455 UpdateTaskItemBtn:
456 /* Update the toolbar buttons */
457 NewIndex = CurrentTaskItem->Index + offset;
458 if (m_TaskBar.SetButtonCommandId(CurrentTaskItem->Index + offset, NewIndex))
459 {
460 CurrentTaskItem->Index = NewIndex;
461 }
462 else
463 CurrentTaskItem->Index = -1;
464 }
465
466 CurrentTaskItem++;
467 }
468 }
469
470
UpdateTaskGroupButton(IN PTASK_GROUP TaskGroup)471 INT UpdateTaskGroupButton(IN PTASK_GROUP TaskGroup)
472 {
473 ASSERT(TaskGroup->Index >= 0);
474
475 /* FIXME: Implement */
476
477 return TaskGroup->Index;
478 }
479
ExpandTaskGroup(IN PTASK_GROUP TaskGroup)480 VOID ExpandTaskGroup(IN PTASK_GROUP TaskGroup)
481 {
482 ASSERT(TaskGroup->dwTaskCount > 0);
483 ASSERT(TaskGroup->IsCollapsed);
484 ASSERT(TaskGroup->Index >= 0);
485
486 /* FIXME: Implement */
487 }
488
GetWndIcon(HWND hwnd)489 HICON GetWndIcon(HWND hwnd)
490 {
491 HICON hIcon = NULL;
492
493 /* Retrieve icon by sending a message */
494 #define GET_ICON(type) \
495 SendMessageTimeout(hwnd, WM_GETICON, (type), 0, SMTO_NOTIMEOUTIFNOTHUNG, 100, (PDWORD_PTR)&hIcon)
496
497 LRESULT bAlive = GET_ICON(g_TaskbarSettings.bSmallIcons ? ICON_SMALL2 : ICON_BIG);
498 if (hIcon)
499 return hIcon;
500
501 if (bAlive)
502 {
503 bAlive = GET_ICON(ICON_SMALL);
504 if (hIcon)
505 return hIcon;
506 }
507
508 if (bAlive)
509 {
510 GET_ICON(g_TaskbarSettings.bSmallIcons ? ICON_BIG : ICON_SMALL2);
511 if (hIcon)
512 return hIcon;
513 }
514 #undef GET_ICON
515
516 /* If we failed, retrieve icon from the window class */
517 hIcon = (HICON)GetClassLongPtr(hwnd, g_TaskbarSettings.bSmallIcons ? GCLP_HICONSM : GCLP_HICON);
518 if (hIcon)
519 return hIcon;
520
521 return (HICON)GetClassLongPtr(hwnd, g_TaskbarSettings.bSmallIcons ? GCLP_HICON : GCLP_HICONSM);
522 }
523
UpdateTaskItemButton(IN PTASK_ITEM TaskItem)524 INT UpdateTaskItemButton(IN PTASK_ITEM TaskItem)
525 {
526 TBBUTTONINFO tbbi = { 0 };
527 HICON icon;
528 WCHAR windowText[255];
529
530 ASSERT(TaskItem->Index >= 0);
531
532 tbbi.cbSize = sizeof(tbbi);
533 tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT | TBIF_IMAGE;
534 tbbi.fsState = TBSTATE_ENABLED;
535 if (m_ActiveTaskItem == TaskItem)
536 tbbi.fsState |= TBSTATE_CHECKED;
537
538 if (TaskItem->RenderFlashed)
539 tbbi.fsState |= TBSTATE_MARKED;
540
541 /* Check if we're updating a button that is the last one in the
542 line. If so, we need to set the TBSTATE_WRAP flag! */
543 if (!m_Tray->IsHorizontal() || (m_ButtonsPerLine != 0 &&
544 (TaskItem->Index + 1) % m_ButtonsPerLine == 0))
545 {
546 tbbi.fsState |= TBSTATE_WRAP;
547 }
548
549 if (GetWndTextFromTaskItem(TaskItem, windowText, _countof(windowText)) > 0)
550 {
551 tbbi.pszText = windowText;
552 }
553
554 icon = GetWndIcon(TaskItem->hWnd);
555 if (!icon)
556 icon = static_cast<HICON>(LoadImageW(NULL, MAKEINTRESOURCEW(OIC_SAMPLE), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
557 TaskItem->IconIndex = ImageList_ReplaceIcon(m_ImageList, TaskItem->IconIndex, icon);
558 tbbi.iImage = TaskItem->IconIndex;
559
560 if (!m_TaskBar.SetButtonInfo(TaskItem->Index, &tbbi))
561 {
562 TaskItem->Index = -1;
563 return -1;
564 }
565
566 TRACE("Updated button %d for hwnd 0x%p\n", TaskItem->Index, TaskItem->hWnd);
567 return TaskItem->Index;
568 }
569
RemoveIcon(IN PTASK_ITEM TaskItem)570 VOID RemoveIcon(IN PTASK_ITEM TaskItem)
571 {
572 TBBUTTONINFO tbbi;
573 PTASK_ITEM currentTaskItem, LastItem;
574
575 if (TaskItem->IconIndex == -1)
576 return;
577
578 tbbi.cbSize = sizeof(tbbi);
579 tbbi.dwMask = TBIF_IMAGE;
580
581 currentTaskItem = m_TaskItems;
582 LastItem = currentTaskItem + m_TaskItemCount;
583 while (currentTaskItem != LastItem)
584 {
585 if (currentTaskItem->IconIndex > TaskItem->IconIndex)
586 {
587 currentTaskItem->IconIndex--;
588 tbbi.iImage = currentTaskItem->IconIndex;
589
590 m_TaskBar.SetButtonInfo(currentTaskItem->Index, &tbbi);
591 }
592 currentTaskItem++;
593 }
594
595 ImageList_Remove(m_ImageList, TaskItem->IconIndex);
596 }
597
FindLastTaskItemOfGroup(IN PTASK_GROUP TaskGroup OPTIONAL,IN PTASK_ITEM NewTaskItem OPTIONAL)598 PTASK_ITEM FindLastTaskItemOfGroup(
599 IN PTASK_GROUP TaskGroup OPTIONAL,
600 IN PTASK_ITEM NewTaskItem OPTIONAL)
601 {
602 PTASK_ITEM TaskItem, LastTaskItem, FoundTaskItem = NULL;
603 DWORD dwTaskCount;
604
605 ASSERT(m_IsGroupingEnabled);
606
607 TaskItem = m_TaskItems;
608 LastTaskItem = TaskItem + m_TaskItemCount;
609
610 dwTaskCount = (TaskGroup != NULL ? TaskGroup->dwTaskCount : MAX_TASKS_COUNT);
611
612 ASSERT(dwTaskCount > 0);
613
614 while (TaskItem != LastTaskItem)
615 {
616 if (TaskItem->Group == TaskGroup)
617 {
618 if ((NewTaskItem != NULL && TaskItem != NewTaskItem) || NewTaskItem == NULL)
619 {
620 FoundTaskItem = TaskItem;
621 }
622
623 if (--dwTaskCount == 0)
624 {
625 /* We found the last task item in the group! */
626 break;
627 }
628 }
629
630 TaskItem++;
631 }
632
633 return FoundTaskItem;
634 }
635
CalculateTaskItemNewButtonIndex(IN PTASK_ITEM TaskItem)636 INT CalculateTaskItemNewButtonIndex(IN PTASK_ITEM TaskItem)
637 {
638 PTASK_GROUP TaskGroup;
639 PTASK_ITEM LastTaskItem;
640
641 /* NOTE: This routine assumes that the group is *not* collapsed! */
642
643 TaskGroup = TaskItem->Group;
644 if (m_IsGroupingEnabled)
645 {
646 if (TaskGroup != NULL)
647 {
648 ASSERT(TaskGroup->Index < 0);
649 ASSERT(!TaskGroup->IsCollapsed);
650
651 if (TaskGroup->dwTaskCount > 1)
652 {
653 LastTaskItem = FindLastTaskItemOfGroup(TaskGroup, TaskItem);
654 if (LastTaskItem != NULL)
655 {
656 /* Since the group is expanded the task items must have an index */
657 ASSERT(LastTaskItem->Index >= 0);
658
659 return LastTaskItem->Index + 1;
660 }
661 }
662 }
663 else
664 {
665 /* Find the last NULL group button. NULL groups are added at the end of the
666 task item list when grouping is enabled */
667 LastTaskItem = FindLastTaskItemOfGroup(NULL, TaskItem);
668 if (LastTaskItem != NULL)
669 {
670 ASSERT(LastTaskItem->Index >= 0);
671
672 return LastTaskItem->Index + 1;
673 }
674 }
675 }
676
677 return m_ButtonCount;
678 }
679
AddTaskItemButton(IN OUT PTASK_ITEM TaskItem)680 INT AddTaskItemButton(IN OUT PTASK_ITEM TaskItem)
681 {
682 WCHAR windowText[255];
683 TBBUTTON tbBtn = { 0 };
684 INT iIndex;
685 HICON icon;
686
687 if (TaskItem->Index >= 0)
688 {
689 return UpdateTaskItemButton(TaskItem);
690 }
691
692 if (TaskItem->Group != NULL &&
693 TaskItem->Group->IsCollapsed)
694 {
695 /* The task group is collapsed, we only need to update the group button */
696 return UpdateTaskGroupButton(TaskItem->Group);
697 }
698
699 icon = GetWndIcon(TaskItem->hWnd);
700 if (!icon)
701 icon = static_cast<HICON>(LoadImageW(NULL, MAKEINTRESOURCEW(OIC_SAMPLE), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
702 TaskItem->IconIndex = ImageList_ReplaceIcon(m_ImageList, -1, icon);
703
704 tbBtn.iBitmap = TaskItem->IconIndex;
705 tbBtn.fsState = TBSTATE_ENABLED | TBSTATE_ELLIPSES;
706 tbBtn.fsStyle = BTNS_CHECK | BTNS_NOPREFIX | BTNS_SHOWTEXT;
707 tbBtn.dwData = TaskItem->Index;
708
709 if (GetWndTextFromTaskItem(TaskItem, windowText, _countof(windowText)) > 0)
710 {
711 tbBtn.iString = (DWORD_PTR) windowText;
712 }
713
714 /* Find out where to insert the new button */
715 iIndex = CalculateTaskItemNewButtonIndex(TaskItem);
716 ASSERT(iIndex >= 0);
717 tbBtn.idCommand = iIndex;
718
719 m_TaskBar.BeginUpdate();
720
721 if (m_TaskBar.InsertButton(iIndex, &tbBtn))
722 {
723 UpdateIndexesAfter(iIndex, TRUE);
724
725 TRACE("Added button %d for hwnd 0x%p\n", iIndex, TaskItem->hWnd);
726
727 TaskItem->Index = iIndex;
728 m_ButtonCount++;
729
730 /* Update button sizes and fix the button wrapping */
731 UpdateButtonsSize(TRUE);
732 return iIndex;
733 }
734
735 m_TaskBar.EndUpdate();
736
737 return -1;
738 }
739
DeleteTaskItemButton(IN OUT PTASK_ITEM TaskItem)740 BOOL DeleteTaskItemButton(IN OUT PTASK_ITEM TaskItem)
741 {
742 PTASK_GROUP TaskGroup;
743 INT iIndex;
744
745 TaskGroup = TaskItem->Group;
746
747 if (TaskItem->Index >= 0)
748 {
749 if ((TaskGroup != NULL && !TaskGroup->IsCollapsed) ||
750 TaskGroup == NULL)
751 {
752 m_TaskBar.BeginUpdate();
753
754 RemoveIcon(TaskItem);
755 iIndex = TaskItem->Index;
756 if (m_TaskBar.DeleteButton(iIndex))
757 {
758 TaskItem->Index = -1;
759 m_ButtonCount--;
760
761 UpdateIndexesAfter(iIndex, FALSE);
762
763 /* Update button sizes and fix the button wrapping */
764 UpdateButtonsSize(TRUE);
765 return TRUE;
766 }
767
768 m_TaskBar.EndUpdate();
769 }
770 }
771
772 return FALSE;
773 }
774
AddToTaskGroup(IN HWND hWnd)775 PTASK_GROUP AddToTaskGroup(IN HWND hWnd)
776 {
777 DWORD dwProcessId;
778 PTASK_GROUP TaskGroup, *PrevLink;
779
780 if (!GetWindowThreadProcessId(hWnd,
781 &dwProcessId))
782 {
783 TRACE("Cannot get process id of hwnd 0x%p\n", hWnd);
784 return NULL;
785 }
786
787 /* Try to find an existing task group */
788 TaskGroup = m_TaskGroups;
789 PrevLink = &m_TaskGroups;
790 while (TaskGroup != NULL)
791 {
792 if (TaskGroup->dwProcessId == dwProcessId)
793 {
794 TaskGroup->dwTaskCount++;
795 return TaskGroup;
796 }
797
798 PrevLink = &TaskGroup->Next;
799 TaskGroup = TaskGroup->Next;
800 }
801
802 /* Allocate a new task group */
803 TaskGroup = (PTASK_GROUP) HeapAlloc(hProcessHeap,
804 HEAP_ZERO_MEMORY,
805 sizeof(*TaskGroup));
806 if (TaskGroup != NULL)
807 {
808 TaskGroup->dwTaskCount = 1;
809 TaskGroup->dwProcessId = dwProcessId;
810 TaskGroup->Index = -1;
811
812 /* Add the task group to the list */
813 *PrevLink = TaskGroup;
814 }
815
816 return TaskGroup;
817 }
818
RemoveTaskFromTaskGroup(IN OUT PTASK_ITEM TaskItem)819 VOID RemoveTaskFromTaskGroup(IN OUT PTASK_ITEM TaskItem)
820 {
821 PTASK_GROUP TaskGroup, CurrentGroup, *PrevLink;
822
823 TaskGroup = TaskItem->Group;
824 if (TaskGroup != NULL)
825 {
826 DWORD dwNewTaskCount = --TaskGroup->dwTaskCount;
827 if (dwNewTaskCount == 0)
828 {
829 /* Find the previous pointer in the chain */
830 CurrentGroup = m_TaskGroups;
831 PrevLink = &m_TaskGroups;
832 while (CurrentGroup != TaskGroup)
833 {
834 PrevLink = &CurrentGroup->Next;
835 CurrentGroup = CurrentGroup->Next;
836 }
837
838 /* Remove the group from the list */
839 ASSERT(TaskGroup == CurrentGroup);
840 *PrevLink = TaskGroup->Next;
841
842 /* Free the task group */
843 HeapFree(hProcessHeap,
844 0,
845 TaskGroup);
846 }
847 else if (TaskGroup->IsCollapsed &&
848 TaskGroup->Index >= 0)
849 {
850 if (dwNewTaskCount > 1)
851 {
852 /* FIXME: Check if we should expand the group */
853 /* Update the task group button */
854 UpdateTaskGroupButton(TaskGroup);
855 }
856 else
857 {
858 /* Expand the group of one task button to a task button */
859 ExpandTaskGroup(TaskGroup);
860 }
861 }
862 }
863 }
864
FindTaskItem(IN HWND hWnd)865 PTASK_ITEM FindTaskItem(IN HWND hWnd)
866 {
867 PTASK_ITEM TaskItem, LastItem;
868
869 TaskItem = m_TaskItems;
870 LastItem = TaskItem + m_TaskItemCount;
871 while (TaskItem != LastItem)
872 {
873 if (TaskItem->hWnd == hWnd)
874 return TaskItem;
875
876 TaskItem++;
877 }
878
879 return NULL;
880 }
881
FindOtherTaskItem(IN HWND hWnd)882 PTASK_ITEM FindOtherTaskItem(IN HWND hWnd)
883 {
884 PTASK_ITEM LastItem, TaskItem;
885 PTASK_GROUP TaskGroup;
886 DWORD dwProcessId;
887
888 if (!GetWindowThreadProcessId(hWnd, &dwProcessId))
889 {
890 return NULL;
891 }
892
893 /* Try to find another task that belongs to the same
894 process as the given window */
895 TaskItem = m_TaskItems;
896 LastItem = TaskItem + m_TaskItemCount;
897 while (TaskItem != LastItem)
898 {
899 TaskGroup = TaskItem->Group;
900 if (TaskGroup != NULL)
901 {
902 if (TaskGroup->dwProcessId == dwProcessId)
903 return TaskItem;
904 }
905 else
906 {
907 DWORD dwProcessIdTask;
908
909 if (GetWindowThreadProcessId(TaskItem->hWnd,
910 &dwProcessIdTask) &&
911 dwProcessIdTask == dwProcessId)
912 {
913 return TaskItem;
914 }
915 }
916
917 TaskItem++;
918 }
919
920 return NULL;
921 }
922
AllocTaskItem()923 PTASK_ITEM AllocTaskItem()
924 {
925 if (m_TaskItemCount >= MAX_TASKS_COUNT)
926 {
927 /* We need the most significant bit in 16 bit command IDs to indicate whether it
928 is a task group or task item. WM_COMMAND limits command IDs to 16 bits! */
929 return NULL;
930 }
931
932 ASSERT(m_AllocatedTaskItems >= m_TaskItemCount);
933
934 if (m_TaskItemCount == 0)
935 {
936 m_TaskItems = (PTASK_ITEM) HeapAlloc(hProcessHeap,
937 0,
938 TASK_ITEM_ARRAY_ALLOC * sizeof(*m_TaskItems));
939 if (m_TaskItems != NULL)
940 {
941 m_AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC;
942 }
943 else
944 return NULL;
945 }
946 else if (m_TaskItemCount >= m_AllocatedTaskItems)
947 {
948 PTASK_ITEM NewArray;
949 SIZE_T NewArrayLength, ActiveTaskItemIndex;
950
951 NewArrayLength = m_AllocatedTaskItems + TASK_ITEM_ARRAY_ALLOC;
952
953 NewArray = (PTASK_ITEM) HeapReAlloc(hProcessHeap,
954 0,
955 m_TaskItems,
956 NewArrayLength * sizeof(*m_TaskItems));
957 if (NewArray != NULL)
958 {
959 if (m_ActiveTaskItem != NULL)
960 {
961 /* Fixup the ActiveTaskItem pointer */
962 ActiveTaskItemIndex = m_ActiveTaskItem - m_TaskItems;
963 m_ActiveTaskItem = NewArray + ActiveTaskItemIndex;
964 }
965 m_AllocatedTaskItems = (WORD) NewArrayLength;
966 m_TaskItems = NewArray;
967 }
968 else
969 return NULL;
970 }
971
972 return m_TaskItems + m_TaskItemCount++;
973 }
974
FreeTaskItem(IN OUT PTASK_ITEM TaskItem)975 VOID FreeTaskItem(IN OUT PTASK_ITEM TaskItem)
976 {
977 WORD wIndex;
978
979 if (TaskItem == m_ActiveTaskItem)
980 m_ActiveTaskItem = NULL;
981
982 wIndex = (WORD) (TaskItem - m_TaskItems);
983 if (wIndex + 1 < m_TaskItemCount)
984 {
985 MoveMemory(TaskItem,
986 TaskItem + 1,
987 (m_TaskItemCount - wIndex - 1) * sizeof(*TaskItem));
988 }
989
990 m_TaskItemCount--;
991 }
992
DeleteTaskItem(IN OUT PTASK_ITEM TaskItem)993 VOID DeleteTaskItem(IN OUT PTASK_ITEM TaskItem)
994 {
995 if (!m_IsDestroying)
996 {
997 /* Delete the task button from the toolbar */
998 DeleteTaskItemButton(TaskItem);
999 }
1000
1001 /* Remove the task from it's group */
1002 RemoveTaskFromTaskGroup(TaskItem);
1003
1004 /* Free the task item */
1005 FreeTaskItem(TaskItem);
1006 }
1007
CheckActivateTaskItem(IN OUT PTASK_ITEM TaskItem)1008 VOID CheckActivateTaskItem(IN OUT PTASK_ITEM TaskItem)
1009 {
1010 PTASK_ITEM CurrentTaskItem;
1011 PTASK_GROUP TaskGroup = NULL;
1012
1013 CurrentTaskItem = m_ActiveTaskItem;
1014
1015 if (TaskItem != NULL)
1016 TaskGroup = TaskItem->Group;
1017
1018 if (m_IsGroupingEnabled &&
1019 TaskGroup != NULL &&
1020 TaskGroup->IsCollapsed)
1021 {
1022 /* FIXME */
1023 return;
1024 }
1025
1026 if (CurrentTaskItem != NULL)
1027 {
1028 PTASK_GROUP CurrentTaskGroup;
1029
1030 if (CurrentTaskItem == TaskItem)
1031 return;
1032
1033 CurrentTaskGroup = CurrentTaskItem->Group;
1034
1035 if (m_IsGroupingEnabled &&
1036 CurrentTaskGroup != NULL &&
1037 CurrentTaskGroup->IsCollapsed)
1038 {
1039 if (CurrentTaskGroup == TaskGroup)
1040 return;
1041
1042 /* FIXME */
1043 }
1044 else
1045 {
1046 m_ActiveTaskItem = NULL;
1047 if (CurrentTaskItem->Index >= 0)
1048 {
1049 UpdateTaskItemButton(CurrentTaskItem);
1050 }
1051 }
1052 }
1053
1054 m_ActiveTaskItem = TaskItem;
1055
1056 if (TaskItem != NULL && TaskItem->Index >= 0)
1057 {
1058 UpdateTaskItemButton(TaskItem);
1059 }
1060 else if (TaskItem == NULL)
1061 {
1062 TRACE("Active TaskItem now NULL\n");
1063 }
1064 }
1065
FindTaskItemByIndex(IN INT Index)1066 PTASK_ITEM FindTaskItemByIndex(IN INT Index)
1067 {
1068 PTASK_ITEM TaskItem, LastItem;
1069
1070 TaskItem = m_TaskItems;
1071 LastItem = TaskItem + m_TaskItemCount;
1072 while (TaskItem != LastItem)
1073 {
1074 if (TaskItem->Index == Index)
1075 return TaskItem;
1076
1077 TaskItem++;
1078 }
1079
1080 return NULL;
1081 }
1082
FindTaskGroupByIndex(IN INT Index)1083 PTASK_GROUP FindTaskGroupByIndex(IN INT Index)
1084 {
1085 PTASK_GROUP CurrentGroup;
1086
1087 CurrentGroup = m_TaskGroups;
1088 while (CurrentGroup != NULL)
1089 {
1090 if (CurrentGroup->Index == Index)
1091 break;
1092
1093 CurrentGroup = CurrentGroup->Next;
1094 }
1095
1096 return CurrentGroup;
1097 }
1098
AddTask(IN HWND hWnd)1099 BOOL AddTask(IN HWND hWnd)
1100 {
1101 PTASK_ITEM TaskItem;
1102
1103 if (!::IsWindow(hWnd) || m_Tray->IsSpecialHWND(hWnd))
1104 return FALSE;
1105
1106 TaskItem = FindTaskItem(hWnd);
1107 if (TaskItem == NULL)
1108 {
1109 TRACE("Add window 0x%p\n", hWnd);
1110 TaskItem = AllocTaskItem();
1111 if (TaskItem != NULL)
1112 {
1113 ZeroMemory(TaskItem, sizeof(*TaskItem));
1114 TaskItem->hWnd = hWnd;
1115 TaskItem->Index = -1;
1116 TaskItem->Group = AddToTaskGroup(hWnd);
1117
1118 if (!m_IsDestroying)
1119 {
1120 AddTaskItemButton(TaskItem);
1121 }
1122 }
1123 }
1124
1125 return TaskItem != NULL;
1126 }
1127
ActivateTaskItem(IN OUT PTASK_ITEM TaskItem OPTIONAL)1128 BOOL ActivateTaskItem(IN OUT PTASK_ITEM TaskItem OPTIONAL)
1129 {
1130 if (TaskItem != NULL)
1131 {
1132 TRACE("Activate window 0x%p on button %d\n", TaskItem->hWnd, TaskItem->Index);
1133 }
1134
1135 CheckActivateTaskItem(TaskItem);
1136 return FALSE;
1137 }
1138
ActivateTask(IN HWND hWnd)1139 BOOL ActivateTask(IN HWND hWnd)
1140 {
1141 PTASK_ITEM TaskItem;
1142
1143 if (!hWnd)
1144 {
1145 return ActivateTaskItem(NULL);
1146 }
1147
1148 TaskItem = FindTaskItem(hWnd);
1149 if (TaskItem == NULL)
1150 {
1151 TaskItem = FindOtherTaskItem(hWnd);
1152 }
1153
1154 if (TaskItem == NULL)
1155 {
1156 WARN("Activate window 0x%p, could not find task\n", hWnd);
1157 RefreshWindowList();
1158 }
1159
1160 return ActivateTaskItem(TaskItem);
1161 }
1162
DeleteTask(IN HWND hWnd)1163 BOOL DeleteTask(IN HWND hWnd)
1164 {
1165 PTASK_ITEM TaskItem;
1166
1167 TaskItem = FindTaskItem(hWnd);
1168 if (TaskItem != NULL)
1169 {
1170 TRACE("Delete window 0x%p on button %d\n", hWnd, TaskItem->Index);
1171 DeleteTaskItem(TaskItem);
1172 return TRUE;
1173 }
1174 //else
1175 //TRACE("Failed to delete window 0x%p\n", hWnd);
1176
1177 return FALSE;
1178 }
1179
DeleteAllTasks()1180 VOID DeleteAllTasks()
1181 {
1182 PTASK_ITEM CurrentTask;
1183
1184 if (m_TaskItemCount > 0)
1185 {
1186 CurrentTask = m_TaskItems + m_TaskItemCount;
1187 do
1188 {
1189 DeleteTaskItem(--CurrentTask);
1190 } while (CurrentTask != m_TaskItems);
1191 }
1192 }
1193
FlashTaskItem(IN OUT PTASK_ITEM TaskItem)1194 VOID FlashTaskItem(IN OUT PTASK_ITEM TaskItem)
1195 {
1196 TaskItem->RenderFlashed = 1;
1197 UpdateTaskItemButton(TaskItem);
1198 }
1199
FlashTask(IN HWND hWnd)1200 BOOL FlashTask(IN HWND hWnd)
1201 {
1202 PTASK_ITEM TaskItem;
1203
1204 TaskItem = FindTaskItem(hWnd);
1205 if (TaskItem != NULL)
1206 {
1207 TRACE("Flashing window 0x%p on button %d\n", hWnd, TaskItem->Index);
1208 FlashTaskItem(TaskItem);
1209 return TRUE;
1210 }
1211
1212 return FALSE;
1213 }
1214
RedrawTaskItem(IN OUT PTASK_ITEM TaskItem)1215 VOID RedrawTaskItem(IN OUT PTASK_ITEM TaskItem)
1216 {
1217 PTASK_GROUP TaskGroup;
1218
1219 TaskGroup = TaskItem->Group;
1220 if (m_IsGroupingEnabled && TaskGroup != NULL)
1221 {
1222 if (TaskGroup->IsCollapsed && TaskGroup->Index >= 0)
1223 {
1224 UpdateTaskGroupButton(TaskGroup);
1225 }
1226 else if (TaskItem->Index >= 0)
1227 {
1228 goto UpdateTaskItem;
1229 }
1230 }
1231 else if (TaskItem->Index >= 0)
1232 {
1233 UpdateTaskItem:
1234 TaskItem->RenderFlashed = 0;
1235 UpdateTaskItemButton(TaskItem);
1236 }
1237 }
1238
1239
RedrawTask(IN HWND hWnd)1240 BOOL RedrawTask(IN HWND hWnd)
1241 {
1242 PTASK_ITEM TaskItem;
1243
1244 TaskItem = FindTaskItem(hWnd);
1245 if (TaskItem != NULL)
1246 {
1247 RedrawTaskItem(TaskItem);
1248 return TRUE;
1249 }
1250
1251 return FALSE;
1252 }
1253
UpdateButtonsSize(IN BOOL bRedrawDisabled)1254 VOID UpdateButtonsSize(IN BOOL bRedrawDisabled)
1255 {
1256 RECT rcClient;
1257 UINT uiRows, uiMax, uiMin, uiBtnsPerLine, ui;
1258 LONG NewBtnSize;
1259 BOOL Horizontal;
1260
1261 /* Update the size of the image list if needed */
1262 int cx, cy;
1263 ImageList_GetIconSize(m_ImageList, &cx, &cy);
1264 if (cx != GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CXSMICON : SM_CXICON) ||
1265 cy != GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CYSMICON : SM_CYICON))
1266 {
1267 ImageList_SetIconSize(m_ImageList,
1268 GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CXSMICON : SM_CXICON),
1269 GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CYSMICON : SM_CYICON));
1270
1271 /* SetIconSize removes all icons so we have to reinsert them */
1272 PTASK_ITEM TaskItem = m_TaskItems;
1273 PTASK_ITEM LastTaskItem = m_TaskItems + m_TaskItemCount;
1274 while (TaskItem != LastTaskItem)
1275 {
1276 TaskItem->IconIndex = -1;
1277 UpdateTaskItemButton(TaskItem);
1278
1279 TaskItem++;
1280 }
1281 m_TaskBar.SetImageList(m_ImageList);
1282 }
1283
1284 if (GetClientRect(&rcClient) && !IsRectEmpty(&rcClient))
1285 {
1286 if (m_ButtonCount > 0)
1287 {
1288 Horizontal = m_Tray->IsHorizontal();
1289
1290 if (Horizontal)
1291 {
1292 TBMETRICS tbm = { 0 };
1293 tbm.cbSize = sizeof(tbm);
1294 tbm.dwMask = TBMF_BUTTONSPACING;
1295 m_TaskBar.GetMetrics(&tbm);
1296
1297 if (m_ButtonSize.cy + tbm.cyButtonSpacing != 0)
1298 uiRows = (rcClient.bottom + tbm.cyButtonSpacing) / (m_ButtonSize.cy + tbm.cyButtonSpacing);
1299 else
1300 uiRows = 1;
1301
1302 if (uiRows == 0)
1303 uiRows = 1;
1304
1305 uiBtnsPerLine = (m_ButtonCount + uiRows - 1) / uiRows;
1306 }
1307 else
1308 {
1309 uiBtnsPerLine = 1;
1310 uiRows = m_ButtonCount;
1311 }
1312
1313 if (!bRedrawDisabled)
1314 m_TaskBar.BeginUpdate();
1315
1316 /* We might need to update the button spacing */
1317 int cxButtonSpacing = m_TaskBar.UpdateTbButtonSpacing(
1318 Horizontal, m_Theme != NULL,
1319 uiRows, uiBtnsPerLine);
1320
1321 /* Determine the minimum and maximum width of a button */
1322 uiMin = GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE));
1323 if (Horizontal)
1324 {
1325 uiMax = GetSystemMetrics(SM_CXMINIMIZED);
1326
1327 /* Calculate the ideal width and make sure it's within the allowed range */
1328 NewBtnSize = (rcClient.right - (uiBtnsPerLine * cxButtonSpacing)) / uiBtnsPerLine;
1329
1330 if (NewBtnSize < (LONG) uiMin)
1331 NewBtnSize = uiMin;
1332 if (NewBtnSize >(LONG)uiMax)
1333 NewBtnSize = uiMax;
1334
1335 /* Recalculate how many buttons actually fit into one line */
1336 uiBtnsPerLine = rcClient.right / (NewBtnSize + cxButtonSpacing);
1337 if (uiBtnsPerLine == 0)
1338 uiBtnsPerLine++;
1339 }
1340 else
1341 {
1342 NewBtnSize = uiMax = rcClient.right;
1343 }
1344
1345 m_ButtonSize.cx = NewBtnSize;
1346
1347 m_ButtonsPerLine = uiBtnsPerLine;
1348
1349 for (ui = 0; ui != m_ButtonCount; ui++)
1350 {
1351 TBBUTTONINFOW tbbi = { 0 };
1352 tbbi.cbSize = sizeof(tbbi);
1353 tbbi.dwMask = TBIF_BYINDEX | TBIF_SIZE | TBIF_STATE;
1354 tbbi.cx = (INT) NewBtnSize;
1355 tbbi.fsState = TBSTATE_ENABLED;
1356
1357 /* Check if we're updating a button that is the last one in the
1358 line. If so, we need to set the TBSTATE_WRAP flag! */
1359 if (Horizontal)
1360 {
1361 if ((ui + 1) % uiBtnsPerLine == 0)
1362 tbbi.fsState |= TBSTATE_WRAP;
1363 }
1364 else
1365 {
1366 tbbi.fsState |= TBSTATE_WRAP;
1367 }
1368
1369 if (m_ActiveTaskItem != NULL &&
1370 m_ActiveTaskItem->Index == (INT)ui)
1371 {
1372 tbbi.fsState |= TBSTATE_CHECKED;
1373 }
1374
1375 m_TaskBar.SetButtonInfo(ui, &tbbi);
1376 }
1377 }
1378 else
1379 {
1380 m_ButtonsPerLine = 0;
1381 m_ButtonSize.cx = 0;
1382 }
1383 }
1384
1385 // FIXME: This seems to be enabling redraws prematurely, but moving it to its right place doesn't work!
1386 m_TaskBar.EndUpdate();
1387 }
1388
EnumWindowsProc(IN HWND hWnd)1389 BOOL CALLBACK EnumWindowsProc(IN HWND hWnd)
1390 {
1391 if (m_Tray->IsTaskWnd(hWnd))
1392 {
1393 TRACE("Adding task for %p...\n", hWnd);
1394 AddTask(hWnd);
1395 }
1396 return TRUE;
1397 }
1398
s_EnumWindowsProc(IN HWND hWnd,IN LPARAM lParam)1399 static BOOL CALLBACK s_EnumWindowsProc(IN HWND hWnd, IN LPARAM lParam)
1400 {
1401 CTaskSwitchWnd * This = (CTaskSwitchWnd *) lParam;
1402
1403 return This->EnumWindowsProc(hWnd);
1404 }
1405
RefreshWindowList()1406 BOOL RefreshWindowList()
1407 {
1408 TRACE("Refreshing window list...\n");
1409 /* Add all windows to the toolbar */
1410 return EnumWindows(s_EnumWindowsProc, (LPARAM)this);
1411 }
1412
OnThemeChanged(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1413 LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1414 {
1415 TRACE("OmThemeChanged\n");
1416
1417 if (m_Theme)
1418 CloseThemeData(m_Theme);
1419
1420 if (IsThemeActive())
1421 m_Theme = OpenThemeData(m_hWnd, L"TaskBand");
1422 else
1423 m_Theme = NULL;
1424
1425 return TRUE;
1426 }
1427
OnCreate(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1428 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1429 {
1430 if (!m_TaskBar.Initialize(m_hWnd))
1431 return FALSE;
1432
1433 SetWindowTheme(m_TaskBar.m_hWnd, L"TaskBand", NULL);
1434
1435 m_ImageList = ImageList_Create(GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CXSMICON : SM_CXICON),
1436 GetSystemMetrics(g_TaskbarSettings.bSmallIcons ? SM_CYSMICON : SM_CYICON),
1437 ILC_COLOR32 | ILC_MASK, 0, 1000);
1438 m_TaskBar.SetImageList(m_ImageList);
1439
1440 /* Set proper spacing between buttons */
1441 m_TaskBar.UpdateTbButtonSpacing(m_Tray->IsHorizontal(), m_Theme != NULL);
1442
1443 /* Register the shell hook */
1444 m_ShellHookMsg = RegisterWindowMessageW(L"SHELLHOOK");
1445
1446 TRACE("ShellHookMsg got assigned number %d\n", m_ShellHookMsg);
1447
1448 RegisterShellHook(m_hWnd, 3); /* 1 if no NT! We're targeting NT so we don't care! */
1449
1450 RefreshWindowList();
1451
1452 /* Recalculate the button size */
1453 UpdateButtonsSize(FALSE);
1454
1455 #if DUMP_TASKS != 0
1456 SetTimer(hwnd, 1, 5000, NULL);
1457 #endif
1458 return TRUE;
1459 }
1460
OnDestroy(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1461 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1462 {
1463 m_IsDestroying = TRUE;
1464
1465 /* Unregister the shell hook */
1466 RegisterShellHook(m_hWnd, FALSE);
1467
1468 CloseThemeData(m_Theme);
1469 DeleteAllTasks();
1470 return TRUE;
1471 }
1472
SendPulseToTray(BOOL bDelete,HWND hwndActive)1473 VOID SendPulseToTray(BOOL bDelete, HWND hwndActive)
1474 {
1475 HWND hwndTray = m_Tray->GetHWND();
1476 ::SendMessage(hwndTray, TWM_PULSE, bDelete, (LPARAM)hwndActive);
1477 }
1478
HandleAppCommand(IN WPARAM wParam,IN LPARAM lParam)1479 BOOL HandleAppCommand(IN WPARAM wParam, IN LPARAM lParam)
1480 {
1481 BOOL Ret = FALSE;
1482
1483 switch (GET_APPCOMMAND_LPARAM(lParam))
1484 {
1485 case APPCOMMAND_BROWSER_SEARCH:
1486 Ret = SHFindFiles(NULL,
1487 NULL);
1488 break;
1489
1490 case APPCOMMAND_BROWSER_HOME:
1491 case APPCOMMAND_LAUNCH_MAIL:
1492 default:
1493 TRACE("Shell app command %d unhandled!\n", (INT) GET_APPCOMMAND_LPARAM(lParam));
1494 break;
1495 }
1496
1497 return Ret;
1498 }
1499
OnShellHook(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1500 LRESULT OnShellHook(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1501 {
1502 BOOL Ret = FALSE;
1503
1504 /* In case the shell hook wasn't registered properly, ignore WM_NULLs*/
1505 if (uMsg == 0)
1506 {
1507 bHandled = FALSE;
1508 return 0;
1509 }
1510
1511 TRACE("Received shell hook message: wParam=%08lx, lParam=%08lx\n", wParam, lParam);
1512
1513 switch ((INT) wParam)
1514 {
1515 case HSHELL_APPCOMMAND:
1516 Ret = HandleAppCommand(wParam, lParam);
1517 break;
1518
1519 case HSHELL_WINDOWCREATED:
1520 SendPulseToTray(FALSE, (HWND)lParam);
1521 AddTask((HWND) lParam);
1522 break;
1523
1524 case HSHELL_WINDOWDESTROYED:
1525 /* The window still exists! Delay destroying it a bit */
1526 SendPulseToTray(TRUE, (HWND)lParam);
1527 DeleteTask((HWND)lParam);
1528 break;
1529
1530 case HSHELL_RUDEAPPACTIVATED:
1531 case HSHELL_WINDOWACTIVATED:
1532 SendPulseToTray(FALSE, (HWND)lParam);
1533 ActivateTask((HWND)lParam);
1534 break;
1535
1536 case HSHELL_FLASH:
1537 FlashTask((HWND) lParam);
1538 break;
1539
1540 case HSHELL_REDRAW:
1541 RedrawTask((HWND) lParam);
1542 break;
1543
1544 case HSHELL_TASKMAN:
1545 ::PostMessage(m_Tray->GetHWND(), TWM_OPENSTARTMENU, 0, 0);
1546 break;
1547
1548 case HSHELL_ACTIVATESHELLWINDOW:
1549 ::SwitchToThisWindow(m_Tray->GetHWND(), TRUE);
1550 ::SetForegroundWindow(m_Tray->GetHWND());
1551 break;
1552
1553 case HSHELL_LANGUAGE:
1554 case HSHELL_SYSMENU:
1555 case HSHELL_ENDTASK:
1556 case HSHELL_ACCESSIBILITYSTATE:
1557 case HSHELL_WINDOWREPLACED:
1558 case HSHELL_WINDOWREPLACING:
1559
1560 case HSHELL_GETMINRECT:
1561 default:
1562 {
1563 #if DEBUG_SHELL_HOOK
1564 int i, found;
1565 for (i = 0, found = 0; i != _countof(hshell_msg); i++)
1566 {
1567 if (hshell_msg[i].msg == (INT) wParam)
1568 {
1569 TRACE("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg[i].msg_name, lParam);
1570 found = 1;
1571 break;
1572 }
1573 }
1574 if (found)
1575 break;
1576 #endif
1577 TRACE("Shell message %d unhandled (lParam = 0x%p)!\n", (INT) wParam, lParam);
1578 break;
1579 }
1580 }
1581
1582 return Ret;
1583 }
1584
HandleTaskItemClick(IN OUT PTASK_ITEM TaskItem)1585 VOID HandleTaskItemClick(IN OUT PTASK_ITEM TaskItem)
1586 {
1587 BOOL bIsMinimized;
1588 BOOL bIsActive;
1589
1590 if (::IsWindow(TaskItem->hWnd))
1591 {
1592 bIsMinimized = ::IsIconic(TaskItem->hWnd);
1593 bIsActive = (TaskItem == m_ActiveTaskItem);
1594
1595 TRACE("Active TaskItem %p, selected TaskItem %p\n", m_ActiveTaskItem, TaskItem);
1596 if (m_ActiveTaskItem)
1597 TRACE("Active TaskItem hWnd=%p, TaskItem hWnd %p\n", m_ActiveTaskItem->hWnd, TaskItem->hWnd);
1598
1599 TRACE("Valid button clicked. HWND=%p, IsMinimized=%s, IsActive=%s...\n",
1600 TaskItem->hWnd, bIsMinimized ? "Yes" : "No", bIsActive ? "Yes" : "No");
1601
1602 if (!bIsMinimized && bIsActive)
1603 {
1604 if (!::IsHungAppWindow(TaskItem->hWnd))
1605 ::ShowWindowAsync(TaskItem->hWnd, SW_MINIMIZE);
1606 TRACE("Valid button clicked. App window Minimized.\n");
1607 }
1608 else
1609 {
1610 ::SwitchToThisWindow(TaskItem->hWnd, TRUE);
1611
1612 TRACE("Valid button clicked. App window Restored.\n");
1613 }
1614 }
1615 }
1616
HandleTaskGroupClick(IN OUT PTASK_GROUP TaskGroup)1617 VOID HandleTaskGroupClick(IN OUT PTASK_GROUP TaskGroup)
1618 {
1619 /* TODO: Show task group menu */
1620 }
1621
HandleButtonClick(IN WORD wIndex)1622 BOOL HandleButtonClick(IN WORD wIndex)
1623 {
1624 PTASK_ITEM TaskItem;
1625 PTASK_GROUP TaskGroup;
1626
1627 if (m_IsGroupingEnabled)
1628 {
1629 TaskGroup = FindTaskGroupByIndex((INT) wIndex);
1630 if (TaskGroup != NULL && TaskGroup->IsCollapsed)
1631 {
1632 HandleTaskGroupClick(TaskGroup);
1633 return TRUE;
1634 }
1635 }
1636
1637 TaskItem = FindTaskItemByIndex((INT) wIndex);
1638 if (TaskItem != NULL)
1639 {
1640 SendPulseToTray(FALSE, TaskItem->hWnd);
1641 HandleTaskItemClick(TaskItem);
1642 return TRUE;
1643 }
1644
1645 return FALSE;
1646 }
1647
1648 static VOID CALLBACK
SendAsyncProc(HWND hwnd,UINT uMsg,DWORD_PTR dwData,LRESULT lResult)1649 SendAsyncProc(HWND hwnd, UINT uMsg, DWORD_PTR dwData, LRESULT lResult)
1650 {
1651 ::PostMessageW(hwnd, WM_NULL, 0, 0);
1652 }
1653
HandleTaskItemRightClick(IN OUT PTASK_ITEM TaskItem)1654 VOID HandleTaskItemRightClick(IN OUT PTASK_ITEM TaskItem)
1655 {
1656 POINT pt;
1657 GetCursorPos(&pt);
1658
1659 SetForegroundWindow(TaskItem->hWnd);
1660
1661 ActivateTask(TaskItem->hWnd);
1662
1663 if (GetForegroundWindow() != TaskItem->hWnd)
1664 ERR("HandleTaskItemRightClick detected the window did not become foreground\n");
1665
1666 ::SendMessageCallbackW(TaskItem->hWnd, WM_POPUPSYSTEMMENU, 0, MAKELPARAM(pt.x, pt.y),
1667 SendAsyncProc, (ULONG_PTR)TaskItem);
1668 }
1669
HandleTaskGroupRightClick(IN OUT PTASK_GROUP TaskGroup)1670 VOID HandleTaskGroupRightClick(IN OUT PTASK_GROUP TaskGroup)
1671 {
1672 /* TODO: Show task group right click menu */
1673 }
1674
HandleButtonRightClick(IN WORD wIndex)1675 BOOL HandleButtonRightClick(IN WORD wIndex)
1676 {
1677 PTASK_ITEM TaskItem;
1678 PTASK_GROUP TaskGroup;
1679 if (m_IsGroupingEnabled)
1680 {
1681 TaskGroup = FindTaskGroupByIndex((INT) wIndex);
1682 if (TaskGroup != NULL && TaskGroup->IsCollapsed)
1683 {
1684 HandleTaskGroupRightClick(TaskGroup);
1685 return TRUE;
1686 }
1687 }
1688
1689 TaskItem = FindTaskItemByIndex((INT) wIndex);
1690
1691 if (TaskItem != NULL)
1692 {
1693 HandleTaskItemRightClick(TaskItem);
1694 return TRUE;
1695 }
1696
1697 return FALSE;
1698 }
1699
1700
HandleItemPaint(IN OUT NMTBCUSTOMDRAW * nmtbcd)1701 LRESULT HandleItemPaint(IN OUT NMTBCUSTOMDRAW *nmtbcd)
1702 {
1703 LRESULT Ret = CDRF_DODEFAULT;
1704 PTASK_GROUP TaskGroup;
1705 PTASK_ITEM TaskItem;
1706
1707 TaskItem = FindTaskItemByIndex((INT) nmtbcd->nmcd.dwItemSpec);
1708 TaskGroup = FindTaskGroupByIndex((INT) nmtbcd->nmcd.dwItemSpec);
1709 if (TaskGroup == NULL && TaskItem != NULL)
1710 {
1711 ASSERT(TaskItem != NULL);
1712
1713 if (TaskItem != NULL && ::IsWindow(TaskItem->hWnd))
1714 {
1715 /* Make the entire button flashing if necessary */
1716 if (nmtbcd->nmcd.uItemState & CDIS_MARKED)
1717 {
1718 Ret = TBCDRF_NOBACKGROUND;
1719 if (!m_Theme)
1720 {
1721 SelectObject(nmtbcd->nmcd.hdc, GetSysColorBrush(COLOR_HIGHLIGHT));
1722 Rectangle(nmtbcd->nmcd.hdc,
1723 nmtbcd->nmcd.rc.left,
1724 nmtbcd->nmcd.rc.top,
1725 nmtbcd->nmcd.rc.right,
1726 nmtbcd->nmcd.rc.bottom);
1727 }
1728 else
1729 {
1730 DrawThemeBackground(m_Theme, nmtbcd->nmcd.hdc, TDP_FLASHBUTTON, 0, &nmtbcd->nmcd.rc, 0);
1731 }
1732 nmtbcd->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
1733 return Ret;
1734 }
1735 }
1736 }
1737 else if (TaskGroup != NULL)
1738 {
1739 /* FIXME: Implement painting for task groups */
1740 }
1741 return Ret;
1742 }
1743
HandleToolbarNotification(IN const NMHDR * nmh)1744 LRESULT HandleToolbarNotification(IN const NMHDR *nmh)
1745 {
1746 LRESULT Ret = 0;
1747
1748 switch (nmh->code)
1749 {
1750 case NM_CUSTOMDRAW:
1751 {
1752 LPNMTBCUSTOMDRAW nmtbcd = (LPNMTBCUSTOMDRAW) nmh;
1753
1754 switch (nmtbcd->nmcd.dwDrawStage)
1755 {
1756
1757 case CDDS_ITEMPREPAINT:
1758 Ret = HandleItemPaint(nmtbcd);
1759 break;
1760
1761 case CDDS_PREPAINT:
1762 Ret = CDRF_NOTIFYITEMDRAW;
1763 break;
1764
1765 default:
1766 Ret = CDRF_DODEFAULT;
1767 break;
1768 }
1769 break;
1770 }
1771 }
1772
1773 return Ret;
1774 }
1775
OnEraseBackground(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1776 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1777 {
1778 HDC hdc = (HDC) wParam;
1779
1780 if (!IsAppThemed())
1781 {
1782 bHandled = FALSE;
1783 return 0;
1784 }
1785
1786 RECT rect;
1787 GetClientRect(&rect);
1788 DrawThemeParentBackground(m_hWnd, hdc, &rect);
1789
1790 return TRUE;
1791 }
1792
OnSize(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1793 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1794 {
1795 SIZE szClient;
1796
1797 szClient.cx = LOWORD(lParam);
1798 szClient.cy = HIWORD(lParam);
1799 if (m_TaskBar.m_hWnd != NULL)
1800 {
1801 m_TaskBar.SetWindowPos(NULL, 0, 0, szClient.cx, szClient.cy, SWP_NOZORDER);
1802
1803 UpdateButtonsSize(FALSE);
1804 }
1805 return TRUE;
1806 }
1807
OnNcHitTest(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1808 LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1809 {
1810 LRESULT Ret = TRUE;
1811 /* We want the tray window to be draggable everywhere, so make the control
1812 appear transparent */
1813 Ret = DefWindowProc(uMsg, wParam, lParam);
1814 if (Ret != HTVSCROLL && Ret != HTHSCROLL)
1815 Ret = HTTRANSPARENT;
1816 return Ret;
1817 }
1818
OnCommand(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1819 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1820 {
1821 LRESULT Ret = TRUE;
1822 if (lParam != 0 && (HWND) lParam == m_TaskBar.m_hWnd)
1823 {
1824 HandleButtonClick(LOWORD(wParam));
1825 }
1826 return Ret;
1827 }
1828
OnNotify(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1829 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1830 {
1831 LRESULT Ret = TRUE;
1832 const NMHDR *nmh = (const NMHDR *) lParam;
1833
1834 if (nmh->hwndFrom == m_TaskBar.m_hWnd)
1835 {
1836 Ret = HandleToolbarNotification(nmh);
1837 }
1838 return Ret;
1839 }
1840
OnUpdateTaskbarPos(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1841 LRESULT OnUpdateTaskbarPos(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1842 {
1843 /* Update the button spacing */
1844 m_TaskBar.UpdateTbButtonSpacing(m_Tray->IsHorizontal(), m_Theme != NULL);
1845 return TRUE;
1846 }
1847
OnTaskbarSettingsChanged(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1848 LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1849 {
1850 BOOL bSettingsChanged = FALSE;
1851 TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
1852
1853 if (newSettings->bGroupButtons != g_TaskbarSettings.bGroupButtons)
1854 {
1855 bSettingsChanged = TRUE;
1856 g_TaskbarSettings.bGroupButtons = newSettings->bGroupButtons;
1857 m_IsGroupingEnabled = g_TaskbarSettings.bGroupButtons;
1858 }
1859
1860 if (newSettings->bSmallIcons != g_TaskbarSettings.bSmallIcons)
1861 {
1862 bSettingsChanged = TRUE;
1863 g_TaskbarSettings.bSmallIcons = newSettings->bSmallIcons;
1864 }
1865
1866 if (bSettingsChanged)
1867 {
1868 /* Refresh each task item view */
1869 RefreshWindowList();
1870 UpdateButtonsSize(FALSE);
1871 }
1872
1873 return 0;
1874 }
1875
OnContextMenu(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1876 LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1877 {
1878 LRESULT Ret = 0;
1879 INT_PTR iBtn = -1;
1880
1881 if (m_TaskBar.m_hWnd != NULL)
1882 {
1883 POINT pt;
1884
1885 pt.x = GET_X_LPARAM(lParam);
1886 pt.y = GET_Y_LPARAM(lParam);
1887
1888 ::ScreenToClient(m_TaskBar.m_hWnd, &pt);
1889
1890 iBtn = m_TaskBar.HitTest(&pt);
1891 if (iBtn >= 0)
1892 {
1893 HandleButtonRightClick(iBtn);
1894 }
1895 }
1896 if (iBtn < 0)
1897 {
1898 /* Not on a taskbar button, so forward message to tray */
1899 Ret = SendMessage(m_Tray->GetHWND(), uMsg, wParam, lParam);
1900 }
1901 return Ret;
1902 }
1903
OnKludgeItemRect(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1904 LRESULT OnKludgeItemRect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1905 {
1906 PTASK_ITEM TaskItem = FindTaskItem((HWND) wParam);
1907 if (TaskItem)
1908 {
1909 RECT* prcMinRect = (RECT*) lParam;
1910 RECT rcItem, rcToolbar;
1911 m_TaskBar.GetItemRect(TaskItem->Index, &rcItem);
1912 m_TaskBar.GetWindowRect(&rcToolbar);
1913
1914 OffsetRect(&rcItem, rcToolbar.left, rcToolbar.top);
1915
1916 *prcMinRect = rcItem;
1917 return TRUE;
1918 }
1919 return FALSE;
1920 }
1921
OnMouseActivate(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1922 LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1923 {
1924 return MA_NOACTIVATE;
1925 }
1926
OnTimer(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1927 LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1928 {
1929 #if DUMP_TASKS != 0
1930 switch (wParam)
1931 {
1932 case 1:
1933 DumpTasks();
1934 break;
1935 }
1936 #endif
1937 return TRUE;
1938 }
1939
OnSetFont(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1940 LRESULT OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1941 {
1942 return m_TaskBar.SendMessageW(uMsg, wParam, lParam);
1943 }
1944
OnSettingChanged(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1945 LRESULT OnSettingChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1946 {
1947 if (wParam == SPI_SETNONCLIENTMETRICS)
1948 {
1949 /* Don't update the font, this will be done when we get a WM_SETFONT from our parent */
1950 UpdateButtonsSize(FALSE);
1951 }
1952
1953 return 0;
1954 }
1955
OnCopyData(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)1956 LRESULT OnCopyData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1957 {
1958 PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT)lParam;
1959 if (cpData->dwData == m_uHardErrorMsg)
1960 {
1961 /* A hard error balloon message */
1962 PBALLOON_HARD_ERROR_DATA pData = (PBALLOON_HARD_ERROR_DATA)cpData->lpData;
1963 ERR("Got balloon data 0x%x, 0x%x, '%S', '%S'\n", pData->Status, pData->dwType, (WCHAR*)((ULONG_PTR)pData + pData->TitleOffset), (WCHAR*)((ULONG_PTR)pData + pData->MessageOffset));
1964 if (pData->cbHeaderSize == sizeof(BALLOON_HARD_ERROR_DATA))
1965 m_HardErrorThread.StartThread(pData);
1966 return TRUE;
1967 }
1968
1969 return FALSE;
1970 }
1971
Initialize(IN HWND hWndParent,IN OUT ITrayWindow * tray)1972 HRESULT Initialize(IN HWND hWndParent, IN OUT ITrayWindow *tray)
1973 {
1974 m_Tray = tray;
1975 m_IsGroupingEnabled = g_TaskbarSettings.bGroupButtons;
1976 Create(hWndParent, 0, szRunningApps, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP);
1977 if (!m_hWnd)
1978 return E_FAIL;
1979 return S_OK;
1980 }
1981
GetWindow(HWND * phwnd)1982 HRESULT WINAPI GetWindow(HWND* phwnd)
1983 {
1984 if (!phwnd)
1985 return E_INVALIDARG;
1986 *phwnd = m_hWnd;
1987 return S_OK;
1988 }
1989
ContextSensitiveHelp(BOOL fEnterMode)1990 HRESULT WINAPI ContextSensitiveHelp(BOOL fEnterMode)
1991 {
1992 return E_NOTIMPL;
1993 }
1994
1995 DECLARE_WND_CLASS_EX(szTaskSwitchWndClass, CS_DBLCLKS, COLOR_3DFACE)
1996
1997 BEGIN_MSG_MAP(CTaskSwitchWnd)
1998 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
1999 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
2000 MESSAGE_HANDLER(WM_SIZE, OnSize)
2001 MESSAGE_HANDLER(WM_CREATE, OnCreate)
2002 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
2003 MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
2004 MESSAGE_HANDLER(WM_COMMAND, OnCommand)
2005 MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
2006 MESSAGE_HANDLER(TSWM_UPDATETASKBARPOS, OnUpdateTaskbarPos)
2007 MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged)
2008 MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
2009 MESSAGE_HANDLER(WM_TIMER, OnTimer)
2010 MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
2011 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChanged)
2012 MESSAGE_HANDLER(m_ShellHookMsg, OnShellHook)
2013 MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
2014 MESSAGE_HANDLER(WM_KLUDGEMINRECT, OnKludgeItemRect)
2015 MESSAGE_HANDLER(WM_COPYDATA, OnCopyData)
2016 END_MSG_MAP()
2017
2018 DECLARE_NOT_AGGREGATABLE(CTaskSwitchWnd)
2019
2020 DECLARE_PROTECT_FINAL_CONSTRUCT()
2021 BEGIN_COM_MAP(CTaskSwitchWnd)
2022 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
2023 END_COM_MAP()
2024 };
2025
CTaskSwitchWnd_CreateInstance(IN HWND hWndParent,IN OUT ITrayWindow * Tray,REFIID riid,void ** ppv)2026 HRESULT CTaskSwitchWnd_CreateInstance(IN HWND hWndParent, IN OUT ITrayWindow *Tray, REFIID riid, void **ppv)
2027 {
2028 return ShellObjectCreatorInit<CTaskSwitchWnd>(hWndParent, Tray, riid, ppv);
2029 }
2030