From ad2c06733859b74faf1decd36bebcd5eab591f95 Mon Sep 17 00:00:00 2001 From: Gregor Anich Date: Tue, 16 Nov 2004 17:25:47 +0000 Subject: [PATCH] Simple implementation of some multi-monitor APIs. svn path=/trunk/; revision=11678 --- reactos/subsys/win32k/include/monitor.h | 30 + reactos/subsys/win32k/ntuser/monitor.c | 883 ++++++++++++++++++++++++ 2 files changed, 913 insertions(+) create mode 100644 reactos/subsys/win32k/include/monitor.h create mode 100644 reactos/subsys/win32k/ntuser/monitor.c diff --git a/reactos/subsys/win32k/include/monitor.h b/reactos/subsys/win32k/include/monitor.h new file mode 100644 index 00000000000..dfe1e68b731 --- /dev/null +++ b/reactos/subsys/win32k/include/monitor.h @@ -0,0 +1,30 @@ +#ifndef _WIN32K_MONITOR_H +#define _WIN32K_MONITOR_H + +#include + +struct GDIDEVICE; + +/* monitor object */ +typedef struct _MONITOR_OBJECT +{ + HANDLE Handle; /* system object handle */ + FAST_MUTEX Lock; /* R/W lock */ + + BOOL IsPrimary; /* wether this is the primary monitor */ + UNICODE_STRING DeviceName; /* name of the monitor */ + GDIDEVICE *GdiDevice; /* pointer to the GDI device to + which this monitor is attached */ + struct _MONITOR_OBJECT *Prev, *Next; /* doubly linked list */ +} MONITOR_OBJECT, *PMONITOR_OBJECT; + +/* functions */ +NTSTATUS InitMonitorImpl(); +NTSTATUS CleanupMonitorImpl(); + +NTSTATUS IntAttachMonitor(GDIDEVICE *pGdiDevice, ULONG DisplayNumber); +NTSTATUS IntDetachMonitor(GDIDEVICE *pGdiDevice); + +#endif /* _WIN32K_MONITOR_H */ + +/* EOF */ diff --git a/reactos/subsys/win32k/ntuser/monitor.c b/reactos/subsys/win32k/ntuser/monitor.c new file mode 100644 index 00000000000..a7b4104c10e --- /dev/null +++ b/reactos/subsys/win32k/ntuser/monitor.c @@ -0,0 +1,883 @@ +/* + * ReactOS W32 Subsystem + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: Monitor support + * FILE: subsys/win32k/ntuser/monitor.c + * PROGRAMER: Anich Gregor (blight@blight.eu.org) + * REVISION HISTORY: + * 26-02-2004 Created + */ + +/* INCLUDES ******************************************************************/ + +#include + +/* FIXME: find include file for these */ +#define MONITORINFOF_PRIMARY 1 +#define MONITOR_DEFAULTTONULL 0 +#define MONITOR_DEFAULTTOPRIMARY 1 +#define MONITOR_DEFAULTTONEAREST 2 + +//#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + +/* list of monitors */ +static PMONITOR_OBJECT MonitorList = NULL; +static FAST_MUTEX MonitorListLock; /* R/W lock for monitor list */ + +/* INITALIZATION FUNCTIONS ****************************************************/ + +NTSTATUS +InitMonitorImpl() +{ + DPRINT("Initializing monitor implementation...\n"); + ExInitializeFastMutex(&MonitorListLock); + + return STATUS_SUCCESS; +} + +NTSTATUS +CleanupMonitorImpl() +{ + DPRINT("Cleaning up monitor implementation...\n"); + /* FIXME: Destroy monitor objects? */ + + return STATUS_SUCCESS; +} + +/* PRIVATE FUNCTIONS **********************************************************/ + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef ABS +# define ABS(a) ((a) < (0) ? (-(a)) : (a)) +#endif + +/* IntCreateMonitorObject + * + * Creates a MONITOR_OBJECT + * + * Return value + * If the function succeeds a pointer to a MONITOR_OBJECT is returned. On failure + * NULL is returned. + */ +static +PMONITOR_OBJECT +IntCreateMonitorObject() +{ + HANDLE Handle; + PMONITOR_OBJECT Monitor; + + Monitor = ObmCreateObject(PsGetWin32Process()->WindowStation->HandleTable, &Handle, otMonitor, sizeof (MONITOR_OBJECT)); + if (Monitor == NULL) + { + return NULL; + } + + Monitor->Handle = Handle; + ExInitializeFastMutex(&Monitor->Lock); + + return Monitor; +} + +/* IntDestroyMonitorObject + * + * Destroys a MONITOR_OBJECT + * You have to be the owner of the monitors lock to safely destroy it. + * + * Arguments + * + * pMonitor + * Pointer to the MONITOR_OBJECT which shall be deleted + */ +static +void +IntDestroyMonitorObject(IN PMONITOR_OBJECT pMonitor) +{ + RtlFreeUnicodeString(&pMonitor->DeviceName); + ObmDereferenceObject(pMonitor); +} + +/* IntGetMonitorObject + * + * Returns the MONITOR_OBJECT for the given monitor handle. + * + * Arguments + * + * hMonitor + * Monitor handle for which to get the MONITOR_OBJECT + * + * Return value + * Returns a pointer to a MONITOR_OBJECT on success and increase the + * refcount of the monitor object; NULL on failure + */ +static +PMONITOR_OBJECT +IntGetMonitorObject(IN HMONITOR hMonitor) +{ + PMONITOR_OBJECT Monitor; + NTSTATUS Status; + + Status = ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable, hMonitor, otMonitor, (PVOID *)&Monitor); + if (!NT_SUCCESS(Status) || Monitor == NULL) + { + /* FIXME: SetLastNtError( status ); ? */ + return NULL; + } + + return Monitor; +} + +/* IntReleaseMonitorObject + * + * Releases the given MONITOR_OBJECT. + * + * Arguments + * + * pMonitor + * MONITOR_OBJECT to be released + */ +#define IntReleaseMonitorObject(MonitorObj) \ + ObmDereferenceObject(MonitorObj); + +/* IntAttachMonitor + * + * Creates a new MONITOR_OBJECT and appends it to the list of monitors. + * + * Arguments + * + * pGdiDevice Pointer to the GDIDEVICE onto which the monitor was attached + * DisplayNumber Display Number (starting with 0) + * + * Return value + * Returns a NTSTATUS + */ +NTSTATUS +IntAttachMonitor(IN GDIDEVICE *pGdiDevice, + IN ULONG DisplayNumber) +{ + PMONITOR_OBJECT Monitor; + WCHAR Buffer[CCHDEVICENAME]; + + DPRINT("Attaching monitor...\n"); + + /* create new monitor object */ + Monitor = IntCreateMonitorObject(); + if (Monitor == NULL) + { + DPRINT("Couldnt create monitor object\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + _snwprintf(Buffer, CCHDEVICENAME, L"\\??\\DISPLAY%d", DisplayNumber + 1); + if (!RtlCreateUnicodeString(&Monitor->DeviceName, Buffer)) + { + DPRINT("Couldn't duplicate monitor name!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Monitor->GdiDevice = pGdiDevice; + ExAcquireFastMutex(&MonitorListLock); + if (MonitorList == NULL) + { + DPRINT("Primary monitor is beeing attached\n"); + Monitor->IsPrimary = TRUE; + MonitorList = Monitor; + } + else + { + PMONITOR_OBJECT p; + DPRINT("Additional monitor is beeing attached\n"); + for (p = MonitorList; p->Next != NULL; p = p->Next); + { + p->Next = Monitor; + } + Monitor->Prev = p; + } + ExReleaseFastMutex(&MonitorListLock); + + return STATUS_SUCCESS; +} + +/* IntDetachMonitor + * + * Deletes a MONITOR_OBJECT and removes it from the list of monitors. + * + * Arguments + * + * pGdiDevice Pointer to the GDIDEVICE from which the monitor was detached + * + * Return value + * Returns a NTSTATUS + */ +NTSTATUS +IntDetachMonitor(IN GDIDEVICE *pGdiDevice) +{ + PMONITOR_OBJECT Monitor; + + ExAcquireFastMutex(&MonitorListLock); + for (Monitor = MonitorList; Monitor != NULL; Monitor = Monitor->Next) + { + if (Monitor->GdiDevice == pGdiDevice) + break; + } + + if (Monitor == NULL) + { + /* no monitor for given device found */ + ExReleaseFastMutex(&MonitorListLock); + return STATUS_INVALID_PARAMETER; + } + + if (Monitor->IsPrimary && (Monitor->Next != NULL || Monitor->Prev != NULL)) + { + PMONITOR_OBJECT NewPrimaryMonitor = (Monitor->Prev != NULL) ? (Monitor->Prev) : (Monitor->Next); + + ExAcquireFastMutex(&NewPrimaryMonitor->Lock); + NewPrimaryMonitor->IsPrimary = TRUE; + ExReleaseFastMutex(&NewPrimaryMonitor->Lock); + } + + if (MonitorList == Monitor) + { + MonitorList = Monitor->Next; + if (Monitor->Next != NULL) + Monitor->Next->Prev = NULL; + } + else + { + Monitor->Prev->Next = Monitor->Next; + if (Monitor->Next != NULL) + Monitor->Next->Prev = Monitor->Prev; + } + ExReleaseFastMutex(&MonitorListLock); + + IntDestroyMonitorObject(Monitor); + + return STATUS_SUCCESS; +} + +/* IntGetPrimaryMonitor + * + * Returns a PMONITOR_OBJECT for the primary monitor + * + * Return value + * PMONITOR_OBJECT + */ +static +PMONITOR_OBJECT +IntGetPrimaryMonitor() +{ + PMONITOR_OBJECT Monitor; + + ExAcquireFastMutex(&MonitorListLock); + for (Monitor = MonitorList; Monitor != NULL; Monitor = Monitor->Next) + { + /* FIXME: I guess locking the monitor is not neccessary to read 1 int */ + if (Monitor->IsPrimary) + break; + } + ExReleaseFastMutex(&MonitorListLock); + + return Monitor; +} + +/* 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. + * + * hMonitorList + * Pointer to an array of HMONITOR which is filled with monitor handles. + * Can be NULL + * + * monitorRectList + * 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 + * + * listSize + * Size of the hMonitorList and monitorRectList arguments. If this is zero + * hMonitorList and monitorRectList are ignored. + * + * flags + * 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 LPCRECT pRect, + OPTIONAL OUT HMONITOR *hMonitorList, + OPTIONAL OUT LPRECT monitorRectList, + OPTIONAL IN DWORD listSize, + OPTIONAL IN DWORD flags) +{ + PMONITOR_OBJECT Monitor, NearestMonitor = NULL; + UINT iCount = 0; + LONG iNearestDistanceX = 0x7fffffff, iNearestDistanceY = 0x7fffffff; + + /* find monitors which intersect the rectangle */ + ExAcquireFastMutex(&MonitorListLock); + for (Monitor = MonitorList; Monitor != NULL; Monitor = Monitor->Next) + { + RECT MonitorRect, IntersectionRect; + + ExAcquireFastMutex(&Monitor->Lock); + MonitorRect.left = 0; /* FIXME: get origin */ + MonitorRect.top = 0; /* FIXME: get origin */ + MonitorRect.right = MonitorRect.left + Monitor->GdiDevice->GDIInfo.ulHorzRes; + MonitorRect.bottom = MonitorRect.top + Monitor->GdiDevice->GDIInfo.ulVertRes; + ExReleaseFastMutex(&Monitor->Lock); + + DPRINT("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n", + MonitorRect.left, MonitorRect.top, MonitorRect.right, MonitorRect.bottom); + + if (pRect != NULL) + { + BOOL intersects = TRUE; + + /* check if the rect intersects the monitor */ + if ((pRect->right < MonitorRect.left) || (pRect->left > MonitorRect.right) || + (pRect->bottom < MonitorRect.top) || (pRect->top > MonitorRect.bottom)) + { + intersects = FALSE; + } + + if (flags == MONITOR_DEFAULTTONEAREST && !intersects) + { + INT distanceX, distanceY; + + distanceX = MIN(ABS(MonitorRect.left - pRect->right), + ABS(pRect->left - MonitorRect.right)); + distanceY = MIN(ABS(MonitorRect.top - pRect->bottom), + ABS(pRect->top - MonitorRect.bottom)); + + if (((distanceX < iNearestDistanceX) && (distanceY <= iNearestDistanceY)) || + ((distanceX <= iNearestDistanceX) && (distanceY < iNearestDistanceY))) + { + iNearestDistanceX = distanceX; + iNearestDistanceY = distanceY; + NearestMonitor = Monitor; + } + } + + if (!intersects) + continue; + + /* calculate intersection */ + IntersectionRect.left = MAX(MonitorRect.left, pRect->left); + IntersectionRect.top = MAX(MonitorRect.top, pRect->top); + IntersectionRect.right = MIN(MonitorRect.right, pRect->right); + IntersectionRect.bottom = MIN(MonitorRect.bottom, pRect->bottom); + } + else + { + IntersectionRect = MonitorRect; + } + + if (iCount < listSize) + { + if (hMonitorList != NULL) + hMonitorList[iCount] = Monitor->Handle; + if (monitorRectList != NULL) + monitorRectList[iCount] = IntersectionRect; + } + iCount++; + } + ExReleaseFastMutex(&MonitorListLock); + + if (iCount == 0 && flags == MONITOR_DEFAULTTONEAREST) + { + if (iCount < listSize) + { + if (hMonitorList != NULL) + hMonitorList[iCount] = NearestMonitor->Handle; + } + iCount++; + } + + return iCount; +} + +/* 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. + * + * pRect + * 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 + * + * hMonitorList + * Pointer to an array of HMONITOR which is filled with monitor handles. + * Can be NULL + * + * monitorRectList + * Pointer to an array of RECT which is filled with intersection rectangles. + * Can be NULL + * + * listSize + * 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 +STDCALL +NtUserEnumDisplayMonitors( + OPTIONAL IN HDC hDC, + OPTIONAL IN LPCRECT pRect, + OPTIONAL OUT HMONITOR *hMonitorList, + OPTIONAL OUT LPRECT monitorRectList, + OPTIONAL IN DWORD listSize) +{ + INT numMonitors, i; + HMONITOR *safeHMonitorList = NULL; + LPRECT safeRectList = NULL; + RECT rect, *myRect; + RECT dcRect; + NTSTATUS status; + + /* get rect */ + if (pRect != NULL) + { + status = MmCopyFromCaller(&rect, pRect, sizeof (RECT)); + if (!NT_SUCCESS(status)) + { + DPRINT("MmCopyFromCaller() failed!\n"); + SetLastNtError(status); + return -1; + } + } + + if (hDC != NULL) + { + PDC dc; + HRGN dcVisRgn; + INT regionType; + + /* get visible region bounding rect */ + dc = DC_LockDc(hDC); + if (dc == NULL) + { + DPRINT("DC_LockDc() failed!\n"); + /* FIXME: setlasterror? */ + return -1; + } + dcVisRgn = dc->w.hVisRgn; + DC_UnlockDc(hDC); + + regionType = NtGdiGetRgnBox(dcVisRgn, &dcRect); + if (regionType == 0) + { + DPRINT("NtGdiGetRgnBox() failed!\n"); + return -1; + } + if (regionType == NULLREGION) + return 0; + if (regionType == COMPLEXREGION) + { /* TODO: warning */ } + + /* if hDC and pRect are given the area of interest is pRect with + coordinate origin at the DC position */ + if (pRect != NULL) + { + rect.left += dcRect.left; + rect.right += dcRect.left; + rect.top += dcRect.top; + rect.bottom += dcRect.top; + } + /* if hDC is given and pRect is not the area of interest is the + bounding rect of hDC */ + else + { + rect = dcRect; + } + } + + if (hDC == NULL && pRect == NULL) + myRect = NULL; + else + myRect = ▭ + + /* find intersecting monitors */ + numMonitors = IntGetMonitorsFromRect(myRect, NULL, NULL, 0, 0); + if (numMonitors == 0 || listSize == 0 || + (hMonitorList == NULL && monitorRectList == NULL)) + { + DPRINT("numMonitors = %d\n", numMonitors); + return numMonitors; + } + + if (hMonitorList != NULL && listSize != 0) + { + safeHMonitorList = ExAllocatePool(PagedPool, sizeof (HMONITOR) * listSize); + if (safeHMonitorList == NULL) + { + /* FIXME: SetLastWin32Error? */ + return -1; + } + } + if (monitorRectList != NULL && listSize != 0) + { + safeRectList = ExAllocatePool(PagedPool, sizeof (RECT) * listSize); + if (safeRectList == NULL) + { + ExFreePool(safeHMonitorList); + /* FIXME: SetLastWin32Error? */ + return -1; + } + } + + /* get intersecting monitors */ + numMonitors = IntGetMonitorsFromRect(myRect, safeHMonitorList, safeRectList, + listSize, 0 ); + + if (hDC != NULL && pRect != NULL && safeRectList != NULL) + for (i = 0; i < numMonitors; i++) + { + safeRectList[i].left -= dcRect.left; + safeRectList[i].right -= dcRect.left; + safeRectList[i].top -= dcRect.top; + safeRectList[i].bottom -= dcRect.top; + } + + /* output result */ + if (hMonitorList != NULL && listSize != 0) + { + status = MmCopyToCaller(hMonitorList, safeHMonitorList, sizeof (HMONITOR) * listSize); + ExFreePool(safeHMonitorList); + if (!NT_SUCCESS(status)) + { + ExFreePool(safeRectList); + SetLastNtError(status); + return -1; + } + } + if (monitorRectList != NULL && listSize != 0) + { + status = MmCopyToCaller(monitorRectList, safeRectList, sizeof (RECT) * listSize); + ExFreePool(safeRectList); + if (!NT_SUCCESS(status)) + { + SetLastNtError(status); + return -1; + } + } + + return numMonitors; +} + +/* NtUserGetMonitorInfo + * + * Retrieves information about a given monitor + * + * Arguments + * + * hMonitor + * Handle to a monitor for which to get information + * + * pMonitorInfo + * 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 recieve the device's name. The + * length should be CCHDEVICENAME + * Can be NULL + * + * Return value + * TRUE on success; FALSE on failure (calls SetLastNtError()) + * + */ +BOOL +STDCALL +NtUserGetMonitorInfo( + IN HMONITOR hMonitor, + OUT LPMONITORINFO pMonitorInfo) +{ + PMONITOR_OBJECT Monitor; + MONITORINFOEXW MonitorInfo; + NTSTATUS Status; + + /* get monitor object */ + if ((Monitor = IntGetMonitorObject(hMonitor)) == NULL) + { + DPRINT("Couldnt find monitor 0x%lx\n", hMonitor); + SetLastNtError(STATUS_INVALID_HANDLE); + return FALSE; + } + + /* get size of pMonitorInfo */ + Status = MmCopyFromCaller(&MonitorInfo.cbSize, &pMonitorInfo->cbSize, sizeof (MonitorInfo.cbSize)); + if (!NT_SUCCESS(Status)) + { + IntReleaseMonitorObject(Monitor); + SetLastNtError(Status); + return FALSE; + } + if ((MonitorInfo.cbSize != sizeof (MONITORINFO)) && + (MonitorInfo.cbSize != sizeof (MONITORINFOEXW))) + { + SetLastNtError(STATUS_INVALID_PARAMETER); + return FALSE; + } + + ExAcquireFastMutex(&Monitor->Lock); + /* fill monitor info */ + MonitorInfo.rcMonitor.left = 0; /* FIXME: get origin */ + MonitorInfo.rcMonitor.top = 0; /* FIXME: get origin */ + MonitorInfo.rcMonitor.right = MonitorInfo.rcMonitor.left + Monitor->GdiDevice->GDIInfo.ulHorzRes; + MonitorInfo.rcMonitor.bottom = MonitorInfo.rcMonitor.top + Monitor->GdiDevice->GDIInfo.ulVertRes; + MonitorInfo.rcWork = MonitorInfo.rcMonitor; /* FIXME: use DEVMODE panning to calculate work area? */ + MonitorInfo.dwFlags = 0; + if (Monitor->IsPrimary) + MonitorInfo.dwFlags |= MONITORINFOF_PRIMARY; + + /* fill device name */ + if (MonitorInfo.cbSize == sizeof (MONITORINFOEXW)) + { + WCHAR nul = L'\0'; + INT len = Monitor->DeviceName.Length; + if (len >= CCHDEVICENAME * sizeof (WCHAR)) + len = (CCHDEVICENAME - 1) * sizeof (WCHAR); + + memcpy(MonitorInfo.szDevice, Monitor->DeviceName.Buffer, len); + memcpy(MonitorInfo.szDevice + (len / sizeof (WCHAR)), &nul, sizeof (WCHAR)); + } + ExReleaseFastMutex(&Monitor->Lock); + IntReleaseMonitorObject(Monitor); + + /* output data */ + Status = MmCopyToCaller(pMonitorInfo, &MonitorInfo, MonitorInfo.cbSize); + if (!NT_SUCCESS(Status)) + { + DPRINT("GetMonitorInfo: MmCopyToCaller failed\n"); + SetLastNtError(Status); + return FALSE; + } + + DPRINT("GetMonitorInfo: success\n"); + + return TRUE; +} + +/* NtUserMonitorFromPoint + * + * Returns a handle to the monitor containing the given point. + * + * Arguments + * + * point + * 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 +STDCALL +NtUserMonitorFromPoint( + IN POINT point, + IN DWORD dwFlags) +{ + INT NumMonitors; + RECT InRect; + HMONITOR hMonitor = NULL; + + /* fill inRect */ + InRect.left = InRect.right = point.x; + InRect.top = InRect.bottom = point.y; + + /* find intersecting monitor */ + NumMonitors = IntGetMonitorsFromRect(&InRect, &hMonitor, NULL, 1, 0); + if (NumMonitors < 0) + { + return (HMONITOR)NULL; + } + + if (hMonitor == NULL) + { + if (dwFlags == MONITOR_DEFAULTTOPRIMARY) + { + PMONITOR_OBJECT MonitorObj = IntGetPrimaryMonitor(); + if (MonitorObj) + hMonitor = MonitorObj->Handle; + } + else if (dwFlags == MONITOR_DEFAULTTONEAREST) + { + NumMonitors = IntGetMonitorsFromRect(&InRect, &hMonitor, NULL, + 1, MONITOR_DEFAULTTONEAREST); + /*ASSERT( (numMonitors > 0) && (hMonitor != NULL) );*/ + } + /* else flag is DEFAULTTONULL */ + } + + return hMonitor; +} + +/* NtUserMonitorFromRect + * + * Returns a handle to the monitor having the largest intersection with a + * given rectangle + * + * Arguments + * + * pRect + * 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 +STDCALL +NtUserMonitorFromRect( + IN LPCRECT pRect, + IN DWORD dwFlags) +{ + INT numMonitors, iLargestArea = -1, i; + LPRECT rectList; + HMONITOR *hMonitorList; + HMONITOR hMonitor = NULL; + RECT rect; + NTSTATUS status; + + /* get rect */ + status = MmCopyFromCaller(&rect, pRect, sizeof (RECT)); + if (!NT_SUCCESS(status)) + { + SetLastNtError(status); + return (HMONITOR)NULL; + } + + /* find intersecting monitors */ + numMonitors = IntGetMonitorsFromRect(&rect, NULL, NULL, 0, 0); + if (numMonitors < 0) + { + return (HMONITOR)NULL; + } + + if (numMonitors == 0) + { + if (dwFlags == MONITOR_DEFAULTTOPRIMARY) + { + PMONITOR_OBJECT monitorObj = IntGetPrimaryMonitor(); + if (monitorObj) + return monitorObj->Handle; + } + else if (dwFlags == MONITOR_DEFAULTTONEAREST) + { + numMonitors = IntGetMonitorsFromRect(&rect, &hMonitor, NULL, + 1, MONITOR_DEFAULTTONEAREST); + if (numMonitors <= 0) + { + /* error? */ + return (HMONITOR)NULL; + } + + if (numMonitors > 0) + return hMonitor; + } + /* else flag is DEFAULTTONULL */ + return (HMONITOR)NULL; + } + + hMonitorList = ExAllocatePool(PagedPool, sizeof (HMONITOR) * numMonitors); + if (hMonitorList == NULL) + { + /* FIXME: SetLastWin32Error? */ + return (HMONITOR)NULL; + } + rectList = ExAllocatePool(PagedPool, sizeof (RECT) * numMonitors); + if (rectList == NULL) + { + ExFreePool(hMonitorList); + /* FIXME: SetLastWin32Error? */ + return (HMONITOR)NULL; + } + + /* get intersecting monitors */ + numMonitors = IntGetMonitorsFromRect(&rect, hMonitorList, rectList, + numMonitors, 0); + if (numMonitors <= 0) + { + return (HMONITOR)NULL; + } + + /* find largest intersection */ + for (i = 0; i < numMonitors; i++) + { + INT area = (rectList[i].right - rectList[i].left) * + (rectList[i].bottom - rectList[i].top); + if (area > iLargestArea) + { + hMonitor = hMonitorList[i]; + } + } + + ExFreePool(hMonitorList); + ExFreePool(rectList); + + return hMonitor; +} + + +HMONITOR +STDCALL +NtUserMonitorFromWindow( + IN HWND hWnd, + IN DWORD dwFlags) +{ + UNIMPLEMENTED; + return (HMONITOR)NULL; +}