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 HANDLE   hApplicationPageEvent = NULL;   /* When this event becomes signaled then we refresh the app list */
42 static BOOL     bSortAscending = TRUE;
43 DWORD WINAPI    ApplicationPageRefreshThread(void *lpParameter);
44 BOOL            noApps;
45 BOOL CALLBACK   EnumWindowsProc(HWND hWnd, LPARAM lParam);
46 void            AddOrUpdateHwnd(HWND hWnd, WCHAR *szTitle, HICON hIcon, BOOL bHung);
47 void            ApplicationPageUpdate(void);
48 void            ApplicationPageOnNotify(WPARAM wParam, LPARAM lParam);
49 void            ApplicationPageShowContextMenu1(void);
50 void            ApplicationPageShowContextMenu2(void);
51 int CALLBACK    ApplicationPageCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
52 int             ProcGetIndexByProcessId(DWORD dwProcessId);
53 
54 #if 0
55 void SwitchToThisWindow (
56 HWND hWnd,   /* Handle to the window that should be activated */
57 BOOL bRestore /* Restore the window if it is minimized */
58 );
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 INT_PTR CALLBACK
87 ApplicationPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
88 {
89     RECT       rc;
90     int        nXDifference;
91     int        nYDifference;
92     LV_COLUMN  column;
93     WCHAR      szTemp[256];
94     int        cx, cy;
95     HANDLE     hRefreshThread = NULL;
96 
97     switch (message) {
98     case WM_INITDIALOG:
99 
100         /* Save the width and height */
101         GetClientRect(hDlg, &rc);
102         nApplicationPageWidth = rc.right;
103         nApplicationPageHeight = rc.bottom;
104 
105         /* Update window position */
106         SetWindowPos(hDlg, NULL, 15, 30, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
107 
108         /* Get handles to the controls */
109         hApplicationPageListCtrl = GetDlgItem(hDlg, IDC_APPLIST);
110         hApplicationPageEndTaskButton = GetDlgItem(hDlg, IDC_ENDTASK);
111         hApplicationPageSwitchToButton = GetDlgItem(hDlg, IDC_SWITCHTO);
112         hApplicationPageNewTaskButton = GetDlgItem(hDlg, IDC_NEWTASK);
113 
114         SetWindowTextW(hApplicationPageListCtrl, L"Tasks");
115 
116         /* Initialize the application page's controls */
117         column.mask = LVCF_TEXT|LVCF_WIDTH;
118 
119         LoadStringW(hInst, IDS_TAB_TASK, szTemp, 256);
120         column.pszText = szTemp;
121         column.cx = 250;
122         (void)ListView_InsertColumn(hApplicationPageListCtrl, 0, &column);    /* Add the "Task" column */
123         column.mask = LVCF_TEXT|LVCF_WIDTH;
124         LoadStringW(hInst, IDS_TAB_STATUS, szTemp, 256);
125         column.pszText = szTemp;
126         column.cx = 95;
127         (void)ListView_InsertColumn(hApplicationPageListCtrl, 1, &column);    /* Add the "Status" column */
128 
129         (void)ListView_SetImageList(hApplicationPageListCtrl, ImageList_Create(16, 16, GetSystemColorDepth()|ILC_MASK, 0, 1), LVSIL_SMALL);
130         (void)ListView_SetImageList(hApplicationPageListCtrl, ImageList_Create(32, 32, GetSystemColorDepth()|ILC_MASK, 0, 1), LVSIL_NORMAL);
131 
132         UpdateApplicationListControlViewSetting();
133 
134         /* Start our refresh thread */
135         hRefreshThread = CreateThread(NULL, 0, ApplicationPageRefreshThread, NULL, 0, NULL);
136 
137         return TRUE;
138 
139     case WM_DESTROY:
140         /* Close the event handle, this will make the */
141         /* refresh thread exit when the wait fails */
142         CloseHandle(hApplicationPageEvent);
143         CloseHandle(hRefreshThread);
144         break;
145 
146     case WM_COMMAND:
147 
148         /* Handle the button clicks */
149         switch (LOWORD(wParam))
150         {
151         case IDC_ENDTASK:
152             ApplicationPage_OnEndTask();
153             break;
154         case IDC_SWITCHTO:
155             ApplicationPage_OnSwitchTo();
156             break;
157         case IDC_NEWTASK:
158             SendMessageW(hMainWnd, WM_COMMAND, MAKEWPARAM(ID_FILE_NEW, 0), 0);
159             break;
160         }
161 
162         break;
163 
164     case WM_SIZE:
165         if (wParam == SIZE_MINIMIZED)
166             return 0;
167 
168         cx = LOWORD(lParam);
169         cy = HIWORD(lParam);
170         nXDifference = cx - nApplicationPageWidth;
171         nYDifference = cy - nApplicationPageHeight;
172         nApplicationPageWidth = cx;
173         nApplicationPageHeight = cy;
174 
175         /* Reposition the application page's controls */
176         GetWindowRect(hApplicationPageListCtrl, &rc);
177         cx = (rc.right - rc.left) + nXDifference;
178         cy = (rc.bottom - rc.top) + nYDifference;
179         SetWindowPos(hApplicationPageListCtrl, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
180         InvalidateRect(hApplicationPageListCtrl, NULL, TRUE);
181 
182         GetClientRect(hApplicationPageEndTaskButton, &rc);
183         MapWindowPoints(hApplicationPageEndTaskButton, hDlg, (LPPOINT)(PRECT)(&rc), (sizeof(RECT)/sizeof(POINT)) );
184         cx = rc.left + nXDifference;
185         cy = rc.top + nYDifference;
186         SetWindowPos(hApplicationPageEndTaskButton, NULL, cx, cy, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
187         InvalidateRect(hApplicationPageEndTaskButton, NULL, TRUE);
188 
189         GetClientRect(hApplicationPageSwitchToButton, &rc);
190         MapWindowPoints(hApplicationPageSwitchToButton, hDlg, (LPPOINT)(PRECT)(&rc), (sizeof(RECT)/sizeof(POINT)) );
191         cx = rc.left + nXDifference;
192         cy = rc.top + nYDifference;
193         SetWindowPos(hApplicationPageSwitchToButton, NULL, cx, cy, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
194         InvalidateRect(hApplicationPageSwitchToButton, NULL, TRUE);
195 
196         GetClientRect(hApplicationPageNewTaskButton, &rc);
197         MapWindowPoints(hApplicationPageNewTaskButton, hDlg, (LPPOINT)(PRECT)(&rc), (sizeof(RECT)/sizeof(POINT)) );
198         cx = rc.left + nXDifference;
199         cy = rc.top + nYDifference;
200         SetWindowPos(hApplicationPageNewTaskButton, NULL, cx, cy, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
201         InvalidateRect(hApplicationPageNewTaskButton, NULL, TRUE);
202 
203         break;
204 
205     case WM_NOTIFY:
206         ApplicationPageOnNotify(wParam, lParam);
207         break;
208 
209     }
210 
211   return 0;
212 }
213 
214 void RefreshApplicationPage(void)
215 {
216     /* Signal the event so that our refresh thread */
217     /* will wake up and refresh the application page */
218     SetEvent(hApplicationPageEvent);
219 }
220 
221 void UpdateApplicationListControlViewSetting(void)
222 {
223     DWORD  dwStyle = GetWindowLongPtrW(hApplicationPageListCtrl, GWL_STYLE);
224 
225     dwStyle &= ~(LVS_REPORT | LVS_ICON | LVS_LIST | LVS_SMALLICON);
226 
227     switch (TaskManagerSettings.ViewMode) {
228     case ID_VIEW_LARGE:   dwStyle |= LVS_ICON; break;
229     case ID_VIEW_SMALL:   dwStyle |= LVS_SMALLICON; break;
230     case ID_VIEW_DETAILS: dwStyle |= LVS_REPORT; break;
231     }
232     SetWindowLongPtrW(hApplicationPageListCtrl, GWL_STYLE, dwStyle);
233 
234     RefreshApplicationPage();
235 }
236 
237 DWORD WINAPI ApplicationPageRefreshThread(void *lpParameter)
238 {
239     INT i;
240     BOOL                            bItemRemoved = FALSE;
241     LV_ITEM                         item;
242     LPAPPLICATION_PAGE_LIST_ITEM    pAPLI = NULL;
243     HIMAGELIST                      hImageListLarge;
244     HIMAGELIST                      hImageListSmall;
245 
246     /* Create the event */
247     hApplicationPageEvent = CreateEventW(NULL, TRUE, TRUE, NULL);
248 
249     /* If we couldn't create the event then exit the thread */
250     if (!hApplicationPageEvent)
251         return 0;
252 
253     while (1)
254     {
255         DWORD   dwWaitVal;
256 
257         /* Wait on the event */
258         dwWaitVal = WaitForSingleObject(hApplicationPageEvent, INFINITE);
259 
260         /* If the wait failed then the event object must have been */
261         /* closed and the task manager is exiting so exit this thread */
262         if (dwWaitVal == WAIT_FAILED)
263             return 0;
264 
265         if (dwWaitVal == WAIT_OBJECT_0)
266         {
267             /* Reset our event */
268             ResetEvent(hApplicationPageEvent);
269 
270             /*
271              * FIXME:
272              *
273              * Should this be EnumDesktopWindows() instead?
274              */
275             noApps = TRUE;
276             EnumWindows(EnumWindowsProc, 0);
277             if (noApps)
278                 (void)ListView_DeleteAllItems(hApplicationPageListCtrl);
279 
280             /* Get the image lists */
281             hImageListLarge = ListView_GetImageList(hApplicationPageListCtrl, LVSIL_NORMAL);
282             hImageListSmall = ListView_GetImageList(hApplicationPageListCtrl, LVSIL_SMALL);
283 
284             /* Check to see if we need to remove any items from the list */
285             for (i=ListView_GetItemCount(hApplicationPageListCtrl)-1; i>=0; i--)
286             {
287                 memset(&item, 0, sizeof(LV_ITEM));
288                 item.mask = LVIF_IMAGE|LVIF_PARAM;
289                 item.iItem = i;
290                 (void)ListView_GetItem(hApplicationPageListCtrl, &item);
291 
292                 pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
293                 if (!IsWindow(pAPLI->hWnd)||
294                     (wcslen(pAPLI->szTitle) <= 0) ||
295                     !IsWindowVisible(pAPLI->hWnd) ||
296                     (GetParent(pAPLI->hWnd) != NULL) ||
297                     (GetWindow(pAPLI->hWnd, GW_OWNER) != NULL) ||
298                     (GetWindowLongPtr(pAPLI->hWnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
299                 {
300                     ImageList_Remove(hImageListLarge, item.iItem);
301                     ImageList_Remove(hImageListSmall, item.iItem);
302 
303                     (void)ListView_DeleteItem(hApplicationPageListCtrl, item.iItem);
304                     HeapFree(GetProcessHeap(), 0, pAPLI);
305                     bItemRemoved = TRUE;
306                 }
307             }
308 
309             /*
310              * If an item was removed from the list then
311              * we need to resync all the items with the
312              * image list
313              */
314             if (bItemRemoved)
315             {
316                 for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++)
317                 {
318                     memset(&item, 0, sizeof(LV_ITEM));
319                     item.mask = LVIF_IMAGE;
320                     item.iItem = i;
321                     item.iImage = i;
322                     (void)ListView_SetItem(hApplicationPageListCtrl, &item);
323                 }
324                 bItemRemoved = FALSE;
325             }
326 
327             ApplicationPageUpdate();
328         }
329     }
330 }
331 
332 BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
333 {
334     HICON   hIcon;
335     WCHAR   szText[260];
336     BOOL    bLargeIcon;
337     BOOL    bHung = FALSE;
338     HICON*  xhIcon = (HICON*)&hIcon;
339 
340     typedef int (FAR __stdcall *IsHungAppWindowProc)(HWND);
341     IsHungAppWindowProc IsHungAppWindow;
342 
343 
344     /* Skip our window */
345     if (hWnd == hMainWnd)
346         return TRUE;
347 
348     bLargeIcon = (TaskManagerSettings.ViewMode == ID_VIEW_LARGE);
349 
350     GetWindowTextW(hWnd, szText, 260); /* Get the window text */
351 
352     /* Check and see if this is a top-level app window */
353     if ((wcslen(szText) <= 0) ||
354         !IsWindowVisible(hWnd) ||
355         (GetParent(hWnd) != NULL) ||
356         (GetWindow(hWnd, GW_OWNER) != NULL) ||
357         (GetWindowLongPtrW(hWnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
358     {
359         return TRUE; /* Skip this window */
360     }
361 
362     noApps = FALSE;
363     /* Get the icon for this window */
364     hIcon = NULL;
365     SendMessageTimeoutW(hWnd, WM_GETICON,bLargeIcon ? ICON_BIG /*1*/ : ICON_SMALL /*0*/, 0, 0, 1000, (PDWORD_PTR)xhIcon);
366 
367     if (!hIcon)
368     {
369         hIcon = (HICON)(LONG_PTR)GetClassLongPtrW(hWnd, bLargeIcon ? GCL_HICON : GCL_HICONSM);
370         if (!hIcon) hIcon = (HICON)(LONG_PTR)GetClassLongPtrW(hWnd, bLargeIcon ? GCL_HICONSM : GCL_HICON);
371         if (!hIcon) SendMessageTimeoutW(hWnd, WM_QUERYDRAGICON, 0, 0, 0, 1000, (PDWORD_PTR)xhIcon);
372         if (!hIcon) SendMessageTimeoutW(hWnd, WM_GETICON, bLargeIcon ? ICON_SMALL /*0*/ : ICON_BIG /*1*/, 0, 0, 1000, (PDWORD_PTR)xhIcon);
373     }
374 
375     if (!hIcon)
376         hIcon = LoadIconW(hInst, bLargeIcon ? MAKEINTRESOURCEW(IDI_WINDOW) : MAKEINTRESOURCEW(IDI_WINDOWSM));
377 
378     bHung = FALSE;
379 
380     IsHungAppWindow = (IsHungAppWindowProc)(FARPROC)GetProcAddress(GetModuleHandleW(L"USER32.DLL"), "IsHungAppWindow");
381 
382     if (IsHungAppWindow)
383         bHung = IsHungAppWindow(hWnd);
384 
385     AddOrUpdateHwnd(hWnd, szText, hIcon, bHung);
386 
387     return TRUE;
388 }
389 
390 void AddOrUpdateHwnd(HWND hWnd, WCHAR *szTitle, HICON hIcon, BOOL bHung)
391 {
392     LPAPPLICATION_PAGE_LIST_ITEM    pAPLI = NULL;
393     HIMAGELIST                      hImageListLarge;
394     HIMAGELIST                      hImageListSmall;
395     LV_ITEM                         item;
396     int                             i;
397     BOOL                            bAlreadyInList = FALSE;
398 
399     memset(&item, 0, sizeof(LV_ITEM));
400 
401     /* Get the image lists */
402     hImageListLarge = ListView_GetImageList(hApplicationPageListCtrl, LVSIL_NORMAL);
403     hImageListSmall = ListView_GetImageList(hApplicationPageListCtrl, LVSIL_SMALL);
404 
405     /* Check to see if it's already in our list */
406     for (i=0; i<ListView_GetItemCount(hApplicationPageListCtrl); i++)
407     {
408         memset(&item, 0, sizeof(LV_ITEM));
409         item.mask = LVIF_IMAGE|LVIF_PARAM;
410         item.iItem = i;
411         (void)ListView_GetItem(hApplicationPageListCtrl, &item);
412 
413         pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)item.lParam;
414         if (pAPLI->hWnd == hWnd)
415         {
416             bAlreadyInList = TRUE;
417             break;
418         }
419     }
420 
421     /* If it is already in the list then update it if necessary */
422     if (bAlreadyInList)
423     {
424         /* Check to see if anything needs updating */
425         if ((pAPLI->hIcon != hIcon) ||
426             (_wcsicmp(pAPLI->szTitle, szTitle) != 0) ||
427             (pAPLI->bHung != bHung))
428         {
429             /* Update the structure */
430             pAPLI->hIcon = hIcon;
431             pAPLI->bHung = bHung;
432             wcscpy(pAPLI->szTitle, szTitle);
433 
434             /* Update the image list */
435             ImageList_ReplaceIcon(hImageListLarge, item.iItem, hIcon);
436             ImageList_ReplaceIcon(hImageListSmall, item.iItem, hIcon);
437 
438             /* Update the list view */
439             (void)ListView_RedrawItems(hApplicationPageListCtrl, 0, ListView_GetItemCount(hApplicationPageListCtrl));
440             /* UpdateWindow(hApplicationPageListCtrl); */
441             InvalidateRect(hApplicationPageListCtrl, NULL, 0);
442         }
443     }
444     /* It is not already in the list so add it */
445     else
446     {
447         pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)HeapAlloc(GetProcessHeap(), 0, sizeof(APPLICATION_PAGE_LIST_ITEM));
448 
449         pAPLI->hWnd = hWnd;
450         pAPLI->hIcon = hIcon;
451         pAPLI->bHung = bHung;
452         wcscpy(pAPLI->szTitle, szTitle);
453 
454         /* Add the item to the list */
455         memset(&item, 0, sizeof(LV_ITEM));
456         item.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
457         ImageList_AddIcon(hImageListLarge, hIcon);
458         item.iImage = ImageList_AddIcon(hImageListSmall, hIcon);
459         item.pszText = LPSTR_TEXTCALLBACK;
460         item.iItem = ListView_GetItemCount(hApplicationPageListCtrl);
461         item.lParam = (LPARAM)pAPLI;
462         (void)ListView_InsertItem(hApplicationPageListCtrl, &item);
463     }
464     return;
465 }
466 
467 void ApplicationPageUpdate(void)
468 {
469     /* Enable or disable the "End Task" & "Switch To" buttons */
470     if (ListView_GetSelectedCount(hApplicationPageListCtrl))
471     {
472         EnableWindow(hApplicationPageEndTaskButton, TRUE);
473     }
474     else
475     {
476         EnableWindow(hApplicationPageEndTaskButton, FALSE);
477     }
478     /* Enable "Switch To" button only if one app is selected */
479     if (ListView_GetSelectedCount(hApplicationPageListCtrl) == 1 )
480     {
481         EnableWindow(hApplicationPageSwitchToButton, TRUE);
482     }
483     else
484     {
485     EnableWindow(hApplicationPageSwitchToButton, FALSE);
486     }
487 
488     /* If we are on the applications tab the windows menu will be */
489     /* present on the menu bar so enable & disable the menu items */
490     if (TabCtrl_GetCurSel(hTabWnd) == 0)
491     {
492         HMENU  hMenu;
493         HMENU  hWindowsMenu;
494 
495         hMenu = GetMenu(hMainWnd);
496         hWindowsMenu = GetSubMenu(hMenu, 3);
497 
498         /* Only one item selected */
499         if (ListView_GetSelectedCount(hApplicationPageListCtrl) == 1)
500         {
501             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
502             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
503             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
504             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
505             EnableMenuItem(hWindowsMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
506             EnableMenuItem(hWindowsMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_ENABLED);
507         }
508         /* More than one item selected */
509         else if (ListView_GetSelectedCount(hApplicationPageListCtrl) > 1)
510         {
511             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_ENABLED);
512             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_ENABLED);
513             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_ENABLED);
514             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_ENABLED);
515             EnableMenuItem(hWindowsMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_ENABLED);
516             EnableMenuItem(hWindowsMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
517         }
518         /* No items selected */
519         else
520         {
521             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEHORIZONTALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
522             EnableMenuItem(hWindowsMenu, ID_WINDOWS_TILEVERTICALLY, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
523             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MINIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
524             EnableMenuItem(hWindowsMenu, ID_WINDOWS_MAXIMIZE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
525             EnableMenuItem(hWindowsMenu, ID_WINDOWS_CASCADE, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
526             EnableMenuItem(hWindowsMenu, ID_WINDOWS_BRINGTOFRONT, MF_BYCOMMAND|MF_DISABLED|MF_GRAYED);
527         }
528     }
529 }
530 
531 void ApplicationPageOnNotify(WPARAM wParam, LPARAM lParam)
532 {
533     int                           idctrl;
534     LPNMHDR                       pnmh;
535     LPNM_LISTVIEW                 pnmv;
536     LV_DISPINFO*                  pnmdi;
537     LPAPPLICATION_PAGE_LIST_ITEM  pAPLI;
538     WCHAR                         szMsg[256];
539 
540 
541     idctrl = (int) wParam;
542     pnmh = (LPNMHDR) lParam;
543     pnmv = (LPNM_LISTVIEW) lParam;
544     pnmdi = (LV_DISPINFO*) lParam;
545 
546     if (pnmh->hwndFrom == hApplicationPageListCtrl) {
547         switch (pnmh->code) {
548         case LVN_ITEMCHANGED:
549             ApplicationPageUpdate();
550             break;
551 
552         case LVN_GETDISPINFO:
553             pAPLI = (LPAPPLICATION_PAGE_LIST_ITEM)pnmdi->item.lParam;
554 
555             /* Update the item text */
556             if (pnmdi->item.iSubItem == 0)
557             {
558                 wcsncpy(pnmdi->item.pszText, pAPLI->szTitle, pnmdi->item.cchTextMax);
559             }
560 
561             /* Update the item status */
562             else if (pnmdi->item.iSubItem == 1)
563             {
564                 if (pAPLI->bHung)
565                 {
566                     LoadStringW( GetModuleHandleW(NULL), IDS_Not_Responding , szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
567                 }
568                 else
569                 {
570                     LoadStringW( GetModuleHandleW(NULL), IDS_Running, (LPWSTR) szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
571                 }
572                 wcsncpy(pnmdi->item.pszText, szMsg, pnmdi->item.cchTextMax);
573             }
574 
575             break;
576 
577         case NM_RCLICK:
578 
579             if (ListView_GetSelectedCount(hApplicationPageListCtrl) < 1)
580             {
581                 ApplicationPageShowContextMenu1();
582             }
583             else
584             {
585                 ApplicationPageShowContextMenu2();
586             }
587 
588             break;
589 
590         case NM_DBLCLK:
591 
592             ApplicationPage_OnSwitchTo();
593 
594             break;
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