1 /*
2  * PROJECT:     ReactOS Task Manager
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Applications Page
5  * COPYRIGHT:   Copyright 1999-2001 Brian Palmer <brianp@reactos.org>
6  *              Copyright 2005 Klemens Friedl <frik85@reactos.at>
7  *              Copyright 2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
8  */
9 
10 #include "precomp.h"
11 
12 typedef struct
13 {
14     HWND    hWnd;
15     WCHAR   szTitle[260];
16     HICON   hIcon;
17     BOOL    bHung;
18 } APPLICATION_PAGE_LIST_ITEM, *LPAPPLICATION_PAGE_LIST_ITEM;
19 
20 HWND            hApplicationPage;               /* Application List Property Page */
21 HWND            hApplicationPageListCtrl;       /* Application ListCtrl Window */
22 HWND            hApplicationPageEndTaskButton;  /* Application End Task button */
23 HWND            hApplicationPageSwitchToButton; /* Application Switch To button */
24 HWND            hApplicationPageNewTaskButton;  /* Application New Task button */
25 static int      nApplicationPageWidth;
26 static int      nApplicationPageHeight;
27 static BOOL     bSortAscending = TRUE;
28 DWORD WINAPI    ApplicationPageRefreshThread(void *lpParameter);
29 BOOL            noApps;
30 BOOL            bApplicationPageSelectionMade = FALSE;
31 
32 BOOL CALLBACK   EnumWindowsProc(HWND hWnd, LPARAM lParam);
33 void            AddOrUpdateHwnd(HWND hWnd, WCHAR *szTitle, HICON hIcon, BOOL bHung);
34 void            ApplicationPageUpdate(void);
35 void            ApplicationPageOnNotify(WPARAM wParam, LPARAM lParam);
36 void            ApplicationPageShowContextMenu1(void);
37 void            ApplicationPageShowContextMenu2(void);
38 int CALLBACK    ApplicationPageCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
39 int             ProcGetIndexByProcessId(DWORD dwProcessId);
40 
41 #ifdef RUN_APPS_PAGE
42 static HANDLE   hApplicationThread = NULL;
43 static DWORD    dwApplicationThread;
44 #endif
45 
46 static INT
GetSystemColorDepth(VOID)47 GetSystemColorDepth(VOID)
48 {
49     DEVMODE pDevMode;
50     INT ColorDepth;
51 
52     pDevMode.dmSize = sizeof(DEVMODE);
53     pDevMode.dmDriverExtra = 0;
54 
55     if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &pDevMode))
56         return ILC_COLOR;
57 
58     switch (pDevMode.dmBitsPerPel)
59     {
60         case 32: ColorDepth = ILC_COLOR32; break;
61         case 24: ColorDepth = ILC_COLOR24; break;
62         case 16: ColorDepth = ILC_COLOR16; break;
63         case  8: ColorDepth = ILC_COLOR8;  break;
64         case  4: ColorDepth = ILC_COLOR4;  break;
65         default: ColorDepth = ILC_COLOR;   break;
66     }
67 
68     return ColorDepth;
69 }
70 
AppPageCleanup(void)71 void AppPageCleanup(void)
72 {
73     int i;
74     LV_ITEM item;
75     LPAPPLICATION_PAGE_LIST_ITEM pData;
76     for (i = 0; i < ListView_GetItemCount(hApplicationPageListCtrl); i++)
77     {
78         memset(&item, 0, sizeof(LV_ITEM));
79         item.mask = LVIF_PARAM;
80         item.iItem = i;
81         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
82         pData = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
83         HeapFree(GetProcessHeap(), 0, pData);
84     }
85 }
86 
87 
88 INT_PTR CALLBACK
ApplicationPageWndProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)89 ApplicationPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
90 {
91     RECT       rc;
92     int        nXDifference;
93     int        nYDifference;
94     LV_COLUMN  column;
95     WCHAR      szTemp[256];
96     int        cx, cy;
97 
98     switch (message) {
99     case WM_INITDIALOG:
100         /* Save the width and height */
101         GetClientRect(hDlg, &rc);
102         nApplicationPageWidth = rc.right;
103         nApplicationPageHeight = rc.bottom;
104 
105         /* Update window position */
106         SetWindowPos(hDlg, NULL, 15, 30, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
107 
108         /* Get handles to the controls */
109         hApplicationPageListCtrl = GetDlgItem(hDlg, IDC_APPLIST);
110         hApplicationPageEndTaskButton = GetDlgItem(hDlg, IDC_ENDTASK);
111         hApplicationPageSwitchToButton = GetDlgItem(hDlg, IDC_SWITCHTO);
112         hApplicationPageNewTaskButton = GetDlgItem(hDlg, IDC_NEWTASK);
113 
114         SetWindowTextW(hApplicationPageListCtrl, L"Tasks");
115 
116         /* Initialize the application page's controls */
117         column.mask = LVCF_TEXT|LVCF_WIDTH;
118 
119         LoadStringW(hInst, IDS_TAB_TASK, szTemp, 256);
120         column.pszText = szTemp;
121         column.cx = 250;
122         (void)ListView_InsertColumn(hApplicationPageListCtrl, 0, &column);    /* Add the "Task" column */
123         column.mask = LVCF_TEXT|LVCF_WIDTH;
124         LoadStringW(hInst, IDS_TAB_STATUS, szTemp, 256);
125         column.pszText = szTemp;
126         column.cx = 95;
127         (void)ListView_InsertColumn(hApplicationPageListCtrl, 1, &column);    /* Add the "Status" column */
128 
129         (void)ListView_SetImageList(hApplicationPageListCtrl, ImageList_Create(16, 16, GetSystemColorDepth()|ILC_MASK, 0, 1), LVSIL_SMALL);
130         (void)ListView_SetImageList(hApplicationPageListCtrl, ImageList_Create(32, 32, GetSystemColorDepth()|ILC_MASK, 0, 1), LVSIL_NORMAL);
131 
132         UpdateApplicationListControlViewSetting();
133 
134         /* Start our refresh thread */
135 #ifdef RUN_APPS_PAGE
136         hApplicationThread = CreateThread(NULL, 0, ApplicationPageRefreshThread, NULL, 0, &dwApplicationThread);
137 #endif
138 
139         /* Refresh page */
140         ApplicationPageUpdate();
141 
142         return TRUE;
143 
144     case WM_DESTROY:
145         /* Close refresh thread */
146 #ifdef RUN_APPS_PAGE
147         EndLocalThread(&hApplicationThread, dwApplicationThread);
148 #endif
149         AppPageCleanup();
150         break;
151 
152     case WM_COMMAND:
153         /* Handle the button clicks */
154         switch (LOWORD(wParam))
155         {
156         case IDC_ENDTASK:
157             ApplicationPage_OnEndTask();
158             break;
159         case IDC_SWITCHTO:
160             ApplicationPage_OnSwitchTo();
161             break;
162         case IDC_NEWTASK:
163             SendMessageW(hMainWnd, WM_COMMAND, MAKEWPARAM(ID_FILE_NEW, 0), 0);
164             break;
165         }
166 
167         break;
168 
169     case WM_SIZE:
170         if (wParam == SIZE_MINIMIZED)
171             return 0;
172 
173         cx = LOWORD(lParam);
174         cy = HIWORD(lParam);
175         nXDifference = cx - nApplicationPageWidth;
176         nYDifference = cy - nApplicationPageHeight;
177         nApplicationPageWidth = cx;
178         nApplicationPageHeight = cy;
179 
180         /* Reposition the application page's controls */
181         GetWindowRect(hApplicationPageListCtrl, &rc);
182         cx = (rc.right - rc.left) + nXDifference;
183         cy = (rc.bottom - rc.top) + nYDifference;
184         SetWindowPos(hApplicationPageListCtrl, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
185         InvalidateRect(hApplicationPageListCtrl, NULL, TRUE);
186 
187         GetClientRect(hApplicationPageEndTaskButton, &rc);
188         MapWindowPoints(hApplicationPageEndTaskButton, hDlg, (LPPOINT)(PRECT)(&rc), sizeof(RECT)/sizeof(POINT));
189         cx = rc.left + nXDifference;
190         cy = rc.top + nYDifference;
191         SetWindowPos(hApplicationPageEndTaskButton, NULL, cx, cy, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
192         InvalidateRect(hApplicationPageEndTaskButton, NULL, TRUE);
193 
194         GetClientRect(hApplicationPageSwitchToButton, &rc);
195         MapWindowPoints(hApplicationPageSwitchToButton, hDlg, (LPPOINT)(PRECT)(&rc), sizeof(RECT)/sizeof(POINT));
196         cx = rc.left + nXDifference;
197         cy = rc.top + nYDifference;
198         SetWindowPos(hApplicationPageSwitchToButton, NULL, cx, cy, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
199         InvalidateRect(hApplicationPageSwitchToButton, NULL, TRUE);
200 
201         GetClientRect(hApplicationPageNewTaskButton, &rc);
202         MapWindowPoints(hApplicationPageNewTaskButton, hDlg, (LPPOINT)(PRECT)(&rc), sizeof(RECT)/sizeof(POINT));
203         cx = rc.left + nXDifference;
204         cy = rc.top + nYDifference;
205         SetWindowPos(hApplicationPageNewTaskButton, NULL, cx, cy, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
206         InvalidateRect(hApplicationPageNewTaskButton, NULL, TRUE);
207 
208         break;
209 
210     case WM_NOTIFY:
211         ApplicationPageOnNotify(wParam, lParam);
212         break;
213 
214     case WM_KEYDOWN:
215         if (wParam == VK_DELETE)
216             ProcessPage_OnEndProcess();
217         break;
218     }
219 
220     return 0;
221 }
222 
RefreshApplicationPage(void)223 void RefreshApplicationPage(void)
224 {
225 #ifdef RUN_APPS_PAGE
226     /* Signal the event so that our refresh thread
227      * will wake up and refresh the application page */
228     PostThreadMessage(dwApplicationThread, WM_TIMER, 0, 0);
229 #endif
230 }
231 
UpdateApplicationListControlViewSetting(void)232 void UpdateApplicationListControlViewSetting(void)
233 {
234     DWORD  dwStyle = GetWindowLongPtrW(hApplicationPageListCtrl, GWL_STYLE);
235 
236     dwStyle &= ~(LVS_REPORT | LVS_ICON | LVS_LIST | LVS_SMALLICON);
237 
238     switch (TaskManagerSettings.ViewMode) {
239     case ID_VIEW_LARGE:   dwStyle |= LVS_ICON; break;
240     case ID_VIEW_SMALL:   dwStyle |= LVS_SMALLICON; break;
241     case ID_VIEW_DETAILS: dwStyle |= LVS_REPORT; break;
242     }
243     SetWindowLongPtrW(hApplicationPageListCtrl, GWL_STYLE, dwStyle);
244 
245     RefreshApplicationPage();
246 }
247 
ApplicationPageRefreshThread(void * lpParameter)248 DWORD WINAPI ApplicationPageRefreshThread(void *lpParameter)
249 {
250     MSG msg;
251     INT i;
252     BOOL                            bItemRemoved = FALSE;
253     LV_ITEM                         item;
254     LPAPPLICATION_PAGE_LIST_ITEM    pAPLI = NULL;
255     HIMAGELIST                      hImageListLarge;
256     HIMAGELIST                      hImageListSmall;
257 
258     /* If we couldn't create the event then exit the thread */
259     while (1)
260     {
261         /*  Wait for an the event or application close */
262         if (GetMessage(&msg, NULL, 0, 0) <= 0)
263             return 0;
264 
265         if (msg.message == WM_TIMER)
266         {
267              // FIXME: Should this be EnumDesktopWindows() instead?
268             noApps = TRUE;
269             EnumWindows(EnumWindowsProc, 0);
270             if (noApps)
271             {
272                 (void)ListView_DeleteAllItems(hApplicationPageListCtrl);
273                 bApplicationPageSelectionMade = FALSE;
274             }
275 
276             /* Get the image lists */
277             hImageListLarge = ListView_GetImageList(hApplicationPageListCtrl, LVSIL_NORMAL);
278             hImageListSmall = ListView_GetImageList(hApplicationPageListCtrl, LVSIL_SMALL);
279 
280             /* Check to see if we need to remove any items from the list */
281             for (i=ListView_GetItemCount(hApplicationPageListCtrl)-1; i>=0; i--)
282             {
283                 memset(&item, 0, sizeof(LV_ITEM));
284                 item.mask = LVIF_IMAGE|LVIF_PARAM;
285                 item.iItem = i;
286                 (void)ListView_GetItem(hApplicationPageListCtrl, &item);
287 
288                 pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
289                 if (!IsWindow(pAPLI->hWnd)||
290                     (wcslen(pAPLI->szTitle) <= 0) ||
291                     !IsWindowVisible(pAPLI->hWnd) ||
292                     (GetParent(pAPLI->hWnd) != NULL) ||
293                     (GetWindow(pAPLI->hWnd, GW_OWNER) != NULL) ||
294                     (GetWindowLongPtr(pAPLI->hWnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
295                 {
296                     ImageList_Remove(hImageListLarge, item.iItem);
297                     ImageList_Remove(hImageListSmall, item.iItem);
298 
299                     (void)ListView_DeleteItem(hApplicationPageListCtrl, item.iItem);
300                     HeapFree(GetProcessHeap(), 0, pAPLI);
301                     bItemRemoved = TRUE;
302                 }
303             }
304 
305             /*
306              * If an item was removed from the list then
307              * we need to resync all the items with the
308              * image list
309              */
310             if (bItemRemoved)
311             {
312                 for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++)
313                 {
314                     memset(&item, 0, sizeof(LV_ITEM));
315                     item.mask = LVIF_IMAGE;
316                     item.iItem = i;
317                     item.iImage = i;
318                     (void)ListView_SetItem(hApplicationPageListCtrl, &item);
319                 }
320                 bItemRemoved = FALSE;
321             }
322 
323             ApplicationPageUpdate();
324         }
325     }
326 }
327 
EnumWindowsProc(HWND hWnd,LPARAM lParam)328 BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
329 {
330     HICON   hIcon;
331     WCHAR   szText[260];
332     BOOL    bLargeIcon;
333     BOOL    bHung = FALSE;
334     LRESULT bAlive;
335 
336     typedef int (FAR __stdcall *IsHungAppWindowProc)(HWND);
337     IsHungAppWindowProc IsHungAppWindow;
338 
339     /* Skip our window */
340     if (hWnd == hMainWnd)
341         return TRUE;
342 
343     bLargeIcon = (TaskManagerSettings.ViewMode == ID_VIEW_LARGE);
344 
345     GetWindowTextW(hWnd, szText, 260); /* Get the window text */
346 
347     /* Check and see if this is a top-level app window */
348     if ((wcslen(szText) <= 0) ||
349         !IsWindowVisible(hWnd) ||
350         (GetParent(hWnd) != NULL) ||
351         (GetWindow(hWnd, GW_OWNER) != NULL) ||
352         (GetWindowLongPtrW(hWnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
353     {
354         return TRUE; /* Skip this window */
355     }
356 
357     noApps = FALSE;
358 
359 #define GET_ICON(type) \
360     SendMessageTimeoutW(hWnd, WM_GETICON, (type), 0, SMTO_ABORTIFHUNG, 100, (PDWORD_PTR)&hIcon)
361 
362     /* Get the icon for this window */
363     hIcon = NULL;
364     bAlive = GET_ICON(bLargeIcon ? ICON_BIG : ICON_SMALL);
365     if (!hIcon)
366     {
367         /* We failed, try to retrieve other icons... */
368         if (!hIcon && bAlive)
369             GET_ICON(bLargeIcon ? ICON_SMALL : ICON_BIG);
370         if (!hIcon)
371             hIcon = (HICON)(LONG_PTR)GetClassLongPtrW(hWnd, bLargeIcon ? GCL_HICON : GCL_HICONSM);
372         if (!hIcon)
373             hIcon = (HICON)(LONG_PTR)GetClassLongPtrW(hWnd, bLargeIcon ? GCL_HICONSM : GCL_HICON);
374 
375         /* If we still do not have any icon, load the default one */
376         if (!hIcon) hIcon = LoadIconW(hInst, bLargeIcon ? MAKEINTRESOURCEW(IDI_WINDOW) : MAKEINTRESOURCEW(IDI_WINDOWSM));
377     }
378 #undef GET_ICON
379 
380     bHung = FALSE;
381 
382     IsHungAppWindow = (IsHungAppWindowProc)(FARPROC)GetProcAddress(GetModuleHandleW(L"USER32.DLL"), "IsHungAppWindow");
383 
384     if (IsHungAppWindow)
385         bHung = IsHungAppWindow(hWnd);
386 
387     AddOrUpdateHwnd(hWnd, szText, hIcon, bHung);
388 
389     return TRUE;
390 }
391 
AddOrUpdateHwnd(HWND hWnd,WCHAR * szTitle,HICON hIcon,BOOL bHung)392 void AddOrUpdateHwnd(HWND hWnd, WCHAR *szTitle, HICON hIcon, BOOL bHung)
393 {
394     LPAPPLICATION_PAGE_LIST_ITEM    pAPLI = NULL;
395     HIMAGELIST                      hImageListLarge;
396     HIMAGELIST                      hImageListSmall;
397     LV_ITEM                         item;
398     int                             i;
399     BOOL                            bAlreadyInList = FALSE;
400 
401     memset(&item, 0, sizeof(LV_ITEM));
402 
403     /* Get the image lists */
404     hImageListLarge = ListView_GetImageList(hApplicationPageListCtrl, LVSIL_NORMAL);
405     hImageListSmall = ListView_GetImageList(hApplicationPageListCtrl, LVSIL_SMALL);
406 
407     /* Check to see if it's already in our list */
408     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++)
409     {
410         memset(&item, 0, sizeof(LV_ITEM));
411         item.mask = LVIF_IMAGE|LVIF_PARAM;
412         item.iItem = i;
413         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
414 
415         pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
416         if (pAPLI->hWnd == hWnd)
417         {
418             bAlreadyInList = TRUE;
419             break;
420         }
421     }
422 
423     /* If it is already in the list then update it if necessary */
424     if (bAlreadyInList)
425     {
426         /* Check to see if anything needs updating */
427         if ((pAPLI->hIcon != hIcon) ||
428             (_wcsicmp(pAPLI->szTitle, szTitle) != 0) ||
429             (pAPLI->bHung != bHung))
430         {
431             /* Update the structure */
432             pAPLI->hIcon = hIcon;
433             pAPLI->bHung = bHung;
434             wcscpy(pAPLI->szTitle, szTitle);
435 
436             /* Update the image list */
437             ImageList_ReplaceIcon(hImageListLarge, item.iItem, hIcon);
438             ImageList_ReplaceIcon(hImageListSmall, item.iItem, hIcon);
439 
440             /* Update the list view */
441             (void)ListView_RedrawItems(hApplicationPageListCtrl, 0, ListView_GetItemCount(hApplicationPageListCtrl));
442             /* UpdateWindow(hApplicationPageListCtrl); */
443             InvalidateRect(hApplicationPageListCtrl, NULL, 0);
444         }
445     }
446     else
447     { // It is not already in the list so add it
448         pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)HeapAlloc(GetProcessHeap(), 0, sizeof(APPLICATION_PAGE_LIST_ITEM));
449 
450         pAPLI->hWnd = hWnd;
451         pAPLI->hIcon = hIcon;
452         pAPLI->bHung = bHung;
453         wcscpy(pAPLI->szTitle, szTitle);
454 
455         /* Add the item to the list */
456         memset(&item, 0, sizeof(LV_ITEM));
457         item.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
458         ImageList_AddIcon(hImageListLarge, hIcon);
459         item.iImage = ImageList_AddIcon(hImageListSmall, hIcon);
460         item.pszText = LPSTR_TEXTCALLBACK;
461         item.iItem = ListView_GetItemCount(hApplicationPageListCtrl);
462         item.lParam = (LPARAM)pAPLI;
463         (void)ListView_InsertItem(hApplicationPageListCtrl, &item);
464     }
465 
466     /* Select first item if any */
467     if ((ListView_GetNextItem(hApplicationPageListCtrl, -1, LVNI_FOCUSED | LVNI_SELECTED) == -1) &&
468         (ListView_GetItemCount(hApplicationPageListCtrl) > 0) && !bApplicationPageSelectionMade)
469     {
470         ListView_SetItemState(hApplicationPageListCtrl, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
471         bApplicationPageSelectionMade = TRUE;
472     }
473 }
474 
ApplicationPageUpdate(void)475 void ApplicationPageUpdate(void)
476 {
477     /* Enable or disable the "End Task" & "Switch To" buttons */
478     if (ListView_GetSelectedCount(hApplicationPageListCtrl))
479         EnableWindow(hApplicationPageEndTaskButton, TRUE);
480     else
481         EnableWindow(hApplicationPageEndTaskButton, FALSE);
482 
483     /* Enable "Switch To" button only if only one app is selected */
484     EnableWindow(hApplicationPageSwitchToButton, (ListView_GetSelectedCount(hApplicationPageListCtrl) == 1));
485 
486     /* If we are on the applications tab the windows menu will be */
487     /* present on the menu bar so enable & disable the menu items */
488     if (TabCtrl_GetCurSel(hTabWnd) == 0)
489     {
490         HMENU  hMenu;
491         HMENU  hWindowsMenu;
492 
493         hMenu = GetMenu(hMainWnd);
494         hWindowsMenu = GetSubMenu(hMenu, 3);
495 
496         if (ListView_GetSelectedCount(hApplicationPageListCtrl) == 1)
497         { // Only one item selected
498             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
499             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
500             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
501             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
502             EnableMenuItem(hWindowsMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
503             EnableMenuItem(hWindowsMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_ENABLED);
504         }
505         else if (ListView_GetSelectedCount(hApplicationPageListCtrl) > 1)
506         { // More than one item selected
507             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_ENABLED);
508             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_ENABLED);
509             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
510             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
511             EnableMenuItem(hWindowsMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_ENABLED);
512             EnableMenuItem(hWindowsMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
513         }
514         else
515         { // No items selected
516             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
517             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
518             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
519             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
520             EnableMenuItem(hWindowsMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
521             EnableMenuItem(hWindowsMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
522         }
523     }
524 }
525 
ApplicationPageOnNotify(WPARAM wParam,LPARAM lParam)526 void ApplicationPageOnNotify(WPARAM wParam, LPARAM lParam)
527 {
528     LPNMHDR                       pnmh;
529     LV_DISPINFO*                  pnmdi;
530     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI;
531     WCHAR                         szMsg[256];
532 
533     pnmh = (LPNMHDR) lParam;
534     pnmdi = (LV_DISPINFO*) lParam;
535 
536     if (pnmh->hwndFrom == hApplicationPageListCtrl) {
537         switch (pnmh->code) {
538         case LVN_ITEMCHANGED:
539             ApplicationPageUpdate();
540             break;
541 
542         case LVN_GETDISPINFO:
543             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)pnmdi->item.lParam;
544 
545             /* Update the item text */
546             if (pnmdi->item.iSubItem == 0)
547                 wcsncpy(pnmdi->item.pszText, pAPLI->szTitle, pnmdi->item.cchTextMax);
548 
549             /* Update the item status */
550             else if (pnmdi->item.iSubItem == 1)
551             {
552                 if (pAPLI->bHung)
553                     LoadStringW(GetModuleHandleW(NULL), IDS_NOT_RESPONDING , szMsg, _countof(szMsg));
554                 else
555                     LoadStringW(GetModuleHandleW(NULL), IDS_RUNNING, (LPWSTR) szMsg, _countof(szMsg));
556                 wcsncpy(pnmdi->item.pszText, szMsg, pnmdi->item.cchTextMax);
557             }
558 
559             break;
560 
561         case NM_RCLICK:
562             if (ListView_GetSelectedCount(hApplicationPageListCtrl) < 1)
563                 ApplicationPageShowContextMenu1();
564             else
565                 ApplicationPageShowContextMenu2();
566             break;
567 
568         case NM_DBLCLK:
569             ApplicationPage_OnSwitchTo();
570             break;
571 
572         case LVN_KEYDOWN:
573             if (((LPNMLVKEYDOWN)lParam)->wVKey == VK_DELETE)
574                 ApplicationPage_OnEndTask();
575             break;
576         }
577     }
578     else if (pnmh->hwndFrom == ListView_GetHeader(hApplicationPageListCtrl))
579     {
580         switch (pnmh->code)
581         {
582         case NM_RCLICK:
583             if (ListView_GetSelectedCount(hApplicationPageListCtrl) < 1)
584                 ApplicationPageShowContextMenu1();
585             else
586                 ApplicationPageShowContextMenu2();
587             break;
588 
589         case HDN_ITEMCLICK:
590             (void)ListView_SortItems(hApplicationPageListCtrl, ApplicationPageCompareFunc, 0);
591             bSortAscending = !bSortAscending;
592             break;
593         }
594     }
595 }
596 
ApplicationPageShowContextMenu1(void)597 void ApplicationPageShowContextMenu1(void)
598 {
599     HMENU  hMenu;
600     HMENU  hSubMenu;
601     POINT  pt;
602 
603     GetCursorPos(&pt);
604 
605     hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_APPLICATION_PAGE_CONTEXT1));
606     hSubMenu = GetSubMenu(hMenu, 0);
607 
608     CheckMenuRadioItem(hSubMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, TaskManagerSettings.ViewMode, MF_BYCOMMAND);
609 
610     TrackPopupMenu(hSubMenu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON, pt.x, pt.y, 0, hMainWnd, NULL);
611 
612     DestroyMenu(hMenu);
613 }
614 
ApplicationPageShowContextMenu2(void)615 void ApplicationPageShowContextMenu2(void)
616 {
617     HMENU  hMenu;
618     HMENU  hSubMenu;
619     POINT  pt;
620 
621     GetCursorPos(&pt);
622 
623     hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_APPLICATION_PAGE_CONTEXT2));
624     hSubMenu = GetSubMenu(hMenu, 0);
625 
626     if (ListView_GetSelectedCount(hApplicationPageListCtrl) == 1)
627     {
628         EnableMenuItem(hSubMenu, ID_APPLICATION_PAGE_SWITCHTO, MF_BYCOMMAND|MF_ENABLED);
629         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
630         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
631         EnableMenuItem(hSubMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
632         EnableMenuItem(hSubMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
633         EnableMenuItem(hSubMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
634         EnableMenuItem(hSubMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_ENABLED);
635     }
636     else if (ListView_GetSelectedCount(hApplicationPageListCtrl) > 1)
637     {
638         EnableMenuItem(hSubMenu, ID_APPLICATION_PAGE_SWITCHTO, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
639         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_ENABLED);
640         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_ENABLED);
641         EnableMenuItem(hSubMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
642         EnableMenuItem(hSubMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
643         EnableMenuItem(hSubMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_ENABLED);
644         EnableMenuItem(hSubMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
645     }
646     else
647     {
648         EnableMenuItem(hSubMenu, ID_APPLICATION_PAGE_SWITCHTO, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
649         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
650         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
651         EnableMenuItem(hSubMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
652         EnableMenuItem(hSubMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
653         EnableMenuItem(hSubMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
654         EnableMenuItem(hSubMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
655     }
656 
657     SetMenuDefaultItem(hSubMenu, ID_APPLICATION_PAGE_SWITCHTO, MF_BYCOMMAND);
658 
659     TrackPopupMenu(hSubMenu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON, pt.x, pt.y, 0, hMainWnd, NULL);
660 
661     DestroyMenu(hMenu);
662 }
663 
ApplicationPage_OnView(DWORD dwMode)664 void ApplicationPage_OnView(DWORD dwMode)
665 {
666     HMENU  hMenu;
667     HMENU  hViewMenu;
668 
669     hMenu = GetMenu(hMainWnd);
670     hViewMenu = GetSubMenu(hMenu, 2);
671 
672     TaskManagerSettings.ViewMode = dwMode;
673     CheckMenuRadioItem(hViewMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, dwMode, MF_BYCOMMAND);
674 
675     UpdateApplicationListControlViewSetting();
676 }
677 
ApplicationPage_OnWindowsTile(DWORD dwMode)678 void ApplicationPage_OnWindowsTile(DWORD dwMode)
679 {
680     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
681     LV_ITEM                       item;
682     int                           i;
683     HWND*                         hWndArray;
684     int                           nWndCount;
685 
686     hWndArray = (HWND*)HeapAlloc(GetProcessHeap(), 0, sizeof(HWND) * ListView_GetItemCount(hApplicationPageListCtrl));
687     nWndCount = 0;
688 
689     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
690         memset(&item, 0, sizeof(LV_ITEM));
691         item.mask = LVIF_STATE|LVIF_PARAM;
692         item.iItem = i;
693         item.stateMask = (UINT)-1;
694         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
695 
696         if (item.state & LVIS_SELECTED) {
697             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
698             if (pAPLI) {
699                 hWndArray[nWndCount] = pAPLI->hWnd;
700                 nWndCount++;
701             }
702         }
703     }
704 
705     TileWindows(NULL, dwMode, NULL, nWndCount, hWndArray);
706     HeapFree(GetProcessHeap(), 0, hWndArray);
707 }
708 
ApplicationPage_OnWindowsMinimize(void)709 void ApplicationPage_OnWindowsMinimize(void)
710 {
711     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
712     LV_ITEM                       item;
713     int                           i;
714 
715     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
716         memset(&item, 0, sizeof(LV_ITEM));
717         item.mask = LVIF_STATE|LVIF_PARAM;
718         item.iItem = i;
719         item.stateMask = (UINT)-1;
720         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
721         if (item.state & LVIS_SELECTED) {
722             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
723             if (pAPLI) {
724                 ShowWindowAsync(pAPLI->hWnd, SW_MINIMIZE);
725             }
726         }
727     }
728 }
729 
ApplicationPage_OnWindowsMaximize(void)730 void ApplicationPage_OnWindowsMaximize(void)
731 {
732     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
733     LV_ITEM                       item;
734     int                           i;
735 
736     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
737         memset(&item, 0, sizeof(LV_ITEM));
738         item.mask = LVIF_STATE|LVIF_PARAM;
739         item.iItem = i;
740         item.stateMask = (UINT)-1;
741         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
742         if (item.state & LVIS_SELECTED) {
743             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
744             if (pAPLI) {
745                 ShowWindowAsync(pAPLI->hWnd, SW_MAXIMIZE);
746             }
747         }
748     }
749 }
750 
ApplicationPage_OnWindowsCascade(void)751 void ApplicationPage_OnWindowsCascade(void)
752 {
753     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
754     LV_ITEM                       item;
755     int                           i;
756     HWND*                         hWndArray;
757     int                           nWndCount;
758 
759     hWndArray = (HWND*)HeapAlloc(GetProcessHeap(), 0, sizeof(HWND) * ListView_GetItemCount(hApplicationPageListCtrl));
760     nWndCount = 0;
761 
762     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
763         memset(&item, 0, sizeof(LV_ITEM));
764         item.mask = LVIF_STATE|LVIF_PARAM;
765         item.iItem = i;
766         item.stateMask = (UINT)-1;
767         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
768         if (item.state & LVIS_SELECTED) {
769             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
770             if (pAPLI) {
771                 hWndArray[nWndCount] = pAPLI->hWnd;
772                 nWndCount++;
773             }
774         }
775     }
776     CascadeWindows(NULL, 0, NULL, nWndCount, hWndArray);
777     HeapFree(GetProcessHeap(), 0, hWndArray);
778 }
779 
ApplicationPage_OnWindowsBringToFront(void)780 void ApplicationPage_OnWindowsBringToFront(void)
781 {
782     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
783     LV_ITEM                       item;
784     int                           i;
785 
786     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
787         memset(&item, 0, sizeof(LV_ITEM));
788         item.mask = LVIF_STATE|LVIF_PARAM;
789         item.iItem = i;
790         item.stateMask = (UINT)-1;
791         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
792         if (item.state & LVIS_SELECTED) {
793             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
794             break;
795         }
796     }
797     if (pAPLI) {
798         SwitchToThisWindow(pAPLI->hWnd, TRUE);
799     }
800 }
801 
ApplicationPage_OnSwitchTo(void)802 void ApplicationPage_OnSwitchTo(void)
803 {
804     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
805     LV_ITEM                       item;
806     int                           i;
807 
808     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
809         memset(&item, 0, sizeof(LV_ITEM));
810         item.mask = LVIF_STATE|LVIF_PARAM;
811         item.iItem = i;
812         item.stateMask = (UINT)-1;
813         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
814 
815         if (item.state & LVIS_SELECTED) {
816             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
817             break;
818         }
819     }
820     if (pAPLI) {
821         SwitchToThisWindow(pAPLI->hWnd, TRUE);
822         if (TaskManagerSettings.MinimizeOnUse)
823             ShowWindowAsync(hMainWnd, SW_MINIMIZE);
824     }
825 }
826 
ApplicationPage_OnEndTask(void)827 void ApplicationPage_OnEndTask(void)
828 {
829     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
830     LV_ITEM                       item;
831     int                           i;
832 
833     /* Trick: on Windows, pressing the CTRL key forces the task to be ended */
834     BOOL ForceEndTask = !!(GetKeyState(VK_CONTROL) & 0x8000);
835 
836     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
837         memset(&item, 0, sizeof(LV_ITEM));
838         item.mask = LVIF_STATE|LVIF_PARAM;
839         item.iItem = i;
840         item.stateMask = (UINT)-1;
841         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
842         if (item.state & LVIS_SELECTED) {
843             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
844             if (pAPLI) {
845                 EndTask(pAPLI->hWnd, 0, ForceEndTask);
846             }
847         }
848     }
849 }
850 
ApplicationPage_OnGotoProcess(void)851 void ApplicationPage_OnGotoProcess(void)
852 {
853     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
854     LV_ITEM                       item;
855     int                           i;
856 
857     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
858         memset(&item, 0, sizeof(LV_ITEM));
859         item.mask = LVIF_STATE|LVIF_PARAM;
860         item.iItem = i;
861         item.stateMask = (UINT)-1;
862         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
863         if (item.state & LVIS_SELECTED) {
864             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
865             break;
866         }
867     }
868     if (pAPLI) {
869         DWORD   dwProcessId;
870 
871         GetWindowThreadProcessId(pAPLI->hWnd, &dwProcessId);
872         /*
873          * Switch to the process tab
874          */
875         TabCtrl_SetCurFocus(hTabWnd, 1);
876         /*
877          * Select the process item in the list
878          */
879         i = ProcGetIndexByProcessId(dwProcessId);
880         if (i != -1)
881         {
882             ListView_SetItemState(hProcessPageListCtrl,
883                                   i,
884                                   LVIS_SELECTED | LVIS_FOCUSED,
885                                   LVIS_SELECTED | LVIS_FOCUSED);
886             (void)ListView_EnsureVisible(hProcessPageListCtrl, i, FALSE);
887         }
888     }
889 }
890 
ApplicationPageCompareFunc(LPARAM lParam1,LPARAM lParam2,LPARAM lParamSort)891 int CALLBACK ApplicationPageCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
892 {
893     LPAPPLICATION_PAGE_LIST_ITEM  Param1;
894     LPAPPLICATION_PAGE_LIST_ITEM  Param2;
895 
896     if (bSortAscending) {
897         Param1 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam1;
898         Param2 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam2;
899     } else {
900         Param1 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam2;
901         Param2 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam1;
902     }
903     return wcscmp(Param1->szTitle, Param2->szTitle);
904 }
905