Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentaskswnd.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS Explorer 00003 * 00004 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 #include <precomp.h> 00022 00023 /* By default we don't use DrawCaptionTemp() because it causes some minimal 00024 drawing glitches with the toolbar custom painting code */ 00025 #define TASK_USE_DRAWCAPTIONTEMP 1 00026 00027 /* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every 00028 5 seconds */ 00029 #define DUMP_TASKS 0 00030 00031 static const TCHAR szTaskSwitchWndClass[] = TEXT("MSTaskSwWClass"); 00032 static const TCHAR szRunningApps[] = TEXT("Running Applications"); 00033 00034 typedef struct _TASK_GROUP 00035 { 00036 /* We have to use a linked list instead of an array so we don't have to 00037 update all pointers to groups in the task item array when removing 00038 groups. */ 00039 struct _TASK_GROUP *Next; 00040 00041 DWORD dwTaskCount; 00042 DWORD dwProcessId; 00043 INT Index; 00044 union 00045 { 00046 DWORD dwFlags; 00047 struct 00048 { 00049 00050 #if TASK_USE_DRAWCAPTIONTEMP != 0 00051 00052 /* DisplayTooltip is TRUE when the group button text didn't fit into 00053 the button. */ 00054 DWORD DisplayTooltip : 1; 00055 00056 #endif 00057 00058 DWORD IsCollapsed : 1; 00059 }; 00060 }; 00061 } TASK_GROUP, *PTASK_GROUP; 00062 00063 typedef struct _TASK_ITEM 00064 { 00065 HWND hWnd; 00066 PTASK_GROUP Group; 00067 INT Index; 00068 00069 #if !(TASK_USE_DRAWCAPTIONTEMP != 0) 00070 00071 INT IconIndex; 00072 00073 #endif 00074 00075 union 00076 { 00077 DWORD dwFlags; 00078 struct 00079 { 00080 00081 #if TASK_USE_DRAWCAPTIONTEMP != 0 00082 00083 /* DisplayTooltip is TRUE when the window text didn't fit into the 00084 button. */ 00085 DWORD DisplayTooltip : 1; 00086 00087 #endif 00088 00089 /* IsFlashing is TRUE when the task bar item should be flashing. */ 00090 DWORD IsFlashing : 1; 00091 00092 /* RenderFlashed is only TRUE if the task bar item should be 00093 drawn with a flash. */ 00094 DWORD RenderFlashed : 1; 00095 }; 00096 }; 00097 } TASK_ITEM, *PTASK_ITEM; 00098 00099 #define TASK_ITEM_ARRAY_ALLOC 64 00100 00101 typedef struct _TASK_SWITCH_WND 00102 { 00103 HWND hWnd; 00104 HWND hWndNotify; 00105 00106 UINT ShellHookMsg; 00107 ITrayWindow *Tray; 00108 00109 PTASK_GROUP TaskGroups; 00110 00111 WORD TaskItemCount; 00112 WORD AllocatedTaskItems; 00113 PTASK_ITEM TaskItems; 00114 PTASK_ITEM ActiveTaskItem; 00115 00116 HWND hWndToolbar; 00117 UINT TbButtonsPerLine; 00118 WORD ToolbarBtnCount; 00119 00120 union 00121 { 00122 DWORD dwFlags; 00123 struct 00124 { 00125 DWORD IsGroupingEnabled : 1; 00126 DWORD IsDestroying : 1; 00127 DWORD IsToolbarSubclassed : 1; 00128 }; 00129 }; 00130 00131 SIZE ButtonSize; 00132 TCHAR szBuf[255]; 00133 } TASK_SWITCH_WND, *PTASK_SWITCH_WND; 00134 00135 #define TSW_TOOLBAR_SUBCLASS_ID 1 00136 00137 #define MAX_TASKS_COUNT (0x7FFF) 00138 00139 static VOID TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This, 00140 IN BOOL bRedrawDisabled); 00141 00142 #if TASK_USE_DRAWCAPTIONTEMP != 0 00143 00144 #define TaskSwitchWnd_GetWndTextFromTaskItem(a,b) NULL 00145 00146 #else /* !TASK_USE_DRAWCAPTIONTEMP */ 00147 00148 static LPTSTR 00149 TaskSwitchWnd_GetWndTextFromTaskItem(IN OUT PTASK_SWITCH_WND This, 00150 IN PTASK_ITEM TaskItem) 00151 { 00152 /* Get the window text without sending a message so we don't hang if an 00153 application isn't responding! */ 00154 if (InternalGetWindowText(TaskItem->hWnd, 00155 This->szBuf, 00156 sizeof(This->szBuf) / sizeof(This->szBuf[0])) > 0) 00157 { 00158 return This->szBuf; 00159 } 00160 00161 return NULL; 00162 } 00163 00164 #endif 00165 00166 #if DUMP_TASKS != 0 00167 static VOID 00168 TaskSwitchWnd_DumpTasks(IN OUT PTASK_SWITCH_WND This) 00169 { 00170 PTASK_GROUP CurrentGroup; 00171 PTASK_ITEM CurrentTaskItem, LastTaskItem; 00172 00173 DbgPrint("Tasks dump:\n"); 00174 if (This->IsGroupingEnabled) 00175 { 00176 CurrentGroup = This->TaskGroups; 00177 while (CurrentGroup != NULL) 00178 { 00179 DbgPrint("- Group PID: 0x%p Tasks: %d Index: %d\n", CurrentGroup->dwProcessId, CurrentGroup->dwTaskCount, CurrentGroup->Index); 00180 00181 CurrentTaskItem = This->TaskItems; 00182 LastTaskItem = CurrentTaskItem + This->TaskItemCount; 00183 while (CurrentTaskItem != LastTaskItem) 00184 { 00185 if (CurrentTaskItem->Group == CurrentGroup) 00186 { 00187 DbgPrint(" + Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); 00188 } 00189 CurrentTaskItem++; 00190 } 00191 00192 CurrentGroup = CurrentGroup->Next; 00193 } 00194 00195 CurrentTaskItem = This->TaskItems; 00196 LastTaskItem = CurrentTaskItem + This->TaskItemCount; 00197 while (CurrentTaskItem != LastTaskItem) 00198 { 00199 if (CurrentTaskItem->Group == NULL) 00200 { 00201 DbgPrint("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); 00202 } 00203 CurrentTaskItem++; 00204 } 00205 } 00206 else 00207 { 00208 CurrentTaskItem = This->TaskItems; 00209 LastTaskItem = CurrentTaskItem + This->TaskItemCount; 00210 while (CurrentTaskItem != LastTaskItem) 00211 { 00212 DbgPrint("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index); 00213 CurrentTaskItem++; 00214 } 00215 } 00216 } 00217 #endif 00218 00219 static VOID 00220 TaskSwitchWnd_BeginUpdate(IN OUT PTASK_SWITCH_WND This) 00221 { 00222 SendMessage(This->hWndToolbar, 00223 WM_SETREDRAW, 00224 FALSE, 00225 0); 00226 } 00227 00228 static VOID 00229 TaskSwitchWnd_EndUpdate(IN OUT PTASK_SWITCH_WND This) 00230 { 00231 SendMessage(This->hWndToolbar, 00232 WM_SETREDRAW, 00233 TRUE, 00234 0); 00235 InvalidateRect(This->hWndToolbar, 00236 NULL, 00237 TRUE); 00238 } 00239 00240 static BOOL 00241 TaskSwitchWnd_SetToolbarButtonCommandId(IN OUT PTASK_SWITCH_WND This, 00242 IN INT iButtonIndex, 00243 IN INT iCommandId) 00244 { 00245 TBBUTTONINFO tbbi; 00246 00247 tbbi.cbSize = sizeof(tbbi); 00248 tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND; 00249 tbbi.idCommand = iCommandId; 00250 00251 return SendMessage(This->hWndToolbar, 00252 TB_SETBUTTONINFO, 00253 (WPARAM)iButtonIndex, 00254 (LPARAM)&tbbi) != 0; 00255 } 00256 00257 static VOID 00258 TaskSwitchWnd_UpdateIndexesAfterButtonInserted(IN OUT PTASK_SWITCH_WND This, 00259 IN INT iIndex) 00260 { 00261 PTASK_GROUP CurrentGroup; 00262 PTASK_ITEM CurrentTaskItem, LastTaskItem; 00263 INT NewIndex; 00264 00265 if (This->IsGroupingEnabled) 00266 { 00267 /* Update all affected groups */ 00268 CurrentGroup = This->TaskGroups; 00269 while (CurrentGroup != NULL) 00270 { 00271 if (CurrentGroup->IsCollapsed && 00272 CurrentGroup->Index >= iIndex) 00273 { 00274 /* Update the toolbar buttons */ 00275 NewIndex = CurrentGroup->Index + 1; 00276 if (TaskSwitchWnd_SetToolbarButtonCommandId(This, 00277 CurrentGroup->Index + 1, 00278 NewIndex)) 00279 { 00280 CurrentGroup->Index = NewIndex; 00281 } 00282 else 00283 CurrentGroup->Index = -1; 00284 } 00285 00286 CurrentGroup = CurrentGroup->Next; 00287 } 00288 } 00289 00290 /* Update all affected task items */ 00291 CurrentTaskItem = This->TaskItems; 00292 LastTaskItem = CurrentTaskItem + This->TaskItemCount; 00293 while (CurrentTaskItem != LastTaskItem) 00294 { 00295 CurrentGroup = CurrentTaskItem->Group; 00296 if (CurrentGroup != NULL) 00297 { 00298 if (!CurrentGroup->IsCollapsed && 00299 CurrentTaskItem->Index >= iIndex) 00300 { 00301 goto UpdateTaskItemBtn; 00302 } 00303 } 00304 else if (CurrentTaskItem->Index >= iIndex) 00305 { 00306 UpdateTaskItemBtn: 00307 /* Update the toolbar buttons */ 00308 NewIndex = CurrentTaskItem->Index + 1; 00309 if (TaskSwitchWnd_SetToolbarButtonCommandId(This, 00310 CurrentTaskItem->Index + 1, 00311 NewIndex)) 00312 { 00313 CurrentTaskItem->Index = NewIndex; 00314 } 00315 else 00316 CurrentTaskItem->Index = -1; 00317 } 00318 00319 CurrentTaskItem++; 00320 } 00321 } 00322 00323 static VOID 00324 TaskSwitchWnd_UpdateIndexesAfterButtonDeleted(IN OUT PTASK_SWITCH_WND This, 00325 IN INT iIndex) 00326 { 00327 PTASK_GROUP CurrentGroup; 00328 PTASK_ITEM CurrentTaskItem, LastTaskItem; 00329 INT NewIndex; 00330 00331 if (This->IsGroupingEnabled) 00332 { 00333 /* Update all affected groups */ 00334 CurrentGroup = This->TaskGroups; 00335 while (CurrentGroup != NULL) 00336 { 00337 if (CurrentGroup->IsCollapsed && 00338 CurrentGroup->Index > iIndex) 00339 { 00340 /* Update the toolbar buttons */ 00341 NewIndex = CurrentGroup->Index - 1; 00342 if (TaskSwitchWnd_SetToolbarButtonCommandId(This, 00343 CurrentGroup->Index - 1, 00344 NewIndex)) 00345 { 00346 CurrentGroup->Index = NewIndex; 00347 } 00348 else 00349 CurrentGroup->Index = -1; 00350 } 00351 00352 CurrentGroup = CurrentGroup->Next; 00353 } 00354 } 00355 00356 /* Update all affected task items */ 00357 CurrentTaskItem = This->TaskItems; 00358 LastTaskItem = CurrentTaskItem + This->TaskItemCount; 00359 while (CurrentTaskItem != LastTaskItem) 00360 { 00361 CurrentGroup = CurrentTaskItem->Group; 00362 if (CurrentGroup != NULL) 00363 { 00364 if (!CurrentGroup->IsCollapsed && 00365 CurrentTaskItem->Index > iIndex) 00366 { 00367 goto UpdateTaskItemBtn; 00368 } 00369 } 00370 else if (CurrentTaskItem->Index > iIndex) 00371 { 00372 UpdateTaskItemBtn: 00373 /* Update the toolbar buttons */ 00374 NewIndex = CurrentTaskItem->Index - 1; 00375 if (TaskSwitchWnd_SetToolbarButtonCommandId(This, 00376 CurrentTaskItem->Index - 1, 00377 NewIndex)) 00378 { 00379 CurrentTaskItem->Index = NewIndex; 00380 } 00381 else 00382 CurrentTaskItem->Index = -1; 00383 } 00384 00385 CurrentTaskItem++; 00386 } 00387 } 00388 00389 static INT 00390 TaskSwitchWnd_UpdateTaskGroupButton(IN OUT PTASK_SWITCH_WND This, 00391 IN PTASK_GROUP TaskGroup) 00392 { 00393 ASSERT(TaskGroup->Index >= 0); 00394 00395 /* FIXME: Implement */ 00396 00397 return TaskGroup->Index; 00398 } 00399 00400 static VOID 00401 TaskSwitchWnd_ExpandTaskGroup(IN OUT PTASK_SWITCH_WND This, 00402 IN PTASK_GROUP TaskGroup) 00403 { 00404 ASSERT(TaskGroup->dwTaskCount > 0); 00405 ASSERT(TaskGroup->IsCollapsed); 00406 ASSERT(TaskGroup->Index >= 0); 00407 00408 /* FIXME: Implement */ 00409 } 00410 00411 static INT 00412 TaskSwitchWnd_UpdateTaskItemButton(IN OUT PTASK_SWITCH_WND This, 00413 IN PTASK_ITEM TaskItem) 00414 { 00415 TBBUTTONINFO tbbi; 00416 00417 ASSERT(TaskItem->Index >= 0); 00418 00419 tbbi.cbSize = sizeof(tbbi); 00420 tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT; 00421 tbbi.fsState = TBSTATE_ENABLED; 00422 if (This->ActiveTaskItem == TaskItem) 00423 tbbi.fsState |= TBSTATE_CHECKED; 00424 00425 /* Check if we're updating a button that is the last one in the 00426 line. If so, we need to set the TBSTATE_WRAP flag! */ 00427 if (This->TbButtonsPerLine != 0 && 00428 (TaskItem->Index + 1) % This->TbButtonsPerLine == 0) 00429 { 00430 tbbi.fsState |= TBSTATE_WRAP; 00431 } 00432 00433 tbbi.pszText = TaskSwitchWnd_GetWndTextFromTaskItem(This, 00434 TaskItem); 00435 00436 if (!SendMessage(This->hWndToolbar, 00437 TB_SETBUTTONINFO, 00438 (WPARAM)TaskItem->Index, 00439 (LPARAM)&tbbi)) 00440 { 00441 TaskItem->Index = -1; 00442 return -1; 00443 } 00444 00445 DbgPrint("Updated button %d for hwnd 0x%p\n", TaskItem->Index, TaskItem->hWnd); 00446 return TaskItem->Index; 00447 } 00448 00449 static PTASK_ITEM 00450 TaskSwitchWnd_FindLastTaskItemOfGroup(IN OUT PTASK_SWITCH_WND This, 00451 IN PTASK_GROUP TaskGroup OPTIONAL, 00452 IN PTASK_ITEM NewTaskItem OPTIONAL) 00453 { 00454 PTASK_ITEM TaskItem, LastTaskItem, FoundTaskItem = NULL; 00455 DWORD dwTaskCount; 00456 00457 ASSERT(This->IsGroupingEnabled); 00458 00459 TaskItem = This->TaskItems; 00460 LastTaskItem = TaskItem + This->TaskItemCount; 00461 00462 dwTaskCount = (TaskGroup != NULL ? TaskGroup->dwTaskCount : MAX_TASKS_COUNT); 00463 00464 ASSERT(dwTaskCount > 0); 00465 00466 while (TaskItem != LastTaskItem) 00467 { 00468 if (TaskItem->Group == TaskGroup) 00469 { 00470 if ((NewTaskItem != NULL && TaskItem != NewTaskItem) || NewTaskItem == NULL) 00471 { 00472 FoundTaskItem = TaskItem; 00473 } 00474 00475 if (--dwTaskCount == 0) 00476 { 00477 /* We found the last task item in the group! */ 00478 break; 00479 } 00480 } 00481 00482 TaskItem++; 00483 } 00484 00485 return FoundTaskItem; 00486 } 00487 00488 static INT 00489 TaskSwitchWnd_CalculateTaskItemNewButtonIndex(IN OUT PTASK_SWITCH_WND This, 00490 IN PTASK_ITEM TaskItem) 00491 { 00492 PTASK_GROUP TaskGroup; 00493 PTASK_ITEM LastTaskItem; 00494 00495 /* NOTE: This routine assumes that the group is *not* collapsed! */ 00496 00497 TaskGroup = TaskItem->Group; 00498 if (This->IsGroupingEnabled) 00499 { 00500 if (TaskGroup != NULL) 00501 { 00502 ASSERT(TaskGroup->Index < 0); 00503 ASSERT(!TaskGroup->IsCollapsed); 00504 00505 if (TaskGroup->dwTaskCount > 1) 00506 { 00507 LastTaskItem = TaskSwitchWnd_FindLastTaskItemOfGroup(This, 00508 TaskGroup, 00509 TaskItem); 00510 if (LastTaskItem != NULL) 00511 { 00512 /* Since the group is expanded the task items must have an index */ 00513 ASSERT(LastTaskItem->Index >= 0); 00514 00515 return LastTaskItem->Index + 1; 00516 } 00517 } 00518 } 00519 else 00520 { 00521 /* Find the last NULL group button. NULL groups are added at the end of the 00522 task item list when grouping is enabled */ 00523 LastTaskItem = TaskSwitchWnd_FindLastTaskItemOfGroup(This, 00524 NULL, 00525 TaskItem); 00526 if (LastTaskItem != NULL) 00527 { 00528 ASSERT(LastTaskItem->Index >= 0); 00529 00530 return LastTaskItem->Index + 1; 00531 } 00532 } 00533 } 00534 00535 return This->ToolbarBtnCount; 00536 } 00537 00538 static INT 00539 TaskSwitchWnd_AddTaskItemButton(IN OUT PTASK_SWITCH_WND This, 00540 IN OUT PTASK_ITEM TaskItem) 00541 { 00542 TBBUTTON tbBtn; 00543 INT iIndex; 00544 00545 if (TaskItem->Index >= 0) 00546 { 00547 return TaskSwitchWnd_UpdateTaskItemButton(This, 00548 TaskItem); 00549 } 00550 00551 if (TaskItem->Group != NULL && 00552 TaskItem->Group->IsCollapsed) 00553 { 00554 /* The task group is collapsed, we only need to update the group button */ 00555 return TaskSwitchWnd_UpdateTaskGroupButton(This, 00556 TaskItem->Group); 00557 } 00558 00559 tbBtn.iBitmap = 0; 00560 tbBtn.fsState = TBSTATE_ENABLED | TBSTATE_ELLIPSES; 00561 tbBtn.fsStyle = BTNS_CHECK | BTNS_NOPREFIX | BTNS_SHOWTEXT; 00562 tbBtn.dwData = TaskItem->Index; 00563 00564 tbBtn.iString = (DWORD_PTR)TaskSwitchWnd_GetWndTextFromTaskItem(This, 00565 TaskItem); 00566 00567 /* Find out where to insert the new button */ 00568 iIndex = TaskSwitchWnd_CalculateTaskItemNewButtonIndex(This, 00569 TaskItem); 00570 ASSERT(iIndex >= 0); 00571 tbBtn.idCommand = iIndex; 00572 00573 TaskSwitchWnd_BeginUpdate(This); 00574 00575 if (SendMessage(This->hWndToolbar, 00576 TB_INSERTBUTTON, 00577 (WPARAM)iIndex, 00578 (LPARAM)&tbBtn)) 00579 { 00580 TaskSwitchWnd_UpdateIndexesAfterButtonInserted(This, 00581 iIndex); 00582 00583 DbgPrint("Added button %d for hwnd 0x%p\n", iIndex, TaskItem->hWnd); 00584 00585 TaskItem->Index = iIndex; 00586 This->ToolbarBtnCount++; 00587 00588 /* Update button sizes and fix the button wrapping */ 00589 TaskSwitchWnd_UpdateButtonsSize(This, 00590 TRUE); 00591 return iIndex; 00592 } 00593 00594 TaskSwitchWnd_EndUpdate(This); 00595 00596 return -1; 00597 } 00598 00599 static BOOL 00600 TaskSwitchWnd_DeleteTaskItemButton(IN OUT PTASK_SWITCH_WND This, 00601 IN OUT PTASK_ITEM TaskItem) 00602 { 00603 PTASK_GROUP TaskGroup; 00604 INT iIndex; 00605 00606 TaskGroup = TaskItem->Group; 00607 00608 if (TaskItem->Index >= 0) 00609 { 00610 if ((TaskGroup != NULL && !TaskGroup->IsCollapsed) || 00611 TaskGroup == NULL) 00612 { 00613 TaskSwitchWnd_BeginUpdate(This); 00614 00615 iIndex = TaskItem->Index; 00616 if (SendMessage(This->hWndToolbar, 00617 TB_DELETEBUTTON, 00618 (WPARAM)iIndex, 00619 0)) 00620 { 00621 TaskItem->Index = -1; 00622 This->ToolbarBtnCount--; 00623 00624 TaskSwitchWnd_UpdateIndexesAfterButtonDeleted(This, 00625 iIndex); 00626 00627 /* Update button sizes and fix the button wrapping */ 00628 TaskSwitchWnd_UpdateButtonsSize(This, 00629 TRUE); 00630 return TRUE; 00631 } 00632 00633 TaskSwitchWnd_EndUpdate(This); 00634 } 00635 } 00636 00637 return FALSE; 00638 } 00639 00640 static PTASK_GROUP 00641 TaskSwitchWnd_AddToTaskGroup(IN OUT PTASK_SWITCH_WND This, 00642 IN HWND hWnd) 00643 { 00644 DWORD dwProcessId; 00645 PTASK_GROUP TaskGroup, *PrevLink; 00646 00647 if (!GetWindowThreadProcessId(hWnd, 00648 &dwProcessId)) 00649 { 00650 DbgPrint("Cannot get process id of hwnd 0x%p\n", hWnd); 00651 return NULL; 00652 } 00653 00654 /* Try to find an existing task group */ 00655 TaskGroup = This->TaskGroups; 00656 PrevLink = &This->TaskGroups; 00657 while (TaskGroup != NULL) 00658 { 00659 if (TaskGroup->dwProcessId == dwProcessId) 00660 { 00661 TaskGroup->dwTaskCount++; 00662 return TaskGroup; 00663 } 00664 00665 PrevLink = &TaskGroup->Next; 00666 TaskGroup = TaskGroup->Next; 00667 } 00668 00669 /* Allocate a new task group */ 00670 TaskGroup = HeapAlloc(hProcessHeap, 00671 0, 00672 sizeof(*TaskGroup)); 00673 if (TaskGroup != NULL) 00674 { 00675 ZeroMemory(TaskGroup, 00676 sizeof(*TaskGroup)); 00677 00678 TaskGroup->dwTaskCount = 1; 00679 TaskGroup->dwProcessId = dwProcessId; 00680 TaskGroup->Index = -1; 00681 00682 /* Add the task group to the list */ 00683 *PrevLink = TaskGroup; 00684 } 00685 00686 return TaskGroup; 00687 } 00688 00689 static VOID 00690 TaskSwitchWnd_RemoveTaskFromTaskGroup(IN OUT PTASK_SWITCH_WND This, 00691 IN OUT PTASK_ITEM TaskItem) 00692 { 00693 PTASK_GROUP TaskGroup, CurrentGroup, *PrevLink; 00694 00695 TaskGroup = TaskItem->Group; 00696 if (TaskGroup != NULL) 00697 { 00698 DWORD dwNewTaskCount = --TaskGroup->dwTaskCount; 00699 if (dwNewTaskCount == 0) 00700 { 00701 /* Find the previous pointer in the chain */ 00702 CurrentGroup = This->TaskGroups; 00703 PrevLink = &This->TaskGroups; 00704 while (CurrentGroup != TaskGroup) 00705 { 00706 PrevLink = &CurrentGroup->Next; 00707 CurrentGroup = CurrentGroup->Next; 00708 } 00709 00710 /* Remove the group from the list */ 00711 ASSERT(TaskGroup == CurrentGroup); 00712 *PrevLink = TaskGroup->Next; 00713 00714 /* Free the task group */ 00715 HeapFree(hProcessHeap, 00716 0, 00717 TaskGroup); 00718 } 00719 else if (TaskGroup->IsCollapsed && 00720 TaskGroup->Index >= 0) 00721 { 00722 if (dwNewTaskCount > 1) 00723 { 00724 /* FIXME: Check if we should expand the group */ 00725 /* Update the task group button */ 00726 TaskSwitchWnd_UpdateTaskGroupButton(This, 00727 TaskGroup); 00728 } 00729 else 00730 { 00731 /* Expand the group of one task button to a task button */ 00732 TaskSwitchWnd_ExpandTaskGroup(This, 00733 TaskGroup); 00734 } 00735 } 00736 } 00737 } 00738 00739 static PTASK_ITEM 00740 TaskSwitchWnd_FindTaskItem(IN OUT PTASK_SWITCH_WND This, 00741 IN HWND hWnd) 00742 { 00743 PTASK_ITEM TaskItem, LastItem; 00744 00745 TaskItem = This->TaskItems; 00746 LastItem = TaskItem + This->TaskItemCount; 00747 while (TaskItem != LastItem) 00748 { 00749 if (TaskItem->hWnd == hWnd) 00750 return TaskItem; 00751 00752 TaskItem++; 00753 } 00754 00755 return NULL; 00756 } 00757 00758 static PTASK_ITEM 00759 TaskSwitchWnd_FindOtherTaskItem(IN OUT PTASK_SWITCH_WND This, 00760 IN HWND hWnd) 00761 { 00762 PTASK_ITEM LastItem, TaskItem; 00763 PTASK_GROUP TaskGroup; 00764 DWORD dwProcessId; 00765 00766 if (!GetWindowThreadProcessId(hWnd, 00767 &dwProcessId)) 00768 { 00769 return NULL; 00770 } 00771 00772 /* Try to find another task that belongs to the same 00773 process as the given window */ 00774 TaskItem = This->TaskItems; 00775 LastItem = TaskItem + This->TaskItemCount; 00776 while (TaskItem != LastItem) 00777 { 00778 TaskGroup = TaskItem->Group; 00779 if (TaskGroup != NULL) 00780 { 00781 if (TaskGroup->dwProcessId == dwProcessId) 00782 return TaskItem; 00783 } 00784 else 00785 { 00786 DWORD dwProcessIdTask; 00787 00788 if (GetWindowThreadProcessId(TaskItem->hWnd, 00789 &dwProcessIdTask) && 00790 dwProcessIdTask == dwProcessId) 00791 { 00792 return TaskItem; 00793 } 00794 } 00795 00796 TaskItem++; 00797 } 00798 00799 return NULL; 00800 } 00801 00802 static PTASK_ITEM 00803 TaskSwitchWnd_AllocTaskItem(IN OUT PTASK_SWITCH_WND This) 00804 { 00805 if (This->TaskItemCount >= MAX_TASKS_COUNT) 00806 { 00807 /* We need the most significant bit in 16 bit command IDs to indicate whether it 00808 is a task group or task item. WM_COMMAND limits command IDs to 16 bits! */ 00809 return NULL; 00810 } 00811 00812 ASSERT(This->AllocatedTaskItems >= This->TaskItemCount); 00813 00814 if (This->TaskItemCount != 0) 00815 { 00816 PTASK_ITEM NewArray; 00817 SIZE_T NewArrayLength, ActiveTaskItemIndex; 00818 00819 NewArrayLength = This->AllocatedTaskItems + TASK_ITEM_ARRAY_ALLOC; 00820 00821 NewArray = HeapReAlloc(hProcessHeap, 00822 0, 00823 This->TaskItems, 00824 NewArrayLength * sizeof(*This->TaskItems)); 00825 if (NewArray != NULL) 00826 { 00827 if (This->ActiveTaskItem != NULL) 00828 { 00829 /* Fixup the ActiveTaskItem pointer */ 00830 ActiveTaskItemIndex = This->ActiveTaskItem - This->TaskItems; 00831 This->ActiveTaskItem = NewArray + ActiveTaskItemIndex; 00832 } 00833 This->AllocatedTaskItems = (WORD)NewArrayLength; 00834 This->TaskItems = NewArray; 00835 } 00836 else 00837 return NULL; 00838 } 00839 else 00840 { 00841 This->TaskItems = HeapAlloc(hProcessHeap, 00842 0, 00843 TASK_ITEM_ARRAY_ALLOC * sizeof(*This->TaskItems)); 00844 if (This->TaskItems != NULL) 00845 { 00846 This->AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC; 00847 } 00848 else 00849 return NULL; 00850 } 00851 00852 return This->TaskItems + This->TaskItemCount++; 00853 } 00854 00855 static VOID 00856 TaskSwitchWnd_FreeTaskItem(IN OUT PTASK_SWITCH_WND This, 00857 IN OUT PTASK_ITEM TaskItem) 00858 { 00859 WORD wIndex; 00860 00861 if (TaskItem == This->ActiveTaskItem) 00862 This->ActiveTaskItem = NULL; 00863 00864 wIndex = (WORD)(TaskItem - This->TaskItems); 00865 if (wIndex + 1 < This->TaskItemCount) 00866 { 00867 MoveMemory(TaskItem, 00868 TaskItem + 1, 00869 (This->TaskItemCount - wIndex - 1) * sizeof(*TaskItem)); 00870 } 00871 00872 This->TaskItemCount--; 00873 } 00874 00875 static VOID 00876 TaskSwitchWnd_DeleteTaskItem(IN OUT PTASK_SWITCH_WND This, 00877 IN OUT PTASK_ITEM TaskItem) 00878 { 00879 if (!This->IsDestroying) 00880 { 00881 /* Delete the task button from the toolbar */ 00882 TaskSwitchWnd_DeleteTaskItemButton(This, 00883 TaskItem); 00884 } 00885 00886 /* Remove the task from it's group */ 00887 TaskSwitchWnd_RemoveTaskFromTaskGroup(This, 00888 TaskItem); 00889 00890 /* Free the task item */ 00891 TaskSwitchWnd_FreeTaskItem(This, 00892 TaskItem); 00893 } 00894 00895 static VOID 00896 TaskSwitchWnd_CheckActivateTaskItem(IN OUT PTASK_SWITCH_WND This, 00897 IN OUT PTASK_ITEM TaskItem) 00898 { 00899 PTASK_ITEM ActiveTaskItem; 00900 PTASK_GROUP TaskGroup = NULL; 00901 00902 ActiveTaskItem = This->ActiveTaskItem; 00903 00904 if (TaskItem != NULL) 00905 TaskGroup = TaskItem->Group; 00906 00907 if (This->IsGroupingEnabled && TaskGroup != NULL) 00908 { 00909 if (TaskGroup->IsCollapsed) 00910 { 00911 /* FIXME */ 00912 } 00913 else 00914 goto ChangeTaskItemButton; 00915 } 00916 else 00917 { 00918 ChangeTaskItemButton: 00919 if (ActiveTaskItem != NULL) 00920 { 00921 PTASK_GROUP ActiveTaskGroup; 00922 00923 if (ActiveTaskItem == TaskItem) 00924 return; 00925 00926 ActiveTaskGroup = ActiveTaskItem->Group; 00927 00928 if (This->IsGroupingEnabled && ActiveTaskGroup != NULL) 00929 { 00930 if (ActiveTaskGroup->IsCollapsed) 00931 { 00932 if (ActiveTaskGroup == TaskGroup) 00933 return; 00934 00935 /* FIXME */ 00936 } 00937 else 00938 goto ChangeActiveTaskItemButton; 00939 } 00940 else 00941 { 00942 ChangeActiveTaskItemButton: 00943 This->ActiveTaskItem = NULL; 00944 if (ActiveTaskItem->Index >= 0) 00945 { 00946 TaskSwitchWnd_UpdateTaskItemButton(This, 00947 ActiveTaskItem); 00948 } 00949 } 00950 } 00951 00952 This->ActiveTaskItem = TaskItem; 00953 00954 if (TaskItem != NULL && TaskItem->Index >= 0) 00955 { 00956 TaskSwitchWnd_UpdateTaskItemButton(This, 00957 TaskItem); 00958 } 00959 } 00960 } 00961 00962 static PTASK_ITEM 00963 FindTaskItemByIndex(IN OUT PTASK_SWITCH_WND This, 00964 IN INT Index) 00965 { 00966 PTASK_ITEM TaskItem, LastItem; 00967 00968 TaskItem = This->TaskItems; 00969 LastItem = TaskItem + This->TaskItemCount; 00970 while (TaskItem != LastItem) 00971 { 00972 if (TaskItem->Index == Index) 00973 return TaskItem; 00974 00975 TaskItem++; 00976 } 00977 00978 return NULL; 00979 } 00980 00981 static PTASK_GROUP 00982 FindTaskGroupByIndex(IN OUT PTASK_SWITCH_WND This, 00983 IN INT Index) 00984 { 00985 PTASK_GROUP CurrentGroup; 00986 00987 CurrentGroup = This->TaskGroups; 00988 while (CurrentGroup != NULL) 00989 { 00990 if (CurrentGroup->Index == Index) 00991 break; 00992 00993 CurrentGroup = CurrentGroup->Next; 00994 } 00995 00996 return CurrentGroup; 00997 } 00998 00999 static BOOL 01000 TaskSwitchWnd_AddTask(IN OUT PTASK_SWITCH_WND This, 01001 IN HWND hWnd) 01002 { 01003 PTASK_ITEM TaskItem; 01004 01005 TaskItem = TaskSwitchWnd_FindTaskItem(This, 01006 hWnd); 01007 if (TaskItem == NULL) 01008 { 01009 DbgPrint("Add window 0x%p\n", hWnd); 01010 TaskItem = TaskSwitchWnd_AllocTaskItem(This); 01011 if (TaskItem != NULL) 01012 { 01013 ZeroMemory(TaskItem, 01014 sizeof(*TaskItem)); 01015 TaskItem->hWnd = hWnd; 01016 TaskItem->Index = -1; 01017 TaskItem->Group = TaskSwitchWnd_AddToTaskGroup(This, 01018 hWnd); 01019 01020 if (!This->IsDestroying) 01021 { 01022 TaskSwitchWnd_AddTaskItemButton(This, 01023 TaskItem); 01024 } 01025 } 01026 } 01027 01028 return TaskItem != NULL; 01029 } 01030 01031 static BOOL 01032 TaskSwitchWnd_ActivateTaskItem(IN OUT PTASK_SWITCH_WND This, 01033 IN OUT PTASK_ITEM TaskItem OPTIONAL) 01034 { 01035 if (TaskItem != NULL) 01036 { 01037 DbgPrint("Activate window 0x%p on button %d\n", TaskItem->hWnd, TaskItem->Index); 01038 } 01039 01040 TaskSwitchWnd_CheckActivateTaskItem(This, 01041 TaskItem); 01042 01043 return FALSE; 01044 } 01045 01046 static BOOL 01047 TaskSwitchWnd_ActivateTask(IN OUT PTASK_SWITCH_WND This, 01048 IN HWND hWnd) 01049 { 01050 PTASK_ITEM TaskItem; 01051 01052 TaskItem = TaskSwitchWnd_FindTaskItem(This, 01053 hWnd); 01054 if (TaskItem == NULL) 01055 { 01056 TaskItem = TaskSwitchWnd_FindOtherTaskItem(This, 01057 hWnd); 01058 } 01059 01060 if (TaskItem == NULL) 01061 { 01062 DbgPrint("Activate window 0x%p, could not find task\n", hWnd); 01063 } 01064 01065 return TaskSwitchWnd_ActivateTaskItem(This, 01066 TaskItem); 01067 } 01068 01069 static BOOL 01070 TaskSwitchWnd_DeleteTask(IN OUT PTASK_SWITCH_WND This, 01071 IN HWND hWnd) 01072 { 01073 PTASK_ITEM TaskItem; 01074 01075 TaskItem = TaskSwitchWnd_FindTaskItem(This, 01076 hWnd); 01077 if (TaskItem != NULL) 01078 { 01079 DbgPrint("Delete window 0x%p on button %d\n", hWnd, TaskItem->Index); 01080 TaskSwitchWnd_DeleteTaskItem(This, 01081 TaskItem); 01082 return TRUE; 01083 } 01084 //else 01085 //DbgPrint("Failed to delete window 0x%p\n", hWnd); 01086 01087 return FALSE; 01088 } 01089 01090 static VOID 01091 TaskSwitchWnd_DeleteAllTasks(IN OUT PTASK_SWITCH_WND This) 01092 { 01093 PTASK_ITEM CurrentTask; 01094 01095 if (This->TaskItemCount > 0) 01096 { 01097 CurrentTask = This->TaskItems + This->TaskItemCount; 01098 do 01099 { 01100 TaskSwitchWnd_DeleteTaskItem(This, 01101 --CurrentTask); 01102 } while (CurrentTask != This->TaskItems); 01103 } 01104 } 01105 01106 static VOID 01107 TaskSwitchWnd_FlashTaskItem(IN OUT PTASK_SWITCH_WND This, 01108 IN OUT PTASK_ITEM TaskItem) 01109 { 01110 /* FIXME: Implement */ 01111 } 01112 01113 static BOOL 01114 TaskSwitchWnd_FlashTask(IN OUT PTASK_SWITCH_WND This, 01115 IN HWND hWnd) 01116 { 01117 PTASK_ITEM TaskItem; 01118 01119 TaskItem = TaskSwitchWnd_FindTaskItem(This, 01120 hWnd); 01121 if (TaskItem != NULL) 01122 { 01123 DbgPrint("Flashing window 0x%p on button %d\n", hWnd, TaskItem->Index); 01124 TaskSwitchWnd_FlashTaskItem(This, 01125 TaskItem); 01126 return TRUE; 01127 } 01128 01129 return FALSE; 01130 } 01131 01132 static VOID 01133 TaskSwitchWnd_RedrawTaskItem(IN OUT PTASK_SWITCH_WND This, 01134 IN OUT PTASK_ITEM TaskItem) 01135 { 01136 PTASK_GROUP TaskGroup; 01137 01138 TaskGroup = TaskItem->Group; 01139 if (This->IsGroupingEnabled && TaskGroup != NULL) 01140 { 01141 if (TaskGroup->IsCollapsed && TaskGroup->Index >= 0) 01142 { 01143 TaskSwitchWnd_UpdateTaskGroupButton(This, 01144 TaskGroup); 01145 } 01146 else if (TaskItem->Index >= 0) 01147 { 01148 goto UpdateTaskItem; 01149 } 01150 } 01151 else if (TaskItem->Index >= 0) 01152 { 01153 UpdateTaskItem: 01154 TaskSwitchWnd_UpdateTaskItemButton(This, 01155 TaskItem); 01156 } 01157 } 01158 01159 01160 static BOOL 01161 TaskSwitchWnd_RedrawTask(IN OUT PTASK_SWITCH_WND This, 01162 IN HWND hWnd) 01163 { 01164 PTASK_ITEM TaskItem; 01165 01166 TaskItem = TaskSwitchWnd_FindTaskItem(This, 01167 hWnd); 01168 if (TaskItem != NULL) 01169 { 01170 TaskSwitchWnd_RedrawTaskItem(This, 01171 TaskItem); 01172 return TRUE; 01173 } 01174 01175 return FALSE; 01176 } 01177 01178 static INT 01179 TaskSwitchWnd_UpdateTbButtonSpacing(IN OUT PTASK_SWITCH_WND This, 01180 IN BOOL bHorizontal, 01181 IN UINT uiRows, 01182 IN UINT uiBtnsPerLine) 01183 { 01184 TBMETRICS tbm; 01185 01186 tbm.cbSize = sizeof(tbm); 01187 tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING; 01188 01189 tbm.cxBarPad = tbm.cyBarPad = 0; 01190 01191 if (bHorizontal || uiBtnsPerLine > 1) 01192 tbm.cxButtonSpacing = (3 * GetSystemMetrics(SM_CXEDGE) / 2); 01193 else 01194 tbm.cxButtonSpacing = 0; 01195 01196 if (!bHorizontal || uiRows > 1) 01197 tbm.cyButtonSpacing = (3 * GetSystemMetrics(SM_CYEDGE) / 2); 01198 else 01199 tbm.cyButtonSpacing = 0; 01200 01201 SendMessage(This->hWndToolbar, 01202 TB_SETMETRICS, 01203 0, 01204 (LPARAM)&tbm); 01205 01206 return tbm.cxButtonSpacing; 01207 } 01208 01209 01210 static VOID 01211 TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This, 01212 IN BOOL bRedrawDisabled) 01213 { 01214 RECT rcClient; 01215 UINT uiRows, uiMax, uiMin, uiBtnsPerLine, ui; 01216 LONG NewBtnSize; 01217 BOOL Horizontal; 01218 TBBUTTONINFO tbbi; 01219 TBMETRICS tbm; 01220 01221 if (GetClientRect(This->hWnd, 01222 &rcClient) && 01223 !IsRectEmpty(&rcClient)) 01224 { 01225 if (This->ToolbarBtnCount > 0) 01226 { 01227 ZeroMemory (&tbm, sizeof (tbm)); 01228 tbm.cbSize = sizeof(tbm); 01229 tbm.dwMask = TBMF_BUTTONSPACING; 01230 SendMessage(This->hWndToolbar, 01231 TB_GETMETRICS, 01232 0, 01233 (LPARAM)&tbm); 01234 01235 uiRows = (rcClient.bottom + tbm.cyButtonSpacing) / (This->ButtonSize.cy + tbm.cyButtonSpacing); 01236 if (uiRows == 0) 01237 uiRows = 1; 01238 01239 uiBtnsPerLine = (This->ToolbarBtnCount + uiRows - 1) / uiRows; 01240 01241 Horizontal = ITrayWindow_IsHorizontal(This->Tray); 01242 01243 if (!bRedrawDisabled) 01244 TaskSwitchWnd_BeginUpdate(This); 01245 01246 /* We might need to update the button spacing */ 01247 tbm.cxButtonSpacing = TaskSwitchWnd_UpdateTbButtonSpacing(This, 01248 Horizontal, 01249 uiRows, 01250 uiBtnsPerLine); 01251 01252 /* Calculate the ideal width and make sure it's within the allowed range */ 01253 NewBtnSize = (rcClient.right - (uiBtnsPerLine * tbm.cxButtonSpacing)) / uiBtnsPerLine; 01254 01255 /* Determine the minimum and maximum width of a button */ 01256 if (Horizontal) 01257 uiMax = GetSystemMetrics(SM_CXMINIMIZED); 01258 else 01259 uiMax = rcClient.right; 01260 01261 uiMin = GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE)); 01262 01263 if (NewBtnSize < (LONG)uiMin) 01264 NewBtnSize = uiMin; 01265 if (NewBtnSize > (LONG)uiMax) 01266 NewBtnSize = uiMax; 01267 01268 This->ButtonSize.cx = NewBtnSize; 01269 01270 /* Recalculate how many buttons actually fit into one line */ 01271 uiBtnsPerLine = rcClient.right / (NewBtnSize + tbm.cxButtonSpacing); 01272 if (uiBtnsPerLine == 0) 01273 uiBtnsPerLine++; 01274 This->TbButtonsPerLine = uiBtnsPerLine; 01275 01276 tbbi.cbSize = sizeof(tbbi); 01277 tbbi.dwMask = TBIF_BYINDEX | TBIF_SIZE | TBIF_STATE; 01278 tbbi.cx = (INT)NewBtnSize; 01279 01280 for (ui = 0; ui != This->ToolbarBtnCount; ui++) 01281 { 01282 tbbi.fsState = TBSTATE_ENABLED; 01283 01284 /* Check if we're updating a button that is the last one in the 01285 line. If so, we need to set the TBSTATE_WRAP flag! */ 01286 if ((ui + 1) % uiBtnsPerLine == 0) 01287 tbbi.fsState |= TBSTATE_WRAP; 01288 01289 if (This->ActiveTaskItem != NULL && 01290 This->ActiveTaskItem->Index == ui) 01291 { 01292 tbbi.fsState |= TBSTATE_CHECKED; 01293 } 01294 01295 SendMessage(This->hWndToolbar, 01296 TB_SETBUTTONINFO, 01297 (WPARAM)ui, 01298 (LPARAM)&tbbi); 01299 } 01300 01301 #if 0 01302 /* FIXME: Force the window to the correct position in case some idiot 01303 did something to us */ 01304 SetWindowPos(This->hWndToolbar, 01305 NULL, 01306 0, 01307 0, 01308 rcClient.right, /* FIXME */ 01309 rcClient.bottom, /* FIXME */ 01310 SWP_NOACTIVATE | SWP_NOZORDER); 01311 #endif 01312 } 01313 else 01314 { 01315 This->TbButtonsPerLine = 0; 01316 This->ButtonSize.cx = 0; 01317 } 01318 } 01319 01320 TaskSwitchWnd_EndUpdate(This); 01321 } 01322 01323 static BOOL CALLBACK 01324 TaskSwitchWnd_EnumWindowsProc(IN HWND hWnd, 01325 IN LPARAM lParam) 01326 { 01327 PTASK_SWITCH_WND This = (PTASK_SWITCH_WND)lParam; 01328 01329 /* Only show windows that still exist and are visible and none of explorer's 01330 special windows (such as the desktop or the tray window) */ 01331 if (IsWindow(hWnd) && IsWindowVisible(hWnd) && 01332 !ITrayWindow_IsSpecialHWND(This->Tray, 01333 hWnd)) 01334 { 01335 /* Don't list popup windows and also no tool windows */ 01336 if (GetWindow(hWnd, 01337 GW_OWNER) == NULL && 01338 !(GetWindowLongPtr(hWnd, 01339 GWL_EXSTYLE) & WS_EX_TOOLWINDOW)) 01340 { 01341 TaskSwitchWnd_AddTask(This, 01342 hWnd); 01343 } 01344 } 01345 01346 return TRUE; 01347 } 01348 01349 static LRESULT CALLBACK 01350 TaskSwichWnd_ToolbarSubclassedProc(IN HWND hWnd, 01351 IN UINT msg, 01352 IN WPARAM wParam, 01353 IN LPARAM lParam, 01354 IN UINT_PTR uIdSubclass, 01355 IN DWORD_PTR dwRefData) 01356 { 01357 LRESULT Ret; 01358 01359 Ret = DefSubclassProc(hWnd, 01360 msg, 01361 wParam, 01362 lParam); 01363 01364 if (msg == WM_NCHITTEST && Ret == HTCLIENT) 01365 { 01366 POINT pt; 01367 01368 /* See if the mouse is on a button */ 01369 pt.x = (SHORT)LOWORD(lParam); 01370 pt.y = (SHORT)HIWORD(lParam); 01371 01372 if (MapWindowPoints(HWND_DESKTOP, 01373 hWnd, 01374 &pt, 01375 1) != 0 && 01376 (INT)SendMessage(hWnd, 01377 TB_HITTEST, 01378 0, 01379 (LPARAM)&pt) < 0) 01380 { 01381 /* Make the control appear to be transparent outside of any buttons */ 01382 Ret = HTTRANSPARENT; 01383 } 01384 } 01385 01386 return Ret; 01387 } 01388 01389 static VOID 01390 TaskSwitchWnd_Create(IN OUT PTASK_SWITCH_WND This) 01391 { 01392 This->hWndToolbar = CreateWindowEx(0, 01393 TOOLBARCLASSNAME, 01394 szRunningApps, 01395 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | 01396 TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_LIST | 01397 TBSTYLE_TRANSPARENT | 01398 CCS_TOP | CCS_NORESIZE | CCS_NODIVIDER, 01399 0, 01400 0, 01401 0, 01402 0, 01403 This->hWnd, 01404 NULL, 01405 hExplorerInstance, 01406 NULL); 01407 01408 if (This->hWndToolbar != NULL) 01409 { 01410 HMODULE hShell32; 01411 SIZE BtnSize; 01412 01413 /* Identify the version we're using */ 01414 SendMessage(This->hWndToolbar, 01415 TB_BUTTONSTRUCTSIZE, 01416 sizeof(TBBUTTON), 01417 0); 01418 01419 /* Calculate the default button size. Don't save this in This->ButtonSize.cx so that 01420 the actual button width gets updated correctly on the first recalculation */ 01421 BtnSize.cx = GetSystemMetrics(SM_CXMINIMIZED); 01422 This->ButtonSize.cy = BtnSize.cy = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); 01423 SendMessage(This->hWndToolbar, 01424 TB_SETBUTTONSIZE, 01425 0, 01426 (LPARAM)MAKELONG(BtnSize.cx, 01427 BtnSize.cy)); 01428 01429 /* We don't want to see partially clipped buttons...not that we could see them... */ 01430 #if 0 01431 SendMessage(This->hWndToolbar, 01432 TB_SETEXTENDEDSTYLE, 01433 0, 01434 TBSTYLE_EX_HIDECLIPPEDBUTTONS); 01435 #endif 01436 01437 /* Set proper spacing between buttons */ 01438 TaskSwitchWnd_UpdateTbButtonSpacing(This, 01439 ITrayWindow_IsHorizontal(This->Tray), 01440 0, 01441 0); 01442 01443 /* Register the shell hook */ 01444 This->ShellHookMsg = RegisterWindowMessage(TEXT("SHELLHOOK")); 01445 hShell32 = GetModuleHandle(TEXT("SHELL32.DLL")); 01446 if (hShell32 != NULL) 01447 { 01448 REGSHELLHOOK RegShellHook; 01449 01450 /* RegisterShellHook */ 01451 RegShellHook = (REGSHELLHOOK)GetProcAddress(hShell32, 01452 (LPCSTR)((LONG)181)); 01453 if (RegShellHook != NULL) 01454 { 01455 RegShellHook(This->hWnd, 01456 3); /* 1 if no NT! We're targeting NT so we don't care! */ 01457 } 01458 } 01459 01460 /* Add all windows to the toolbar */ 01461 EnumWindows(TaskSwitchWnd_EnumWindowsProc, 01462 (LPARAM)This); 01463 01464 /* Recalculate the button size */ 01465 TaskSwitchWnd_UpdateButtonsSize(This, 01466 FALSE); 01467 01468 /* Subclass the toolbar control because it doesn't provide a 01469 NM_NCHITTEST notification */ 01470 This->IsToolbarSubclassed = SetWindowSubclass(This->hWndToolbar, 01471 TaskSwichWnd_ToolbarSubclassedProc, 01472 TSW_TOOLBAR_SUBCLASS_ID, 01473 (DWORD_PTR)This); 01474 } 01475 } 01476 01477 static VOID 01478 TaskSwitchWnd_NCDestroy(IN OUT PTASK_SWITCH_WND This) 01479 { 01480 HMODULE hShell32; 01481 01482 This->IsDestroying = TRUE; 01483 01484 /* Unregister the shell hook */ 01485 hShell32 = GetModuleHandle(TEXT("SHELL32.DLL")); 01486 if (hShell32 != NULL) 01487 { 01488 REGSHELLHOOK RegShellHook; 01489 01490 /* RegisterShellHook */ 01491 RegShellHook = (REGSHELLHOOK)GetProcAddress(hShell32, 01492 (LPCSTR)((LONG)181)); 01493 if (RegShellHook != NULL) 01494 { 01495 RegShellHook(This->hWnd, 01496 FALSE); 01497 } 01498 } 01499 01500 TaskSwitchWnd_DeleteAllTasks(This); 01501 } 01502 01503 static BOOL 01504 TaskSwitchWnd_HandleAppCommand(IN OUT PTASK_SWITCH_WND This, 01505 IN WPARAM wParam, 01506 IN LPARAM lParam) 01507 { 01508 BOOL Ret = FALSE; 01509 01510 switch (GET_APPCOMMAND_LPARAM(lParam)) 01511 { 01512 case APPCOMMAND_BROWSER_SEARCH: 01513 Ret = SHFindFiles(NULL, 01514 NULL); 01515 break; 01516 01517 case APPCOMMAND_BROWSER_HOME: 01518 case APPCOMMAND_LAUNCH_MAIL: 01519 default: 01520 DbgPrint("Shell app command %d unhandled!\n", (INT)GET_APPCOMMAND_LPARAM(lParam)); 01521 break; 01522 } 01523 01524 return Ret; 01525 } 01526 01527 01528 static LRESULT 01529 TaskSwitchWnd_HandleShellHookMsg(IN OUT PTASK_SWITCH_WND This, 01530 IN WPARAM wParam, 01531 IN LPARAM lParam) 01532 { 01533 BOOL Ret = FALSE; 01534 01535 switch ((INT)wParam) 01536 { 01537 case HSHELL_APPCOMMAND: 01538 TaskSwitchWnd_HandleAppCommand(This, 01539 wParam, 01540 lParam); 01541 Ret = TRUE; 01542 break; 01543 01544 case HSHELL_WINDOWCREATED: 01545 TaskSwitchWnd_AddTask(This, 01546 (HWND)lParam); 01547 Ret = TRUE; 01548 break; 01549 01550 case HSHELL_WINDOWDESTROYED: 01551 /* The window still exists! Delay destroying it a bit */ 01552 TaskSwitchWnd_DeleteTask(This, 01553 (HWND)lParam); 01554 Ret = TRUE; 01555 break; 01556 01557 case HSHELL_ACTIVATESHELLWINDOW: 01558 goto UnhandledShellMessage; 01559 01560 case HSHELL_RUDEAPPACTIVATED: 01561 goto UnhandledShellMessage; 01562 01563 case HSHELL_WINDOWACTIVATED: 01564 TaskSwitchWnd_ActivateTask(This, 01565 (HWND)lParam); 01566 Ret = TRUE; 01567 break; 01568 01569 case HSHELL_GETMINRECT: 01570 goto UnhandledShellMessage; 01571 01572 case HSHELL_FLASH: 01573 TaskSwitchWnd_FlashTask(This, 01574 (HWND)lParam); 01575 Ret = TRUE; 01576 break; 01577 01578 case HSHELL_REDRAW: 01579 TaskSwitchWnd_RedrawTask(This, 01580 (HWND)lParam); 01581 Ret = TRUE; 01582 break; 01583 01584 case HSHELL_TASKMAN: 01585 case HSHELL_LANGUAGE: 01586 case HSHELL_SYSMENU: 01587 case HSHELL_ENDTASK: 01588 case HSHELL_ACCESSIBILITYSTATE: 01589 case HSHELL_WINDOWREPLACED: 01590 case HSHELL_WINDOWREPLACING: 01591 default: 01592 { 01593 static const struct { 01594 INT msg; 01595 LPCWSTR msg_name; 01596 } hshell_msg[] = { 01597 {HSHELL_WINDOWCREATED, L"HSHELL_WINDOWCREATED"}, 01598 {HSHELL_WINDOWDESTROYED, L"HSHELL_WINDOWDESTROYED"}, 01599 {HSHELL_ACTIVATESHELLWINDOW, L"HSHELL_ACTIVATESHELLWINDOW"}, 01600 {HSHELL_WINDOWACTIVATED, L"HSHELL_WINDOWACTIVATED"}, 01601 {HSHELL_GETMINRECT, L"HSHELL_GETMINRECT"}, 01602 {HSHELL_REDRAW, L"HSHELL_REDRAW"}, 01603 {HSHELL_TASKMAN, L"HSHELL_TASKMAN"}, 01604 {HSHELL_LANGUAGE, L"HSHELL_LANGUAGE"}, 01605 {HSHELL_SYSMENU, L"HSHELL_SYSMENU"}, 01606 {HSHELL_ENDTASK, L"HSHELL_ENDTASK"}, 01607 {HSHELL_ACCESSIBILITYSTATE, L"HSHELL_ACCESSIBILITYSTATE"}, 01608 {HSHELL_APPCOMMAND, L"HSHELL_APPCOMMAND"}, 01609 {HSHELL_WINDOWREPLACED, L"HSHELL_WINDOWREPLACED"}, 01610 {HSHELL_WINDOWREPLACING, L"HSHELL_WINDOWREPLACING"}, 01611 {HSHELL_RUDEAPPACTIVATED, L"HSHELL_RUDEAPPACTIVATED"}, 01612 }; 01613 int i, found; 01614 UnhandledShellMessage: 01615 for (i = 0, found = 0; i != sizeof(hshell_msg) / sizeof(hshell_msg[0]); i++) 01616 { 01617 if (hshell_msg[i].msg == (INT)wParam) 01618 { 01619 DbgPrint("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg[i].msg_name, lParam); 01620 found = 1; 01621 break; 01622 } 01623 } 01624 if (!found) 01625 { 01626 DbgPrint("Shell message %d unhandled (lParam = 0x%p)!\n", (INT)wParam, lParam); 01627 } 01628 break; 01629 } 01630 } 01631 01632 return Ret; 01633 } 01634 01635 static VOID 01636 TaskSwitchWnd_EnableGrouping(IN OUT PTASK_SWITCH_WND This, 01637 IN BOOL bEnable) 01638 { 01639 This->IsGroupingEnabled = bEnable; 01640 01641 /* Collapse or expand groups if neccessary */ 01642 TaskSwitchWnd_UpdateButtonsSize(This, 01643 FALSE); 01644 } 01645 01646 static VOID 01647 TaskSwitchWnd_HandleTaskItemClick(IN OUT PTASK_SWITCH_WND This, 01648 IN OUT PTASK_ITEM TaskItem) 01649 { 01650 BOOL bIsMinimized; 01651 BOOL bIsActive; 01652 01653 if (IsWindow(TaskItem->hWnd)) 01654 { 01655 bIsMinimized = IsIconic(TaskItem->hWnd); 01656 bIsActive = (TaskItem == This->ActiveTaskItem); 01657 01658 if (!bIsMinimized && bIsActive) 01659 { 01660 PostMessage(TaskItem->hWnd, 01661 WM_SYSCOMMAND, 01662 SC_MINIMIZE, 01663 0); 01664 } 01665 else 01666 { 01667 if (bIsMinimized) 01668 { 01669 PostMessage(TaskItem->hWnd, 01670 WM_SYSCOMMAND, 01671 SC_RESTORE, 01672 0); 01673 } 01674 01675 SetForegroundWindow(TaskItem->hWnd); 01676 } 01677 } 01678 } 01679 01680 static VOID 01681 TaskSwitchWnd_HandleTaskGroupClick(IN OUT PTASK_SWITCH_WND This, 01682 IN OUT PTASK_GROUP TaskGroup) 01683 { 01684 /* TODO: Show task group menu */ 01685 } 01686 01687 static BOOL 01688 TaskSwitchWnd_HandleButtonClick(IN OUT PTASK_SWITCH_WND This, 01689 IN WORD wIndex) 01690 { 01691 PTASK_ITEM TaskItem; 01692 PTASK_GROUP TaskGroup; 01693 01694 if (This->IsGroupingEnabled) 01695 { 01696 TaskGroup = FindTaskGroupByIndex(This, 01697 (INT)wIndex); 01698 if (TaskGroup != NULL && TaskGroup->IsCollapsed) 01699 { 01700 TaskSwitchWnd_HandleTaskGroupClick(This, 01701 TaskGroup); 01702 return TRUE; 01703 } 01704 } 01705 01706 TaskItem = FindTaskItemByIndex(This, 01707 (INT)wIndex); 01708 if (TaskItem != NULL) 01709 { 01710 TaskSwitchWnd_HandleTaskItemClick(This, 01711 TaskItem); 01712 return TRUE; 01713 } 01714 01715 return FALSE; 01716 } 01717 01718 01719 static VOID 01720 TaskSwitchWnd_HandleTaskItemRightClick(IN OUT PTASK_SWITCH_WND This, 01721 IN OUT PTASK_ITEM TaskItem) 01722 { 01723 01724 HMENU hmenu = GetSystemMenu(TaskItem->hWnd, FALSE); 01725 01726 if (hmenu) { 01727 POINT pt; 01728 int cmd; 01729 GetCursorPos(&pt); 01730 cmd = TrackPopupMenu(hmenu, TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_RETURNCMD, pt.x, pt.y, 0, This->hWndToolbar, NULL); 01731 if (cmd) { 01732 SetForegroundWindow(TaskItem->hWnd); // reactivate window after the context menu has closed 01733 PostMessage(TaskItem->hWnd, WM_SYSCOMMAND, cmd, 0); 01734 } 01735 } 01736 } 01737 01738 static VOID 01739 TaskSwitchWnd_HandleTaskGroupRightClick(IN OUT PTASK_SWITCH_WND This, 01740 IN OUT PTASK_GROUP TaskGroup) 01741 { 01742 /* TODO: Show task group right click menu */ 01743 } 01744 01745 static BOOL 01746 TaskSwitchWnd_HandleButtonRightClick(IN OUT PTASK_SWITCH_WND This, 01747 IN WORD wIndex) 01748 { 01749 PTASK_ITEM TaskItem; 01750 PTASK_GROUP TaskGroup; 01751 if (This->IsGroupingEnabled) 01752 { 01753 TaskGroup = FindTaskGroupByIndex(This, 01754 (INT)wIndex); 01755 if (TaskGroup != NULL && TaskGroup->IsCollapsed) 01756 { 01757 TaskSwitchWnd_HandleTaskGroupRightClick(This, 01758 TaskGroup); 01759 return TRUE; 01760 } 01761 } 01762 01763 TaskItem = FindTaskItemByIndex(This, 01764 (INT)wIndex); 01765 01766 if (TaskItem != NULL) 01767 { 01768 TaskSwitchWnd_HandleTaskItemRightClick(This, 01769 TaskItem); 01770 return TRUE; 01771 } 01772 01773 return FALSE; 01774 } 01775 01776 01777 static LRESULT 01778 TaskSwichWnd_HandleItemPaint(IN OUT PTASK_SWITCH_WND This, 01779 IN OUT NMTBCUSTOMDRAW *nmtbcd) 01780 { 01781 HFONT hCaptionFont, hBoldCaptionFont; 01782 LRESULT Ret = CDRF_DODEFAULT; 01783 PTASK_GROUP TaskGroup; 01784 PTASK_ITEM TaskItem; 01785 01786 #if TASK_USE_DRAWCAPTIONTEMP != 0 01787 01788 UINT uidctFlags = DC_TEXT | DC_ICON | DC_NOSENDMSG; 01789 01790 #endif 01791 TaskItem = FindTaskItemByIndex(This, 01792 (INT)nmtbcd->nmcd.dwItemSpec); 01793 TaskGroup = FindTaskGroupByIndex(This, 01794 (INT)nmtbcd->nmcd.dwItemSpec); 01795 if (TaskGroup == NULL && TaskItem != NULL) 01796 { 01797 ASSERT(TaskItem != NULL); 01798 01799 if (TaskItem != NULL && IsWindow(TaskItem->hWnd)) 01800 { 01801 hCaptionFont = ITrayWindow_GetCaptionFonts(This->Tray, 01802 &hBoldCaptionFont); 01803 if (nmtbcd->nmcd.uItemState & CDIS_CHECKED) 01804 hCaptionFont = hBoldCaptionFont; 01805 01806 #if TASK_USE_DRAWCAPTIONTEMP != 0 01807 01808 /* Make sure we don't draw on the button edges */ 01809 InflateRect(&nmtbcd->nmcd.rc, 01810 -GetSystemMetrics(SM_CXEDGE), 01811 -GetSystemMetrics(SM_CYEDGE)); 01812 01813 if ((nmtbcd->nmcd.uItemState & CDIS_MARKED) && TaskItem->RenderFlashed) 01814 { 01815 /* This is a slight glitch. We have to move the rectangle so that 01816 the button content appears to be pressed. However, when flashing 01817 is enabled, we can see a light line at the top and left inner 01818 border. We need to fill that area with the flashing color. Note 01819 that since we're using DrawCaptionTemp() the flashing color is 01820 COLOR_ACTIVECAPTION, not COLOR_HIGHLIGHT! */ 01821 FillRect(nmtbcd->nmcd.hdc, 01822 &nmtbcd->nmcd.rc, 01823 (HBRUSH)(COLOR_ACTIVECAPTION + 1)); 01824 01825 /* Make the button content appear pressed. This however draws a bit 01826 into the right and bottom border of the button edge, making it 01827 look a bit odd. However, selecting a clipping region to prevent 01828 that from happening causes problems with DrawCaptionTemp()! */ 01829 OffsetRect(&nmtbcd->nmcd.rc, 01830 1, 01831 1); 01832 01833 /* Render flashed */ 01834 uidctFlags |= DC_ACTIVE; 01835 } 01836 else 01837 { 01838 uidctFlags |= DC_INBUTTON; 01839 if (nmtbcd->nmcd.uItemState & CDIS_CHECKED) 01840 uidctFlags |= DC_ACTIVE; 01841 } 01842 01843 if (DrawCapTemp != NULL) 01844 { 01845 /* Draw the button content */ 01846 TaskItem->DisplayTooltip = !DrawCapTemp(TaskItem->hWnd, 01847 nmtbcd->nmcd.hdc, 01848 &nmtbcd->nmcd.rc, 01849 hCaptionFont, 01850 NULL, 01851 NULL, 01852 uidctFlags); 01853 } 01854 01855 return CDRF_SKIPDEFAULT; 01856 01857 #else /* !TASK_USE_DRAWCAPTIONTEMP */ 01858 01859 /* Make the entire button flashing if neccessary */ 01860 if (nmtbcd->nmcd.uItemState & CDIS_MARKED) 01861 { 01862 if (TaskItem->RenderFlashed) 01863 { 01864 nmtbcd->hbrMonoDither = GetSysColorBrush(COLOR_HIGHLIGHT); 01865 nmtbcd->clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT); 01866 nmtbcd->nHLStringBkMode = TRANSPARENT; 01867 01868 /* We don't really need to set clrMark because we set the 01869 background mode to TRANSPARENT! */ 01870 nmtbcd->clrMark = GetSysColor(COLOR_HIGHLIGHT); 01871 01872 Ret |= TBCDRF_USECDCOLORS; 01873 } 01874 else 01875 Ret |= TBCDRF_NOMARK; 01876 } 01877 01878 /* Select the font we want to use */ 01879 SelectObject(nmtbcd->nmcd.hdc, 01880 hCaptionFont); 01881 return Ret | CDRF_NEWFONT; 01882 01883 #endif 01884 01885 } 01886 } 01887 else if (TaskGroup != NULL) 01888 { 01889 /* FIXME: Implement painting for task groups */ 01890 } 01891 01892 return Ret; 01893 } 01894 01895 static LRESULT 01896 TaskSwitchWnd_HandleToolbarNotification(IN OUT PTASK_SWITCH_WND This, 01897 IN const NMHDR *nmh) 01898 { 01899 LRESULT Ret = 0; 01900 01901 switch (nmh->code) 01902 { 01903 case NM_CUSTOMDRAW: 01904 { 01905 LPNMTBCUSTOMDRAW nmtbcd = (LPNMTBCUSTOMDRAW)nmh; 01906 01907 switch (nmtbcd->nmcd.dwDrawStage) 01908 { 01909 01910 #if TASK_USE_DRAWCAPTIONTEMP != 0 01911 01912 case CDDS_ITEMPREPAINT: 01913 /* We handle drawing in the post-paint stage so that we 01914 don't have to draw the button edges, etc */ 01915 Ret = CDRF_NOTIFYPOSTPAINT; 01916 break; 01917 01918 case CDDS_ITEMPOSTPAINT: 01919 01920 #else /* !TASK_USE_DRAWCAPTIONTEMP */ 01921 01922 case CDDS_ITEMPREPAINT: 01923 01924 #endif 01925 01926 Ret = TaskSwichWnd_HandleItemPaint(This, 01927 nmtbcd); 01928 break; 01929 01930 case CDDS_PREPAINT: 01931 Ret = CDRF_NOTIFYITEMDRAW; 01932 break; 01933 01934 default: 01935 Ret = CDRF_DODEFAULT; 01936 break; 01937 } 01938 break; 01939 } 01940 } 01941 01942 return Ret; 01943 } 01944 01945 static LRESULT CALLBACK 01946 TaskSwitchWndProc(IN HWND hwnd, 01947 IN UINT uMsg, 01948 IN WPARAM wParam, 01949 IN LPARAM lParam) 01950 { 01951 PTASK_SWITCH_WND This = NULL; 01952 LRESULT Ret = FALSE; 01953 01954 if (uMsg != WM_NCCREATE) 01955 { 01956 This = (PTASK_SWITCH_WND)GetWindowLongPtr(hwnd, 01957 0); 01958 } 01959 01960 if (This != NULL || uMsg == WM_NCCREATE) 01961 { 01962 switch (uMsg) 01963 { 01964 case WM_SIZE: 01965 { 01966 SIZE szClient; 01967 01968 szClient.cx = LOWORD(lParam); 01969 szClient.cy = HIWORD(lParam); 01970 if (This->hWndToolbar != NULL) 01971 { 01972 SetWindowPos(This->hWndToolbar, 01973 NULL, 01974 0, 01975 0, 01976 szClient.cx, 01977 szClient.cy, 01978 SWP_NOZORDER); 01979 01980 TaskSwitchWnd_UpdateButtonsSize(This, 01981 FALSE); 01982 } 01983 break; 01984 } 01985 01986 case WM_NCHITTEST: 01987 { 01988 /* We want the tray window to be draggable everywhere, so make the control 01989 appear transparent */ 01990 Ret = DefWindowProc(hwnd, 01991 uMsg, 01992 wParam, 01993 lParam); 01994 if (Ret != HTVSCROLL && Ret != HTHSCROLL) 01995 Ret = HTTRANSPARENT; 01996 break; 01997 } 01998 01999 case WM_COMMAND: 02000 { 02001 if (lParam != 0 && (HWND)lParam == This->hWndToolbar) 02002 { 02003 TaskSwitchWnd_HandleButtonClick(This, 02004 LOWORD(wParam)); 02005 } 02006 break; 02007 } 02008 02009 case WM_NOTIFY: 02010 { 02011 const NMHDR *nmh = (const NMHDR *)lParam; 02012 02013 if (nmh->hwndFrom == This->hWndToolbar) 02014 { 02015 Ret = TaskSwitchWnd_HandleToolbarNotification(This, 02016 nmh); 02017 } 02018 break; 02019 } 02020 02021 case TSWM_ENABLEGROUPING: 02022 { 02023 Ret = This->IsGroupingEnabled; 02024 if (wParam != This->IsGroupingEnabled) 02025 { 02026 TaskSwitchWnd_EnableGrouping(This, 02027 (BOOL)wParam); 02028 } 02029 break; 02030 } 02031 02032 case TSWM_UPDATETASKBARPOS: 02033 { 02034 /* Update the button spacing */ 02035 TaskSwitchWnd_UpdateTbButtonSpacing(This, 02036 ITrayWindow_IsHorizontal(This->Tray), 02037 0, 02038 0); 02039 break; 02040 } 02041 02042 case WM_CONTEXTMENU: 02043 { 02044 if (This->hWndToolbar != NULL) 02045 { 02046 POINT pt; 02047 INT_PTR iBtn; 02048 02049 pt.x = (LONG)LOWORD(lParam); 02050 pt.y = (LONG)HIWORD(lParam); 02051 02052 MapWindowPoints(NULL, 02053 This->hWndToolbar, 02054 &pt, 02055 1); 02056 02057 iBtn = (INT_PTR)SendMessage(This->hWndToolbar, 02058 TB_HITTEST, 02059 0, 02060 (LPARAM)&pt); 02061 if (iBtn >= 0) 02062 { 02063 TaskSwitchWnd_HandleButtonRightClick(This, 02064 iBtn); 02065 } 02066 else 02067 goto ForwardContextMenuMsg; 02068 } 02069 else 02070 { 02071 ForwardContextMenuMsg: 02072 /* Forward message */ 02073 Ret = SendMessage(ITrayWindow_GetHWND(This->Tray), 02074 uMsg, 02075 wParam, 02076 lParam); 02077 } 02078 break; 02079 } 02080 02081 case WM_NCCREATE: 02082 { 02083 LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam; 02084 This = (PTASK_SWITCH_WND)HeapAlloc(hProcessHeap, 02085 0, 02086 sizeof(*This)); 02087 if (This == NULL) 02088 return FALSE; 02089 02090 ZeroMemory(This, 02091 sizeof(*This)); 02092 This->hWnd = hwnd; 02093 This->hWndNotify = CreateStruct->hwndParent; 02094 This->Tray = (ITrayWindow*)CreateStruct->lpCreateParams; 02095 This->IsGroupingEnabled = TRUE; /* FIXME */ 02096 SetWindowLongPtr(hwnd, 02097 0, 02098 (LONG_PTR)This); 02099 02100 return TRUE; 02101 } 02102 02103 case WM_CREATE: 02104 TaskSwitchWnd_Create(This); 02105 02106 #if DUMP_TASKS != 0 02107 SetTimer(hwnd, 02108 1, 02109 5000, 02110 NULL); 02111 #endif 02112 02113 break; 02114 02115 case WM_DESTROY: 02116 if (This->IsToolbarSubclassed) 02117 { 02118 if (RemoveWindowSubclass(This->hWndToolbar, 02119 TaskSwichWnd_ToolbarSubclassedProc, 02120 TSW_TOOLBAR_SUBCLASS_ID)) 02121 { 02122 This->IsToolbarSubclassed = FALSE; 02123 } 02124 } 02125 break; 02126 02127 case WM_NCDESTROY: 02128 TaskSwitchWnd_NCDestroy(This); 02129 HeapFree(hProcessHeap, 02130 0, 02131 This); 02132 SetWindowLongPtr(hwnd, 02133 0, 02134 0); 02135 break; 02136 02137 #if DUMP_TASKS != 0 02138 case WM_TIMER: 02139 switch(wParam) 02140 { 02141 case 1: 02142 TaskSwitchWnd_DumpTasks(This); 02143 break; 02144 } 02145 break; 02146 #endif 02147 02148 default: 02149 /* HandleDefaultMessage: */ 02150 if (uMsg == This->ShellHookMsg && This->ShellHookMsg != 0) 02151 { 02152 /* Process shell messages */ 02153 Ret = (LRESULT)TaskSwitchWnd_HandleShellHookMsg(This, 02154 wParam, 02155 lParam); 02156 break; 02157 } 02158 02159 Ret = DefWindowProc(hwnd, 02160 uMsg, 02161 wParam, 02162 lParam); 02163 break; 02164 } 02165 } 02166 else 02167 { 02168 Ret = DefWindowProc(hwnd, 02169 uMsg, 02170 wParam, 02171 lParam); 02172 } 02173 02174 return Ret; 02175 } 02176 02177 02178 HWND 02179 CreateTaskSwitchWnd(IN HWND hWndParent, 02180 IN OUT ITrayWindow *Tray) 02181 { 02182 HWND hwndTaskBar; 02183 02184 hwndTaskBar = CreateWindowEx(0, 02185 szTaskSwitchWndClass, 02186 szRunningApps, 02187 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, 02188 0, 02189 0, 02190 0, 02191 0, 02192 hWndParent, 02193 NULL, 02194 hExplorerInstance, 02195 (LPVOID)Tray); 02196 02197 return hwndTaskBar; 02198 } 02199 02200 BOOL 02201 RegisterTaskSwitchWndClass(VOID) 02202 { 02203 WNDCLASS wc; 02204 02205 wc.style = CS_DBLCLKS; 02206 wc.lpfnWndProc = TaskSwitchWndProc; 02207 wc.cbClsExtra = 0; 02208 wc.cbWndExtra = sizeof(PTASK_SWITCH_WND); 02209 wc.hInstance = hExplorerInstance; 02210 wc.hIcon = NULL; 02211 wc.hCursor = LoadCursor(NULL, 02212 IDC_ARROW); 02213 wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); 02214 wc.lpszMenuName = NULL; 02215 wc.lpszClassName = szTaskSwitchWndClass; 02216 02217 return RegisterClass(&wc) != 0; 02218 } 02219 02220 VOID 02221 UnregisterTaskSwitchWndClass(VOID) 02222 { 02223 UnregisterClass(szTaskSwitchWndClass, 02224 hExplorerInstance); 02225 } Generated on Sun May 27 2012 04:18:27 for ReactOS by
1.7.6.1
|