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