1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: win32ss/user/user32/controls/appswitch.c
5 * PURPOSE: app switching functionality
6 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
7 * David Quintana (gigaherz@gmail.com)
8 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
9 */
10
11 //
12 // TODO:
13 // Move to Win32k.
14 // Add registry support.
15 //
16 //
17
18 #include <user32.h>
19
20 WINE_DEFAULT_DEBUG_CHANNEL(user32);
21
22 #define DIALOG_MARGIN 8 // margin of dialog contents
23
24 #define CX_ICON 32 // width of icon
25 #define CY_ICON 32 // height of icon
26 #define ICON_MARGIN 4 // margin width around an icon
27
28 #define CX_ITEM (CX_ICON + 2 * ICON_MARGIN)
29 #define CY_ITEM (CY_ICON + 2 * ICON_MARGIN)
30 #define ITEM_MARGIN 4 // margin width around an item
31
32 #define CX_ITEM_SPACE (CX_ITEM + 2 * ITEM_MARGIN)
33 #define CY_ITEM_SPACE (CY_ITEM + 2 * ITEM_MARGIN)
34
35 #define CY_TEXT_MARGIN 4 // margin height around text
36
37 // limit the number of windows shown in the alt-tab window
38 // 120 windows results in (12*40) by (10*40) pixels worth of icons.
39 #define MAX_WINDOWS 120
40
41 // Global variables
42 HWND switchdialog = NULL;
43 HFONT dialogFont;
44 int selectedWindow = 0;
45 BOOL isOpen = FALSE;
46
47 int fontHeight=0;
48
49 WCHAR windowText[1024];
50
51 HWND windowList[MAX_WINDOWS];
52 HICON iconList[MAX_WINDOWS];
53 int windowCount = 0;
54
55 int cxBorder, cyBorder;
56 int nItems, nCols, nRows;
57 int itemsW, itemsH;
58 int totalW, totalH;
59 int xOffset, yOffset;
60 POINT ptStart;
61
62 int nShift = 0;
63
64 BOOL Esc = FALSE;
65
66 BOOL CoolSwitch = TRUE;
67 int CoolSwitchRows = 3;
68 int CoolSwitchColumns = 7;
69
70 // window style
71 const DWORD Style = WS_POPUP | WS_BORDER | WS_DISABLED;
72 const DWORD ExStyle = WS_EX_TOPMOST | WS_EX_DLGMODALFRAME | WS_EX_TOOLWINDOW;
73
LoadCoolSwitchSettings(void)74 BOOL LoadCoolSwitchSettings(void)
75 {
76 CoolSwitch = TRUE;
77 CoolSwitchRows = 3;
78 CoolSwitchColumns = 7;
79
80 // FIXME: load the settings from registry
81
82 TRACE("CoolSwitch: %d\n", CoolSwitch);
83 TRACE("CoolSwitchRows: %d\n", CoolSwitchRows);
84 TRACE("CoolSwitchColumns: %d\n", CoolSwitchColumns);
85
86 return TRUE;
87 }
88
ResizeAndCenter(HWND hwnd,int width,int height)89 void ResizeAndCenter(HWND hwnd, int width, int height)
90 {
91 int x, y;
92 RECT Rect;
93
94 int screenwidth = GetSystemMetrics(SM_CXSCREEN);
95 int screenheight = GetSystemMetrics(SM_CYSCREEN);
96
97 x = (screenwidth - width) / 2;
98 y = (screenheight - height) / 2;
99
100 SetRect(&Rect, x, y, x + width, y + height);
101 AdjustWindowRectEx(&Rect, Style, FALSE, ExStyle);
102
103 x = Rect.left;
104 y = Rect.top;
105 width = Rect.right - Rect.left;
106 height = Rect.bottom - Rect.top;
107 MoveWindow(hwnd, x, y, width, height, FALSE);
108
109 ptStart.x = x;
110 ptStart.y = y;
111 }
112
CompleteSwitch(BOOL doSwitch)113 void CompleteSwitch(BOOL doSwitch)
114 {
115 if (!isOpen)
116 return;
117
118 isOpen = FALSE;
119
120 TRACE("[ATbot] CompleteSwitch Hiding Window.\n");
121 ShowWindowAsync(switchdialog, SW_HIDE);
122
123 if(doSwitch)
124 {
125 if(selectedWindow >= windowCount)
126 return;
127
128 // FIXME: workaround because reactos fails to activate the previous window correctly.
129 //if(selectedWindow != 0)
130 {
131 HWND hwnd = windowList[selectedWindow];
132
133 GetWindowTextW(hwnd, windowText, _countof(windowText));
134
135 TRACE("[ATbot] CompleteSwitch Switching to 0x%08x (%ls)\n", hwnd, windowText);
136
137 SwitchToThisWindow(hwnd, TRUE);
138 }
139 }
140
141 windowCount = 0;
142 }
143
EnumerateCallback(HWND window,LPARAM lParam)144 BOOL CALLBACK EnumerateCallback(HWND window, LPARAM lParam)
145 {
146 HICON hIcon = NULL;
147 LRESULT bAlive;
148
149 UNREFERENCED_PARAMETER(lParam);
150
151 // First try to get the big icon assigned to the window
152 #define ICON_TIMEOUT 100 // in milliseconds
153 bAlive = SendMessageTimeoutW(window, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG | SMTO_BLOCK,
154 ICON_TIMEOUT, (PDWORD_PTR)&hIcon);
155 if (!hIcon)
156 {
157 // If no icon is assigned, try to get the icon assigned to the windows' class
158 hIcon = (HICON)GetClassLongPtrW(window, GCL_HICON);
159 if (!hIcon)
160 {
161 // If we still don't have an icon, see if we can do with the small icon,
162 // or a default application icon
163 if (bAlive)
164 {
165 SendMessageTimeoutW(window, WM_GETICON, ICON_SMALL2, 0,
166 SMTO_ABORTIFHUNG | SMTO_BLOCK, ICON_TIMEOUT,
167 (PDWORD_PTR)&hIcon);
168 }
169 #undef ICON_TIMEOUT
170 if (!hIcon)
171 {
172 // using windows logo icon as default
173 hIcon = gpsi->hIconWindows;
174 if (!hIcon)
175 {
176 //if all attempts to get icon fails go to the next window
177 return TRUE;
178 }
179 }
180 }
181 }
182
183 windowList[windowCount] = window;
184 iconList[windowCount] = CopyIcon(hIcon);
185 windowCount++;
186
187 // If we got to the max number of windows, we won't be able to add any more
188 return (windowCount < MAX_WINDOWS);
189 }
190
GetNiceRootOwner(HWND hwnd)191 static HWND GetNiceRootOwner(HWND hwnd)
192 {
193 HWND hwndOwner;
194 DWORD ExStyle, OwnerExStyle;
195
196 for (;;)
197 {
198 // A window with WS_EX_APPWINDOW is treated as if it has no owner
199 ExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
200 if (ExStyle & WS_EX_APPWINDOW)
201 break;
202
203 // Is the owner visible?
204 // An window with WS_EX_TOOLWINDOW is treated as if it weren't visible
205 hwndOwner = GetWindow(hwnd, GW_OWNER);
206 OwnerExStyle = GetWindowLong(hwndOwner, GWL_EXSTYLE);
207 if (!IsWindowVisible(hwndOwner) || (OwnerExStyle & WS_EX_TOOLWINDOW))
208 break;
209
210 hwnd = hwndOwner;
211 }
212
213 return hwnd;
214 }
215
216 // c.f. http://blogs.msdn.com/b/oldnewthing/archive/2007/10/08/5351207.aspx
IsAltTabWindow(HWND hwnd)217 BOOL IsAltTabWindow(HWND hwnd)
218 {
219 DWORD ExStyle;
220 RECT rc;
221 HWND hwndTry, hwndWalk;
222 WCHAR szClass[64];
223
224 // must be visible
225 if (!IsWindowVisible(hwnd))
226 return FALSE;
227
228 // must not be WS_EX_TOOLWINDOW nor WS_EX_NOACTIVATE
229 ExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
230 if (ExStyle & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))
231 return FALSE;
232
233 // must be not empty rect
234 GetWindowRect(hwnd, &rc);
235 if (IsRectEmpty(&rc))
236 return FALSE;
237
238 // check special windows
239 if (!GetClassNameW(hwnd, szClass, _countof(szClass)) ||
240 wcscmp(szClass, L"Shell_TrayWnd") == 0 ||
241 wcscmp(szClass, L"Progman") == 0)
242 {
243 return TRUE;
244 }
245
246 // get 'nice' root owner
247 hwndWalk = GetNiceRootOwner(hwnd);
248
249 // walk back from hwndWalk toward hwnd
250 for (;;)
251 {
252 hwndTry = GetLastActivePopup(hwndWalk);
253 if (hwndTry == hwndWalk)
254 break;
255
256 ExStyle = GetWindowLong(hwndTry, GWL_EXSTYLE);
257 if (IsWindowVisible(hwndTry) && !(ExStyle & WS_EX_TOOLWINDOW))
258 break;
259
260 hwndWalk = hwndTry;
261 }
262
263 return hwnd == hwndTry; // Reached?
264 }
265
266 static BOOL CALLBACK
EnumWindowsProc(HWND hwnd,LPARAM lParam)267 EnumWindowsProc(HWND hwnd, LPARAM lParam)
268 {
269 if (IsAltTabWindow(hwnd))
270 {
271 if (!EnumerateCallback(hwnd, lParam))
272 return FALSE;
273 }
274 return TRUE;
275 }
276
ProcessMouseMessage(UINT message,LPARAM lParam)277 void ProcessMouseMessage(UINT message, LPARAM lParam)
278 {
279 int xPos = LOWORD(lParam);
280 int yPos = HIWORD(lParam);
281
282 int xIndex = (xPos - DIALOG_MARGIN) / CX_ITEM_SPACE;
283 int yIndex = (yPos - DIALOG_MARGIN) / CY_ITEM_SPACE;
284
285 if (xIndex < 0 || nCols <= xIndex ||
286 yIndex < 0 || nRows <= yIndex)
287 {
288 return;
289 }
290
291 selectedWindow = (yIndex*nCols) + xIndex;
292 if (message == WM_MOUSEMOVE)
293 {
294 InvalidateRect(switchdialog, NULL, TRUE);
295 //RedrawWindow(switchdialog, NULL, NULL, 0);
296 }
297 else
298 {
299 selectedWindow = (yIndex*nCols) + xIndex;
300 CompleteSwitch(TRUE);
301 }
302 }
303
OnPaint(HWND hWnd)304 void OnPaint(HWND hWnd)
305 {
306 HDC dialogDC;
307 PAINTSTRUCT paint;
308 RECT cRC, textRC;
309 int i, xPos, yPos, CharCount;
310 HFONT dcFont;
311 HICON hIcon;
312 HPEN hPen;
313 COLORREF Color;
314
315 // check
316 if (nCols == 0 || nItems == 0)
317 return;
318
319 // begin painting
320 dialogDC = BeginPaint(hWnd, &paint);
321 if (dialogDC == NULL)
322 return;
323
324 // fill the client area
325 GetClientRect(hWnd, &cRC);
326 FillRect(dialogDC, &cRC, (HBRUSH)(COLOR_3DFACE + 1));
327
328 // if the selection index exceeded the display items, then
329 // do display item shifting
330 if (selectedWindow >= nItems)
331 nShift = selectedWindow - nItems + 1;
332 else
333 nShift = 0;
334
335 for (i = 0; i < nItems; ++i)
336 {
337 // get the icon to display
338 hIcon = iconList[i + nShift];
339
340 // calculate the position where we start drawing
341 xPos = DIALOG_MARGIN + CX_ITEM_SPACE * (i % nCols) + ITEM_MARGIN;
342 yPos = DIALOG_MARGIN + CY_ITEM_SPACE * (i / nCols) + ITEM_MARGIN;
343
344 // centering
345 if (nItems < CoolSwitchColumns)
346 {
347 xPos += (itemsW - nItems * CX_ITEM_SPACE) / 2;
348 }
349
350 // if this position is selected,
351 if (selectedWindow == i + nShift)
352 {
353 // create a solid pen
354 Color = GetSysColor(COLOR_HIGHLIGHT);
355 hPen = CreatePen(PS_SOLID, 1, Color);
356
357 // draw a rectangle with using the pen
358 SelectObject(dialogDC, hPen);
359 SelectObject(dialogDC, GetStockObject(NULL_BRUSH));
360 Rectangle(dialogDC, xPos, yPos, xPos + CX_ITEM, yPos + CY_ITEM);
361 Rectangle(dialogDC, xPos + 1, yPos + 1,
362 xPos + CX_ITEM - 1, yPos + CY_ITEM - 1);
363
364 // delete the pen
365 DeleteObject(hPen);
366 }
367
368 // draw icon
369 DrawIconEx(dialogDC, xPos + ICON_MARGIN, yPos + ICON_MARGIN,
370 hIcon, CX_ICON, CY_ICON, 0, NULL, DI_NORMAL);
371 }
372
373 // set the text rectangle
374 SetRect(&textRC, DIALOG_MARGIN, DIALOG_MARGIN + itemsH,
375 totalW - DIALOG_MARGIN, totalH - DIALOG_MARGIN);
376
377 // draw the sunken button around text
378 DrawFrameControl(dialogDC, &textRC, DFC_BUTTON,
379 DFCS_BUTTONPUSH | DFCS_PUSHED);
380
381 // get text
382 CharCount = GetWindowTextW(windowList[selectedWindow], windowText,
383 _countof(windowText));
384
385 // draw text
386 dcFont = SelectObject(dialogDC, dialogFont);
387 SetTextColor(dialogDC, GetSysColor(COLOR_BTNTEXT));
388 SetBkMode(dialogDC, TRANSPARENT);
389 DrawTextW(dialogDC, windowText, CharCount, &textRC,
390 DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE);
391 SelectObject(dialogDC, dcFont);
392
393 // end painting
394 EndPaint(hWnd, &paint);
395 }
396
CreateSwitcherWindow(HINSTANCE hInstance)397 DWORD CreateSwitcherWindow(HINSTANCE hInstance)
398 {
399 switchdialog = CreateWindowExW( WS_EX_TOPMOST|WS_EX_DLGMODALFRAME|WS_EX_TOOLWINDOW,
400 WC_SWITCH,
401 L"",
402 WS_POPUP|WS_BORDER|WS_DISABLED,
403 CW_USEDEFAULT,
404 CW_USEDEFAULT,
405 400, 150,
406 NULL, NULL,
407 hInstance, NULL);
408 if (!switchdialog)
409 {
410 TRACE("[ATbot] Task Switcher Window failed to create.\n");
411 return 0;
412 }
413
414 isOpen = FALSE;
415 return 1;
416 }
417
GetDialogFont(VOID)418 DWORD GetDialogFont(VOID)
419 {
420 HDC tDC;
421 TEXTMETRIC tm;
422
423 dialogFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
424
425 tDC = GetDC(0);
426 GetTextMetrics(tDC, &tm);
427 fontHeight = tm.tmHeight;
428 ReleaseDC(0, tDC);
429
430 return 1;
431 }
432
PrepareWindow(VOID)433 void PrepareWindow(VOID)
434 {
435 nItems = windowCount;
436
437 nCols = CoolSwitchColumns;
438 nRows = (nItems + CoolSwitchColumns - 1) / CoolSwitchColumns;
439 if (nRows > CoolSwitchRows)
440 {
441 nRows = CoolSwitchRows;
442 nItems = nRows * nCols;
443 }
444
445 itemsW = nCols * CX_ITEM_SPACE;
446 itemsH = nRows * CY_ITEM_SPACE;
447
448 totalW = itemsW + 2 * DIALOG_MARGIN;
449 totalH = itemsH + 2 * DIALOG_MARGIN;
450 totalH += fontHeight + 2 * CY_TEXT_MARGIN;
451
452 ResizeAndCenter(switchdialog, totalW, totalH);
453 }
454
ProcessHotKey(VOID)455 BOOL ProcessHotKey(VOID)
456 {
457 if (!isOpen)
458 {
459 windowCount = 0;
460 EnumWindows(EnumWindowsProc, 0);
461
462 if (windowCount == 0)
463 return FALSE;
464
465 if (windowCount == 1)
466 {
467 SwitchToThisWindow(windowList[0], TRUE);
468 return FALSE;
469 }
470
471 if (!CreateSwitcherWindow(User32Instance))
472 return FALSE;
473
474 selectedWindow = 1;
475
476 TRACE("[ATbot] HotKey Received. Opening window.\n");
477 ShowWindowAsync(switchdialog, SW_SHOWNORMAL);
478 SwitchToThisWindow(switchdialog, TRUE);
479 isOpen = TRUE;
480 }
481 else
482 {
483 TRACE("[ATbot] HotKey Received Rotating.\n");
484 selectedWindow = (selectedWindow + 1)%windowCount;
485 InvalidateRect(switchdialog, NULL, TRUE);
486 }
487 return TRUE;
488 }
489
RotateTasks(BOOL bShift)490 void RotateTasks(BOOL bShift)
491 {
492 HWND hwndFirst, hwndLast;
493 DWORD Size;
494
495 if (windowCount < 2 || !Esc)
496 return;
497
498 hwndFirst = windowList[0];
499 hwndLast = windowList[windowCount - 1];
500
501 if (bShift)
502 {
503 SetWindowPos(hwndLast, HWND_TOP, 0, 0, 0, 0,
504 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
505 SWP_NOOWNERZORDER | SWP_NOREPOSITION | SWP_ASYNCWINDOWPOS);
506
507 SwitchToThisWindow(hwndLast, TRUE);
508
509 Size = (windowCount - 1) * sizeof(HWND);
510 MoveMemory(&windowList[1], &windowList[0], Size);
511 windowList[0] = hwndLast;
512 }
513 else
514 {
515 SetWindowPos(hwndFirst, hwndLast, 0, 0, 0, 0,
516 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
517 SWP_NOOWNERZORDER | SWP_NOREPOSITION | SWP_ASYNCWINDOWPOS);
518
519 SwitchToThisWindow(windowList[1], TRUE);
520
521 Size = (windowCount - 1) * sizeof(HWND);
522 MoveMemory(&windowList[0], &windowList[1], Size);
523 windowList[windowCount - 1] = hwndFirst;
524 }
525 }
526
MoveLeft(void)527 static void MoveLeft(void)
528 {
529 selectedWindow = selectedWindow - 1;
530 if (selectedWindow < 0)
531 selectedWindow = windowCount - 1;
532 InvalidateRect(switchdialog, NULL, TRUE);
533 }
534
MoveRight(void)535 static void MoveRight(void)
536 {
537 selectedWindow = (selectedWindow + 1) % windowCount;
538 InvalidateRect(switchdialog, NULL, TRUE);
539 }
540
MoveUp(void)541 static void MoveUp(void)
542 {
543 INT iRow = selectedWindow / nCols;
544 INT iCol = selectedWindow % nCols;
545
546 --iRow;
547 if (iRow < 0)
548 iRow = nRows - 1;
549
550 selectedWindow = iRow * nCols + iCol;
551 if (selectedWindow >= windowCount)
552 selectedWindow = windowCount - 1;
553 InvalidateRect(switchdialog, NULL, TRUE);
554 }
555
MoveDown(void)556 static void MoveDown(void)
557 {
558 INT iRow = selectedWindow / nCols;
559 INT iCol = selectedWindow % nCols;
560
561 ++iRow;
562 if (iRow >= nRows)
563 iRow = 0;
564
565 selectedWindow = iRow * nCols + iCol;
566 if (selectedWindow >= windowCount)
567 selectedWindow = windowCount - 1;
568 InvalidateRect(switchdialog, NULL, TRUE);
569 }
570
571 VOID
DestroyAppWindows(VOID)572 DestroyAppWindows(VOID)
573 {
574 // for every item of the icon list:
575 INT i;
576 for (i = 0; i < windowCount; ++i)
577 {
578 // destroy the icon
579 DestroyIcon(iconList[i]);
580 iconList[i] = NULL;
581 }
582 }
583
DoAppSwitch(WPARAM wParam,LPARAM lParam)584 LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam )
585 {
586 HWND hwndActive;
587 MSG msg;
588
589 // FIXME: Is loading timing OK?
590 LoadCoolSwitchSettings();
591
592 if (!CoolSwitch)
593 return 0;
594
595 // Already in the loop.
596 if (switchdialog || Esc) return 0;
597
598 if (lParam == VK_ESCAPE)
599 {
600 Esc = TRUE;
601
602 windowCount = 0;
603 EnumWindows(EnumWindowsProc, 0);
604
605 if (windowCount < 2)
606 return 0;
607
608 RotateTasks(GetAsyncKeyState(VK_SHIFT) < 0);
609
610 hwndActive = GetActiveWindow();
611
612 if (hwndActive == NULL)
613 {
614 Esc = FALSE;
615 return 0;
616 }
617 }
618
619 // Capture current active window.
620 hwndActive = GetActiveWindow();
621 if (hwndActive)
622 SetCapture(hwndActive);
623
624 switch (lParam)
625 {
626 case VK_TAB:
627 if (!GetDialogFont() || !ProcessHotKey())
628 goto Exit;
629 break;
630
631 case VK_ESCAPE:
632 break;
633
634 default:
635 goto Exit;
636 }
637
638 if (!hwndActive)
639 goto Exit;
640
641 // Main message loop:
642 while (1)
643 {
644 for (;;)
645 {
646 if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ))
647 {
648 if (!CallMsgFilterW( &msg, MSGF_NEXTWINDOW )) break;
649 /* remove the message from the queue */
650 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
651 }
652 else
653 WaitMessage();
654 }
655
656 switch (msg.message)
657 {
658 case WM_KEYUP:
659 {
660 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
661 if (msg.wParam == VK_MENU)
662 {
663 CompleteSwitch(TRUE);
664 }
665 else if (msg.wParam == VK_RETURN)
666 {
667 CompleteSwitch(TRUE);
668 }
669 else if (msg.wParam == VK_ESCAPE)
670 {
671 TRACE("DoAppSwitch VK_ESCAPE 2\n");
672 CompleteSwitch(FALSE);
673 }
674 goto Exit; //break;
675 }
676
677 case WM_SYSKEYDOWN:
678 {
679 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
680 if (HIWORD(msg.lParam) & KF_ALTDOWN)
681 {
682 if ( msg.wParam == VK_TAB )
683 {
684 if (Esc) break;
685 if (GetKeyState(VK_SHIFT) < 0)
686 {
687 MoveLeft();
688 }
689 else
690 {
691 MoveRight();
692 }
693 }
694 else if ( msg.wParam == VK_ESCAPE )
695 {
696 if (!Esc) break;
697 RotateTasks(GetKeyState(VK_SHIFT) < 0);
698 }
699 else if ( msg.wParam == VK_LEFT )
700 {
701 MoveLeft();
702 }
703 else if ( msg.wParam == VK_RIGHT )
704 {
705 MoveRight();
706 }
707 else if ( msg.wParam == VK_UP )
708 {
709 MoveUp();
710 }
711 else if ( msg.wParam == VK_DOWN )
712 {
713 MoveDown();
714 }
715 }
716 break;
717 }
718
719 case WM_LBUTTONUP:
720 PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
721 ProcessMouseMessage(msg.message, msg.lParam);
722 goto Exit;
723
724 default:
725 if (PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ))
726 {
727 TranslateMessage(&msg);
728 DispatchMessageW(&msg);
729 }
730 break;
731 }
732 }
733 Exit:
734 ReleaseCapture();
735 if (switchdialog) DestroyWindow(switchdialog);
736 if (Esc) DestroyAppWindows();
737 switchdialog = NULL;
738 selectedWindow = 0;
739 windowCount = 0;
740 Esc = FALSE;
741 return 0;
742 }
743
744 //
745 // Switch System Class Window Proc.
746 //
SwitchWndProc_common(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL unicode)747 LRESULT WINAPI SwitchWndProc_common(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL unicode )
748 {
749 PWND pWnd;
750 PALTTABINFO ati;
751 pWnd = ValidateHwnd(hWnd);
752 if (pWnd)
753 {
754 if (!pWnd->fnid)
755 {
756 NtUserSetWindowFNID(hWnd, FNID_SWITCH);
757 }
758 }
759
760 switch (uMsg)
761 {
762 case WM_NCCREATE:
763 if (!(ati = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ati))))
764 return 0;
765 SetWindowLongPtrW( hWnd, 0, (LONG_PTR)ati );
766 return TRUE;
767
768 case WM_SHOWWINDOW:
769 if (wParam)
770 {
771 PrepareWindow();
772 ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0);
773 ati->cbSize = sizeof(ALTTABINFO);
774 ati->cItems = nItems;
775 ati->cColumns = nCols;
776 ati->cRows = nRows;
777 if (nCols)
778 {
779 ati->iColFocus = (selectedWindow - nShift) % nCols;
780 ati->iRowFocus = (selectedWindow - nShift) / nCols;
781 }
782 else
783 {
784 ati->iColFocus = 0;
785 ati->iRowFocus = 0;
786 }
787 ati->cxItem = CX_ITEM_SPACE;
788 ati->cyItem = CY_ITEM_SPACE;
789 ati->ptStart = ptStart;
790 }
791 return 0;
792
793 case WM_MOUSEMOVE:
794 ProcessMouseMessage(uMsg, lParam);
795 return 0;
796
797 case WM_ACTIVATE:
798 if (wParam == WA_INACTIVE)
799 {
800 CompleteSwitch(FALSE);
801 }
802 return 0;
803
804 case WM_PAINT:
805 OnPaint(hWnd);
806 return 0;
807
808 case WM_DESTROY:
809 isOpen = FALSE;
810 ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0);
811 HeapFree( GetProcessHeap(), 0, ati );
812 SetWindowLongPtrW( hWnd, 0, 0 );
813 DestroyAppWindows();
814 NtUserSetWindowFNID(hWnd, FNID_DESTROY);
815 return 0;
816 }
817 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
818 }
819
SwitchWndProcA(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)820 LRESULT WINAPI SwitchWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
821 {
822 return SwitchWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
823 }
824
SwitchWndProcW(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)825 LRESULT WINAPI SwitchWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
826 {
827 return SwitchWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
828 }
829