ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

taskswnd.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.