diff --git a/reactos/win32ss/user/user32/controls/appswitch.c b/reactos/win32ss/user/user32/controls/appswitch.c index 229ee8495f9..cd13841107e 100644 --- a/reactos/win32ss/user/user32/controls/appswitch.c +++ b/reactos/win32ss/user/user32/controls/appswitch.c @@ -5,13 +5,37 @@ * PURPOSE: app switching functionality * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) * David Quintana (gigaherz@gmail.com) + * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ +// +// TODO: +// Move to Win32k. +// Add registry support. +// +// + + #include #include WINE_DEFAULT_DEBUG_CHANNEL(user32); +#define DIALOG_MARGIN 8 // margin of dialog contents + +#define CX_ICON 32 // width of icon +#define CY_ICON 32 // height of icon +#define ICON_MARGIN 4 // margin width around an icon + +#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 + +#define CX_ITEM_SPACE (CX_ITEM + 2 * ITEM_MARGIN) +#define CY_ITEM_SPACE (CY_ITEM + 2 * ITEM_MARGIN) + +#define CY_TEXT_MARGIN 4 // margin height around text + // 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 @@ -35,28 +59,74 @@ int nItems, nCols, nRows; int itemsW, itemsH; int totalW, totalH; int xOffset, yOffset; -POINT pt; +POINT ptStart; + +int nShift = 0; + +BOOL Esc = FALSE; + +BOOL CoolSwitch = TRUE; +int CoolSwitchRows = 3; +int CoolSwitchColumns = 7; + +// window style +const DWORD Style = WS_POPUP | WS_BORDER | WS_DISABLED; +const DWORD ExStyle = WS_EX_TOPMOST | WS_EX_DLGMODALFRAME | WS_EX_TOOLWINDOW; + +DWORD wtodw(const WCHAR *psz) +{ + const WCHAR *pch = psz; + DWORD Value = 0; + while ('0' <= *pch && *pch <= '9') + { + Value *= 10; + Value += *pch - L'0'; + } + return Value; +} + +BOOL LoadCoolSwitchSettings(void) +{ + CoolSwitch = TRUE; + CoolSwitchRows = 3; + CoolSwitchColumns = 7; + + // FIXME: load the settings from registry + + TRACE("CoolSwitch: %d\n", CoolSwitch); + TRACE("CoolSwitchRows: %d\n", CoolSwitchRows); + TRACE("CoolSwitchColumns: %d\n", CoolSwitchColumns); + + return TRUE; +} void ResizeAndCenter(HWND hwnd, int width, int height) { + int x, y; + RECT Rect; + int screenwidth = GetSystemMetrics(SM_CXSCREEN); int screenheight = GetSystemMetrics(SM_CYSCREEN); - pt.x = (screenwidth - width) / 2; - pt.y = (screenheight - height) / 2; + x = (screenwidth - width) / 2; + y = (screenheight - height) / 2; - MoveWindow(hwnd, pt.x, pt.y, width, height, FALSE); + SetRect(&Rect, x, y, x + width, y + height); + AdjustWindowRectEx(&Rect, Style, FALSE, ExStyle); + + x = Rect.left; + y = Rect.top; + width = Rect.right - Rect.left; + height = Rect.bottom - Rect.top; + MoveWindow(hwnd, x, y, width, height, FALSE); + + ptStart.x = x; + ptStart.y = y; } void MakeWindowActive(HWND hwnd) { - WINDOWPLACEMENT wpl; - - wpl.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(hwnd, &wpl); - - TRACE("GetWindowPlacement wpl.showCmd %d\n",wpl.showCmd); - if (wpl.showCmd == SW_SHOWMINIMIZED) + if (IsIconic(hwnd)) ShowWindowAsync(hwnd, SW_RESTORE); BringWindowToTop(hwnd); // same as: SetWindowPos(hwnd,HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); ? @@ -139,7 +209,7 @@ BOOL CALLBACK EnumerateCallback(HWND window, LPARAM lParam) // If we got to the max number of windows, // we won't be able to add any more - if(windowCount == MAX_WINDOWS) + if(windowCount >= MAX_WINDOWS) return FALSE; return TRUE; @@ -164,17 +234,14 @@ void ProcessMouseMessage(UINT message, LPARAM lParam) int xPos = LOWORD(lParam); int yPos = HIWORD(lParam); - int xIndex = (xPos - xOffset)/40; - int xOff = (xPos - xOffset)%40; + 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; - - if(xOff > 32 || xIndex > nItems) - return; - - if(yOff > 32 || yIndex > nRows) - return; + if (xIndex < 0 || nCols <= xIndex || + yIndex < 0 || nRows <= yIndex) + { + return; + } selectedWindow = (yIndex*nCols) + xIndex; if (message == WM_MOUSEMOVE) @@ -191,63 +258,95 @@ void ProcessMouseMessage(UINT message, LPARAM lParam) 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 < CoolSwitchColumns) + { + 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) @@ -288,27 +387,23 @@ DWORD GetDialogFont(VOID) void PrepareWindow(VOID) { - cxBorder = GetSystemMetrics(SM_CXBORDER); - cyBorder = GetSystemMetrics(SM_CYBORDER); - nItems = windowCount; - nCols = min(max(nItems,8),12); - nRows = (nItems+nCols-1)/nCols; - itemsW = nCols*32 + (nCols+1)*8; - itemsH = nRows*32 + (nRows+1)*8; - - totalW = itemsW + 2*cxBorder + 4; - totalH = itemsH + 2*cyBorder + fontHeight + 8; // give extra pixels for the window title - - xOffset = 8; - yOffset = 8; - - if (nItems < nCols) + nCols = CoolSwitchColumns; + nRows = (nItems + CoolSwitchColumns - 1) / CoolSwitchColumns; + if (nRows > CoolSwitchRows) { - int w2 = nItems*32 + (nItems-1)*8; - xOffset = (itemsW-w2)/2; + nRows = CoolSwitchRows; + nItems = nRows * nCols; } + + itemsW = nCols * CX_ITEM_SPACE; + itemsH = nRows * CY_ITEM_SPACE; + + totalW = itemsW + 2 * DIALOG_MARGIN; + totalH = itemsH + 2 * DIALOG_MARGIN; + totalH += fontHeight + 2 * CY_TEXT_MARGIN; + ResizeAndCenter(switchdialog, totalW, totalH); } @@ -338,20 +433,95 @@ BOOL ProcessHotKey(VOID) return TRUE; } +void RotateTasks(BOOL bShift) +{ + HWND hwndFirst, hwndLast; + DWORD Size; + + if (windowCount < 2 || !Esc) + return; + + hwndFirst = windowList[0]; + hwndLast = windowList[windowCount - 1]; + + if (bShift) + { + SetWindowPos(hwndLast, HWND_TOP, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER | SWP_NOREPOSITION); + + MakeWindowActive(hwndLast); + + Size = (windowCount - 1) * sizeof(HWND); + MoveMemory(&windowList[1], &windowList[0], Size); + windowList[0] = hwndLast; + } + else + { + SetWindowPos(hwndFirst, hwndLast, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER | SWP_NOREPOSITION); + + MakeWindowActive(windowList[1]); + + Size = (windowCount - 1) * sizeof(HWND); + MoveMemory(&windowList[0], &windowList[1], Size); + windowList[windowCount - 1] = hwndFirst; + } +} + +VOID +DestroyAppWindows(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 hwnd, hwndActive; + HWND hwndActive; MSG msg; - BOOL Esc = FALSE; - INT Count = 0; - WCHAR Text[1024]; + + // FIXME: Is loading timing OK? + LoadCoolSwitchSettings(); + + if (!CoolSwitch) + return 0; // Already in the loop. - if (switchdialog) return 0; + if (switchdialog || Esc) return 0; hwndActive = GetActiveWindow(); // Nothing is active so exit. if (!hwndActive) return 0; + + if (lParam == VK_ESCAPE) + { + Esc = TRUE; + + windowCount = 0; + EnumWindowsZOrder(EnumerateCallback, 0); + + if (windowCount < 2) + return 0; + + RotateTasks(GetAsyncKeyState(VK_SHIFT) < 0); + + hwndActive = GetActiveWindow(); + + if (hwndActive == NULL) + { + Esc = FALSE; + return 0; + } + } + // Capture current active window. SetCapture( hwndActive ); @@ -364,25 +534,6 @@ LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam ) break; 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; default: @@ -429,41 +580,25 @@ LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam ) 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) - { - selectedWindow = (selectedWindow + 1)%windowCount; - } - else + if (GetKeyState(VK_SHIFT) < 0) { selectedWindow = selectedWindow - 1; if (selectedWindow < 0) selectedWindow = windowCount - 1; } + else + { + selectedWindow = (selectedWindow + 1)%windowCount; + } InvalidateRect(switchdialog, NULL, TRUE); } else if ( msg.wParam == VK_ESCAPE ) { if (!Esc) break; - if (windowCount < 2) - goto Exit; - if (wParam == SC_NEXTWINDOW) - { - Count = (Count + 1)%windowCount; - } - else - { - Count--; - if (Count < 0) - Count = windowCount - 1; - } - hwnd = windowList[Count]; - GetWindowTextW(hwnd, Text, _countof(Text)); - MakeWindowActive(hwnd); + RotateTasks(GetKeyState(VK_SHIFT) < 0); } } break; @@ -486,23 +621,14 @@ LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam ) Exit: ReleaseCapture(); if (switchdialog) DestroyWindow(switchdialog); + if (Esc) DestroyAppWindows(); switchdialog = NULL; selectedWindow = 0; windowCount = 0; + Esc = FALSE; return 0; } -VOID -DestroyAppWindows(VOID) -{ - INT i; - for (i=0; i< windowCount; i++) - { - HICON hIcon = iconList[i]; - DestroyIcon(hIcon); - } -} - // // Switch System Class Window Proc. // @@ -532,10 +658,23 @@ LRESULT WINAPI SwitchWndProc_common(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM { PrepareWindow(); ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0); + ati->cbSize = sizeof(ALTTABINFO); ati->cItems = nItems; - ati->cxItem = ati->cyItem = 43; - ati->cRows = nRows; 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; } return 0;