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