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