Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

316 lines
9.6 KiB

/****************************** Module Header ******************************\
* Module Name: multimon.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Multimonitor APIs.
*
* History:
* 27-Sep-1996 adams Stub implementation for NT 5.
* 20-Feb-1997 adams Port from NT4 SP3.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/* last monitor the cursor was clipped to */
PMONITOR gpMonitorMouse;
/***************************************************************************\
* ClipPointToDesktop
*
* Clips the point the nearest monitor on the desktop.
*
* Arguments:
* lppt - The point to clip.
*
* History:
* 22-Sep-1996 adams Created.
* 04-Sep-1998 MCostea Use _MonitorFromPoint()
\***************************************************************************/
void
ClipPointToDesktop(LPPOINT lppt)
{
PMONITOR pMonitor;
UserAssert(!gpDispInfo->fDesktopIsRect &&
"You shouldn't call this function if the desktop is a rectangle.\n"
"Just clip to gpsi->rcScreen instead.");
/*
* Optimization: The cursor is likely to be on the monitor it was last on,
* so check for that case.
*/
if (gpMonitorMouse != NULL && PtInRect(&gpMonitorMouse->rcMonitor, *lppt)) {
return;
}
pMonitor = _MonitorFromPoint(*lppt, MONITOR_DEFAULTTONEAREST);
/*
* Remember the monitor the cursor is on.
*/
gpMonitorMouse = pMonitor;
if (lppt->x < pMonitor->rcMonitor.left) {
lppt->x = pMonitor->rcMonitor.left;
} else if (lppt->x >= pMonitor->rcMonitor.right) {
lppt->x = pMonitor->rcMonitor.right-1;
}
if (lppt->y < pMonitor->rcMonitor.top) {
lppt->y = pMonitor->rcMonitor.top;
} else if (lppt->y >= pMonitor->rcMonitor.bottom) {
lppt->y = pMonitor->rcMonitor.bottom-1;
}
}
/***************************************************************************\
* xxxEnumDisplayMonitors
*
* Enumerates the monitors in a display.
*
* Arguments:
* hdcPaint - An HDC with a particular visible region. The HDC
* passed to lpfnEnum will have the capabilities of that monitor,
* with its visible region clipped to the monitor and hdcPaint.
* If hdcPaint is NULL, the hdcMonitor passed to lpfnEnum will be NULL.
*
* lprcClip - A rectangle to clip the area to. If hdcPaint is non-NULL,
* the coordinates have the origin of hdcPaint. If hdcPaint is NULL,
* the coordinates are virtual screen coordinates. If lprcClip is NULL,
* no clipping is performed.
*
* lpfnEnum - The enumeration function.
*
* dwData - Application-defined data that is passed through to the
* enumeration function.
*
* fInternal - TRUE if the callback is in the kernel, FALSE otherwise.
*
* History:
* 22-Sep-1996 adams Created.
\***************************************************************************/
BOOL
xxxEnumDisplayMonitors(
HDC hdcPaint,
LPRECT lprcPaint,
MONITORENUMPROC lpfnEnum,
LPARAM lData,
BOOL fInternal)
{
RECT rcPaint;
POINT ptOrg;
RECT rcMonitorPaint;
BOOL fReturn;
PMONITOR pMonitor;
TL tlpMonitor;
PTHREADINFO ptiCurrent = PtiCurrent();
PDCE pdcePaint;
HDC hdcMonitor;
PWND pwndOrg;
/*
* Validate the DC passed in.
*/
if (hdcPaint) {
if ((pdcePaint = LookupDC(hdcPaint)) == NULL) {
RIPMSG0(RIP_WARNING, "EnumDisplayMonitors: LookupDC failed");
return FALSE;
}
pwndOrg = pdcePaint->pwndOrg;
/*
* Intersect the painting area with the clipbox. If there
* isn't anything, bail out now.
*/
if (GreGetClipBox(hdcPaint, &rcPaint, FALSE) == NULLREGION)
return TRUE;
if (lprcPaint && !IntersectRect(&rcPaint, &rcPaint, lprcPaint))
return TRUE;
/*
* rcPaint is in dc coordinates. We must convert to screen
* coords so we can intersect with monitors.
*/
GreGetDCOrg(hdcPaint, &ptOrg);
OffsetRect(&rcPaint, ptOrg.x, ptOrg.y);
} else {
CopyRect(&rcPaint, &gpDispInfo->rcScreen);
if (lprcPaint && !IntersectRect(&rcPaint, &rcPaint, lprcPaint))
return TRUE;
}
fReturn = TRUE;
for (pMonitor = gpDispInfo->pMonitorFirst; pMonitor != NULL;
pMonitor = pMonitor->pMonitorNext) {
/*
* Note: the check for MONF_VISIBLE was removed to allow mirror drivers
* to see monitor specific updates.
*/
if (!IntersectRect(&rcMonitorPaint, &rcPaint, &pMonitor->rcMonitor)) {
continue;
}
if (hdcPaint) {
if ((hdcMonitor = GetMonitorDC(pdcePaint, pMonitor)) == NULL) {
RIPMSG0(RIP_WARNING, "EnumDisplayMonitors: GetMonitorDC failed");
return FALSE;
}
OffsetRect(&rcMonitorPaint, -ptOrg.x, -ptOrg.y);
GreIntersectClipRect(
hdcMonitor,
rcMonitorPaint.left,
rcMonitorPaint.top,
rcMonitorPaint.right,
rcMonitorPaint.bottom);
} else {
hdcMonitor = NULL;
}
ThreadLockAlwaysWithPti(ptiCurrent, pMonitor, &tlpMonitor);
if (fInternal) {
fReturn = (*lpfnEnum) (
(HMONITOR) pMonitor,
hdcMonitor,
&rcMonitorPaint,
lData);
} else {
fReturn = xxxClientMonitorEnumProc(
PtoH(pMonitor),
hdcMonitor,
&rcMonitorPaint,
lData,
lpfnEnum);
}
/*
* We just called back and the monitor has been freed if
* ThreadUnlock returns NULL. The entire monitor configuration may
* have changed, the monitors may have been rearranged, so just stop
* enumerating at this point.
*/
if (ThreadUnlock(&tlpMonitor) == NULL || HMIsMarkDestroy(pMonitor)) {
/*
* During the callback, pMonitor was destroyed
* so we have to bail out. pMonitor->pNext may also
* have been ruined.
* Windows Bug #488330.
*/
RIPMSGF1(RIP_WARNING, "pMonitor %p has been destroyed during the callback",
pMonitor);
#if DBG
{
/*
* Double check to see pMonitor does not
* appear in the monitor list.
*/
PMONITOR pMonitorTmp = gpDispInfo->pMonitorFirst;
while (pMonitorTmp) {
UserAssert(pMonitorTmp != pMonitor);
pMonitorTmp = pMonitorTmp->pMonitorNext;
}
}
#endif
fReturn = FALSE;
}
if (hdcMonitor)
ReleaseCacheDC(hdcMonitor, FALSE);
if (!fReturn) {
/*
* Something went wrong, we have to bail out.
*/
break;
}
/*
* Revalidate hdcPaint, since it could have been messed with
* in the callback.
*/
if (hdcPaint) {
if ((pdcePaint = LookupDC(hdcPaint)) == NULL) {
RIPMSG0(RIP_WARNING, "EnumDisplayMonitors: LookupDC failed");
return FALSE;
}
if (pdcePaint->pwndOrg != pwndOrg) {
RIPMSG0(RIP_WARNING, "EnumDisplayMonitors: wrong window");
return FALSE;
}
}
}
return fReturn;
}
/***************************************************************************\
* DestroyMonitor
*
* This function doesn't keep track of the visible monitors count because
* it assumes that after it was called the count will be recalculated, such
* as the case during mode changes. For a final unlock the monitor will have
* been removed from the monitor list already, so the count doesn't need to
* be recalculated.
*
* 5-May-1998 vadimg created
\***************************************************************************/
void DestroyMonitor(PMONITOR pMonitor)
{
UserAssert(pMonitor);
/*
* Remove references to this monitor from the global data.
*/
if (pMonitor == gpMonitorMouse) {
gpMonitorMouse = NULL;
}
/*
* Remove from the monitor list.
*/
REMOVE_FROM_LIST(MONITOR, gpDispInfo->pMonitorFirst, pMonitor, pMonitorNext);
/*
* Make sure the primary monitor points to a valid monitor. During the
* mode changes the primary monitor will be recalculated as appropriate.
*/
if (pMonitor == gpDispInfo->pMonitorPrimary) {
gpDispInfo->pMonitorPrimary = gpDispInfo->pMonitorFirst;
}
/*
* Clean up the next link here...
*/
pMonitor->pMonitorNext = NULL;
/*
* To make sure memory write operations are retired
* before really destroying the monitor object:
*/
Win32MemoryBarrier();
if (HMMarkObjectDestroy(pMonitor)) {
if (pMonitor->hrgnMonitor) {
GreDeleteObject(pMonitor->hrgnMonitor);
}
HMFreeObject(pMonitor);
}
}