mirror of
https://github.com/reactos/reactos.git
synced 2024-08-24 12:18:57 +00:00
1009 lines
27 KiB
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;
|
|
}
|