merge trunk head (37902)
[reactos.git] / reactos / subsystems / win32 / csrss / win32csr / appswitch.c
1
2 /*
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: subsys/csrss/win32csr/appswitch.c
6 * PURPOSE: app switching functionality
7 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
8 */
9
10 #include "w32csr.h"
11 //#define NDEBUG
12 #include <debug.h>
13
14 typedef struct APPSWITCH_ITEM
15 {
16 HWND hwndDlg;
17 DWORD zPos;
18 HICON hIcon;
19 BOOL bFocus;
20 struct APPSWITCH_ITEM * Next;
21 WCHAR szText[1];
22 }APPSWITCH_ITEM, *PAPPSWITCH_ITEM;
23
24 static PAPPSWITCH_ITEM pRoot = NULL;
25 static DWORD NumOfWindows = 0;
26 static HWND hAppWindowDlg = NULL;
27 static HHOOK hhk = NULL;
28
29 UINT WINAPI PrivateExtractIconExW(LPCWSTR,int,HICON*,HICON*,UINT);
30
31
32 BOOL
33 CALLBACK
34 EnumWindowEnumProc(
35 HWND hwnd,
36 LPARAM lParam
37 )
38 {
39 PAPPSWITCH_ITEM pItem;
40 UINT Length;
41 HICON hIcon;
42 PAPPSWITCH_ITEM pCurItem;
43 DWORD dwPid;
44 HANDLE hProcess;
45 WCHAR szFileName[MAX_PATH] = {0};
46
47 /* check if the enumerated window is visible */
48 if (!IsWindowVisible(hwnd))
49 return TRUE;
50 /* get window icon */
51 hIcon = (HICON)SendMessage(hwnd, WM_GETICON, ICON_BIG, 0);
52 if (!hIcon)
53 {
54 GetWindowThreadProcessId(hwnd, &dwPid);
55 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, dwPid);
56 if (hProcess)
57 {
58 if (GetModuleFileNameExW(hProcess, NULL, szFileName, MAX_PATH))
59 {
60 szFileName[MAX_PATH-1] = L'\0';
61 PrivateExtractIconExW(szFileName, 0, &hIcon, NULL, 1);
62 }
63 }
64 }
65 else
66 {
67 /* icons from WM_GETICON need to be copied */
68 hIcon = CopyIcon(hIcon);
69 }
70 /* get the text length */
71 Length = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
72 /* allocate item structure for it */
73 pItem = (PAPPSWITCH_ITEM)HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(APPSWITCH_ITEM) + Length * sizeof(WCHAR));
74 if (!pItem)
75 return TRUE;
76 if (Length)
77 {
78 /* retrieve the window text when available */
79 SendMessageW(hwnd, WM_GETTEXT, Length+1, (LPARAM)pItem->szText);
80 }
81 /* copy the window icon */
82 pItem->hIcon = hIcon;
83 /* store window handle */
84 pItem->hwndDlg = hwnd;
85 /* is the window the active window */
86 if (GetActiveWindow() == hwnd)
87 pItem->bFocus = TRUE;
88
89 if (!pRoot)
90 {
91 /* first item */
92 pRoot = pItem;
93 return TRUE;
94 }
95
96 /* enumerate the last item */
97 pCurItem = pRoot;
98 while(pCurItem->Next)
99 pCurItem = pCurItem->Next;
100
101 /* insert it into the list */
102 pCurItem->Next = pItem;
103 NumOfWindows++;
104 return TRUE;
105 }
106
107 VOID
108 EnumerateAppWindows(HDESK hDesk, HWND hwndDlg)
109 {
110 /* initialize defaults */
111 pRoot = NULL;
112 NumOfWindows = 0;
113 hAppWindowDlg = hwndDlg;
114 /* enumerate all windows */
115 EnumDesktopWindows(hDesk, EnumWindowEnumProc, (LPARAM)NULL);
116 if (NumOfWindows > 7)
117 {
118 /* FIXME resize window */
119 }
120 }
121
122 VOID
123 MarkNextEntryAsActive()
124 {
125 PAPPSWITCH_ITEM pItem;
126
127 pItem = pRoot;
128 if (!pRoot)
129 return;
130
131 while(pItem)
132 {
133 if (pItem->bFocus)
134 {
135 pItem->bFocus = FALSE;
136 if (pItem->Next)
137 pItem->Next->bFocus = TRUE;
138 else
139 pRoot->bFocus = TRUE;
140 }
141 pItem = pItem->Next;
142 }
143
144 InvalidateRgn(hAppWindowDlg, NULL, TRUE);
145 }
146
147
148 LRESULT
149 CALLBACK
150 KeyboardHookProc(
151 int nCode,
152 WPARAM wParam,
153 LPARAM lParam
154 )
155 {
156 PKBDLLHOOKSTRUCT hk = (PKBDLLHOOKSTRUCT) lParam;
157
158 if (wParam == WM_SYSKEYUP)
159 {
160 /* is tab key pressed */
161 if (hk->vkCode == VK_TAB)
162 {
163 if (hAppWindowDlg == NULL)
164 {
165 /* FIXME
166 * launch window
167 */
168 DPRINT1("launch alt-tab window\n");
169 }
170 else
171 {
172 MarkNextEntryAsActive();
173 }
174 }
175 }
176 return CallNextHookEx(hhk, nCode, wParam, lParam);
177 }
178
179 VOID
180 PaintAppWindows(HWND hwndDlg, HDC hDc)
181 {
182 DWORD dwIndex, X, Y;
183 PAPPSWITCH_ITEM pCurItem;
184 RECT Rect;
185 DWORD XSize, YSize, XMax;
186 HBRUSH hBrush;
187
188 X = 10;
189 Y = 10;
190 XSize = GetSystemMetrics(SM_CXICON);
191 YSize = GetSystemMetrics(SM_CYICON);
192 XMax = (XSize+(XSize/2)) * 7 + X;
193 pCurItem = pRoot;
194
195 for (dwIndex = 0; dwIndex < NumOfWindows; dwIndex++)
196 {
197 if (X >= XMax)
198 {
199 X = 10;
200 Y += YSize + (YSize/2);
201 }
202 if (pCurItem->bFocus)
203 {
204 hBrush = CreateSolidBrush(RGB(30, 30, 255));
205 SetRect(&Rect, X-5, Y-5, X + XSize + 5, Y + YSize + 5);
206 FillRect(hDc, &Rect, hBrush);
207 DeleteObject((HGDIOBJ)hBrush);
208 SendDlgItemMessageW(hwndDlg, IDC_STATIC_CUR_APP, WM_SETTEXT, 0, (LPARAM)pCurItem->szText);
209 }
210
211 DrawIcon(hDc, X, Y, pCurItem->hIcon);
212 pCurItem = pCurItem->Next;
213 X += XSize +(XSize/2);
214 }
215 }
216 VOID
217 DestroyAppWindows()
218 {
219 PAPPSWITCH_ITEM pCurItem, pNextItem;
220
221 pCurItem = pRoot;
222 while(pCurItem)
223 {
224 pNextItem = pCurItem->Next;
225 DestroyIcon(pCurItem->hIcon);
226 HeapFree(Win32CsrApiHeap, 0, pCurItem);
227 pCurItem = pNextItem;
228 }
229 pRoot = NULL;
230 hAppWindowDlg = NULL;
231 NumOfWindows = 0;
232 }
233
234 INT_PTR
235 CALLBACK
236 SwitchWindowDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
237 {
238 PAINTSTRUCT Paint;
239 HDESK hInput;
240
241 switch (message)
242 {
243 case WM_INITDIALOG:
244 hInput = OpenInputDesktop(0,0, GENERIC_ALL);
245 if (hInput)
246 {
247 EnumerateAppWindows(hInput, hwndDlg);
248 CloseDesktop(hInput);
249 }
250 return TRUE;
251 case WM_PAINT:
252 BeginPaint(hwndDlg, &Paint);
253 PaintAppWindows(hwndDlg, Paint.hdc);
254 EndPaint(hwndDlg, &Paint);
255 break;
256 case WM_DESTROY:
257 DestroyAppWindows();
258 break;
259 }
260 return FALSE;
261 }
262
263 VOID
264 WINAPI
265 InitializeAppSwitchHook()
266 {
267 hhk = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, NULL, 0);
268 DPRINT("InitializeAppSwitchHook hhk %p\n", hhk);
269 }