📄 monitor.c
字号:
/*
* 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 <w32k.h>
/* 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 <debug.h>
/* GLOBALS *******************************************************************/
/* list of monitors */
static PMONITOR_OBJECT gMonitorList = NULL;
/* INITALIZATION FUNCTIONS ****************************************************/
NTSTATUS
InitMonitorImpl()
{
DPRINT("Initializing monitor implementation...\n");
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(gHandleTable, &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);
}
static
PMONITOR_OBJECT FASTCALL
UserGetMonitorObject(IN HMONITOR hMonitor)
{
PMONITOR_OBJECT Monitor;
if (!hMonitor)
{
SetLastWin32Error(ERROR_INVALID_MONITOR_HANDLE);
return NULL;
}
Monitor = (PMONITOR_OBJECT)UserGetObject(gHandleTable, hMonitor, otMonitor);
if (!Monitor)
{
SetLastWin32Error(ERROR_INVALID_MONITOR_HANDLE);
return NULL;
}
ASSERT(USER_BODY_TO_HEADER(Monitor)->RefCount >= 0);
return Monitor;
}
/* 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;
if (gMonitorList == NULL)
{
DPRINT("Primary monitor is beeing attached\n");
Monitor->IsPrimary = TRUE;
gMonitorList = Monitor;
}
else
{
PMONITOR_OBJECT p;
DPRINT("Additional monitor is beeing attached\n");
for (p = gMonitorList; p->Next != NULL; p = p->Next)
;
{
p->Next = Monitor;
}
Monitor->Prev = p;
}
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;
for (Monitor = gMonitorList; Monitor != NULL; Monitor = Monitor->Next)
{
if (Monitor->GdiDevice == pGdiDevice)
break;
}
if (Monitor == NULL)
{
/* no monitor for given device found */
return STATUS_INVALID_PARAMETER;
}
if (Monitor->IsPrimary && (Monitor->Next != NULL || Monitor->Prev != NULL))
{
PMONITOR_OBJECT NewPrimaryMonitor = (Monitor->Prev != NULL) ? (Monitor->Prev) : (Monitor->Next);
ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&NewPrimaryMonitor->Lock);
NewPrimaryMonitor->IsPrimary = TRUE;
ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&NewPrimaryMonitor->Lock);
}
if (gMonitorList == Monitor)
{
gMonitorList = 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;
}
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;
for (Monitor = gMonitorList; Monitor != NULL; Monitor = Monitor->Next)
{
/* FIXME: I guess locking the monitor is not neccessary to read 1 int */
if (Monitor->IsPrimary)
break;
}
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 */
for (Monitor = gMonitorList; Monitor != NULL; Monitor = Monitor->Next)
{
RECT MonitorRect, IntersectionRect;
ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&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;
ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&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++;
}
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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -