Cygwin/X: Preserve client area size and position on Windows window style change

When the style changes, adjust the window size so the client area remains the same.

Otherwise the window size may change when sizing is reflected from Windows to X, and
some windows are drawn expecting them to be exactly the requested size (e.g. the
gmplayer control window)

Use DeferWindowPos to delay the resize to preserve client area on WM_STYLECHANGING
until after the style change has actually happened in WM_STYLECHANGED

As a consquence of this, we need to be more careful to create windows with exactly
the requested placement and client area initially, so the client area matches what
the X client requested

Also synchronize the X windows idea of the placement of a window which Windows is
allowed to place

Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk>
Reviewed-by: Colin Harrison <colin.harrison@virgin.net>
Tested-by: Colin Harrison <colin.harrison@virgin.net>
This commit is contained in:
Jon TURNEY 2010-08-12 15:00:01 +01:00
parent 1d7f3a0031
commit e78628406f
3 changed files with 91 additions and 5 deletions

View File

@ -493,6 +493,8 @@ winCreateWindowsWindow (WindowPtr pWin)
winPrivScreenPtr pScreenPriv = pWinPriv->pScreenPriv;
WinXSizeHints hints;
WindowPtr pDaddy;
DWORD dwStyle, dwExStyle;
RECT rc;
winInitMultiWindowClass();
@ -517,6 +519,8 @@ winCreateWindowsWindow (WindowPtr pWin)
iY = CW_USEDEFAULT;
}
winDebug("winCreateWindowsWindow - %dx%d @ %dx%d\n", iWidth, iHeight, iX, iY);
if (winMultiWindowGetTransientFor (pWin, &pDaddy))
{
if (pDaddy)
@ -538,13 +542,32 @@ winCreateWindowsWindow (WindowPtr pWin)
}
}
/* Create the window */
/* Make it OVERLAPPED in create call since WS_POPUP doesn't support */
/* Make it WS_OVERLAPPED in create call since WS_POPUP doesn't support */
/* CW_USEDEFAULT, change back to popup after creation */
hWnd = CreateWindowExA (WS_EX_TOOLWINDOW, /* Extended styles */
dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
dwExStyle = WS_EX_TOOLWINDOW;
/*
Calculate the window coordinates containing the requested client area,
being careful to preseve CW_USEDEFAULT
*/
rc.top = (iY != CW_USEDEFAULT) ? iY : 0;
rc.left = (iX != CW_USEDEFAULT) ? iX : 0;
rc.bottom = rc.top + iHeight;
rc.right = rc.left + iWidth;
AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);
if (iY != CW_USEDEFAULT) iY = rc.top;
if (iX != CW_USEDEFAULT) iX = rc.left;
iHeight = rc.bottom - rc.top;
iWidth = rc.right - rc.left;
winDebug("winCreateWindowsWindow - %dx%d @ %dx%d\n", iWidth, iHeight, iX, iY);
/* Create the window */
hWnd = CreateWindowExA (dwExStyle, /* Extended styles */
WINDOW_CLASS_X, /* Class name */
WINDOW_TITLE_X, /* Window name */
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
dwStyle, /* Styles */
iX, /* Horizontal position */
iY, /* Vertical position */
iWidth, /* Right edge */
@ -569,6 +592,10 @@ winCreateWindowsWindow (WindowPtr pWin)
SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
SetWindowPos (hWnd, 0, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
/* Adjust the X window to match the window placement we actually got... */
winAdjustXWindow (pWin, hWnd);
/* Make sure it gets the proper system menu for a WS_POPUP, too */
GetSystemMenu (hWnd, TRUE);

View File

@ -1008,6 +1008,64 @@ winTopLevelWindowProc (HWND hwnd, UINT message,
winAdjustXWindow (pWin, hwnd);
return 0; /* end of WM_SIZE handler */
case WM_STYLECHANGING:
/*
When the style changes, adjust the Windows window size so the client area remains the same size,
and adjust the Windows window position so that the client area remains in the same place.
*/
{
RECT newWinRect;
DWORD dwExStyle;
DWORD dwStyle;
DWORD newStyle = ((STYLESTRUCT *)lParam)->styleNew;
WINDOWINFO wi;
dwExStyle = GetWindowLongPtr (hwnd, GWL_EXSTYLE);
dwStyle = GetWindowLongPtr (hwnd, GWL_STYLE);
winDebug("winTopLevelWindowProc - WM_STYLECHANGING from %08x %08x\n", dwStyle, dwExStyle);
if (wParam == GWL_EXSTYLE)
dwExStyle = newStyle;
if (wParam == GWL_STYLE)
dwStyle = newStyle;
winDebug("winTopLevelWindowProc - WM_STYLECHANGING to %08x %08x\n", dwStyle, dwExStyle);
/* Get client rect in screen coordinates */
wi.cbSize = sizeof(WINDOWINFO);
GetWindowInfo(hwnd, &wi);
winDebug("winTopLevelWindowProc - WM_STYLECHANGING client area {%d, %d, %d, %d}, {%d x %d}\n", wi.rcClient.left, wi.rcClient.top, wi.rcClient.right, wi.rcClient.bottom, wi.rcClient.right - wi.rcClient.left, wi.rcClient.bottom - wi.rcClient.top);
newWinRect = wi.rcClient;
if (!AdjustWindowRectEx(&newWinRect, dwStyle, FALSE, dwExStyle))
winDebug("winTopLevelWindowProc - WM_STYLECHANGING AdjustWindowRectEx failed\n");
winDebug("winTopLevelWindowProc - WM_STYLECHANGING window area should be {%d, %d, %d, %d}, {%d x %d}\n", newWinRect.left, newWinRect.top, newWinRect.right, newWinRect.bottom, newWinRect.right - newWinRect.left, newWinRect.bottom - newWinRect.top);
/*
Style change hasn't happened yet, so we can't adjust the window size yet, as the winAdjustXWindow()
which WM_SIZE does will use the current (unchanged) style. Instead make a note to change it when
WM_STYLECHANGED is received...
*/
pWinPriv->hDwp = BeginDeferWindowPos(1);
pWinPriv->hDwp = DeferWindowPos(pWinPriv->hDwp, hwnd, NULL, newWinRect.left, newWinRect.top, newWinRect.right - newWinRect.left, newWinRect.bottom - newWinRect.top, SWP_NOACTIVATE | SWP_NOZORDER);
}
return 0;
case WM_STYLECHANGED:
{
if (pWinPriv->hDwp)
{
EndDeferWindowPos(pWinPriv->hDwp);
pWinPriv->hDwp = NULL;
}
winDebug("winTopLevelWindowProc - WM_STYLECHANGED done\n");
}
return 0;
case WM_MOUSEACTIVATE:
/* Check if this window needs to be made active when clicked */

View File

@ -79,6 +79,7 @@ typedef struct
HWND hWnd;
winPrivScreenPtr pScreenPriv;
Bool fXKilled;
HDWP hDwp;
/* Privates used by primary fb DirectDraw server */
LPDDSURFACEDESC pddsdPrimary;