Updating device context to work with multiple monitors (r=hyatt). fixes bugs 21942, 32611.

This commit is contained in:
pinkerton%netscape.com 2006-01-11 21:28:03 +00:00
Родитель 654e4a9aa7
Коммит 73252e88b8
4 изменённых файлов: 249 добавлений и 46 удалений

Просмотреть файл

@ -20,14 +20,61 @@
* Contributor(s):
*/
//
// We have to do this in order to have access to the multiple-monitor
// APIs that are only defined when WINVER is >= 0x0500. Don't worry,
// these won't actually be called unless they are present.
//
#undef WINVER
#define WINVER 0x0500
#include "nsScreenManagerWin.h"
#include "nsScreenWin.h"
// needed because there are unicode/ansi versions of this routine
// and we need to make sure we get the correct one.
#ifdef UNICODE
#define GetMonitorInfoQuoted "GetMonitorInfoW"
#else
#define GetMonitorInfoQuoted "GetMonitorInfoA"
#endif
typedef HMONITOR (*MonitorFromRectProc)(LPCRECT inRect, DWORD inFlag);
typedef BOOL (*EnumDisplayMonitorsProc)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
BOOL CALLBACK CountMonitors ( HMONITOR, HDC, LPRECT, LPARAM ioCount ) ;
class ScreenListItem
{
public:
ScreenListItem ( HMONITOR inMon, nsIScreen* inScreen )
: mMon(inMon), mScreen(inScreen) { } ;
HMONITOR mMon;
nsCOMPtr<nsIScreen> mScreen;
};
nsScreenManagerWin :: nsScreenManagerWin ( )
: mHasMultiMonitorAPIs(PR_FALSE), mGetMonitorInfoProc(nsnull), mMonitorFromRectProc(nsnull),
mEnumDisplayMonitorsProc(nsnull), mNumberOfScreens(0)
{
NS_INIT_REFCNT();
// figure out if we can call the multiple monitor APIs that are only
// available on Win98/2000.
HMODULE lib = GetModuleHandle("user32.dll");
if ( lib ) {
mGetMonitorInfoProc = GetProcAddress ( lib, GetMonitorInfoQuoted );
mMonitorFromRectProc = GetProcAddress ( lib, "MonitorFromRect" );
mEnumDisplayMonitorsProc = GetProcAddress ( lib, "EnumDisplayMonitors" );
if ( mGetMonitorInfoProc && mMonitorFromRectProc && mEnumDisplayMonitorsProc )
mHasMultiMonitorAPIs = PR_TRUE;
}
printf("has multiple monitor apis is %ld\n", mHasMultiMonitorAPIs);
// nothing else to do. I guess we could cache a bunch of information
// here, but we want to ask the device at runtime in case anything
// has changed.
@ -36,7 +83,11 @@ nsScreenManagerWin :: nsScreenManagerWin ( )
nsScreenManagerWin :: ~nsScreenManagerWin()
{
// nothing to see here.
// walk our list of cached screens and delete them.
for ( int i = 0; i < mScreenList.Count(); ++i ) {
ScreenListItem* item = NS_REINTERPRET_CAST(ScreenListItem*, mScreenList[i]);
delete item;
}
}
@ -53,14 +104,26 @@ NS_IMPL_ISUPPORTS(nsScreenManagerWin, NS_GET_IID(nsIScreenManager))
// screen. This should change when a multi-monitor impl is done.
//
nsIScreen*
nsScreenManagerWin :: CreateNewScreenObject ( HDC inScreen )
nsScreenManagerWin :: CreateNewScreenObject ( HDC inContext, void* inScreen )
{
nsIScreen* retval = nsnull;
if ( !mCachedMainScreen )
mCachedMainScreen = new nsScreenWin ( inScreen );
NS_IF_ADDREF(retval = mCachedMainScreen.get());
nsIScreen* retScreen = nsnull;
return retval;
// look through our screen list, hoping to find it. If it's not there,
// add it and return the new one.
for ( int i = 0; i < mScreenList.Count(); ++i ) {
ScreenListItem* curr = NS_REINTERPRET_CAST(ScreenListItem*, mScreenList[i]);
if ( inScreen == curr->mMon ) {
NS_IF_ADDREF(retScreen = curr->mScreen.get());
return retScreen;
}
} // for each screen.
retScreen = new nsScreenWin(inContext, inScreen);
ScreenListItem* listItem = new ScreenListItem ( (HMONITOR)inScreen, retScreen );
mScreenList.AppendElement ( listItem );
NS_IF_ADDREF(retScreen);
return retScreen;
}
@ -78,23 +141,24 @@ nsScreenManagerWin :: ScreenForRect ( PRInt32 inLeft, PRInt32 inTop, PRInt32 inW
{
if ( !(inWidth || inHeight) ) {
NS_WARNING ( "trying to find screen for sizeless window, using primary monitor" );
*outScreen = CreateNewScreenObject ( ::GetDC(nsnull) ); // addrefs
*outScreen = CreateNewScreenObject ( ::GetDC(nsnull), nsnull ); // addrefs
return NS_OK;
}
RECT globalWindowBounds = { inLeft, inTop, inLeft + inWidth, inTop + inHeight };
// we want to use ::MonitorFromRect() but it doesn't exist under 95/NT. For now, just
// always return the primary monitor.
void* genScreen = nsnull;
if ( mHasMultiMonitorAPIs ) {
MonitorFromRectProc proc = (MonitorFromRectProc)mMonitorFromRectProc;
HMONITOR screen = (*proc)( &globalWindowBounds, MONITOR_DEFAULTTOPRIMARY );
printf("*** found screen %x\n", screen);
genScreen = screen;
//XXX find the DC for this screen??
}
*outScreen = CreateNewScreenObject ( ::GetDC(nsnull), genScreen ); // addrefs
*outScreen = CreateNewScreenObject ( ::GetDC(nsnull) ); // addrefs
#if 0
HMONITOR screen = ::MonitorFromRect ( &globalWindowBounds, MONITOR_DEFAULTTOPRIMARY );
*outScreen = CreateNewScreenObject ( deviceWindowIsOn ); // addrefs
#endif
return NS_OK;
} // ScreenForRect
@ -109,12 +173,30 @@ nsScreenManagerWin :: ScreenForRect ( PRInt32 inLeft, PRInt32 inTop, PRInt32 inW
NS_IMETHODIMP
nsScreenManagerWin :: GetPrimaryScreen(nsIScreen** aPrimaryScreen)
{
*aPrimaryScreen = CreateNewScreenObject ( ::GetDC(nsnull) ); // addrefs
*aPrimaryScreen = CreateNewScreenObject ( ::GetDC(nsnull), nsnull ); // addrefs
return NS_OK;
} // GetPrimaryScreen
//
// CountMonitors
//
// Will be called once for every monitor in the system. Just
// increments the parameter, which holds a ptr to a PRUin32 holding the
// count up to this point.
//
BOOL CALLBACK
CountMonitors ( HMONITOR, HDC, LPRECT, LPARAM ioParam )
{
PRUint32* countPtr = NS_REINTERPRET_CAST(PRUint32*, ioParam);
++(*countPtr);
return TRUE; // continue the enumeration
} // CountMonitors
//
// GetNumberOfScreens
//
@ -123,7 +205,21 @@ nsScreenManagerWin :: GetPrimaryScreen(nsIScreen** aPrimaryScreen)
NS_IMETHODIMP
nsScreenManagerWin :: GetNumberOfScreens(PRUint32 *aNumberOfScreens)
{
*aNumberOfScreens = 1;
if ( mNumberOfScreens )
*aNumberOfScreens = mNumberOfScreens;
else {
if ( mHasMultiMonitorAPIs ) {
// use a rect that spans a HUGE area to pick up all screens
RECT largeArea = { -32767, -32767, 32767, 32767 };
PRUint32 count = 0;
EnumDisplayMonitorsProc proc = (EnumDisplayMonitorsProc)mEnumDisplayMonitorsProc;
BOOL result = (*proc)(nsnull, &largeArea, (MONITORENUMPROC)CountMonitors, (LPARAM)&count);
*aNumberOfScreens = mNumberOfScreens = count;
} // if there can be > 1 screen
else
*aNumberOfScreens = mNumberOfScreens = 1;
}
printf("****** number of sceens %ld\n", mNumberOfScreens);
return NS_OK;
} // GetNumberOfScreens

Просмотреть файл

@ -24,11 +24,14 @@
#define nsScreenManagerWin_h___
#include "nsIScreenManager.h"
#include <windows.h>
#include "nsCOMPtr.h"
#include "nsVoidArray.h"
class nsIScreen;
//------------------------------------------------------------------------
class nsScreenManagerWin : public nsIScreenManager
@ -42,10 +45,20 @@ public:
private:
nsIScreen* CreateNewScreenObject ( HDC inScreen ) ;
nsIScreen* CreateNewScreenObject ( HDC inContext, void* inScreen ) ;
PRBool mHasMultiMonitorAPIs;
PRUint32 mNumberOfScreens;
// function pointers for multi-monitor API system calls that we use. Not
// valid unless |mHasMultiMonitorAPIs| is true
FARPROC mGetMonitorInfoProc;
FARPROC mMonitorFromRectProc;
FARPROC mEnumDisplayMonitorsProc;
// cache the screens to avoid the memory allocations
nsAutoVoidArray mScreenList;
// cache the primary screen object to avoid memory allocation every time
nsCOMPtr<nsIScreen> mCachedMainScreen;
};
#endif // nsScreenManagerWin_h___

Просмотреть файл

@ -20,17 +20,48 @@
* Contributor(s):
*/
//
// We have to do this in order to have access to the multiple-monitor
// APIs that are only defined when WINVER is >= 0x0500. Don't worry,
// these won't actually be called unless they are present.
//
#undef WINVER
#define WINVER 0x0500
#include "nsScreenWin.h"
nsScreenWin :: nsScreenWin ( HDC inScreen )
: mScreen(inScreen)
// needed because there are unicode/ansi versions of this routine
// and we need to make sure we get the correct one.
#ifdef UNICODE
#define GetMonitorInfoQuoted "GetMonitorInfoW"
#else
#define GetMonitorInfoQuoted "GetMonitorInfoA"
#endif
typedef BOOL (*GetMonitorInfoProc)(HMONITOR inMon, LPMONITORINFO ioInfo);
nsScreenWin :: nsScreenWin ( HDC inContext, void* inScreen )
: mContext(inContext), mScreen(inScreen), mHasMultiMonitorAPIs(PR_FALSE),
mGetMonitorInfoProc(nsnull)
{
NS_INIT_REFCNT();
NS_ASSERTION ( inScreen, "Passing null device to nsScreenWin" );
NS_ASSERTION ( ::GetDeviceCaps(inScreen, TECHNOLOGY) == DT_RASDISPLAY, "Not a display screen");
NS_ASSERTION ( inContext, "Passing null device to nsScreenWin" );
NS_ASSERTION ( ::GetDeviceCaps(inContext, TECHNOLOGY) == DT_RASDISPLAY, "Not a display screen");
// figure out if we can call the multiple monitor APIs that are only
// available on Win98/2000.
HMODULE lib = GetModuleHandle("user32.dll");
if ( lib ) {
mGetMonitorInfoProc = GetProcAddress ( lib, GetMonitorInfoQuoted );
if ( mGetMonitorInfoProc )
mHasMultiMonitorAPIs = PR_TRUE;
}
printf("has multiple monitor apis is %ld\n", mHasMultiMonitorAPIs);
// nothing else to do. I guess we could cache a bunch of information
// here, but we want to ask the device at runtime in case anything
// has changed.
@ -50,7 +81,16 @@ NS_IMPL_ISUPPORTS(nsScreenWin, NS_GET_IID(nsIScreen))
NS_IMETHODIMP
nsScreenWin :: GetWidth(PRInt32 *aWidth)
{
*aWidth = ::GetDeviceCaps(mScreen, HORZRES);
if ( mScreen && mHasMultiMonitorAPIs ) {
GetMonitorInfoProc proc = (GetMonitorInfoProc)mGetMonitorInfoProc;
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
BOOL success = (*proc)( (HMONITOR)mScreen, &info );
if ( success )
*aWidth = info.rcMonitor.right - info.rcMonitor.left;
}
else
*aWidth = ::GetDeviceCaps(mContext, HORZRES);
return NS_OK;
} // GetWidth
@ -59,7 +99,16 @@ nsScreenWin :: GetWidth(PRInt32 *aWidth)
NS_IMETHODIMP
nsScreenWin :: GetHeight(PRInt32 *aHeight)
{
*aHeight = ::GetDeviceCaps(mScreen, VERTRES);
if ( mScreen && mHasMultiMonitorAPIs ) {
GetMonitorInfoProc proc = (GetMonitorInfoProc)mGetMonitorInfoProc;
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
BOOL success = (*proc)( (HMONITOR)mScreen, &info );
if ( success )
*aHeight = info.rcMonitor.bottom - info.rcMonitor.top;
}
else
*aHeight = ::GetDeviceCaps(mContext, VERTRES);
return NS_OK;
} // GetHeight
@ -68,7 +117,8 @@ nsScreenWin :: GetHeight(PRInt32 *aHeight)
NS_IMETHODIMP
nsScreenWin :: GetPixelDepth(PRInt32 *aPixelDepth)
{
*aPixelDepth = ::GetDeviceCaps(mScreen, BITSPIXEL);
//XXX not sure how to get this info for multiple monitors, this might be ok...
*aPixelDepth = ::GetDeviceCaps(mContext, BITSPIXEL);
return NS_OK;
} // GetPixelDepth
@ -85,10 +135,19 @@ nsScreenWin :: GetColorDepth(PRInt32 *aColorDepth)
NS_IMETHODIMP
nsScreenWin :: GetAvailWidth(PRInt32 *aAvailWidth)
{
// XXX Needs to be rewritten for a non-primary monitor?
RECT workArea;
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
*aAvailWidth = workArea.right - workArea.left;
if ( mScreen && mHasMultiMonitorAPIs ) {
GetMonitorInfoProc proc = (GetMonitorInfoProc)mGetMonitorInfoProc;
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
BOOL success = (*proc)( (HMONITOR)mScreen, &info );
if ( success )
*aAvailWidth = info.rcWork.right - info.rcWork.left;
}
else {
RECT workArea;
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
*aAvailWidth = workArea.right - workArea.left;
}
return NS_OK;
} // GetAvailWidth
@ -97,9 +156,19 @@ nsScreenWin :: GetAvailWidth(PRInt32 *aAvailWidth)
NS_IMETHODIMP
nsScreenWin :: GetAvailHeight(PRInt32 *aAvailHeight)
{
RECT workArea;
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
*aAvailHeight = workArea.bottom - workArea.top;
if ( mScreen && mHasMultiMonitorAPIs ) {
GetMonitorInfoProc proc = (GetMonitorInfoProc)mGetMonitorInfoProc;
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
BOOL success = (*proc)( (HMONITOR)mScreen, &info );
if ( success )
*aAvailHeight = info.rcWork.bottom - info.rcWork.top;
}
else {
RECT workArea;
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
*aAvailHeight = workArea.bottom - workArea.top;
}
return NS_OK;
} // GetAvailHeight
@ -108,9 +177,19 @@ nsScreenWin :: GetAvailHeight(PRInt32 *aAvailHeight)
NS_IMETHODIMP
nsScreenWin :: GetAvailLeft(PRInt32 *aAvailLeft)
{
RECT workArea;
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
*aAvailLeft = workArea.left;
if ( mScreen && mHasMultiMonitorAPIs ) {
GetMonitorInfoProc proc = (GetMonitorInfoProc)mGetMonitorInfoProc;
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
BOOL success = (*proc)( (HMONITOR)mScreen, &info );
if ( success )
*aAvailLeft = info.rcWork.left;
}
else {
RECT workArea;
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
*aAvailLeft = workArea.left;
}
return NS_OK;
} // GetAvailLeft
@ -119,10 +198,19 @@ nsScreenWin :: GetAvailLeft(PRInt32 *aAvailLeft)
NS_IMETHODIMP
nsScreenWin :: GetAvailTop(PRInt32 *aAvailTop)
{
RECT workArea;
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
*aAvailTop = workArea.top;
if ( mScreen && mHasMultiMonitorAPIs ) {
GetMonitorInfoProc proc = (GetMonitorInfoProc)mGetMonitorInfoProc;
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
BOOL success = (*proc)( (HMONITOR)mScreen, &info );
if ( success )
*aAvailTop = info.rcWork.top;
}
else {
RECT workArea;
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
*aAvailTop = workArea.top;
}
return NS_OK;
} // GetAvailTop

Просмотреть файл

@ -31,7 +31,7 @@
class nsScreenWin : public nsIScreen
{
public:
nsScreenWin ( HDC inScreen );
nsScreenWin ( HDC inContext, void* inScreen );
~nsScreenWin();
NS_DECL_ISUPPORTS
@ -43,7 +43,13 @@ private:
// asked.
//PRBool IsPrimaryScreen ( ) const { return (mScreen == ::GetMainDevice()); }
HDC mScreen; // the dc that represents this screen
// function pointers for multi-monitor API system calls that we use. Not
// valid unless |mHasMultiMonitorAPIs| is true
PRBool mHasMultiMonitorAPIs;
FARPROC mGetMonitorInfoProc ;
HDC mContext; // the dc that represents this screen
void* mScreen; // a |HMONITOR|, can't use this type in header file though.
};
#endif // nsScreenWin_h___