Author: jimtabor
Date: Tue Nov 22 03:54:55 2016
New Revision: 73332
URL:
http://svn.reactos.org/svn/reactos?rev=73332&view=rev
Log:
[User32]
- Patch by Katayama Hirofumi MZ : Improve task switcher's appearance.
- Debugged Alt+Esc
- Pixel perfect
- Implemented "Display Item Shifting"
- Added comments.
Modified:
trunk/reactos/win32ss/user/user32/controls/appswitch.c
Modified: trunk/reactos/win32ss/user/user32/controls/appswitch.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/user32/contro…
==============================================================================
--- trunk/reactos/win32ss/user/user32/controls/appswitch.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/user32/controls/appswitch.c [iso-8859-1] Tue Nov 22
03:54:55 2016
@@ -5,12 +5,36 @@
* PURPOSE: app switching functionality
* PROGRAMMERS: Johannes Anderwald (johannes.anderwald(a)reactos.org)
* David Quintana (gigaherz(a)gmail.com)
+ * Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
*/
+
+//
+// TODO:
+// Move to Win32k.
+// Add registry support.
+//
+//
+
#include <user32.h>
#include <wine/debug.h>
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.
@@ -35,28 +59,74 @@
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;
-
- MoveWindow(hwnd, pt.x, pt.y, width, height, FALSE);
+ x = (screenwidth - width) / 2;
+ y = (screenheight - height) / 2;
+
+ 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 @@
// 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 @@
int xPos = LOWORD(lParam);
int yPos = HIWORD(lParam);
- int xIndex = (xPos - xOffset)/40;
- int xOff = (xPos - xOffset)%40;
-
- int yIndex = (yPos - yOffset)/40;
- int yOff = (yPos - yOffset)%40;
-
- if(xOff > 32 || xIndex > nItems)
- return;
-
- if(yOff > 32 || yIndex > nRows)
- return;
+ int xIndex = (xPos - DIALOG_MARGIN) / CX_ITEM_SPACE;
+ int yIndex = (yPos - DIALOG_MARGIN) / CY_ITEM_SPACE;
+
+ if (xIndex < 0 || nCols <= xIndex ||
+ yIndex < 0 || nRows <= yIndex)
+ {
+ return;
+ }
selectedWindow = (yIndex*nCols) + xIndex;
if (message == WM_MOUSEMOVE)
@@ -191,63 +258,95 @@
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));
-
- dialogDC = BeginPaint(hWnd, &paint);
- {
- GetClientRect(hWnd, &cRC);
- FillRect(dialogDC, &cRC, GetSysColorBrush(COLOR_MENU));
-
- for(i=0; i< windowCount; i++)
- {
- HICON hIcon = iconList[i];
-
- int xpos = xOffset + 40 * (i % nCols);
- int ypos = yOffset + 40 * (i / nCols);
-
- 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);
- }
-
- dcFont = SelectObject(dialogDC, dialogFont);
- SetTextColor(dialogDC, GetSysColor(COLOR_BTNTEXT));
- SetBkMode(dialogDC, TRANSPARENT);
-
- 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);
+ HDC dialogDC;
+ PAINTSTRUCT paint;
+ RECT cRC, textRC;
+ int i, xPos, yPos, CharCount;
+ HFONT dcFont;
+ HICON hIcon;
+ HPEN hPen;
+ COLORREF Color;
+
+ // check
+ if (nCols == 0 || nItems == 0)
+ return;
+
+ // begin painting
+ dialogDC = BeginPaint(hWnd, &paint);
+ if (dialogDC == NULL)
+ return;
+
+ // fill the client area
+ GetClientRect(hWnd, &cRC);
+ FillRect(dialogDC, &cRC, (HBRUSH)(COLOR_3DFACE + 1));
+
+ // if the selection index exceeded the display items, then
+ // do display item shifting
+ if (selectedWindow >= nItems)
+ nShift = selectedWindow - nItems + 1;
+ else
+ nShift = 0;
+
+ for (i = 0; i < nItems; ++i)
+ {
+ // get the icon to display
+ hIcon = iconList[i + nShift];
+
+ // 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 @@
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)
- {
- int w2 = nItems*32 + (nItems-1)*8;
- xOffset = (itemsW-w2)/2;
- }
+
+ nCols = CoolSwitchColumns;
+ nRows = (nItems + CoolSwitchColumns - 1) / CoolSwitchColumns;
+ if (nRows > CoolSwitchRows)
+ {
+ 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 @@
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 @@
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 @@
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,21 +621,12 @@
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);
- }
}
//
@@ -532,10 +658,23 @@
{
PrepareWindow();
ati = (PALTTABINFO)GetWindowLongPtrW(hWnd, 0);
+ ati->cbSize = sizeof(ALTTABINFO);
ati->cItems = nItems;
- ati->cxItem = ati->cyItem = 43;
+ ati->cColumns = nCols;
ati->cRows = nRows;
- ati->cColumns = nCols;
+ 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;