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 only one app is selected */
516     EnableWindow(hApplicationPageSwitchToButton, (ListView_GetSelectedCount(hApplicationPageListCtrl) == 1));
517 
518     /* If we are on the applications tab the windows menu will be */
519     /* present on the menu bar so enable & disable the menu items */
520     if (TabCtrl_GetCurSel(hTabWnd) == 0)
521     {
522         HMENU  hMenu;
523         HMENU  hWindowsMenu;
524 
525         hMenu = GetMenu(hMainWnd);
526         hWindowsMenu = GetSubMenu(hMenu, 3);
527 
528         /* Only one item selected */
529         if (ListView_GetSelectedCount(hApplicationPageListCtrl) == 1)
530         {
531             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
532             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
533             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
534             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
535             EnableMenuItem(hWindowsMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
536             EnableMenuItem(hWindowsMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_ENABLED);
537         }
538         /* More than one item selected */
539         else if (ListView_GetSelectedCount(hApplicationPageListCtrl) > 1)
540         {
541             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_ENABLED);
542             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_ENABLED);
543             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
544             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
545             EnableMenuItem(hWindowsMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_ENABLED);
546             EnableMenuItem(hWindowsMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
547         }
548         /* No items selected */
549         else
550         {
551             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
552             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
553             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
554             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
555             EnableMenuItem(hWindowsMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
556             EnableMenuItem(hWindowsMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
557         }
558     }
559 }
560 
561 void ApplicationPageOnNotify(WPARAM wParam, LPARAM lParam)
562 {
563     LPNMHDR                       pnmh;
564     LV_DISPINFO*                  pnmdi;
565     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI;
566     WCHAR                         szMsg[256];
567 
568     pnmh = (LPNMHDR) lParam;
569     pnmdi = (LV_DISPINFO*) lParam;
570 
571     if (pnmh->hwndFrom == hApplicationPageListCtrl) {
572         switch (pnmh->code) {
573         case LVN_ITEMCHANGED:
574             ApplicationPageUpdate();
575             break;
576 
577         case LVN_GETDISPINFO:
578             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)pnmdi->item.lParam;
579 
580             /* Update the item text */
581             if (pnmdi->item.iSubItem == 0)
582             {
583                 wcsncpy(pnmdi->item.pszText, pAPLI->szTitle, pnmdi->item.cchTextMax);
584             }
585 
586             /* Update the item status */
587             else if (pnmdi->item.iSubItem == 1)
588             {
589                 if (pAPLI->bHung)
590                 {
591                     LoadStringW( GetModuleHandleW(NULL), IDS_NOT_RESPONDING , szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
592                 }
593                 else
594                 {
595                     LoadStringW( GetModuleHandleW(NULL), IDS_RUNNING, (LPWSTR) szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
596                 }
597                 wcsncpy(pnmdi->item.pszText, szMsg, pnmdi->item.cchTextMax);
598             }
599 
600             break;
601 
602         case NM_RCLICK:
603 
604             if (ListView_GetSelectedCount(hApplicationPageListCtrl) < 1)
605             {
606                 ApplicationPageShowContextMenu1();
607             }
608             else
609             {
610                 ApplicationPageShowContextMenu2();
611             }
612 
613             break;
614 
615         case NM_DBLCLK:
616 
617             ApplicationPage_OnSwitchTo();
618 
619             break;
620 
621         case LVN_KEYDOWN:
622 
623             if (((LPNMLVKEYDOWN)lParam)->wVKey == VK_DELETE)
624                 ApplicationPage_OnEndTask();
625 
626             break;
627 
628         }
629     }
630     else if (pnmh->hwndFrom == ListView_GetHeader(hApplicationPageListCtrl))
631     {
632         switch (pnmh->code)
633         {
634         case NM_RCLICK:
635 
636             if (ListView_GetSelectedCount(hApplicationPageListCtrl) < 1)
637             {
638                 ApplicationPageShowContextMenu1();
639             }
640             else
641             {
642                 ApplicationPageShowContextMenu2();
643             }
644 
645             break;
646 
647         case HDN_ITEMCLICK:
648 
649             (void)ListView_SortItems(hApplicationPageListCtrl, ApplicationPageCompareFunc, 0);
650             bSortAscending = !bSortAscending;
651 
652             break;
653         }
654     }
655 
656 }
657 
658 void ApplicationPageShowContextMenu1(void)
659 {
660     HMENU  hMenu;
661     HMENU  hSubMenu;
662     POINT  pt;
663 
664     GetCursorPos(&pt);
665 
666     hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_APPLICATION_PAGE_CONTEXT1));
667     hSubMenu = GetSubMenu(hMenu, 0);
668 
669     CheckMenuRadioItem(hSubMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, TaskManagerSettings.ViewMode, MF_BYCOMMAND);
670 
671     TrackPopupMenu(hSubMenu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON, pt.x, pt.y, 0, hMainWnd, NULL);
672 
673     DestroyMenu(hMenu);
674 }
675 
676 void ApplicationPageShowContextMenu2(void)
677 {
678     HMENU  hMenu;
679     HMENU  hSubMenu;
680     POINT  pt;
681 
682     GetCursorPos(&pt);
683 
684     hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_APPLICATION_PAGE_CONTEXT2));
685     hSubMenu = GetSubMenu(hMenu, 0);
686 
687     if (ListView_GetSelectedCount(hApplicationPageListCtrl) == 1)
688     {
689         EnableMenuItem(hSubMenu, ID_APPLICATION_PAGE_SWITCHTO, MF_BYCOMMAND|MF_ENABLED);
690         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
691         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
692         EnableMenuItem(hSubMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
693         EnableMenuItem(hSubMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
694         EnableMenuItem(hSubMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
695         EnableMenuItem(hSubMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_ENABLED);
696     }
697     else if (ListView_GetSelectedCount(hApplicationPageListCtrl) > 1)
698     {
699         EnableMenuItem(hSubMenu, ID_APPLICATION_PAGE_SWITCHTO, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
700         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_ENABLED);
701         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_ENABLED);
702         EnableMenuItem(hSubMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
703         EnableMenuItem(hSubMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
704         EnableMenuItem(hSubMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_ENABLED);
705         EnableMenuItem(hSubMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
706     }
707     else
708     {
709         EnableMenuItem(hSubMenu, ID_APPLICATION_PAGE_SWITCHTO, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
710         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
711         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
712         EnableMenuItem(hSubMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
713         EnableMenuItem(hSubMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
714         EnableMenuItem(hSubMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
715         EnableMenuItem(hSubMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
716     }
717 
718     SetMenuDefaultItem(hSubMenu, ID_APPLICATION_PAGE_SWITCHTO, MF_BYCOMMAND);
719 
720     TrackPopupMenu(hSubMenu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON, pt.x, pt.y, 0, hMainWnd, NULL);
721 
722     DestroyMenu(hMenu);
723 }
724 
725 void ApplicationPage_OnView(DWORD dwMode)
726 {
727     HMENU  hMenu;
728     HMENU  hViewMenu;
729 
730     hMenu = GetMenu(hMainWnd);
731     hViewMenu = GetSubMenu(hMenu, 2);
732 
733     TaskManagerSettings.ViewMode = dwMode;
734     CheckMenuRadioItem(hViewMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, dwMode, MF_BYCOMMAND);
735 
736     UpdateApplicationListControlViewSetting();
737 }
738 
739 void ApplicationPage_OnWindowsTile(DWORD dwMode)
740 {
741     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
742     LV_ITEM                       item;
743     int                           i;
744     HWND*                         hWndArray;
745     int                           nWndCount;
746 
747     hWndArray = (HWND*)HeapAlloc(GetProcessHeap(), 0, sizeof(HWND) * ListView_GetItemCount(hApplicationPageListCtrl));
748     nWndCount = 0;
749 
750     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
751         memset(&item, 0, sizeof(LV_ITEM));
752         item.mask = LVIF_STATE|LVIF_PARAM;
753         item.iItem = i;
754         item.stateMask = (UINT)-1;
755         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
756 
757         if (item.state & LVIS_SELECTED) {
758             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
759             if (pAPLI) {
760                 hWndArray[nWndCount] = pAPLI->hWnd;
761                 nWndCount++;
762             }
763         }
764     }
765 
766     TileWindows(NULL, dwMode, NULL, nWndCount, hWndArray);
767     HeapFree(GetProcessHeap(), 0, hWndArray);
768 }
769 
770 void ApplicationPage_OnWindowsMinimize(void)
771 {
772     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
773     LV_ITEM                       item;
774     int                           i;
775 
776     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
777         memset(&item, 0, sizeof(LV_ITEM));
778         item.mask = LVIF_STATE|LVIF_PARAM;
779         item.iItem = i;
780         item.stateMask = (UINT)-1;
781         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
782         if (item.state & LVIS_SELECTED) {
783             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
784             if (pAPLI) {
785                 ShowWindowAsync(pAPLI->hWnd, SW_MINIMIZE);
786             }
787         }
788     }
789 }
790 
791 void ApplicationPage_OnWindowsMaximize(void)
792 {
793     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
794     LV_ITEM                       item;
795     int                           i;
796 
797     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
798         memset(&item, 0, sizeof(LV_ITEM));
799         item.mask = LVIF_STATE|LVIF_PARAM;
800         item.iItem = i;
801         item.stateMask = (UINT)-1;
802         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
803         if (item.state & LVIS_SELECTED) {
804             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
805             if (pAPLI) {
806                 ShowWindowAsync(pAPLI->hWnd, SW_MAXIMIZE);
807             }
808         }
809     }
810 }
811 
812 void ApplicationPage_OnWindowsCascade(void)
813 {
814     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
815     LV_ITEM                       item;
816     int                           i;
817     HWND*                         hWndArray;
818     int                           nWndCount;
819 
820     hWndArray = (HWND*)HeapAlloc(GetProcessHeap(), 0, sizeof(HWND) * ListView_GetItemCount(hApplicationPageListCtrl));
821     nWndCount = 0;
822 
823     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
824         memset(&item, 0, sizeof(LV_ITEM));
825         item.mask = LVIF_STATE|LVIF_PARAM;
826         item.iItem = i;
827         item.stateMask = (UINT)-1;
828         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
829         if (item.state & LVIS_SELECTED) {
830             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
831             if (pAPLI) {
832                 hWndArray[nWndCount] = pAPLI->hWnd;
833                 nWndCount++;
834             }
835         }
836     }
837     CascadeWindows(NULL, 0, NULL, nWndCount, hWndArray);
838     HeapFree(GetProcessHeap(), 0, hWndArray);
839 }
840 
841 void ApplicationPage_OnWindowsBringToFront(void)
842 {
843     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
844     LV_ITEM                       item;
845     int                           i;
846 
847     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
848         memset(&item, 0, sizeof(LV_ITEM));
849         item.mask = LVIF_STATE|LVIF_PARAM;
850         item.iItem = i;
851         item.stateMask = (UINT)-1;
852         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
853         if (item.state & LVIS_SELECTED) {
854             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
855             break;
856         }
857     }
858     if (pAPLI) {
859         SwitchToThisWindow(pAPLI->hWnd, TRUE);
860     }
861 }
862 
863 void ApplicationPage_OnSwitchTo(void)
864 {
865     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
866     LV_ITEM                       item;
867     int                           i;
868 
869     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
870         memset(&item, 0, sizeof(LV_ITEM));
871         item.mask = LVIF_STATE|LVIF_PARAM;
872         item.iItem = i;
873         item.stateMask = (UINT)-1;
874         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
875 
876         if (item.state & LVIS_SELECTED) {
877             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
878             break;
879         }
880     }
881     if (pAPLI) {
882         SwitchToThisWindow(pAPLI->hWnd, TRUE);
883         if (TaskManagerSettings.MinimizeOnUse)
884             ShowWindowAsync(hMainWnd, SW_MINIMIZE);
885     }
886 }
887 
888 void ApplicationPage_OnEndTask(void)
889 {
890     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
891     LV_ITEM                       item;
892     int                           i;
893 
894     /* Trick: on Windows, pressing the CTRL key forces the task to be ended */
895     BOOL ForceEndTask = !!(GetKeyState(VK_CONTROL) & 0x8000);
896 
897     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
898         memset(&item, 0, sizeof(LV_ITEM));
899         item.mask = LVIF_STATE|LVIF_PARAM;
900         item.iItem = i;
901         item.stateMask = (UINT)-1;
902         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
903         if (item.state & LVIS_SELECTED) {
904             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
905             if (pAPLI) {
906                 EndTask(pAPLI->hWnd, 0, ForceEndTask);
907             }
908         }
909     }
910 }
911 
912 void ApplicationPage_OnGotoProcess(void)
913 {
914     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
915     LV_ITEM                       item;
916     int                           i;
917 
918     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
919         memset(&item, 0, sizeof(LV_ITEM));
920         item.mask = LVIF_STATE|LVIF_PARAM;
921         item.iItem = i;
922         item.stateMask = (UINT)-1;
923         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
924         if (item.state & LVIS_SELECTED) {
925             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
926             break;
927         }
928     }
929     if (pAPLI) {
930         DWORD   dwProcessId;
931 
932         GetWindowThreadProcessId(pAPLI->hWnd, &dwProcessId);
933         /*
934          * Switch to the process tab
935          */
936         TabCtrl_SetCurFocus(hTabWnd, 1);
937         /*
938          * Select the process item in the list
939          */
940         i = ProcGetIndexByProcessId(dwProcessId);
941         if (i != -1)
942         {
943             ListView_SetItemState(hProcessPageListCtrl,
944                                   i,
945                                   LVIS_SELECTED | LVIS_FOCUSED,
946                                   LVIS_SELECTED | LVIS_FOCUSED);
947             (void)ListView_EnsureVisible(hProcessPageListCtrl,
948                                          i,
949                                          FALSE);
950         }
951     }
952 }
953 
954 int CALLBACK ApplicationPageCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
955 {
956     LPAPPLICATION_PAGE_LIST_ITEM  Param1;
957     LPAPPLICATION_PAGE_LIST_ITEM  Param2;
958 
959     if (bSortAscending) {
960         Param1 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam1;
961         Param2 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam2;
962     } else {
963         Param1 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam2;
964         Param2 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam1;
965     }
966     return wcscmp(Param1->szTitle, Param2->szTitle);
967 }
968