Index: reactos/win32ss/user/user32/controls/appswitch.c =================================================================== --- reactos/win32ss/user/user32/controls/appswitch.c (revision 72934) +++ reactos/win32ss/user/user32/controls/appswitch.c (working copy) @@ -5,6 +5,7 @@ * PURPOSE: app switching functionality * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) * David Quintana (gigaherz@gmail.com) + * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ #include @@ -12,259 +13,342 @@ #include WINE_DEFAULT_DEBUG_CHANNEL(user32); -// limit the number of windows shown in the alt-tab window -// 120 windows results in (12*40) by (10*40) pixels worth of icons. -#define MAX_WINDOWS 120 +// +// Constants +// +#define DIALOG_MARGIN 8 // margin of dialog contents -// Global variables -HWND switchdialog = NULL; -HFONT dialogFont; -int selectedWindow = 0; -BOOL isOpen = FALSE; +#define CX_ICON 32 // width of icon +#define CY_ICON 32 // height of icon +#define ICON_MARGIN 4 // margin width around an icon -int fontHeight=0; +#define CX_ITEM (CX_ICON + 2 * ICON_MARGIN) +#define CY_ITEM (CY_ICON + 2 * ICON_MARGIN) +#define ITEM_MARGIN 4 // margin width around an item -WCHAR windowText[1024]; +#define CX_ITEM_SPACE (CX_ITEM + 2 * ITEM_MARGIN) +#define CY_ITEM_SPACE (CY_ITEM + 2 * ITEM_MARGIN) -HWND windowList[MAX_WINDOWS]; -HICON iconList[MAX_WINDOWS]; -int windowCount = 0; +#define CY_TEXT_MARGIN 4 // margin height around text -int cxBorder, cyBorder; -int nItems, nCols, nRows; -int itemsW, itemsH; -int totalW, totalH; -int xOffset, yOffset; -POINT pt; +#define MIN_COLUMNS 6 // min. # of columns +#define MAX_COLUMNS 8 // max. # of columns +#define MAX_ROWS 4 // max. # of rows -void ResizeAndCenter(HWND hwnd, int width, int height) +#define MAX_WINDOWS 120 // max. # of windows + +// +// global variables +// +HWND hSwitchDialog = NULL; // the dialog +HFONT dialogFont = NULL; // the font +int selectedWindow = 0; // index of the selected window +BOOL isOpen = FALSE; // whether it is in switcher mode + +int fontHeight = 0; // text height + +WCHAR windowText[1024]; // window text + +int windowCount = 0; // # of windows +HWND windowList[MAX_WINDOWS] = {NULL}; // the window list +HICON iconList[MAX_WINDOWS] = {NULL}; // the icon list + +int nItems, nCols, nRows; // # of display items, columns, rows +int itemsW, itemsH; // width and height of items area +int totalW, totalH; // total width and total height + +BOOL FirstEsc = FALSE; // whether it is in FirstEsc mode +POINT ptStart; + +int nShift = 0; // display item shifting count + +// window style +const DWORD Style = WS_POPUP | WS_BORDER | WS_DISABLED; +const DWORD ExStyle = WS_EX_TOPMOST | WS_EX_DLGMODALFRAME | WS_EX_TOOLWINDOW; + +void ResizeAndCenter(HWND hwnd, int Width, int Height) { - int screenwidth = GetSystemMetrics(SM_CXSCREEN); - int screenheight = GetSystemMetrics(SM_CYSCREEN); + INT x, y; + RECT Rect; - pt.x = (screenwidth - width) / 2; - pt.y = (screenheight - height) / 2; + // get the screen size + int ScreenWidth = GetSystemMetrics(SM_CXSCREEN); + int ScreenHeight = GetSystemMetrics(SM_CYSCREEN); - MoveWindow(hwnd, pt.x, pt.y, width, height, FALSE); + // centering position + x = (ScreenWidth - Width) / 2; + y = (ScreenHeight - Height) / 2; + + // adjust position and size by window style + SetRect(&Rect, x, y, x + Width, y + Height); + AdjustWindowRectEx(&Rect, Style, FALSE, ExStyle); + + // now move and resize + x = Rect.left; + y = Rect.top; + Width = Rect.right - Rect.left; + Height = Rect.bottom - Rect.top; + MoveWindow(hwnd, x, y, Width, Height, FALSE); + + // save position + ptStart.x = x; + ptStart.y = y; } void MakeWindowActive(HWND hwnd) { - WINDOWPLACEMENT wpl; + // is it minimized? + if (IsIconic(hwnd)) + { + // restore + ShowWindowAsync(hwnd, SW_RESTORE); + } - wpl.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(hwnd, &wpl); - - TRACE("GetWindowPlacement wpl.showCmd %d\n",wpl.showCmd); - if (wpl.showCmd == SW_SHOWMINIMIZED) - ShowWindowAsync(hwnd, SW_RESTORE); - - BringWindowToTop(hwnd); // same as: SetWindowPos(hwnd,HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); ? - SetForegroundWindow(hwnd); + // make it top and activate + BringWindowToTop(hwnd); + SetForegroundWindow(hwnd); } void CompleteSwitch(BOOL doSwitch) { - if (!isOpen) - return; + HWND hwnd; - isOpen = FALSE; + if (!isOpen) + return; - TRACE("[ATbot] CompleteSwitch Hiding Window.\n"); - ShowWindow(switchdialog, SW_HIDE); + isOpen = FALSE; - if(doSwitch) - { - if(selectedWindow >= windowCount) - return; + // hide switcher + TRACE("[ATbot] CompleteSwitch Hiding Window.\n"); + ShowWindow(hSwitchDialog, SW_HIDE); - // FIXME: workaround because reactos fails to activate the previous window correctly. - //if(selectedWindow != 0) - { - HWND hwnd = windowList[selectedWindow]; + if (doSwitch) + { + // boundary check + if (selectedWindow < 0 || selectedWindow >= windowCount) + return; - GetWindowTextW(hwnd, windowText, _countof(windowText)); + // get the selected window handle + hwnd = windowList[selectedWindow]; - TRACE("[ATbot] CompleteSwitch Switching to 0x%08x (%ls)\n", hwnd, windowText); + GetWindowTextW(hwnd, windowText, _countof(windowText)); + TRACE("[ATbot] CompleteSwitch Switching to 0x%08x (%ls)\n", hwnd, windowText); - MakeWindowActive(hwnd); - } - } + MakeWindowActive(hwnd); + } - windowCount = 0; + windowCount = 0; } -BOOL CALLBACK EnumerateCallback(HWND window, LPARAM lParam) +BOOL CALLBACK EnumerateCallback(HWND hWnd, LPARAM lParam) { - HICON hIcon; + HICON hIcon; + UNREFERENCED_PARAMETER(lParam); - UNREFERENCED_PARAMETER(lParam); + // ignore if hidden window + if (!IsWindowVisible(hWnd)) + return TRUE; // continue - if (!IsWindowVisible(window)) - return TRUE; + // check class name + GetClassNameW(hWnd, windowText, _countof(windowText)); + if (wcscmp(L"Shell_TrayWnd", windowText) == 0 || + wcscmp(L"Progman", windowText) == 0) + { + // ignore if specific system class + return TRUE; // continue + } - GetClassNameW(window, windowText, _countof(windowText)); - if ((wcscmp(L"Shell_TrayWnd", windowText)==0) || - (wcscmp(L"Progman", windowText)==0) ) - return TRUE; - - // First try to get the big icon assigned to the window - hIcon = (HICON)SendMessageW(window, WM_GETICON, ICON_BIG, 0); - if (!hIcon) - { - // If no icon is assigned, try to get the icon assigned to the windows' class - hIcon = (HICON)GetClassLongPtrW(window, GCL_HICON); - if (!hIcon) - { - // If we still don't have an icon, see if we can do with the small icon, - // or a default application icon - hIcon = (HICON)SendMessageW(window, WM_GETICON, ICON_SMALL2, 0); - if (!hIcon) - { - // using windows logo icon as default - hIcon = gpsi->hIconWindows; - if (!hIcon) + // First try to get the big icon assigned to the window + hIcon = (HICON)SendMessageW(hWnd, WM_GETICON, ICON_BIG, 0); + if (hIcon == NULL) + { + // If no icon is assigned, try to get the icon assigned to the + // windows' class + hIcon = (HICON)GetClassLongPtrW(hWnd, GCL_HICON); + if (hIcon == NULL) + { + // If we still don't have an icon, see if we can do with the small + // icon, or a default application icon + hIcon = (HICON)SendMessageW(hWnd, WM_GETICON, ICON_SMALL2, 0); + if (hIcon == NULL) { - //if all attempts to get icon fails go to the next window - return TRUE; + // using windows logo icon as default + hIcon = gpsi->hIconWindows; + if (hIcon == NULL) + { + // if all attempts to get icon fails go to the next hWnd + return TRUE; // continue + } } - } - } - } + } + } - windowList[windowCount] = window; - iconList[windowCount] = CopyIcon(hIcon); + // add an item to the list + windowList[windowCount] = hWnd; + iconList[windowCount] = CopyIcon(hIcon); + windowCount++; - windowCount++; + // If we got to the max number of windows, + // we won't be able to add any more + if (windowCount >= MAX_WINDOWS) + return FALSE; // stop - // If we got to the max number of windows, - // we won't be able to add any more - if(windowCount == MAX_WINDOWS) - return FALSE; - - return TRUE; + return TRUE; // continue } // Function mostly compatible with the normal EnumWindows, // except it lists in Z-Order and it doesn't ensure consistency // if a window is removed while enumerating -void EnumWindowsZOrder(WNDENUMPROC callback, LPARAM lParam) +void EnumWindowsZOrder(WNDENUMPROC Callback, LPARAM lParam) { - HWND next = GetTopWindow(NULL); - while (next != NULL) + // for every window: + HWND Next = GetTopWindow(NULL); + while (Next != NULL) { - if(!callback(next, lParam)) - break; - next = GetWindow(next, GW_HWNDNEXT); + // call the callback function + if (!Callback(Next, lParam)) + break; + + // get next window + Next = GetWindow(Next, GW_HWNDNEXT); } } void ProcessMouseMessage(UINT message, LPARAM lParam) { - int xPos = LOWORD(lParam); - int yPos = HIWORD(lParam); + // get the position + int xPos = LOWORD(lParam); + int yPos = HIWORD(lParam); - int xIndex = (xPos - xOffset)/40; - int xOff = (xPos - xOffset)%40; + // get the indexes + int xIndex = (xPos - DIALOG_MARGIN) / CX_ITEM_SPACE; + int yIndex = (yPos - DIALOG_MARGIN) / CY_ITEM_SPACE; - int yIndex = (yPos - yOffset)/40; - int yOff = (yPos - yOffset)%40; + // boundary check + if (xIndex < 0 || nCols <= xIndex || + yIndex < 0 || nRows <= yIndex) + { + return; + } - if(xOff > 32 || xIndex > nItems) - return; + // select the window + selectedWindow = (yIndex * nCols) + xIndex; - if(yOff > 32 || yIndex > nRows) - return; - - selectedWindow = (yIndex*nCols) + xIndex; - if (message == WM_MOUSEMOVE) - { - InvalidateRect(switchdialog, NULL, TRUE); - //RedrawWindow(switchdialog, NULL, NULL, 0); - } - else - { - selectedWindow = (yIndex*nCols) + xIndex; - CompleteSwitch(TRUE); - } + if (message != WM_MOUSEMOVE) + { + // user clicked + selectedWindow = (yIndex * nCols) + xIndex; + CompleteSwitch(TRUE); + } } void OnPaint(HWND hWnd) { - HDC dialogDC; - PAINTSTRUCT paint; - RECT cRC, textRC; - int i; - HBRUSH hBrush; - HPEN hPen; - HFONT dcFont; - COLORREF cr; - int nch = GetWindowTextW(windowList[selectedWindow], windowText, _countof(windowText)); + HDC dialogDC; + PAINTSTRUCT paint; + RECT cRC, textRC; + int i, xPos, yPos, CharCount; + HFONT dcFont; + HICON hIcon; + HPEN hPen; + COLORREF Color; - dialogDC = BeginPaint(hWnd, &paint); - { - GetClientRect(hWnd, &cRC); - FillRect(dialogDC, &cRC, GetSysColorBrush(COLOR_MENU)); + // check + if (nCols == 0 || nItems == 0) + return; - for(i=0; i< windowCount; i++) - { - HICON hIcon = iconList[i]; + // begin painting + dialogDC = BeginPaint(hWnd, &paint); + if (dialogDC == NULL) + return; - int xpos = xOffset + 40 * (i % nCols); - int ypos = yOffset + 40 * (i / nCols); + // fill the client area + GetClientRect(hWnd, &cRC); + FillRect(dialogDC, &cRC, (HBRUSH)(COLOR_3DFACE + 1)); - if (selectedWindow == i) - { - hBrush = GetSysColorBrush(COLOR_HIGHLIGHT); - } - else - { - hBrush = GetSysColorBrush(COLOR_MENU); - } -#if TRUE - cr = GetSysColor(COLOR_BTNTEXT); // doesn't look right! >_< - hPen = CreatePen(PS_DOT, 1, cr); - SelectObject(dialogDC, hPen); - SelectObject(dialogDC, hBrush); - Rectangle(dialogDC, xpos-2, ypos-2, xpos+32+2, ypos+32+2); - DeleteObject(hPen); - // Must NOT destroy the system brush! -#else - RECT rc = { xpos-2, ypos-2, xpos+32+2, ypos+32+2 }; - FillRect(dialogDC, &rc, hBrush); -#endif - DrawIcon(dialogDC, xpos, ypos, hIcon); - } + // if the selection index exceeded the display items, then + // do display item shifting + if (selectedWindow >= nItems) + nShift = selectedWindow - nItems + 1; + else + nShift = 0; - dcFont = SelectObject(dialogDC, dialogFont); - SetTextColor(dialogDC, GetSysColor(COLOR_BTNTEXT)); - SetBkMode(dialogDC, TRANSPARENT); + for (i = 0; i < nItems; ++i) + { + // get the icon to display + hIcon = iconList[i + nShift]; - textRC.top = itemsH; - textRC.left = 8; - textRC.right = totalW - 8; - textRC.bottom = totalH - 8; - DrawTextW(dialogDC, windowText, nch, &textRC, DT_CENTER|DT_END_ELLIPSIS); - SelectObject(dialogDC, dcFont); - } - EndPaint(hWnd, &paint); + // calculate the position where we start drawing + xPos = DIALOG_MARGIN + CX_ITEM_SPACE * (i % nCols) + ITEM_MARGIN; + yPos = DIALOG_MARGIN + CY_ITEM_SPACE * (i / nCols) + ITEM_MARGIN; + + // centering + if (nItems < MIN_COLUMNS) + { + xPos += (itemsW - nItems * CX_ITEM_SPACE) / 2; + } + + // if this position is selected, + if (selectedWindow == i + nShift) + { + // create a solid pen + Color = GetSysColor(COLOR_HIGHLIGHT); + hPen = CreatePen(PS_SOLID, 1, Color); + + // draw a rectangle with using the pen + SelectObject(dialogDC, hPen); + SelectObject(dialogDC, GetStockObject(NULL_BRUSH)); + Rectangle(dialogDC, xPos, yPos, xPos + CX_ITEM, yPos + CY_ITEM); + Rectangle(dialogDC, xPos + 1, yPos + 1, + xPos + CX_ITEM - 1, yPos + CY_ITEM - 1); + + // delete the pen + DeleteObject(hPen); + } + + // draw icon + DrawIconEx(dialogDC, xPos + ICON_MARGIN, yPos + ICON_MARGIN, + hIcon, CX_ICON, CY_ICON, 0, NULL, DI_NORMAL); + } + + // set the text rectangle + SetRect(&textRC, DIALOG_MARGIN, DIALOG_MARGIN + itemsH, + totalW - DIALOG_MARGIN, totalH - DIALOG_MARGIN); + + // draw the sunken button around text + DrawFrameControl(dialogDC, &textRC, DFC_BUTTON, + DFCS_BUTTONPUSH | DFCS_PUSHED); + + // get text + CharCount = GetWindowTextW(windowList[selectedWindow], windowText, + _countof(windowText)); + + // draw text + dcFont = SelectObject(dialogDC, dialogFont); + SetTextColor(dialogDC, GetSysColor(COLOR_BTNTEXT)); + SetBkMode(dialogDC, TRANSPARENT); + DrawTextW(dialogDC, windowText, CharCount, &textRC, + DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE); + SelectObject(dialogDC, dcFont); + + // end painting + EndPaint(hWnd, &paint); } DWORD CreateSwitcherWindow(HINSTANCE hInstance) { - switchdialog = CreateWindowExW( WS_EX_TOPMOST|WS_EX_DLGMODALFRAME|WS_EX_TOOLWINDOW, - WC_SWITCH, - L"", - WS_POPUP|WS_BORDER|WS_DISABLED, - CW_USEDEFAULT, - CW_USEDEFAULT, - 400, 150, - NULL, NULL, - hInstance, NULL); - if (!switchdialog) + hSwitchDialog = CreateWindowExW(ExStyle, + WC_SWITCH, + NULL, + Style, + CW_USEDEFAULT, CW_USEDEFAULT, + 400, 150, + NULL, NULL, + hInstance, NULL); + if (hSwitchDialog == NULL) { - TRACE("[ATbot] Task Switcher Window failed to create.\n"); - return 0; + TRACE("[ATbot] Task Switcher Window failed to create.\n"); + return 0; } isOpen = FALSE; @@ -271,307 +355,413 @@ return 1; } -DWORD GetDialogFont(VOID) +BOOL GetDialogFont(void) { - HDC tDC; - TEXTMETRIC tm; + HDC tDC; + TEXTMETRIC tm; - dialogFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + // get the default GUI font + dialogFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); - tDC = GetDC(0); - GetTextMetrics(tDC, &tm); - fontHeight = tm.tmHeight; - ReleaseDC(0, tDC); + // get the font height + tDC = GetDC(0); + GetTextMetrics(tDC, &tm); + fontHeight = tm.tmHeight; + ReleaseDC(0, tDC); - return 1; + return TRUE; } void PrepareWindow(VOID) { - cxBorder = GetSystemMetrics(SM_CXBORDER); - cyBorder = GetSystemMetrics(SM_CYBORDER); + // set item count + nItems = windowCount; - nItems = windowCount; - nCols = min(max(nItems,8),12); - nRows = (nItems+nCols-1)/nCols; + // calculate the number of displayable columns + nCols = nItems; + if (nCols < MIN_COLUMNS) + nCols = MIN_COLUMNS; + if (nCols > MAX_COLUMNS) + nCols = MAX_COLUMNS; - itemsW = nCols*32 + (nCols+1)*8; - itemsH = nRows*32 + (nRows+1)*8; + // calculate the number of displayable rows + nRows = (nItems + MAX_COLUMNS - 1) / MAX_COLUMNS; + if (nRows > MAX_ROWS) + { + // if too large, fix it + nRows = MAX_ROWS; + nItems = nRows * nCols; + } - totalW = itemsW + 2*cxBorder + 4; - totalH = itemsH + 2*cyBorder + fontHeight + 8; // give extra pixels for the window title + // calculate width and height of items area + itemsW = nCols * CX_ITEM_SPACE; + itemsH = nRows * CY_ITEM_SPACE; - xOffset = 8; - yOffset = 8; + // calculate total width and height + totalW = itemsW + 2 * DIALOG_MARGIN; + totalH = itemsH + 2 * DIALOG_MARGIN; + totalH += fontHeight + 2 * CY_TEXT_MARGIN; - if (nItems < nCols) - { - int w2 = nItems*32 + (nItems-1)*8; - xOffset = (itemsW-w2)/2; - } - ResizeAndCenter(switchdialog, totalW, totalH); + // move and resize now + ResizeAndCenter(hSwitchDialog, totalW, totalH); } BOOL ProcessHotKey(VOID) { - if (!isOpen) - { - windowCount=0; - EnumWindowsZOrder(EnumerateCallback, 0); + // is it in switcher mode? + if (isOpen) + { + if (windowCount < 2) + return FALSE; // no need to switch - if (windowCount < 2) - return FALSE; + // select next + TRACE("[ATbot] HotKey Received Rotating.\n"); + selectedWindow = (selectedWindow + 1) % windowCount; - selectedWindow = 1; + // let it redraw + InvalidateRect(hSwitchDialog, NULL, TRUE); + } + else + { + // create the list + windowCount = 0; + EnumWindowsZOrder(EnumerateCallback, 0); - TRACE("[ATbot] HotKey Received. Opening window.\n"); - ShowWindow(switchdialog, SW_SHOWNORMAL); - MakeWindowActive(switchdialog); - isOpen = TRUE; - } - else - { - TRACE("[ATbot] HotKey Received Rotating.\n"); - selectedWindow = (selectedWindow + 1)%windowCount; - InvalidateRect(switchdialog, NULL, TRUE); - } - return TRUE; + if (windowCount < 2) + return FALSE; // no need to switch + + // select the second + selectedWindow = 1; + + // show the dialog + TRACE("[ATbot] HotKey Received. Opening window.\n"); + ShowWindow(hSwitchDialog, SW_SHOWNORMAL); + MakeWindowActive(hSwitchDialog); + + // enter switcher mode + isOpen = TRUE; + } + + return TRUE; // success } -LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam ) +void RotateTasks(void) { - HWND hwnd, hwndActive; - MSG msg; - BOOL Esc = FALSE; - INT Count = 0; - WCHAR Text[1024]; + HWND hwndFirst, hwndLast; + DWORD Size; - // Already in the loop. - if (switchdialog) return 0; + if (windowCount < 2 || !FirstEsc) + return; - hwndActive = GetActiveWindow(); - // Nothing is active so exit. - if (!hwndActive) return 0; - // Capture current active window. - SetCapture( hwndActive ); + hwndFirst = windowList[0]; + hwndLast = windowList[windowCount - 1]; - switch (lParam) - { - case VK_TAB: - if( !CreateSwitcherWindow(User32Instance) ) goto Exit; - if( !GetDialogFont() ) goto Exit; - if( !ProcessHotKey() ) goto Exit; - break; + // insert the first after the last + SetWindowPos(hwndFirst, hwndLast, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER | SWP_NOREPOSITION); - case VK_ESCAPE: - windowCount = 0; - Count = 0; - EnumWindowsZOrder(EnumerateCallback, 0); - if (windowCount < 2) goto Exit; - if (wParam == SC_NEXTWINDOW) - Count = 1; - else - { - if (windowCount == 2) - Count = 0; - else - Count = windowCount - 1; - } - TRACE("DoAppSwitch VK_ESCAPE 1 Count %d windowCount %d\n",Count,windowCount); - hwnd = windowList[Count]; - GetWindowTextW(hwnd, Text, _countof(Text)); - TRACE("[ATbot] Switching to 0x%08x (%ls)\n", hwnd, Text); - MakeWindowActive(hwnd); - Esc = TRUE; - break; + // second to top + MakeWindowActive(windowList[1]); - default: - goto Exit; - } - // Main message loop: - while (1) - { - for (;;) - { - if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE )) - { - if (!CallMsgFilterW( &msg, MSGF_NEXTWINDOW )) break; - /* remove the message from the queue */ - PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); - } - else - WaitMessage(); - } + // rotate the window list + Size = (windowCount - 1) * sizeof(HWND); + MoveMemory(&windowList[0], &windowList[1], Size); + windowList[windowCount - 1] = hwndFirst; +} - switch (msg.message) - { - case WM_KEYUP: +VOID +DestroyAppIcons(VOID) +{ + // for every item of the icon list: + INT i; + for (i = 0; i < windowCount; ++i) + { + // destroy the icon + DestroyIcon(iconList[i]); + iconList[i] = NULL; + } +} + +LRESULT WINAPI DoAppSwitch(WPARAM wParam, LPARAM lParam) +{ + HWND hwndActive; + MSG msg; + + // already in the loop? + if (hSwitchDialog || FirstEsc) + return 0; + + hwndActive = GetActiveWindow(); + + // nothing is active so exit? + if (hwndActive == NULL) + return 0; + + // if [Esc] key was pressed, + if (lParam == VK_ESCAPE) + { + // enter FirstEsc mode + FirstEsc = TRUE; + + // get the list + windowCount = 0; + EnumWindowsZOrder(EnumerateCallback, 0); + + if (windowCount < 2) + return 0; // no need to switch + + // rotate now + RotateTasks(); + + hwndActive = GetActiveWindow(); + + // nothing is active so exit? + if (hwndActive == NULL) { - PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); - if (msg.wParam == VK_MENU) - { - CompleteSwitch(TRUE); - } - else if (msg.wParam == VK_RETURN) - { - CompleteSwitch(TRUE); - } - else if (msg.wParam == VK_ESCAPE) - { - TRACE("DoAppSwitch VK_ESCAPE 2\n"); - CompleteSwitch(FALSE); - } - goto Exit; //break; + FirstEsc = FALSE; + return 0; } + } - case WM_SYSKEYDOWN: + // Capture current active window. + SetCapture(hwndActive); + + switch (lParam) + { + case VK_TAB: + // create the dialog + if (!CreateSwitcherWindow(User32Instance)) + goto Exit; + // get font + if (!GetDialogFont()) + goto Exit; + // process the key + if (!ProcessHotKey()) + goto Exit; + break; + + case VK_ESCAPE: + break; + + default: + goto Exit; + } + + // main message loop: + while (1) + { + for (;;) { - PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); - if (HIWORD(msg.lParam) & KF_ALTDOWN) - { - INT Shift; - if ( msg.wParam == VK_TAB ) - { - if (Esc) break; - Shift = GetKeyState(VK_SHIFT) & 0x8000 ? SC_PREVWINDOW : SC_NEXTWINDOW; - if (Shift == SC_NEXTWINDOW) + if (PeekMessageW(&msg, 0, 0, 0, PM_NOREMOVE)) + { + if (!CallMsgFilterW(&msg, MSGF_NEXTWINDOW)) + break; + + // remove the message from the queue + PeekMessageW(&msg, 0, msg.message, msg.message, PM_REMOVE); + } + else + { + WaitMessage(); + } + } + + switch (msg.message) + { + case WM_KEYUP: + // remove the message + PeekMessageW(&msg, 0, msg.message, msg.message, PM_REMOVE); + + if (msg.wParam == VK_MENU || msg.wParam == VK_RETURN) { - selectedWindow = (selectedWindow + 1)%windowCount; + // [Alt] or [Enter] key was released + CompleteSwitch(TRUE); } - else + else if (msg.wParam == VK_ESCAPE) { - selectedWindow = selectedWindow - 1; - if (selectedWindow < 0) - selectedWindow = windowCount - 1; + // [Esc] key was released + TRACE("DoAppSwitch VK_ESCAPE 2\n"); + CompleteSwitch(FALSE); } - InvalidateRect(switchdialog, NULL, TRUE); - } - else if ( msg.wParam == VK_ESCAPE ) - { - if (!Esc) break; - if (windowCount < 2) - goto Exit; - if (wParam == SC_NEXTWINDOW) + goto Exit; + + case WM_SYSKEYDOWN: + // remove the message + PeekMessageW(&msg, 0, msg.message, msg.message, PM_REMOVE); + + if (HIWORD(msg.lParam) & KF_ALTDOWN) // [Alt] is down { - Count = (Count + 1)%windowCount; + if (msg.wParam == VK_TAB) // [Tab] key was pressed + { + // if it is in FirstEsc mode, ignore it + if (FirstEsc) + break; + + if (GetKeyState(VK_SHIFT) < 0) + { + // [Shift] key was pressed: select previous one + selectedWindow = selectedWindow - 1; + if (selectedWindow < 0) + selectedWindow = windowCount - 1; + } + else + { + // select next + selectedWindow = (selectedWindow + 1) % windowCount; + } + + // redraw + InvalidateRect(hSwitchDialog, NULL, TRUE); + } + else if (msg.wParam == VK_ESCAPE) + { + // unless FirstEsc mode, then exit + if (!FirstEsc) + goto Exit; + + // rotate now + RotateTasks(); + } } - else + break; + + case WM_LBUTTONUP: + // remove the message + PeekMessageW(&msg, 0, msg.message, msg.message, PM_REMOVE); + + ProcessMouseMessage(msg.message, msg.lParam); + goto Exit; + + default: + // remove the message + if (PeekMessageW(&msg, 0, msg.message, msg.message, PM_REMOVE)) { - Count--; - if (Count < 0) - Count = windowCount - 1; + // translate and dispatch the message + TranslateMessage(&msg); + DispatchMessageW(&msg); } - hwnd = windowList[Count]; - GetWindowTextW(hwnd, Text, _countof(Text)); - MakeWindowActive(hwnd); - } - } - break; + break; } + } - case WM_LBUTTONUP: - PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE ); - ProcessMouseMessage(msg.message, msg.lParam); - goto Exit; - - default: - if (PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE )) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - break; - } - } Exit: - ReleaseCapture(); - if (switchdialog) DestroyWindow(switchdialog); - switchdialog = NULL; - selectedWindow = 0; - windowCount = 0; - return 0; + // leave mode and clean up + ReleaseCapture(); + if (hSwitchDialog) + DestroyWindow(hSwitchDialog); + if (FirstEsc) + DestroyAppIcons(); + hSwitchDialog = NULL; + selectedWindow = 0; + windowCount = 0; + FirstEsc = FALSE; + return 0; } -VOID -DestroyAppWindows(VOID) +// switch system class window proc. +LRESULT WINAPI +SwitchWndProc_common(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL Unicode) { - INT i; - for (i=0; i< windowCount; i++) - { - HICON hIcon = iconList[i]; - DestroyIcon(hIcon); - } -} + PWND pWnd; + PALTTABINFO ati; + HANDLE hHeap; -// -// Switch System Class Window Proc. -// -LRESULT WINAPI SwitchWndProc_common(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL unicode ) -{ - PWND pWnd; - PALTTABINFO ati; - pWnd = ValidateHwnd(hWnd); - if (pWnd) - { - if (!pWnd->fnid) - { - NtUserSetWindowFNID(hWnd, FNID_SWITCH); - } - } + pWnd = ValidateHwnd(hWnd); + if (pWnd) + { + if (!pWnd->fnid) + { + NtUserSetWindowFNID(hWnd, FNID_SWITCH); + } + } - switch (uMsg) - { - case WM_NCCREATE: - if (!(ati = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ati)))) - return 0; - SetWindowLongPtrW( hWnd, 0, (LONG_PTR)ati ); - return TRUE; + switch (uMsg) + { + case WM_NCCREATE: + // allocate ALTTABINFO + hHeap = GetProcessHeap(); + ati = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(*ati)); + if (ati == NULL) + return FALSE; // failure - case WM_SHOWWINDOW: - if (wParam) - { - PrepareWindow(); - ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0); - ati->cItems = nItems; - ati->cxItem = ati->cyItem = 43; - ati->cRows = nRows; - ati->cColumns = nCols; - } - return 0; + // associate ALTTABINFO to window + SetWindowLongPtrW(hWnd, 0, (LONG_PTR)ati); + return TRUE; // success - case WM_MOUSEMOVE: - ProcessMouseMessage(uMsg, lParam); - return 0; + case WM_SHOWWINDOW: + if (wParam) + { + // create, move, resize + PrepareWindow(); - case WM_ACTIVATE: - if (wParam == WA_INACTIVE) - { - CompleteSwitch(FALSE); - } - return 0; + // fill the ALTTABINFO structure + ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0); + ati->cbSize = sizeof(ALTTABINFO); + ati->cItems = nItems; + ati->cColumns = nCols; + ati->cRows = nRows; + if (nCols) + { + ati->iColFocus = (selectedWindow - nShift) % nCols; + ati->iRowFocus = (selectedWindow - nShift) / nCols; + } + else + { + ati->iColFocus = 0; + ati->iRowFocus = 0; + } + ati->cxItem = CX_ITEM_SPACE; + ati->cyItem = CY_ITEM_SPACE; + ati->ptStart = ptStart; + } + break; - case WM_PAINT: - OnPaint(hWnd); - return 0; + case WM_MOUSEMOVE: + ProcessMouseMessage(uMsg, lParam); + break; - case WM_DESTROY: - isOpen = FALSE; - ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0); - HeapFree( GetProcessHeap(), 0, ati ); - SetWindowLongPtrW( hWnd, 0, 0 ); - DestroyAppWindows(); - NtUserSetWindowFNID(hWnd, FNID_DESTROY); - return 0; - } - return DefWindowProcW(hWnd, uMsg, wParam, lParam); + case WM_ACTIVATE: + if (wParam == WA_INACTIVE) + { + CompleteSwitch(FALSE); + } + break; + + case WM_PAINT: + OnPaint(hWnd); + break; + + case WM_DESTROY: + // leave mode + isOpen = FALSE; + + // clean up + ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0); + SetWindowLongPtrW(hWnd, 0, 0); + HeapFree(GetProcessHeap(), 0, ati); + DestroyAppIcons(); + + NtUserSetWindowFNID(hWnd, FNID_DESTROY); + break; + + default: + if (Unicode) + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + else + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + } + return 0; } +// ANSI version of window procedure LRESULT WINAPI SwitchWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - return SwitchWndProc_common(hWnd, uMsg, wParam, lParam, FALSE); + return SwitchWndProc_common(hWnd, uMsg, wParam, lParam, FALSE); } +// Wide (Unicode) version of window procedure LRESULT WINAPI SwitchWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - return SwitchWndProc_common(hWnd, uMsg, wParam, lParam, TRUE); + return SwitchWndProc_common(hWnd, uMsg, wParam, lParam, TRUE); }