зеркало из https://github.com/mozilla/pjs.git
Updating device context to work with multiple monitors (r=hyatt). fixes bugs 21942, 32611.
This commit is contained in:
Родитель
654e4a9aa7
Коммит
73252e88b8
|
@ -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___
|
||||
|
|
Загрузка…
Ссылка в новой задаче