hw/xwin: Bug fixes for screen sizing when the screen window is on a non-primary monitor

There is a bug that when the -screen option is used to specify a monitor for
the screen window to be located on, but no explicit size is specified
(and the -multiplemonitors option isn't specified), the screen
window size is always constrained to fit the work area of the primary
monitor (rather than the work area of the specified monitor)

This gives incorrect results if you want a screen the same size as your
non-primary monitor (e.g. by using -screen 0 @2) and your non-primary
monitor is larger than your primary monitor.

(This can be worked around by specifying -multiplemonitors and an explicit
screen size the same size as the monitor (e.g. -multiplemonitors -screen 0
1600x1200@2))

Fix to use work area for the monitor specified for the screen, rather than the
primary monitor work area (unless -multiplemonitors is used, in which case we
continue to use the virtual desktop work area instead)

Also fix the adjustment for an autohide taskbar, so that it is only done if the
taskbar is on the same monitor as the screen (or -multiplemonitors is used)

Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk>
Reviewed-by: Colin Harrison <colin.harrison@virgin.net>
This commit is contained in:
Jon TURNEY 2012-07-05 14:01:03 +01:00
parent 090856b55b
commit 7e07d61857
5 changed files with 94 additions and 34 deletions

View File

@ -388,6 +388,7 @@ typedef struct {
DWORD dwScreen;
int iMonitor;
HMONITOR hMonitor;
DWORD dwUserWidth;
DWORD dwUserHeight;
DWORD dwWidth;

View File

@ -34,10 +34,6 @@
#include "win.h"
#include "shellapi.h"
#ifndef ABS_AUTOHIDE
#define ABS_AUTOHIDE 1
#endif
/*
* Local function prototypes
*/
@ -46,7 +42,7 @@ static Bool
winGetWorkArea(RECT * prcWorkArea, winScreenInfo * pScreenInfo);
static Bool
winAdjustForAutoHide(RECT * prcWorkArea);
winAdjustForAutoHide(RECT * prcWorkArea, winScreenInfo * pScreenInfo);
/*
* Create a full screen window
@ -218,7 +214,7 @@ winCreateBoundingWindowWindowed(ScreenPtr pScreen)
winGetWorkArea(&rcWorkArea, pScreenInfo);
/* Adjust for auto-hide taskbars */
winAdjustForAutoHide(&rcWorkArea);
winAdjustForAutoHide(&rcWorkArea, pScreenInfo);
/* Did the user specify a position? */
if (pScreenInfo->fUserGavePosition) {
@ -501,14 +497,32 @@ winGetWorkArea(RECT * prcWorkArea, winScreenInfo * pScreenInfo)
int iLeft, iTop;
int iPrimaryNonWorkAreaWidth, iPrimaryNonWorkAreaHeight;
/* Use GetMonitorInfo to get work area for monitor */
if (!pScreenInfo->fMultipleMonitors) {
MONITORINFO mi;
mi.cbSize = sizeof(MONITORINFO);
if (GetMonitorInfo(pScreenInfo->hMonitor, &mi)) {
*prcWorkArea = mi.rcWork;
winDebug("winGetWorkArea - Monitor %d WorkArea: %d %d %d %d\n",
pScreenInfo->iMonitor,
(int) prcWorkArea->top, (int) prcWorkArea->left,
(int) prcWorkArea->bottom, (int) prcWorkArea->right);
}
else {
ErrorF("winGetWorkArea - GetMonitorInfo() failed for monitor %d\n",
pScreenInfo->iMonitor);
}
/* Bail out here if we aren't using multiple monitors */
return TRUE;
}
/* SPI_GETWORKAREA only gets the work area of the primary screen. */
SystemParametersInfo(SPI_GETWORKAREA, 0, prcWorkArea, 0);
/* Bail out here if we aren't using multiple monitors */
if (!pScreenInfo->fMultipleMonitors)
return TRUE;
winDebug("winGetWorkArea - Original WorkArea: %d %d %d %d\n",
winDebug("winGetWorkArea - Primary Monitor WorkArea: %d %d %d %d\n",
(int) prcWorkArea->top, (int) prcWorkArea->left,
(int) prcWorkArea->bottom, (int) prcWorkArea->right);
@ -556,16 +570,39 @@ winGetWorkArea(RECT * prcWorkArea, winScreenInfo * pScreenInfo)
return TRUE;
}
static Bool
winTaskbarOnScreenEdge(unsigned int uEdge, winScreenInfo * pScreenInfo)
{
APPBARDATA abd;
HWND hwndAutoHide;
ZeroMemory(&abd, sizeof(abd));
abd.cbSize = sizeof(abd);
abd.uEdge = uEdge;
hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
if (hwndAutoHide != NULL) {
/*
Found an autohide taskbar on that edge, but is it on the
same monitor as the screen window?
*/
if (pScreenInfo->fMultipleMonitors ||
(MonitorFromWindow(hwndAutoHide, MONITOR_DEFAULTTONULL) ==
pScreenInfo->hMonitor))
return TRUE;
}
return FALSE;
}
/*
* Adjust the client area so that any auto-hide toolbars
* will work correctly.
*/
static Bool
winAdjustForAutoHide(RECT * prcWorkArea)
winAdjustForAutoHide(RECT * prcWorkArea, winScreenInfo * pScreenInfo)
{
APPBARDATA abd;
HWND hwndAutoHide;
winDebug("winAdjustForAutoHide - Original WorkArea: %d %d %d %d\n",
(int) prcWorkArea->top, (int) prcWorkArea->left,
@ -577,34 +614,31 @@ winAdjustForAutoHide(RECT * prcWorkArea)
if (SHAppBarMessage(ABM_GETSTATE, &abd) & ABS_AUTOHIDE)
winDebug("winAdjustForAutoHide - Taskbar is auto hide\n");
/*
Despite the forgoing, we are checking for any AppBar
hiding along a monitor edge, not just the Windows TaskBar.
*/
/* Look for a TOP auto-hide taskbar */
abd.uEdge = ABE_TOP;
hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
if (hwndAutoHide != NULL) {
if (winTaskbarOnScreenEdge(ABE_TOP, pScreenInfo)) {
winDebug("winAdjustForAutoHide - Found TOP auto-hide taskbar\n");
prcWorkArea->top += 1;
}
/* Look for a LEFT auto-hide taskbar */
abd.uEdge = ABE_LEFT;
hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
if (hwndAutoHide != NULL) {
if (winTaskbarOnScreenEdge(ABE_LEFT, pScreenInfo)) {
winDebug("winAdjustForAutoHide - Found LEFT auto-hide taskbar\n");
prcWorkArea->left += 1;
}
/* Look for a BOTTOM auto-hide taskbar */
abd.uEdge = ABE_BOTTOM;
hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
if (hwndAutoHide != NULL) {
if (winTaskbarOnScreenEdge(ABE_BOTTOM, pScreenInfo)) {
winDebug("winAdjustForAutoHide - Found BOTTOM auto-hide taskbar\n");
prcWorkArea->bottom -= 1;
}
/* Look for a RIGHT auto-hide taskbar */
abd.uEdge = ABE_RIGHT;
hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
if (hwndAutoHide != NULL) {
if (winTaskbarOnScreenEdge(ABE_RIGHT, pScreenInfo)) {
winDebug("winAdjustForAutoHide - Found RIGHT auto-hide taskbar\n");
prcWorkArea->right -= 1;
}
@ -613,14 +647,5 @@ winAdjustForAutoHide(RECT * prcWorkArea)
(int) prcWorkArea->top, (int) prcWorkArea->left,
(int) prcWorkArea->bottom, (int) prcWorkArea->right);
#if 0
/* Obtain the task bar window dimensions */
abd.hWnd = hwndAutoHide;
hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETTASKBARPOS, &abd);
winDebug("hwndAutoHide %08x abd.hWnd %08x %d %d %d %d\n",
hwndAutoHide, abd.hWnd,
abd.rc.top, abd.rc.left, abd.rc.bottom, abd.rc.right);
#endif
return TRUE;
}

View File

@ -48,6 +48,7 @@ getMonitorInfo(HMONITOR hMonitor, HDC hdc, LPRECT rect, LPARAM _data)
data->monitorOffsetY = rect->top;
data->monitorHeight = rect->bottom - rect->top;
data->monitorWidth = rect->right - rect->left;
data->monitorHandle = hMonitor;
return FALSE;
}
return TRUE;

View File

@ -1,3 +1,31 @@
/*
Copyright 1993, 1998 The Open Group
Copyright (C) Colin Harrison 2005-2008
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from The Open Group.
*/
/* data returned for monitor information */
struct GetMonitorInfoData {
@ -9,6 +37,7 @@ struct GetMonitorInfoData {
int monitorOffsetY;
int monitorHeight;
int monitorWidth;
HMONITOR monitorHandle;
};
Bool QueryMonitor(int index, struct GetMonitorInfoData *data);

View File

@ -115,6 +115,7 @@ winInitializeScreenDefaults(void)
}
defaultScreenInfo.iMonitor = 1;
defaultScreenInfo.hMonitor = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY);
defaultScreenInfo.dwWidth = dwWidth;
defaultScreenInfo.dwHeight = dwHeight;
defaultScreenInfo.dwUserWidth = dwWidth;
@ -333,6 +334,7 @@ ddxProcessArgument(int argc, char *argv[], int i)
g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = FALSE;
g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE;
g_ScreenInfo[nScreenNum].iMonitor = iMonitor;
g_ScreenInfo[nScreenNum].hMonitor = data.monitorHandle;
g_ScreenInfo[nScreenNum].dwWidth = data.monitorWidth;
g_ScreenInfo[nScreenNum].dwHeight = data.monitorHeight;
g_ScreenInfo[nScreenNum].dwUserWidth = data.monitorWidth;
@ -383,6 +385,7 @@ ddxProcessArgument(int argc, char *argv[], int i)
}
else if (data.bMonitorSpecifiedExists == TRUE) {
g_ScreenInfo[nScreenNum].iMonitor = iMonitor;
g_ScreenInfo[nScreenNum].hMonitor = data.monitorHandle;
g_ScreenInfo[nScreenNum].dwInitialX +=
data.monitorOffsetX;
g_ScreenInfo[nScreenNum].dwInitialY +=
@ -415,6 +418,7 @@ ddxProcessArgument(int argc, char *argv[], int i)
iMonitor);
g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE;
g_ScreenInfo[nScreenNum].iMonitor = iMonitor;
g_ScreenInfo[nScreenNum].hMonitor = data.monitorHandle;
g_ScreenInfo[nScreenNum].dwInitialX = data.monitorOffsetX;
g_ScreenInfo[nScreenNum].dwInitialY = data.monitorOffsetY;
}