reactos/win32ss/user/ntuser/monitor.c

1009 lines
27 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: pMonitor support
* FILE: subsys/win32k/ntuser/monitor.c
* PROGRAMERS: Anich Gregor (blight@blight.eu.org)
* Rafal Harabien (rafalh@reactos.org)
*/
#include <win32k.h>
DBG_DEFAULT_CHANNEL(UserMonitor);
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
/* List of monitors */
static PMONITOR gMonitorList = NULL;
/* PRIVATE FUNCTIONS **********************************************************/
/* IntCreateMonitorObject
*
* Creates a MONITOR
*
* Return value
* If the function succeeds a pointer to a MONITOR is returned. On failure
* NULL is returned.
*/
static
PMONITOR
IntCreateMonitorObject(VOID)
{
return UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_MONITOR, sizeof(MONITOR));
}
/* IntDestroyMonitorObject
*
* Destroys a MONITOR
* You have to be the owner of the monitors lock to safely destroy it.
*
* Arguments
*
* pMonitor
* Pointer to the MONITOR which shall be deleted
*/
static
void
IntDestroyMonitorObject(IN PMONITOR pMonitor)
{
/* Remove monitor region */
if (pMonitor->hrgnMonitor)
{
GreSetObjectOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_POWNED);
GreDeleteObject(pMonitor->hrgnMonitor);
}
/* Destroy monitor object */
UserDereferenceObject(pMonitor);
UserDeleteObject(UserHMGetHandle(pMonitor), TYPE_MONITOR);
}
/* UserGetMonitorObject
*
* Returns monitor object from handle or sets last error if handle is invalid
*
* Arguments
*
* hMonitor
* Handle of MONITOR object
*/
PMONITOR NTAPI
UserGetMonitorObject(IN HMONITOR hMonitor)
{
PMONITOR pMonitor;
if (!hMonitor)
{
EngSetLastError(ERROR_INVALID_MONITOR_HANDLE);
return NULL;
}
pMonitor = (PMONITOR)UserGetObject(gHandleTable, hMonitor, TYPE_MONITOR);
if (!pMonitor)
{
EngSetLastError(ERROR_INVALID_MONITOR_HANDLE);
return NULL;
}
return pMonitor;
}
/* UserGetPrimaryMonitor
*
* Returns a PMONITOR for the primary monitor
*
* Return value
* PMONITOR
*/
PMONITOR NTAPI
UserGetPrimaryMonitor(VOID)
{
PMONITOR pMonitor;
/* Find primary monitor */
for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext)
{
if (pMonitor->IsPrimary)
break;
}
return pMonitor;
}
/* UserAttachMonitor
*
* Creates a new MONITOR and appends it to the list of monitors.
*
* Arguments
*
* pGdiDevice Pointer to the PDEVOBJ onto which the monitor was attached
* DisplayNumber Display Number (starting with 0)
*
* Return value
* Returns a NTSTATUS
*/
NTSTATUS NTAPI
UserAttachMonitor(IN HDEV hDev)
{
PMONITOR pMonitor;
TRACE("Attaching monitor...\n");
/* Create new monitor object */
pMonitor = IntCreateMonitorObject();
if (pMonitor == NULL)
{
TRACE("Couldnt create monitor object\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
pMonitor->hDev = hDev;
pMonitor->cWndStack = 0;
if (gMonitorList == NULL)
{
TRACE("Primary monitor is beeing attached\n");
pMonitor->IsPrimary = TRUE;
gMonitorList = pMonitor;
}
else
{
PMONITOR pmonLast = gMonitorList;
TRACE("Additional monitor is beeing attached\n");
while (pmonLast->pMonitorNext != NULL)
pmonLast = pmonLast->pMonitorNext;
pmonLast->pMonitorNext = pMonitor;
}
UserUpdateMonitorSize(hDev);
return STATUS_SUCCESS;
}
/* UserDetachMonitor
*
* Deletes a MONITOR and removes it from the list of monitors.
*
* Arguments
*
* pGdiDevice Pointer to the PDEVOBJ from which the monitor was detached
*
* Return value
* Returns a NTSTATUS
*/
NTSTATUS NTAPI
UserDetachMonitor(IN HDEV hDev)
{
PMONITOR pMonitor = gMonitorList, *pLink = &gMonitorList;
/* Find monitor attached to given device */
while (pMonitor != NULL)
{
if (pMonitor->hDev == hDev)
break;
pLink = &pMonitor->pMonitorNext;
pMonitor = pMonitor->pMonitorNext;
}
if (pMonitor == NULL)
{
/* No monitor has been found */
return STATUS_INVALID_PARAMETER;
}
/* We destroy primary monitor - set next as primary */
if (pMonitor->IsPrimary && pMonitor->pMonitorNext != NULL)
pMonitor->pMonitorNext->IsPrimary = TRUE;
/* Update Next ptr in previous monitor */
*pLink = pMonitor->pMonitorNext;
/* Finally destroy monitor */
IntDestroyMonitorObject(pMonitor);
return STATUS_SUCCESS;
}
/* UserUpdateMonitorSize
*
* Reset size of the monitor using atached device
*
* Arguments
*
* PMONITOR
* pGdiDevice Pointer to the PDEVOBJ, which size has changed
*
* Return value
* Returns a NTSTATUS
*/
NTSTATUS NTAPI
UserUpdateMonitorSize(IN HDEV hDev)
{
PMONITOR pMonitor;
SIZEL DeviceSize;
/* Find monitor attached to given device */
for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext)
{
if (pMonitor->hDev == hDev)
break;
}
if (pMonitor == NULL)
{
/* No monitor has been found */
return STATUS_INVALID_PARAMETER;
}
/* Get the size of the hdev */
PDEVOBJ_sizl((PPDEVOBJ)hDev, &DeviceSize);
/* Update monitor size */
pMonitor->rcMonitor.left = 0;
pMonitor->rcMonitor.top = 0;
pMonitor->rcMonitor.right = pMonitor->rcMonitor.left + DeviceSize.cx;
pMonitor->rcMonitor.bottom = pMonitor->rcMonitor.top + DeviceSize.cy;
pMonitor->rcWork = pMonitor->rcMonitor;
/* Destroy monitor region... */
if (pMonitor->hrgnMonitor)
{
GreSetObjectOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_POWNED);
GreDeleteObject(pMonitor->hrgnMonitor);
}
/* ...and create new one */
pMonitor->hrgnMonitor = NtGdiCreateRectRgn(
pMonitor->rcMonitor.left,
pMonitor->rcMonitor.top,
pMonitor->rcMonitor.right,
pMonitor->rcMonitor.bottom);
if (pMonitor->hrgnMonitor)
IntGdiSetRegionOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_PUBLIC);
//
// Should be Virtual accumulation of all the available monitors.
//
gpsi->rcScreenReal = pMonitor->rcMonitor;
return STATUS_SUCCESS;
}
/* IntGetMonitorsFromRect
*
* Returns a list of monitor handles/rectangles. The rectangles in the list are
* the areas of intersection with the monitors.
*
* Arguments
*
* pRect
* Rectangle in desktop coordinates. If this is NULL all monitors are
* returned and the rect list is filled with the sizes of the monitors.
*
* phMonitorList
* Pointer to an array of HMONITOR which is filled with monitor handles.
* Can be NULL
*
* prcMonitorList
* Pointer to an array of RECT which is filled with intersection rects in
* desktop coordinates.
* Can be NULL, will be ignored if no intersecting monitor is found and
* flags is MONITOR_DEFAULTTONEAREST
*
* dwListSize
* Size of the phMonitorList and prcMonitorList arguments. If this is zero
* phMonitorList and prcMonitorList are ignored.
*
* dwFlags
* Either 0 or MONITOR_DEFAULTTONEAREST (ignored if rect is NULL)
*
* Returns
* The number of monitors which intersect the specified region.
*/
static
UINT
IntGetMonitorsFromRect(OPTIONAL IN LPCRECTL pRect,
OPTIONAL OUT HMONITOR *phMonitorList,
OPTIONAL OUT PRECTL prcMonitorList,
OPTIONAL IN DWORD dwListSize,
OPTIONAL IN DWORD dwFlags)
{
PMONITOR pMonitor, pNearestMonitor = NULL, pPrimaryMonitor = NULL;
UINT cMonitors = 0;
ULONG iNearestDistance = 0xffffffff;
/* Find monitors which intersects the rectangle */
for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext)
{
RECTL MonitorRect, IntersectionRect;
MonitorRect = pMonitor->rcMonitor;
TRACE("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n",
MonitorRect.left, MonitorRect.top, MonitorRect.right, MonitorRect.bottom);
/* Save primary monitor for later usage */
if (dwFlags == MONITOR_DEFAULTTOPRIMARY && pMonitor->IsPrimary)
pPrimaryMonitor = pMonitor;
/* Check if a rect is given */
if (pRect == NULL)
{
/* No rect given, so use the full monitor rect */
IntersectionRect = MonitorRect;
}
/* We have a rect, calculate intersection */
else if (!RECTL_bIntersectRect(&IntersectionRect, &MonitorRect, pRect))
{
/* Rects did not intersect */
if (dwFlags == MONITOR_DEFAULTTONEAREST)
{
ULONG cx, cy, iDistance;
/* Get x and y distance */
cx = min(abs(MonitorRect.left - pRect->right),
abs(pRect->left - MonitorRect.right));
cy = min(abs(MonitorRect.top - pRect->bottom),
abs(pRect->top - MonitorRect.bottom));
/* Calculate distance square */
iDistance = cx * cx + cy * cy;
/* Check if this is the new nearest monitor */
if (iDistance < iNearestDistance)
{
iNearestDistance = iDistance;
pNearestMonitor = pMonitor;
}
}
continue;
}
/* Check if there's space in the buffer */
if (cMonitors < dwListSize)
{
/* Save monitor data */
if (phMonitorList != NULL)
phMonitorList[cMonitors] = UserHMGetHandle(pMonitor);
if (prcMonitorList != NULL)
prcMonitorList[cMonitors] = IntersectionRect;
}
/* Increase count of found monitors */
cMonitors++;
}
/* Nothing has been found? */
if (cMonitors == 0)
{
/* Check if we shall default to the nearest monitor */
if (dwFlags == MONITOR_DEFAULTTONEAREST && pNearestMonitor)
{
if (phMonitorList && dwListSize > 0)
phMonitorList[cMonitors] = UserHMGetHandle(pNearestMonitor);
cMonitors++;
}
/* Check if we shall default to the primary monitor */
else if (dwFlags == MONITOR_DEFAULTTOPRIMARY && pPrimaryMonitor)
{
if (phMonitorList != NULL && dwListSize > 0)
phMonitorList[cMonitors] = UserHMGetHandle(pPrimaryMonitor);
cMonitors++;
}
}
return cMonitors;
}
PMONITOR NTAPI
UserMonitorFromRect(
PRECTL pRect,
DWORD dwFlags)
{
ULONG cMonitors, LargestArea = 0, i;
PRECTL prcMonitorList = NULL;
HMONITOR *phMonitorList = NULL;
HMONITOR hMonitor = NULL;
/* Check if flags are valid */
if (dwFlags != MONITOR_DEFAULTTONULL &&
dwFlags != MONITOR_DEFAULTTOPRIMARY &&
dwFlags != MONITOR_DEFAULTTONEAREST)
{
EngSetLastError(ERROR_INVALID_FLAGS);
return NULL;
}
/* Find intersecting monitors */
cMonitors = IntGetMonitorsFromRect(pRect, &hMonitor, NULL, 1, dwFlags);
if (cMonitors <= 1)
{
/* No or one monitor found. Just return handle. */
goto cleanup;
}
/* There is more than one monitor. Find monitor with largest intersection.
Temporary reset hMonitor */
hMonitor = NULL;
/* Allocate helper buffers */
phMonitorList = ExAllocatePoolWithTag(PagedPool,
sizeof(HMONITOR) * cMonitors,
USERTAG_MONITORRECTS);
if (phMonitorList == NULL)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
prcMonitorList = ExAllocatePoolWithTag(PagedPool,
sizeof(RECT) * cMonitors,
USERTAG_MONITORRECTS);
if (prcMonitorList == NULL)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
/* Get intersecting monitors again but now with rectangle list */
cMonitors = IntGetMonitorsFromRect(pRect, phMonitorList, prcMonitorList,
cMonitors, 0);
/* Find largest intersection */
for (i = 0; i < cMonitors; i++)
{
ULONG Area = (prcMonitorList[i].right - prcMonitorList[i].left) *
(prcMonitorList[i].bottom - prcMonitorList[i].top);
if (Area >= LargestArea)
{
hMonitor = phMonitorList[i];
LargestArea = Area;
}
}
cleanup:
if (phMonitorList)
ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS);
if (prcMonitorList)
ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS);
return UserGetMonitorObject(hMonitor);
}
PMONITOR
FASTCALL
UserMonitorFromPoint(
IN POINT pt,
IN DWORD dwFlags)
{
RECTL rc;
HMONITOR hMonitor = NULL;
/* Check if flags are valid */
if (dwFlags != MONITOR_DEFAULTTONULL &&
dwFlags != MONITOR_DEFAULTTOPRIMARY &&
dwFlags != MONITOR_DEFAULTTONEAREST)
{
EngSetLastError(ERROR_INVALID_FLAGS);
return NULL;
}
/* Fill rect (bottom-right exclusive) */
rc.left = pt.x;
rc.right = pt.x + 1;
rc.top = pt.y;
rc.bottom = pt.y + 1;
/* Find intersecting monitor */
IntGetMonitorsFromRect(&rc, &hMonitor, NULL, 1, dwFlags);
return UserGetMonitorObject(hMonitor);
}
/* PUBLIC FUNCTIONS ***********************************************************/
/* NtUserEnumDisplayMonitors
*
* Enumerates display monitors which intersect the given HDC/cliprect
*
* Arguments
*
* hdc
* Handle to a DC for which to enum intersecting monitors. If this is NULL
* it returns all monitors which are part of the current virtual screen.
*
* pUnsafeRect
* Clipping rectangle with coordinate system origin at the DCs origin if the
* given HDC is not NULL or in virtual screen coordinated if it is NULL.
* Can be NULL
*
* phUnsafeMonitorList
* Pointer to an array of HMONITOR which is filled with monitor handles.
* Can be NULL
*
* prcUnsafeMonitorList
* Pointer to an array of RECT which is filled with intersection rectangles.
* Can be NULL
*
* dwListSize
* Size of the hMonitorList and monitorRectList arguments. If this is zero
* hMonitorList and monitorRectList are ignored.
*
* Returns
* The number of monitors which intersect the specified region or -1 on failure.
*/
INT
APIENTRY
NtUserEnumDisplayMonitors(
OPTIONAL IN HDC hdc,
OPTIONAL IN LPCRECTL pUnsafeRect,
OPTIONAL OUT HMONITOR *phUnsafeMonitorList,
OPTIONAL OUT PRECTL prcUnsafeMonitorList,
OPTIONAL IN DWORD dwListSize)
{
UINT cMonitors, i;
INT iRet = -1;
HMONITOR *phMonitorList = NULL;
PRECTL prcMonitorList = NULL;
RECTL rc, *pRect;
RECTL DcRect = {0};
NTSTATUS Status;
/* Get rectangle */
if (pUnsafeRect != NULL)
{
Status = MmCopyFromCaller(&rc, pUnsafeRect, sizeof(RECT));
if (!NT_SUCCESS(Status))
{
TRACE("MmCopyFromCaller() failed!\n");
SetLastNtError(Status);
return -1;
}
}
if (hdc != NULL)
{
PDC pDc;
INT iRgnType;
/* Get visible region bounding rect */
pDc = DC_LockDc(hdc);
if (pDc == NULL)
{
TRACE("DC_LockDc() failed!\n");
/* FIXME: setlasterror? */
return -1;
}
iRgnType = REGION_GetRgnBox(pDc->prgnVis, &DcRect);
DC_UnlockDc(pDc);
if (iRgnType == 0)
{
TRACE("NtGdiGetRgnBox() failed!\n");
return -1;
}
if (iRgnType == NULLREGION)
return 0;
if (iRgnType == COMPLEXREGION)
{
/* TODO: Warning */
}
/* If hdc and pRect are given the area of interest is pRect with
coordinate origin at the DC position */
if (pUnsafeRect != NULL)
{
rc.left += DcRect.left;
rc.right += DcRect.left;
rc.top += DcRect.top;
rc.bottom += DcRect.top;
}
/* If hdc is given and pRect is not the area of interest is the
bounding rect of hdc */
else
{
rc = DcRect;
}
}
if (hdc == NULL && pUnsafeRect == NULL)
pRect = NULL;
else
pRect = &rc;
UserEnterShared();
/* Find intersecting monitors */
cMonitors = IntGetMonitorsFromRect(pRect, NULL, NULL, 0, MONITOR_DEFAULTTONULL);
if (cMonitors == 0 || dwListSize == 0 ||
(phUnsafeMonitorList == NULL && prcUnsafeMonitorList == NULL))
{
/* Simple case - just return monitors count */
TRACE("cMonitors = %u\n", cMonitors);
iRet = cMonitors;
goto cleanup;
}
/* Allocate safe buffers */
if (phUnsafeMonitorList != NULL && dwListSize != 0)
{
phMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * dwListSize, USERTAG_MONITORRECTS);
if (phMonitorList == NULL)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
}
if (prcUnsafeMonitorList != NULL && dwListSize != 0)
{
prcMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof(RECT) * dwListSize,USERTAG_MONITORRECTS);
if (prcMonitorList == NULL)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
}
/* Get intersecting monitors */
cMonitors = IntGetMonitorsFromRect(pRect, phMonitorList, prcMonitorList,
dwListSize, MONITOR_DEFAULTTONULL);
if (hdc != NULL && pRect != NULL && prcMonitorList != NULL)
{
for (i = 0; i < min(cMonitors, dwListSize); i++)
{
_Analysis_assume_(i < dwListSize);
prcMonitorList[i].left -= DcRect.left;
prcMonitorList[i].right -= DcRect.left;
prcMonitorList[i].top -= DcRect.top;
prcMonitorList[i].bottom -= DcRect.top;
}
}
/* Output result */
if (phUnsafeMonitorList != NULL && dwListSize != 0)
{
Status = MmCopyToCaller(phUnsafeMonitorList, phMonitorList, sizeof(HMONITOR) * dwListSize);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
goto cleanup;
}
}
if (prcUnsafeMonitorList != NULL && dwListSize != 0)
{
Status = MmCopyToCaller(prcUnsafeMonitorList, prcMonitorList, sizeof(RECT) * dwListSize);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
goto cleanup;
}
}
/* Return monitors count on success */
iRet = cMonitors;
cleanup:
if (phMonitorList)
ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS);
if (prcMonitorList)
ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS);
UserLeave();
return iRet;
}
/* NtUserGetMonitorInfo
*
* Retrieves information about a given monitor
*
* Arguments
*
* hMonitor
* Handle to a monitor for which to get information
*
* pMonitorInfoUnsafe
* Pointer to a MONITORINFO struct which is filled with the information.
* The cbSize member must be set to sizeof(MONITORINFO) or
* sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts
* from MONITORINFO will be filled.
*
* pDevice
* Pointer to a UNICODE_STRING which will receive the device's name. The
* length should be CCHDEVICENAME
* Can be NULL
*
* Return value
* TRUE on success; FALSE on failure (calls SetLastNtError())
*
*/
BOOL
APIENTRY
NtUserGetMonitorInfo(
IN HMONITOR hMonitor,
OUT LPMONITORINFO pMonitorInfoUnsafe)
{
PMONITOR pMonitor;
MONITORINFOEXW MonitorInfo;
NTSTATUS Status;
BOOL bRet = FALSE;
PWCHAR pwstrDeviceName;
TRACE("Enter NtUserGetMonitorInfo\n");
UserEnterShared();
/* Get monitor object */
pMonitor = UserGetMonitorObject(hMonitor);
if (!pMonitor)
{
TRACE("Couldnt find monitor %p\n", hMonitor);
goto cleanup;
}
/* Check if pMonitorInfoUnsafe is valid */
if(pMonitorInfoUnsafe == NULL)
{
SetLastNtError(STATUS_INVALID_PARAMETER);
goto cleanup;
}
pwstrDeviceName = ((PPDEVOBJ)(pMonitor->hDev))->pGraphicsDevice->szWinDeviceName;
/* Get size of pMonitorInfoUnsafe */
Status = MmCopyFromCaller(&MonitorInfo.cbSize, &pMonitorInfoUnsafe->cbSize, sizeof(MonitorInfo.cbSize));
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
goto cleanup;
}
/* Check if size of struct is valid */
if (MonitorInfo.cbSize != sizeof(MONITORINFO) &&
MonitorInfo.cbSize != sizeof(MONITORINFOEXW))
{
SetLastNtError(STATUS_INVALID_PARAMETER);
goto cleanup;
}
/* Fill monitor info */
MonitorInfo.rcMonitor = pMonitor->rcMonitor;
MonitorInfo.rcWork = pMonitor->rcWork;
MonitorInfo.dwFlags = 0;
if (pMonitor->IsPrimary)
MonitorInfo.dwFlags |= MONITORINFOF_PRIMARY;
/* Fill device name */
if (MonitorInfo.cbSize == sizeof(MONITORINFOEXW))
{
RtlStringCbCopyNExW(MonitorInfo.szDevice,
sizeof(MonitorInfo.szDevice),
pwstrDeviceName,
(wcslen(pwstrDeviceName)+1) * sizeof(WCHAR),
NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
}
/* Output data */
Status = MmCopyToCaller(pMonitorInfoUnsafe, &MonitorInfo, MonitorInfo.cbSize);
if (!NT_SUCCESS(Status))
{
TRACE("GetMonitorInfo: MmCopyToCaller failed\n");
SetLastNtError(Status);
goto cleanup;
}
TRACE("GetMonitorInfo: success\n");
bRet = TRUE;
cleanup:
TRACE("Leave NtUserGetMonitorInfo, ret=%i\n", bRet);
UserLeave();
return bRet;
}
/* NtUserMonitorFromPoint
*
* Returns a handle to the monitor containing the given point.
*
* Arguments
*
* pt
* Point for which to find monitor
*
* dwFlags
* Specifies the behaviour if the point isn't on any of the monitors.
*
* Return value
* If the point is found a handle to the monitor is returned; if not the
* return value depends on dwFlags
*/
HMONITOR
APIENTRY
NtUserMonitorFromPoint(
IN POINT pt,
IN DWORD dwFlags)
{
RECTL rc;
HMONITOR hMonitor = NULL;
/* Check if flags are valid */
if (dwFlags != MONITOR_DEFAULTTONULL &&
dwFlags != MONITOR_DEFAULTTOPRIMARY &&
dwFlags != MONITOR_DEFAULTTONEAREST)
{
EngSetLastError(ERROR_INVALID_FLAGS);
return NULL;
}
/* Fill rect (bottom-right exclusive) */
rc.left = pt.x;
rc.right = pt.x + 1;
rc.top = pt.y;
rc.bottom = pt.y + 1;
UserEnterShared();
/* Find intersecting monitor */
IntGetMonitorsFromRect(&rc, &hMonitor, NULL, 1, dwFlags);
UserLeave();
return hMonitor;
}
/* NtUserMonitorFromRect
*
* Returns a handle to the monitor having the largest intersection with a
* given rectangle
*
* Arguments
*
* pRectUnsafe
* Pointer to a RECT for which to find monitor
*
* dwFlags
* Specifies the behaviour if no monitor intersects the given rect
*
* Return value
* If a monitor intersects the rect a handle to it is returned; if not the
* return value depends on dwFlags
*/
HMONITOR
APIENTRY
NtUserMonitorFromRect(
IN LPCRECTL pRectUnsafe,
IN DWORD dwFlags)
{
ULONG cMonitors, LargestArea = 0, i;
PRECTL prcMonitorList = NULL;
HMONITOR *phMonitorList = NULL;
HMONITOR hMonitor = NULL;
RECTL Rect;
NTSTATUS Status;
/* Check if flags are valid */
if (dwFlags != MONITOR_DEFAULTTONULL &&
dwFlags != MONITOR_DEFAULTTOPRIMARY &&
dwFlags != MONITOR_DEFAULTTONEAREST)
{
EngSetLastError(ERROR_INVALID_FLAGS);
return NULL;
}
/* Copy rectangle to safe buffer */
Status = MmCopyFromCaller(&Rect, pRectUnsafe, sizeof (RECT));
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
return NULL;
}
UserEnterShared();
/* Find intersecting monitors */
cMonitors = IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags);
if (cMonitors <= 1)
{
/* No or one monitor found. Just return handle. */
goto cleanup;
}
/* There is more than one monitor. Find monitor with largest intersection.
Temporary reset hMonitor */
hMonitor = NULL;
/* Allocate helper buffers */
phMonitorList = ExAllocatePoolWithTag(PagedPool,
sizeof(HMONITOR) * cMonitors,
USERTAG_MONITORRECTS);
if (phMonitorList == NULL)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
prcMonitorList = ExAllocatePoolWithTag(PagedPool,
sizeof(RECT) * cMonitors,
USERTAG_MONITORRECTS);
if (prcMonitorList == NULL)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
/* Get intersecting monitors again but now with rectangle list */
cMonitors = IntGetMonitorsFromRect(&Rect, phMonitorList, prcMonitorList,
cMonitors, 0);
/* Find largest intersection */
for (i = 0; i < cMonitors; i++)
{
ULONG Area = (prcMonitorList[i].right - prcMonitorList[i].left) *
(prcMonitorList[i].bottom - prcMonitorList[i].top);
if (Area >= LargestArea)
{
hMonitor = phMonitorList[i];
LargestArea = Area;
}
}
cleanup:
if (phMonitorList)
ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS);
if (prcMonitorList)
ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS);
UserLeave();
return hMonitor;
}
HMONITOR
APIENTRY
NtUserMonitorFromWindow(
IN HWND hWnd,
IN DWORD dwFlags)
{
PWND pWnd;
HMONITOR hMonitor = NULL;
RECTL Rect = {0, 0, 0, 0};
TRACE("Enter NtUserMonitorFromWindow\n");
/* Check if flags are valid */
if (dwFlags != MONITOR_DEFAULTTONULL &&
dwFlags != MONITOR_DEFAULTTOPRIMARY &&
dwFlags != MONITOR_DEFAULTTONEAREST)
{
EngSetLastError(ERROR_INVALID_FLAGS);
return NULL;
}
UserEnterShared();
/* If window is given, use it first */
if (hWnd)
{
/* Get window object */
pWnd = UserGetWindowObject(hWnd);
if (!pWnd)
goto cleanup;
/* Find only monitors which have intersection with given window */
Rect.left = Rect.right = pWnd->rcWindow.left;
Rect.top = Rect.bottom = pWnd->rcWindow.bottom;
}
/* Find monitors now */
IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags);
cleanup:
TRACE("Leave NtUserMonitorFromWindow, ret=%p\n", hMonitor);
UserLeave();
return hMonitor;
}