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