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 
357     typedef int (FAR __stdcall *IsHungAppWindowProc)(HWND);
358     IsHungAppWindowProc IsHungAppWindow;
359 
360     /* Skip our window */
361     if (hWnd == hMainWnd)
362         return TRUE;
363 
364     bLargeIcon = (TaskManagerSettings.ViewMode == ID_VIEW_LARGE);
365 
366     GetWindowTextW(hWnd, szText, 260); /* Get the window text */
367 
368     /* Check and see if this is a top-level app window */
369     if ((wcslen(szText) <= 0) ||
370         !IsWindowVisible(hWnd) ||
371         (GetParent(hWnd) != NULL) ||
372         (GetWindow(hWnd, GW_OWNER) != NULL) ||
373         (GetWindowLongPtrW(hWnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
374     {
375         return TRUE; /* Skip this window */
376     }
377 
378     noApps = FALSE;
379 
380     /* Get the icon for this window */
381     hIcon = NULL;
382     SendMessageTimeoutW(hWnd, WM_GETICON, bLargeIcon ? ICON_BIG : ICON_SMALL, 0, 0, 1000, (PDWORD_PTR)&hIcon);
383     if (!hIcon)
384     {
385         /* We failed, try to retrieve other icons... */
386         hIcon = (HICON)(LONG_PTR)GetClassLongPtrW(hWnd, bLargeIcon ? GCL_HICON : GCL_HICONSM);
387         if (!hIcon) hIcon = (HICON)(LONG_PTR)GetClassLongPtrW(hWnd, bLargeIcon ? GCL_HICONSM : GCL_HICON);
388         if (!hIcon) SendMessageTimeoutW(hWnd, WM_QUERYDRAGICON, 0, 0, 0, 1000, (PDWORD_PTR)&hIcon);
389         if (!hIcon) SendMessageTimeoutW(hWnd, WM_GETICON, bLargeIcon ? ICON_SMALL : ICON_BIG, 0, 0, 1000, (PDWORD_PTR)&hIcon);
390 
391         /* If we still do not have any icon, load the default one */
392         if (!hIcon) hIcon = LoadIconW(hInst, bLargeIcon ? MAKEINTRESOURCEW(IDI_WINDOW) : MAKEINTRESOURCEW(IDI_WINDOWSM));
393     }
394 
395     bHung = FALSE;
396 
397     IsHungAppWindow = (IsHungAppWindowProc)(FARPROC)GetProcAddress(GetModuleHandleW(L"USER32.DLL"), "IsHungAppWindow");
398 
399     if (IsHungAppWindow)
400         bHung = IsHungAppWindow(hWnd);
401 
402     AddOrUpdateHwnd(hWnd, szText, hIcon, bHung);
403 
404     return TRUE;
405 }
406 
407 void AddOrUpdateHwnd(HWND hWnd, WCHAR *szTitle, HICON hIcon, BOOL bHung)
408 {
409     LPAPPLICATION_PAGE_LIST_ITEM    pAPLI = NULL;
410     HIMAGELIST                      hImageListLarge;
411     HIMAGELIST                      hImageListSmall;
412     LV_ITEM                         item;
413     int                             i;
414     BOOL                            bAlreadyInList = FALSE;
415 
416     memset(&item, 0, sizeof(LV_ITEM));
417 
418     /* Get the image lists */
419     hImageListLarge = ListView_GetImageList(hApplicationPageListCtrl, LVSIL_NORMAL);
420     hImageListSmall = ListView_GetImageList(hApplicationPageListCtrl, LVSIL_SMALL);
421 
422     /* Check to see if it's already in our list */
423     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++)
424     {
425         memset(&item, 0, sizeof(LV_ITEM));
426         item.mask = LVIF_IMAGE|LVIF_PARAM;
427         item.iItem = i;
428         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
429 
430         pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
431         if (pAPLI->hWnd == hWnd)
432         {
433             bAlreadyInList = TRUE;
434             break;
435         }
436     }
437 
438     /* If it is already in the list then update it if necessary */
439     if (bAlreadyInList)
440     {
441         /* Check to see if anything needs updating */
442         if ((pAPLI->hIcon != hIcon) ||
443             (_wcsicmp(pAPLI->szTitle, szTitle) != 0) ||
444             (pAPLI->bHung != bHung))
445         {
446             /* Update the structure */
447             pAPLI->hIcon = hIcon;
448             pAPLI->bHung = bHung;
449             wcscpy(pAPLI->szTitle, szTitle);
450 
451             /* Update the image list */
452             ImageList_ReplaceIcon(hImageListLarge, item.iItem, hIcon);
453             ImageList_ReplaceIcon(hImageListSmall, item.iItem, hIcon);
454 
455             /* Update the list view */
456             (void)ListView_RedrawItems(hApplicationPageListCtrl, 0, ListView_GetItemCount(hApplicationPageListCtrl));
457             /* UpdateWindow(hApplicationPageListCtrl); */
458             InvalidateRect(hApplicationPageListCtrl, NULL, 0);
459         }
460     }
461     /* It is not already in the list so add it */
462     else
463     {
464         pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)HeapAlloc(GetProcessHeap(), 0, sizeof(APPLICATION_PAGE_LIST_ITEM));
465 
466         pAPLI->hWnd = hWnd;
467         pAPLI->hIcon = hIcon;
468         pAPLI->bHung = bHung;
469         wcscpy(pAPLI->szTitle, szTitle);
470 
471         /* Add the item to the list */
472         memset(&item, 0, sizeof(LV_ITEM));
473         item.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
474         ImageList_AddIcon(hImageListLarge, hIcon);
475         item.iImage = ImageList_AddIcon(hImageListSmall, hIcon);
476         item.pszText = LPSTR_TEXTCALLBACK;
477         item.iItem = ListView_GetItemCount(hApplicationPageListCtrl);
478         item.lParam = (LPARAM)pAPLI;
479         (void)ListView_InsertItem(hApplicationPageListCtrl, &item);
480     }
481 
482     /* Select first item if any */
483     if ((ListView_GetNextItem(hApplicationPageListCtrl, -1, LVNI_FOCUSED | LVNI_SELECTED) == -1) &&
484         (ListView_GetItemCount(hApplicationPageListCtrl) > 0) && !bApplicationPageSelectionMade)
485     {
486         ListView_SetItemState(hApplicationPageListCtrl, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
487         bApplicationPageSelectionMade = TRUE;
488     }
489     /*
490     else
491     {
492         bApplicationPageSelectionMade = FALSE;
493     }
494     */
495 }
496 
497 void ApplicationPageUpdate(void)
498 {
499     /* Enable or disable the "End Task" & "Switch To" buttons */
500     if (ListView_GetSelectedCount(hApplicationPageListCtrl))
501     {
502         EnableWindow(hApplicationPageEndTaskButton, TRUE);
503     }
504     else
505     {
506         EnableWindow(hApplicationPageEndTaskButton, FALSE);
507     }
508     /* Enable "Switch To" button only if one app is selected */
509     if (ListView_GetSelectedCount(hApplicationPageListCtrl) == 1 )
510     {
511         EnableWindow(hApplicationPageSwitchToButton, TRUE);
512     }
513     else
514     {
515     EnableWindow(hApplicationPageSwitchToButton, FALSE);
516     }
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_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
690         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
691         EnableMenuItem(hSubMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
692         EnableMenuItem(hSubMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
693         EnableMenuItem(hSubMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
694         EnableMenuItem(hSubMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_ENABLED);
695     }
696     else if (ListView_GetSelectedCount(hApplicationPageListCtrl) > 1)
697     {
698         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_ENABLED);
699         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_ENABLED);
700         EnableMenuItem(hSubMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
701         EnableMenuItem(hSubMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
702         EnableMenuItem(hSubMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_ENABLED);
703         EnableMenuItem(hSubMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
704     }
705     else
706     {
707         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
708         EnableMenuItem(hSubMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
709         EnableMenuItem(hSubMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
710         EnableMenuItem(hSubMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
711         EnableMenuItem(hSubMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
712         EnableMenuItem(hSubMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
713     }
714 
715     SetMenuDefaultItem(hSubMenu, ID_APPLICATION_PAGE_SWITCHTO, MF_BYCOMMAND);
716 
717     TrackPopupMenu(hSubMenu, TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON, pt.x, pt.y, 0, hMainWnd, NULL);
718 
719     DestroyMenu(hMenu);
720 }
721 
722 void ApplicationPage_OnView(DWORD dwMode)
723 {
724     HMENU  hMenu;
725     HMENU  hViewMenu;
726 
727     hMenu = GetMenu(hMainWnd);
728     hViewMenu = GetSubMenu(hMenu, 2);
729 
730     TaskManagerSettings.ViewMode = dwMode;
731     CheckMenuRadioItem(hViewMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, dwMode, MF_BYCOMMAND);
732 
733     UpdateApplicationListControlViewSetting();
734 }
735 
736 void ApplicationPage_OnWindowsTile(DWORD dwMode)
737 {
738     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
739     LV_ITEM                       item;
740     int                           i;
741     HWND*                         hWndArray;
742     int                           nWndCount;
743 
744     hWndArray = (HWND*)HeapAlloc(GetProcessHeap(), 0, sizeof(HWND) * ListView_GetItemCount(hApplicationPageListCtrl));
745     nWndCount = 0;
746 
747     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
748         memset(&item, 0, sizeof(LV_ITEM));
749         item.mask = LVIF_STATE|LVIF_PARAM;
750         item.iItem = i;
751         item.stateMask = (UINT)-1;
752         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
753 
754         if (item.state & LVIS_SELECTED) {
755             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
756             if (pAPLI) {
757                 hWndArray[nWndCount] = pAPLI->hWnd;
758                 nWndCount++;
759             }
760         }
761     }
762 
763     TileWindows(NULL, dwMode, NULL, nWndCount, hWndArray);
764     HeapFree(GetProcessHeap(), 0, hWndArray);
765 }
766 
767 void ApplicationPage_OnWindowsMinimize(void)
768 {
769     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
770     LV_ITEM                       item;
771     int                           i;
772 
773     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
774         memset(&item, 0, sizeof(LV_ITEM));
775         item.mask = LVIF_STATE|LVIF_PARAM;
776         item.iItem = i;
777         item.stateMask = (UINT)-1;
778         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
779         if (item.state & LVIS_SELECTED) {
780             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
781             if (pAPLI) {
782                 ShowWindowAsync(pAPLI->hWnd, SW_MINIMIZE);
783             }
784         }
785     }
786 }
787 
788 void ApplicationPage_OnWindowsMaximize(void)
789 {
790     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
791     LV_ITEM                       item;
792     int                           i;
793 
794     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
795         memset(&item, 0, sizeof(LV_ITEM));
796         item.mask = LVIF_STATE|LVIF_PARAM;
797         item.iItem = i;
798         item.stateMask = (UINT)-1;
799         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
800         if (item.state & LVIS_SELECTED) {
801             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
802             if (pAPLI) {
803                 ShowWindowAsync(pAPLI->hWnd, SW_MAXIMIZE);
804             }
805         }
806     }
807 }
808 
809 void ApplicationPage_OnWindowsCascade(void)
810 {
811     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
812     LV_ITEM                       item;
813     int                           i;
814     HWND*                         hWndArray;
815     int                           nWndCount;
816 
817     hWndArray = (HWND*)HeapAlloc(GetProcessHeap(), 0, sizeof(HWND) * ListView_GetItemCount(hApplicationPageListCtrl));
818     nWndCount = 0;
819 
820     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
821         memset(&item, 0, sizeof(LV_ITEM));
822         item.mask = LVIF_STATE|LVIF_PARAM;
823         item.iItem = i;
824         item.stateMask = (UINT)-1;
825         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
826         if (item.state & LVIS_SELECTED) {
827             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
828             if (pAPLI) {
829                 hWndArray[nWndCount] = pAPLI->hWnd;
830                 nWndCount++;
831             }
832         }
833     }
834     CascadeWindows(NULL, 0, NULL, nWndCount, hWndArray);
835     HeapFree(GetProcessHeap(), 0, hWndArray);
836 }
837 
838 void ApplicationPage_OnWindowsBringToFront(void)
839 {
840     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
841     LV_ITEM                       item;
842     int                           i;
843 
844     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
845         memset(&item, 0, sizeof(LV_ITEM));
846         item.mask = LVIF_STATE|LVIF_PARAM;
847         item.iItem = i;
848         item.stateMask = (UINT)-1;
849         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
850         if (item.state & LVIS_SELECTED) {
851             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
852             break;
853         }
854     }
855     if (pAPLI) {
856         SwitchToThisWindow(pAPLI->hWnd, TRUE);
857     }
858 }
859 
860 void ApplicationPage_OnSwitchTo(void)
861 {
862     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
863     LV_ITEM                       item;
864     int                           i;
865 
866     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
867         memset(&item, 0, sizeof(LV_ITEM));
868         item.mask = LVIF_STATE|LVIF_PARAM;
869         item.iItem = i;
870         item.stateMask = (UINT)-1;
871         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
872 
873         if (item.state & LVIS_SELECTED) {
874             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
875             break;
876         }
877     }
878     if (pAPLI) {
879         SwitchToThisWindow(pAPLI->hWnd, TRUE);
880         if (TaskManagerSettings.MinimizeOnUse)
881             ShowWindowAsync(hMainWnd, SW_MINIMIZE);
882     }
883 }
884 
885 void ApplicationPage_OnEndTask(void)
886 {
887     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
888     LV_ITEM                       item;
889     int                           i;
890 
891     /* Trick: on Windows, pressing the CTRL key forces the task to be ended */
892     BOOL ForceEndTask = !!(GetKeyState(VK_CONTROL) & 0x8000);
893 
894     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
895         memset(&item, 0, sizeof(LV_ITEM));
896         item.mask = LVIF_STATE|LVIF_PARAM;
897         item.iItem = i;
898         item.stateMask = (UINT)-1;
899         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
900         if (item.state & LVIS_SELECTED) {
901             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
902             if (pAPLI) {
903                 EndTask(pAPLI->hWnd, 0, ForceEndTask);
904             }
905         }
906     }
907 }
908 
909 void ApplicationPage_OnGotoProcess(void)
910 {
911     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI = NULL;
912     LV_ITEM                       item;
913     int                           i;
914 
915     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++) {
916         memset(&item, 0, sizeof(LV_ITEM));
917         item.mask = LVIF_STATE|LVIF_PARAM;
918         item.iItem = i;
919         item.stateMask = (UINT)-1;
920         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
921         if (item.state & LVIS_SELECTED) {
922             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
923             break;
924         }
925     }
926     if (pAPLI) {
927         DWORD   dwProcessId;
928 
929         GetWindowThreadProcessId(pAPLI->hWnd, &dwProcessId);
930         /*
931          * Switch to the process tab
932          */
933         TabCtrl_SetCurFocus(hTabWnd, 1);
934         /*
935          * Select the process item in the list
936          */
937         i = ProcGetIndexByProcessId(dwProcessId);
938         if (i != -1)
939         {
940             ListView_SetItemState(hProcessPageListCtrl,
941                                   i,
942                                   LVIS_SELECTED | LVIS_FOCUSED,
943                                   LVIS_SELECTED | LVIS_FOCUSED);
944             (void)ListView_EnsureVisible(hProcessPageListCtrl,
945                                          i,
946                                          FALSE);
947         }
948     }
949 }
950 
951 int CALLBACK ApplicationPageCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
952 {
953     LPAPPLICATION_PAGE_LIST_ITEM  Param1;
954     LPAPPLICATION_PAGE_LIST_ITEM  Param2;
955 
956     if (bSortAscending) {
957         Param1 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam1;
958         Param2 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam2;
959     } else {
960         Param1 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam2;
961         Param2 = (LPAPPLICATION_PAGE_LIST_ITEM)lParam1;
962     }
963     return wcscmp(Param1->szTitle, Param2->szTitle);
964 }
965