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
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);
|
|
}
|
|
}
|