mirror of
https://github.com/reactos/reactos.git
synced 2024-11-26 21:13:30 +08:00
[NTUSER] Rewrite Window Snap handling (#5705)
Fixes many Window Snap related bugs and uses the WS_EX2_VERTICALLYMAXIMIZED* styles to remember which edge it is snapped to. The most significant change is that GetWindowPlacement lies about the normal position when it is snapped, just like Windows. CORE-19160 CORE-19165 CORE-19166
This commit is contained in:
parent
6fb67ddc0e
commit
f3d03760e9
@ -788,112 +788,66 @@ IntDefWindowProc(
|
||||
}
|
||||
if (g_bWindowSnapEnabled && (IS_KEY_DOWN(gafAsyncKeyState, VK_LWIN) || IS_KEY_DOWN(gafAsyncKeyState, VK_RWIN)))
|
||||
{
|
||||
BOOL IsTaskBar;
|
||||
DWORD StyleTB;
|
||||
DWORD ExStyleTB;
|
||||
HWND hwndTop = UserGetForegroundWindow();
|
||||
PWND topWnd = UserGetWindowObject(hwndTop);
|
||||
BOOL allowSnap;
|
||||
|
||||
// MS Doc: foreground window can be NULL, e.g. when window is losing activation
|
||||
if (!topWnd)
|
||||
return 0;
|
||||
|
||||
// We want to forbid snapping operations on the TaskBar
|
||||
// We use a heuristic for detecting the TaskBar Wnd by its typical Style & ExStyle Values
|
||||
ExStyleTB = (topWnd->ExStyle & WS_EX_TOOLWINDOW);
|
||||
StyleTB = (topWnd->style & (WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN));
|
||||
IsTaskBar = (StyleTB == (WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN))
|
||||
&& (ExStyleTB == WS_EX_TOOLWINDOW);
|
||||
TRACE("ExStyle=%x Style=%x IsTaskBar=%d\n", ExStyleTB, StyleTB, IsTaskBar);
|
||||
allowSnap = IntIsSnapAllowedForWindow(topWnd);
|
||||
/* Allow the minimize action if it has a minimize button, even if the window cannot be snapped (e.g. Calc.exe) */
|
||||
if (!allowSnap && (topWnd->style & (WS_MINIMIZEBOX|WS_THICKFRAME)) == WS_MINIMIZEBOX)
|
||||
allowSnap = wParam == VK_DOWN;
|
||||
|
||||
if (!IsTaskBar)
|
||||
if (allowSnap)
|
||||
{
|
||||
if ((topWnd->style & WS_THICKFRAME) == 0)
|
||||
return 0;
|
||||
UINT snapped = IntGetWindowSnapEdge(topWnd);
|
||||
|
||||
if (wParam == VK_DOWN)
|
||||
{
|
||||
if (topWnd->style & WS_MAXIMIZE)
|
||||
{
|
||||
co_IntSendMessage(hwndTop, WM_SYSCOMMAND, SC_RESTORE, lParam);
|
||||
|
||||
/* "Normal size" must be erased after restoring, otherwise it will block next side snap actions */
|
||||
RECTL_vSetEmptyRect(&topWnd->InternalPos.NormalRect);
|
||||
}
|
||||
co_IntSendMessage(hwndTop, WM_SYSCOMMAND, SC_RESTORE, MAKELONG(0, 1));
|
||||
else if (snapped)
|
||||
co_IntUnsnapWindow(topWnd);
|
||||
else
|
||||
{
|
||||
co_IntSendMessage(hwndTop, WM_SYSCOMMAND, SC_MINIMIZE, lParam);
|
||||
}
|
||||
co_IntSendMessage(hwndTop, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(0, 1));
|
||||
}
|
||||
else if (wParam == VK_UP)
|
||||
{
|
||||
RECT currentRect;
|
||||
if ((topWnd->InternalPos.NormalRect.right == topWnd->InternalPos.NormalRect.left) ||
|
||||
(topWnd->InternalPos.NormalRect.top == topWnd->InternalPos.NormalRect.bottom))
|
||||
{
|
||||
currentRect = topWnd->rcWindow;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentRect = topWnd->InternalPos.NormalRect;
|
||||
}
|
||||
co_IntSendMessage(hwndTop, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
|
||||
|
||||
// save normal rect if maximazing snapped window
|
||||
topWnd->InternalPos.NormalRect = currentRect;
|
||||
if (topWnd->style & WS_MINIMIZE)
|
||||
co_IntSendMessage(hwndTop, WM_SYSCOMMAND, SC_RESTORE, MAKELONG(0, 1));
|
||||
else
|
||||
co_IntSendMessage(hwndTop, WM_SYSCOMMAND, SC_MAXIMIZE, MAKELONG(0, 1));
|
||||
}
|
||||
else if (wParam == VK_LEFT || wParam == VK_RIGHT)
|
||||
{
|
||||
RECT snapRect, normalRect, windowRect;
|
||||
BOOL snapped;
|
||||
normalRect = topWnd->InternalPos.NormalRect;
|
||||
snapped = (normalRect.left != 0 && normalRect.right != 0 &&
|
||||
normalRect.top != 0 && normalRect.bottom != 0);
|
||||
UINT edge = wParam == VK_LEFT ? HTLEFT : HTRIGHT;
|
||||
UINT otherEdge = edge == HTLEFT ? HTRIGHT : HTLEFT;
|
||||
|
||||
if (topWnd->style & WS_MAXIMIZE)
|
||||
{
|
||||
co_IntSendMessage(hwndTop, WM_SYSCOMMAND, SC_RESTORE, lParam);
|
||||
snapped = FALSE;
|
||||
/* SC_RESTORE + Snap causes the window to visually move twice, place it manually in the snap position */
|
||||
RECT normalRect = topWnd->InternalPos.NormalRect;
|
||||
co_IntCalculateSnapPosition(topWnd, edge, &topWnd->InternalPos.NormalRect); /* Calculate edge position */
|
||||
IntSetSnapEdge(topWnd, edge); /* Tell everyone the edge we are snapped to */
|
||||
co_IntSendMessage(hwndTop, WM_SYSCOMMAND, SC_RESTORE, MAKELONG(0, 1));
|
||||
IntSetSnapInfo(topWnd, edge, &normalRect); /* Reset the real place to unsnap to */
|
||||
snapped = HTNOWHERE; /* Force snap */
|
||||
}
|
||||
windowRect = topWnd->rcWindow;
|
||||
#if 0 /* Windows 8 does this but is it a good feature? */
|
||||
else if (snapped == edge)
|
||||
{
|
||||
/* Already snapped to this edge, snap to the opposite side */
|
||||
edge = otherEdge;
|
||||
}
|
||||
#endif
|
||||
|
||||
UserSystemParametersInfo(SPI_GETWORKAREA, 0, &snapRect, 0);
|
||||
if (wParam == VK_LEFT)
|
||||
{
|
||||
snapRect.right = (snapRect.left + snapRect.right) / 2;
|
||||
}
|
||||
else // VK_RIGHT
|
||||
{
|
||||
snapRect.left = (snapRect.left + snapRect.right) / 2;
|
||||
}
|
||||
|
||||
if (snapped)
|
||||
{
|
||||
// if window was snapped but moved to other location - restore normal size
|
||||
if (!IntEqualRect(&snapRect, &windowRect))
|
||||
{
|
||||
RECT empty = {0, 0, 0, 0};
|
||||
co_WinPosSetWindowPos(topWnd,
|
||||
0,
|
||||
normalRect.left,
|
||||
normalRect.top,
|
||||
normalRect.right - normalRect.left,
|
||||
normalRect.bottom - normalRect.top,
|
||||
0);
|
||||
topWnd->InternalPos.NormalRect = empty;
|
||||
}
|
||||
}
|
||||
if (snapped == otherEdge)
|
||||
co_IntUnsnapWindow(topWnd);
|
||||
else
|
||||
{
|
||||
co_WinPosSetWindowPos(topWnd,
|
||||
0,
|
||||
snapRect.left,
|
||||
snapRect.top,
|
||||
snapRect.right - snapRect.left,
|
||||
snapRect.bottom - snapRect.top,
|
||||
0);
|
||||
topWnd->InternalPos.NormalRect = windowRect;
|
||||
}
|
||||
co_IntSnapWindow(topWnd, edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,6 +136,18 @@ NC_GetSysPopupPos(PWND Wnd, RECT *Rect)
|
||||
}
|
||||
}
|
||||
|
||||
static UINT
|
||||
GetSnapActivationPoint(PWND Wnd, POINT pt)
|
||||
{
|
||||
RECT wa;
|
||||
UserSystemParametersInfo(SPI_GETWORKAREA, 0, &wa, 0); /* FIXME: MultiMon of PWND */
|
||||
|
||||
if (pt.x <= wa.left) return HTLEFT;
|
||||
if (pt.x >= wa.right-1) return HTRIGHT;
|
||||
if (pt.y <= wa.top) return HTTOP; /* Maximize */
|
||||
return HTNOWHERE;
|
||||
}
|
||||
|
||||
LONG FASTCALL
|
||||
DefWndStartSizeMove(PWND Wnd, WPARAM wParam, POINT *capturePoint)
|
||||
{
|
||||
@ -239,13 +251,15 @@ VOID FASTCALL
|
||||
DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
{
|
||||
MSG msg;
|
||||
RECT sizingRect, mouseRect, origRect, unmodRect;
|
||||
RECT sizingRect, mouseRect, origRect, unmodRect, snapPreviewRect;
|
||||
PRECT pFrameRect = &sizingRect;
|
||||
HDC hdc;
|
||||
LONG hittest = (LONG)(wParam & 0x0f);
|
||||
PCURICON_OBJECT DragCursor = NULL, OldCursor = NULL;
|
||||
POINT minTrack, maxTrack;
|
||||
POINT capturePoint, pt;
|
||||
ULONG Style, ExStyle;
|
||||
UINT orgSnap = IntGetWindowSnapEdge(pwnd), snap = orgSnap;
|
||||
BOOL thickframe;
|
||||
BOOL iconic;
|
||||
BOOL moved = FALSE;
|
||||
@ -262,6 +276,8 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
iconic = (Style & WS_MINIMIZE) != 0;
|
||||
|
||||
if (((Style & WS_MAXIMIZE) && syscommand != SC_MOVE) || !IntIsWindowVisible(pwnd)) return;
|
||||
if ((Style & (WS_MAXIMIZE | WS_CHILD)) == WS_MAXIMIZE)
|
||||
orgSnap = snap = HTTOP;
|
||||
|
||||
thickframe = UserHasThickFrameStyle(Style, ExStyle) && !iconic;
|
||||
|
||||
@ -294,7 +310,7 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
{
|
||||
co_UserSetCapture(UserHMGetHandle(pwnd));
|
||||
hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
|
||||
if (!hittest)
|
||||
if (!hittest)
|
||||
{
|
||||
IntReleaseCapture();
|
||||
return;
|
||||
@ -402,56 +418,20 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
else if (g_bWindowSnapEnabled && (msg.message == WM_LBUTTONUP ||
|
||||
(msg.message == WM_MOUSEMOVE && (msg.wParam & MK_LBUTTON) == 0)))
|
||||
{ // If WindowSnapEnabled: Decide whether to snap before exiting
|
||||
DWORD ExStyleTB, StyleTB;
|
||||
BOOL IsTaskBar;
|
||||
|
||||
// We want to forbid snapping operations on the TaskBar
|
||||
// We use a heuristic for detecting the TaskBar Wnd by its typical Style & ExStyle Values
|
||||
ExStyleTB = (ExStyle & WS_EX_TOOLWINDOW);
|
||||
StyleTB = (Style & (WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN));
|
||||
IsTaskBar = (StyleTB == (WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN))
|
||||
&& (ExStyleTB == WS_EX_TOOLWINDOW);
|
||||
TRACE("ExStyle=%x Style=%x IsTaskBar=%d\n", ExStyleTB, StyleTB, IsTaskBar);
|
||||
|
||||
// check for snapping if was moved by caption
|
||||
if (!IsTaskBar && hittest == HTCAPTION && thickframe && (ExStyle & WS_EX_MDICHILD) == 0)
|
||||
if (hittest == HTCAPTION && thickframe && /* Check for snapping if was moved by caption */
|
||||
IntIsSnapAllowedForWindow(pwnd) && (ExStyle & WS_EX_MDICHILD) == 0)
|
||||
{
|
||||
RECT snapRect;
|
||||
BOOL doSideSnap = FALSE;
|
||||
UserSystemParametersInfo(SPI_GETWORKAREA, 0, &snapRect, 0);
|
||||
|
||||
// snap to left
|
||||
if (pt.x <= snapRect.left)
|
||||
BOOLEAN wasSnap = IntIsWindowSnapped(pwnd); /* Need the live snap state, not orgSnap nor maximized state */
|
||||
UINT snapTo = iconic ? HTNOWHERE : GetSnapActivationPoint(pwnd, pt);
|
||||
if (snapTo)
|
||||
{
|
||||
snapRect.right = (snapRect.right - snapRect.left) / 2 + snapRect.left;
|
||||
doSideSnap = TRUE;
|
||||
}
|
||||
// snap to right
|
||||
if (pt.x >= snapRect.right-1)
|
||||
{
|
||||
snapRect.left = (snapRect.right - snapRect.left) / 2 + snapRect.left;
|
||||
doSideSnap = TRUE;
|
||||
}
|
||||
|
||||
if (doSideSnap)
|
||||
{
|
||||
co_WinPosSetWindowPos(pwnd,
|
||||
NULL,
|
||||
snapRect.left,
|
||||
snapRect.top,
|
||||
snapRect.right - snapRect.left,
|
||||
snapRect.bottom - snapRect.top,
|
||||
SWP_NOACTIVATE);
|
||||
pwnd->InternalPos.NormalRect = origRect;
|
||||
}
|
||||
else
|
||||
{
|
||||
// maximize if on dragged to top
|
||||
if (pt.y <= snapRect.top)
|
||||
{
|
||||
co_IntSendMessage(UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MAXIMIZE, 0);
|
||||
pwnd->InternalPos.NormalRect = origRect;
|
||||
}
|
||||
if (DragFullWindows)
|
||||
{
|
||||
co_IntSnapWindow(pwnd, snapTo);
|
||||
if (!wasSnap)
|
||||
pwnd->InternalPos.NormalRect = origRect;
|
||||
}
|
||||
snap = snapTo;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -468,10 +448,10 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
|
||||
if (msg.message == WM_KEYDOWN) switch(msg.wParam)
|
||||
{
|
||||
case VK_UP: pt.y -= 8; break;
|
||||
case VK_DOWN: pt.y += 8; break;
|
||||
case VK_LEFT: pt.x -= 8; break;
|
||||
case VK_RIGHT: pt.x += 8; break;
|
||||
case VK_UP: pt.y -= 8; break;
|
||||
case VK_DOWN: pt.y += 8; break;
|
||||
case VK_LEFT: pt.x -= 8; break;
|
||||
case VK_RIGHT: pt.x += 8; break;
|
||||
}
|
||||
|
||||
pt.x = max( pt.x, mouseRect.left );
|
||||
@ -484,63 +464,99 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
|
||||
if (dx || dy)
|
||||
{
|
||||
if ( !moved )
|
||||
{
|
||||
moved = TRUE;
|
||||
if ( iconic ) /* ok, no system popup tracking */
|
||||
if (!moved)
|
||||
{
|
||||
moved = TRUE;
|
||||
if (iconic) /* ok, no system popup tracking */
|
||||
{
|
||||
OldCursor = UserSetCursor(DragCursor, FALSE);
|
||||
UserShowCursor( TRUE );
|
||||
UserShowCursor(TRUE);
|
||||
}
|
||||
else if(!DragFullWindows)
|
||||
UserDrawMovingFrame( hdc, &sizingRect, thickframe );
|
||||
}
|
||||
else if (!DragFullWindows)
|
||||
UserDrawMovingFrame(hdc, &sizingRect, thickframe);
|
||||
}
|
||||
|
||||
if (msg.message == WM_KEYDOWN) UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
|
||||
else
|
||||
{
|
||||
RECT newRect = unmodRect;
|
||||
if (msg.message == WM_KEYDOWN)
|
||||
{
|
||||
UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
RECT newRect = unmodRect;
|
||||
|
||||
if (!iconic && !DragFullWindows) UserDrawMovingFrame( hdc, &sizingRect, thickframe );
|
||||
if (!iconic && !DragFullWindows)
|
||||
{
|
||||
UserDrawMovingFrame(hdc, pFrameRect, thickframe);
|
||||
pFrameRect = &sizingRect;
|
||||
}
|
||||
if (hittest == HTCAPTION)
|
||||
{
|
||||
/* Restore window size if it is snapped */
|
||||
if (!RECTL_bIsEmptyRect(&pwnd->InternalPos.NormalRect) &&
|
||||
!IntEqualRect(&pwnd->InternalPos.NormalRect, &pwnd->rcWindow))
|
||||
PRECT pr = &newRect;
|
||||
LONG width, height, capcy, snapTo;
|
||||
if (snap && syscommand == SC_MOVE && !iconic &&
|
||||
!RECTL_bIsEmptyRect(&pwnd->InternalPos.NormalRect))
|
||||
{
|
||||
UserSetCursorPos(max(0, pwnd->InternalPos.NormalRect.left) + pt.x, pwnd->InternalPos.NormalRect.top + pt.y, 0, 0, FALSE);
|
||||
*pr = pwnd->InternalPos.NormalRect;
|
||||
origRect = *pr; /* Save normal size - is required when window unsnapped from one side and snapped to another holding mouse down */
|
||||
|
||||
/* Save normal size - it required when window unsnapped from one side and snapped to another holding mouse down */
|
||||
origRect = pwnd->InternalPos.NormalRect;
|
||||
/* Try to position the center of the caption where the mouse is horizontally */
|
||||
capcy = UserGetSystemMetrics((ExStyle & WS_EX_TOPMOST) ? SM_CYSMCAPTION : SM_CYCAPTION); /* No border, close enough */
|
||||
width = pr->right - pr->left;
|
||||
height = pr->bottom - pr->top;
|
||||
pr->left = pt.x - width / 2;
|
||||
pr->right = pr->left + width;
|
||||
pr->top = mouseRect.top;
|
||||
pr->bottom = pr->top + height;
|
||||
if (pr->left < mouseRect.left)
|
||||
{
|
||||
pr->left = mouseRect.left;
|
||||
pr->right = pr->left + width;
|
||||
}
|
||||
if ((pwnd->ExStyle & WS_EX_LAYOUTRTL) && pr->right > mouseRect.right)
|
||||
{
|
||||
pr->left = mouseRect.right - width;
|
||||
pr->right = pr->left + width;
|
||||
}
|
||||
UserSetCursorPos(pt.x, pr->top + capcy / 2, 0, 0, FALSE);
|
||||
snap = FALSE;
|
||||
dx = dy = 0; /* Don't offset this move */
|
||||
if (DragFullWindows)
|
||||
{
|
||||
IntSetStyle(pwnd, 0, WS_MAXIMIZE);
|
||||
IntSetSnapEdge(pwnd, HTNOWHERE);
|
||||
|
||||
/* Restore from maximized state */
|
||||
if (Style & WS_MAXIMIZE)
|
||||
{
|
||||
co_IntSendMessage(UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_RESTORE, 0);
|
||||
/* Have to move and size it now because we don't want SWP_NOSIZE */
|
||||
co_WinPosSetWindowPos(pwnd, HWND_TOP, pr->left, pr->top, width, height, SWP_NOACTIVATE);
|
||||
}
|
||||
/* Restore snapped to left/right place */
|
||||
else
|
||||
}
|
||||
else if (!snap && syscommand == SC_MOVE && !iconic)
|
||||
{
|
||||
if ((snapTo = GetSnapActivationPoint(pwnd, pt)) != 0)
|
||||
{
|
||||
co_WinPosSetWindowPos(pwnd,
|
||||
NULL,
|
||||
pwnd->InternalPos.NormalRect.left,
|
||||
pwnd->InternalPos.NormalRect.top,
|
||||
pwnd->InternalPos.NormalRect.right - pwnd->InternalPos.NormalRect.left,
|
||||
pwnd->InternalPos.NormalRect.bottom - pwnd->InternalPos.NormalRect.top,
|
||||
0);
|
||||
co_IntCalculateSnapPosition(pwnd, snapTo, &snapPreviewRect);
|
||||
if (DragFullWindows)
|
||||
{
|
||||
/* TODO: Show preview of snap */
|
||||
}
|
||||
else
|
||||
{
|
||||
pFrameRect = &snapPreviewRect;
|
||||
UserDrawMovingFrame(hdc, pFrameRect, thickframe);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
RECTL_vSetEmptyRect(&pwnd->InternalPos.NormalRect);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* regular window moving */
|
||||
RECTL_vOffsetRect(&newRect, dx, dy);
|
||||
}
|
||||
if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
|
||||
else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
|
||||
if (ON_TOP_BORDER(hittest)) newRect.top += dy;
|
||||
else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
|
||||
capturePoint = pt;
|
||||
if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
|
||||
else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
|
||||
if (ON_TOP_BORDER(hittest)) newRect.top += dy;
|
||||
else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
|
||||
|
||||
capturePoint = pt;
|
||||
|
||||
//
|
||||
// Save the new position to the unmodified rectangle. This allows explorer task bar
|
||||
@ -549,7 +565,7 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
//
|
||||
unmodRect = newRect;
|
||||
|
||||
/* determine the hit location */
|
||||
/* Determine the hit location */
|
||||
if (syscommand == SC_SIZE)
|
||||
{
|
||||
WPARAM wpSizingHit = 0;
|
||||
@ -561,7 +577,7 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
else
|
||||
co_IntSendMessage( UserHMGetHandle(pwnd), WM_MOVING, 0, (LPARAM)&newRect );
|
||||
|
||||
if (!iconic)
|
||||
if (!iconic)
|
||||
{
|
||||
if (!DragFullWindows)
|
||||
UserDrawMovingFrame( hdc, &newRect, thickframe );
|
||||
@ -609,7 +625,7 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
}
|
||||
}
|
||||
sizingRect = newRect;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,8 +647,12 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
*/
|
||||
if (OldCursor) UserDereferenceObject(OldCursor);
|
||||
}
|
||||
else if ( moved && !DragFullWindows )
|
||||
UserDrawMovingFrame( hdc, &sizingRect, thickframe );
|
||||
else
|
||||
{
|
||||
UINT eraseFinalFrame = moved && !DragFullWindows;
|
||||
if (eraseFinalFrame)
|
||||
UserDrawMovingFrame(hdc, pFrameRect, thickframe); // Undo the XOR drawing
|
||||
}
|
||||
|
||||
UserReleaseDC(NULL, hdc, FALSE);
|
||||
|
||||
@ -656,49 +676,57 @@ DefWndDoSizeMove(PWND pwnd, WORD wParam)
|
||||
/* window moved or resized */
|
||||
if (moved)
|
||||
{
|
||||
BOOL forceSizing = !iconic && hittest == HTCAPTION && (!!orgSnap != !!snap);
|
||||
UINT swp = (!forceSizing && hittest == HTCAPTION) ? SWP_NOSIZE : 0;
|
||||
|
||||
/* if the moving/resizing isn't canceled call SetWindowPos
|
||||
* with the new position or the new size of the window
|
||||
*/
|
||||
if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
|
||||
{
|
||||
/* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
|
||||
if (!DragFullWindows || iconic )
|
||||
{
|
||||
co_WinPosSetWindowPos( pwnd,
|
||||
0,
|
||||
sizingRect.left,
|
||||
sizingRect.top,
|
||||
sizingRect.right - sizingRect.left,
|
||||
sizingRect.bottom - sizingRect.top,
|
||||
( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
|
||||
}
|
||||
/* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
|
||||
if (!DragFullWindows || iconic)
|
||||
{
|
||||
if (snap)
|
||||
{
|
||||
co_IntSnapWindow(pwnd, snap);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (orgSnap && !snap)
|
||||
{
|
||||
IntSetStyle(pwnd, 0, WS_MAXIMIZE);
|
||||
IntSetSnapInfo(pwnd, HTNOWHERE, NULL);
|
||||
}
|
||||
co_WinPosSetWindowPos(pwnd, HWND_TOP, sizingRect.left, sizingRect.top,
|
||||
sizingRect.right - sizingRect.left,
|
||||
sizingRect.bottom - sizingRect.top, swp);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* restore previous size/position */
|
||||
if ( DragFullWindows )
|
||||
{
|
||||
co_WinPosSetWindowPos( pwnd,
|
||||
0,
|
||||
origRect.left,
|
||||
origRect.top,
|
||||
origRect.right - origRect.left,
|
||||
origRect.bottom - origRect.top,
|
||||
( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
|
||||
}
|
||||
{
|
||||
/* restore previous size/position */
|
||||
if (orgSnap)
|
||||
{
|
||||
co_IntSnapWindow(pwnd, orgSnap);
|
||||
}
|
||||
else if (DragFullWindows)
|
||||
{
|
||||
co_WinPosSetWindowPos(pwnd, HWND_TOP, origRect.left, origRect.top,
|
||||
origRect.right - origRect.left,
|
||||
origRect.bottom - origRect.top, swp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( IntIsWindow(UserHMGetHandle(pwnd)) )
|
||||
if (IntIsWindow(UserHMGetHandle(pwnd)))
|
||||
{
|
||||
if ( iconic )
|
||||
{
|
||||
/* Single click brings up the system menu when iconized */
|
||||
if ( !moved )
|
||||
{
|
||||
if( Style & WS_SYSMENU )
|
||||
co_IntSendMessage( UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
|
||||
}
|
||||
}
|
||||
/* Single click brings up the system menu when iconized */
|
||||
if (iconic && !moved && (Style & WS_SYSMENU))
|
||||
{
|
||||
co_IntSendMessage(UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x, pt.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -549,7 +549,13 @@ WinPosInitInternalPos(PWND Wnd, RECTL *RestoreRect)
|
||||
}
|
||||
else
|
||||
{
|
||||
Wnd->InternalPos.NormalRect = Rect;
|
||||
/* Lie about the snap; Windows does this so applications don't save their
|
||||
* position as a snap but rather the unsnapped "real" position. */
|
||||
if (!IntIsWindowSnapped(Wnd) ||
|
||||
RECTL_bIsEmptyRect(&Wnd->InternalPos.NormalRect))
|
||||
{
|
||||
Wnd->InternalPos.NormalRect = Rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2487,6 +2493,7 @@ co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
|
||||
case SW_MAXIMIZE:
|
||||
{
|
||||
//ERR("MinMaximize Maximize\n");
|
||||
IntSetSnapEdge(Wnd, HTNOWHERE); /* Mark as not snapped (for Win+Left,Up,Down) */
|
||||
if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
|
||||
{
|
||||
SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
|
||||
@ -2535,6 +2542,12 @@ co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
|
||||
else
|
||||
{
|
||||
*NewPos = wpl.rcNormalPosition;
|
||||
if (ShowFlag != SW_SHOWNORMAL && ShowFlag != SW_SHOWDEFAULT)
|
||||
{
|
||||
UINT edge = IntGetWindowSnapEdge(Wnd);
|
||||
if (edge)
|
||||
co_IntCalculateSnapPosition(Wnd, edge, NewPos);
|
||||
}
|
||||
NewPos->right -= NewPos->left;
|
||||
NewPos->bottom -= NewPos->top;
|
||||
break;
|
||||
@ -3863,4 +3876,139 @@ NtUserWindowFromPoint(LONG X, LONG Y)
|
||||
return Ret;
|
||||
}
|
||||
|
||||
/* Windows 10 (1903?)
|
||||
BOOL APIENTRY
|
||||
NtUserIsWindowArranged(HWND hWnd)
|
||||
{
|
||||
PWND pwnd = UserGetWindowObject(hWnd);
|
||||
return pwnd && IntIsWindowSnapped(pwnd);
|
||||
}
|
||||
*/
|
||||
|
||||
UINT FASTCALL
|
||||
IntGetWindowSnapEdge(PWND Wnd)
|
||||
{
|
||||
if (Wnd->ExStyle2 & WS_EX2_VERTICALLYMAXIMIZEDLEFT) return HTLEFT;
|
||||
if (Wnd->ExStyle2 & WS_EX2_VERTICALLYMAXIMIZEDRIGHT) return HTRIGHT;
|
||||
return HTNOWHERE;
|
||||
}
|
||||
|
||||
VOID FASTCALL
|
||||
co_IntCalculateSnapPosition(PWND Wnd, UINT Edge, OUT RECT *Pos)
|
||||
{
|
||||
POINT maxs, mint, maxt;
|
||||
UINT width, height;
|
||||
UserSystemParametersInfo(SPI_GETWORKAREA, 0, Pos, 0); /* FIXME: MultiMon of PWND */
|
||||
|
||||
co_WinPosGetMinMaxInfo(Wnd, &maxs, NULL, &mint, &maxt);
|
||||
width = Pos->right - Pos->left;
|
||||
width = min(min(max(width / 2, mint.x), maxt.x), width);
|
||||
height = Pos->bottom - Pos->top;
|
||||
height = min(max(height, mint.y), maxt.y);
|
||||
|
||||
switch (Edge)
|
||||
{
|
||||
case HTTOP: /* Maximized (Calculate RECT snap preview for SC_MOVE) */
|
||||
height = min(Pos->bottom - Pos->top, maxs.y);
|
||||
break;
|
||||
case HTLEFT:
|
||||
Pos->right = width;
|
||||
break;
|
||||
case HTRIGHT:
|
||||
Pos->left = Pos->right - width;
|
||||
break;
|
||||
default:
|
||||
ERR("Unexpected snap edge %#x\n", Edge);
|
||||
}
|
||||
Pos->bottom = Pos->top + height;
|
||||
}
|
||||
|
||||
VOID FASTCALL
|
||||
co_IntSnapWindow(PWND Wnd, UINT Edge)
|
||||
{
|
||||
RECT newPos;
|
||||
BOOLEAN wasSnapped = IntIsWindowSnapped(Wnd);
|
||||
UINT normal = !(Wnd->style & (WS_MAXIMIZE | WS_MINIMIZE));
|
||||
USER_REFERENCE_ENTRY ref;
|
||||
BOOLEAN hasRef = FALSE;
|
||||
|
||||
if (Edge == HTTOP)
|
||||
{
|
||||
co_IntSendMessage(UserHMGetHandle(Wnd), WM_SYSCOMMAND, SC_MAXIMIZE, 0);
|
||||
return;
|
||||
}
|
||||
else if (Edge)
|
||||
{
|
||||
UserRefObjectCo(Wnd, &ref);
|
||||
hasRef = TRUE;
|
||||
co_IntCalculateSnapPosition(Wnd, Edge, &newPos);
|
||||
IntSetSnapInfo(Wnd, Edge, (wasSnapped || !normal) ? NULL : &Wnd->rcWindow);
|
||||
}
|
||||
else if (wasSnapped)
|
||||
{
|
||||
if (!normal)
|
||||
{
|
||||
IntSetSnapEdge(Wnd, HTNOWHERE);
|
||||
return;
|
||||
}
|
||||
newPos = Wnd->InternalPos.NormalRect;
|
||||
IntSetSnapInfo(Wnd, HTNOWHERE, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
return; /* Already unsnapped, do nothing */
|
||||
}
|
||||
|
||||
TRACE("WindowSnap: %d->%d\n", IntGetWindowSnapEdge(Wnd), Edge);
|
||||
co_WinPosSetWindowPos(Wnd, HWND_TOP,
|
||||
newPos.left,
|
||||
newPos.top,
|
||||
newPos.right - newPos.left,
|
||||
newPos.bottom - newPos.top,
|
||||
0);
|
||||
if (hasRef)
|
||||
UserDerefObjectCo(Wnd);
|
||||
}
|
||||
|
||||
VOID FASTCALL
|
||||
IntSetSnapEdge(PWND Wnd, UINT Edge)
|
||||
{
|
||||
UINT styleMask = WS_EX2_VERTICALLYMAXIMIZEDLEFT | WS_EX2_VERTICALLYMAXIMIZEDRIGHT;
|
||||
UINT style = 0;
|
||||
switch (Edge)
|
||||
{
|
||||
case HTNOWHERE:
|
||||
style = 0;
|
||||
break;
|
||||
case HTTOP: /* Maximize throws away the snap */
|
||||
style = 0;
|
||||
break;
|
||||
case HTLEFT:
|
||||
style = WS_EX2_VERTICALLYMAXIMIZEDLEFT;
|
||||
break;
|
||||
case HTRIGHT:
|
||||
style = WS_EX2_VERTICALLYMAXIMIZEDRIGHT;
|
||||
break;
|
||||
default:
|
||||
ERR("Unexpected snap edge %#x\n", Edge);
|
||||
}
|
||||
Wnd->ExStyle2 = (Wnd->ExStyle2 & ~styleMask) | style;
|
||||
}
|
||||
|
||||
VOID FASTCALL
|
||||
IntSetSnapInfo(PWND Wnd, UINT Edge, IN const RECT *Pos OPTIONAL)
|
||||
{
|
||||
RECT r;
|
||||
IntSetSnapEdge(Wnd, Edge);
|
||||
if (Edge != HTNOWHERE)
|
||||
{
|
||||
RECTL_vSetEmptyRect(&r);
|
||||
Pos = (Wnd->style & WS_MINIMIZE) ? NULL : &r;
|
||||
}
|
||||
if (Pos)
|
||||
{
|
||||
Wnd->InternalPos.NormalRect = *Pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
@ -71,3 +71,34 @@ BOOL FASTCALL IntClientToScreen(PWND,LPPOINT);
|
||||
BOOL FASTCALL IntGetWindowRect(PWND,RECTL*);
|
||||
BOOL UserHasWindowEdge(DWORD,DWORD);
|
||||
VOID UserGetWindowBorders(DWORD,DWORD,SIZE*,BOOL);
|
||||
|
||||
UINT FASTCALL IntGetWindowSnapEdge(PWND Wnd);
|
||||
VOID FASTCALL co_IntCalculateSnapPosition(PWND Wnd, UINT Edge, OUT RECT *Pos);
|
||||
VOID FASTCALL co_IntSnapWindow(PWND Wnd, UINT Edge);
|
||||
VOID FASTCALL IntSetSnapEdge(PWND Wnd, UINT Edge);
|
||||
VOID FASTCALL IntSetSnapInfo(PWND Wnd, UINT Edge, IN const RECT *Pos OPTIONAL);
|
||||
|
||||
FORCEINLINE VOID
|
||||
co_IntUnsnapWindow(PWND Wnd)
|
||||
{
|
||||
co_IntSnapWindow(Wnd, 0);
|
||||
}
|
||||
|
||||
FORCEINLINE BOOLEAN
|
||||
IntIsWindowSnapped(PWND Wnd)
|
||||
{
|
||||
return (Wnd->ExStyle2 & (WS_EX2_VERTICALLYMAXIMIZEDLEFT | WS_EX2_VERTICALLYMAXIMIZEDRIGHT)) != 0;
|
||||
}
|
||||
|
||||
FORCEINLINE BOOLEAN
|
||||
IntIsSnapAllowedForWindow(PWND Wnd)
|
||||
{
|
||||
/* We want to forbid snapping operations on the TaskBar and on child windows.
|
||||
* We use a heuristic for detecting the TaskBar by its typical Style & ExStyle. */
|
||||
const UINT style = Wnd->style;
|
||||
const UINT tbws = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
||||
const UINT tbes = WS_EX_TOOLWINDOW;
|
||||
BOOLEAN istb = (style & tbws) == tbws && (Wnd->ExStyle & (tbes | WS_EX_APPWINDOW)) == tbes;
|
||||
BOOLEAN thickframe = (style & WS_THICKFRAME) && (style & (WS_DLGFRAME | WS_BORDER)) != WS_DLGFRAME;
|
||||
return thickframe && !(style & WS_CHILD) && !istb;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user