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