Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1774 lines
48 KiB

/*========================================================================== *
* Copyright (C) 1994-1995 Microsoft Corporation. All Rights Reserved.
*
* File: ddmode.c
* Content: DirectDraw mode support
* History:
* Date By Reason
* ==== == ======
* 31-jan-95 craige split out of ddraw.c and enhanced
* 27-feb-95 craige new sync. macros
* 01-mar-95 craige Win95 mode stuff
* 19-mar-95 craige use HRESULTs
* 28-mar-95 craige made modeset work again
* 01-apr-95 craige happy fun joy updated header file
* 19-apr-95 craige check for invalid callback in EnumDisplayModes
* 14-may-95 craige allow BPP change; validate EnumDisplayModes modes
* 15-may-95 craige keep track of who changes the mode
* 02-jun-95 craige keep track of the mode set by a process
* 06-jun-95 craige added internal fn RestoreDisplayMode
* 11-jun-95 craige don't allow mode switch if surfaces locked
* 12-jun-95 craige new process list stuff
* 25-jun-95 craige one ddraw mutex
* 28-jun-95 craige ENTER_DDRAW at very start of fns
* 30-jun-95 craige turned off > 16bpp
* 01-jul-95 craige bug 106 - always went to last mode if mode not found
* 02-jul-95 craige RestoreDisplayMode needs to call HEL too
* 04-jul-95 craige YEEHAW: new driver struct; SEH
* 05-jul-95 craige crank up priority during mode change
* 13-jul-95 craige first step in mode set fix; made it work
* 19-jul-95 craige bug 189 - graphics mode change being ignored sometimes
* 20-jul-95 craige internal reorg to prevent thunking during modeset
* 22-jul-95 craige bug 216 - random hang switching bpp - fixed by
* using apps hwnd to hide things.
* bug 230 - unsupported starting modes
* 29-jul-95 toddla allways call HEL for SetMode for display driver
* 10-aug-95 toddla EnumDisplayModes changed to take a lp not a lplp
* 02-sep-95 craige bug 854: disable > 640x480 modes for rel 1
* 04-sep-95 craige bug 894: allow forcing of mode set
* 08-sep-95 craige bug 932: set preferred mode after RestoreDisplayMode
* 05-jan-96 kylej add interface structures
* 09-jan-96 kylej enable >640x480 modes for rel 2
* 27-feb-96 colinmc ensured that bits-per-pixel is always tested for
* when enumerating display modes and that enumeration
* always assumes you will be in exclusive mode when
* you actually do the mode switch
* 11-mar-96 jeffno Dynamic mode switch stuff for NT
* 24-mar-96 kylej Check modes with monitor profile
* 26-mar-96 jeffno Added ModeChangedOnENTERDDRAW
*
***************************************************************************/
#include "ddrawpr.h"
#ifdef WINNT
#include "ddrawgdi.h"
#endif
static DDHALMODEINFO ddmiModeXModes[] =
{
{
320, // width (in pixels) of mode
200, // height (in pixels) of mode
320, // pitch (in bytes) of mode
8, // bits per pixel
(WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX), // flags
0, // refresh rate
0, // red bit mask
0, // green bit mask
0, // blue bit mask
0 // alpha bit mask
},
{
320, // width (in pixels) of mode
240, // height (in pixels) of mode
320, // pitch (in bytes) of mode
8, // bits per pixel
(WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX), // flags
0, // refresh rate
0, // red bit mask
0, // green bit mask
0, // blue bit mask
0 // alpha bit mask
}
};
#define NUM_MODEX_MODES (sizeof( ddmiModeXModes ) / sizeof( ddmiModeXModes[0] ) )
/*
* makeDEVMODE
*
* create a DEVMODE struct (and flags) from mode info
*
* NOTE: We now always set the exclusive bit here and
* we always set the bpp. This is because we were
* previously not setting the bpp when not exclusive
* so the checking code was always passing the surface
* if it could do a mode of that size regardless of
* color depth.
*
* The new semantics of EnumDisplayModes is that it
* gives you a list of all display modes you could
* switch into if you were exclusive.
*/
static void makeDEVMODE(
LPDDRAWI_DIRECTDRAW_GBL this,
LPDDHALMODEINFO pmi,
BOOL inexcl,
BOOL useRefreshRate,
LPDWORD pcds_flags,
LPDEVMODE pdm )
{
pdm->dmSize = sizeof( *pdm );
pdm->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
if( useRefreshRate & (pmi->wRefreshRate != 0))
pdm->dmFields |= DM_DISPLAYFREQUENCY;
pdm->dmPelsWidth = pmi->dwWidth;
pdm->dmPelsHeight = pmi->dwHeight;
pdm->dmBitsPerPel = pmi->dwBPP;
pdm->dmDisplayFrequency = pmi->wRefreshRate;
*pcds_flags = (
#ifdef WIN95
CDS_EXCLUSIVE
|
#endif
CDS_FULLSCREEN
);
} /* makeDEVMODE */
/*
* AddModeXModes
*/
void AddModeXModes( LPDDRAWI_DIRECTDRAW_GBL pdrv )
{
DWORD i;
DWORD j;
LPDDHALMODEINFO pmi_i;
LPDDHALMODEINFO pmi_j;
BOOL hasmode[NUM_MODEX_MODES];
DWORD newmodecnt;
LPDDHALMODEINFO pmi;
for( j=0;j<NUM_MODEX_MODES; j++ )
{
hasmode[j] = FALSE;
}
/*
* find out what modes are already supported
*/
for( i=0;i<pdrv->dwNumModes;i++ )
{
pmi_i = &pdrv->lpModeInfo[i];
for( j=0;j<NUM_MODEX_MODES; j++ )
{
pmi_j = &ddmiModeXModes[j];
if( (pmi_i->dwWidth == pmi_j->dwWidth) &&
(pmi_i->dwHeight == pmi_j->dwHeight) &&
(pmi_i->dwBPP == pmi_j->dwBPP) &&
((pmi_i->wFlags & pmi_j->wFlags) & DDMODEINFO_PALETTIZED ) )
{
// There is a mode already in the mode table the same as the modeX mode.
// check to make sure that the driver really supports it
DWORD cds_flags;
DEVMODE dm;
int cds_rc;
makeDEVMODE( pdrv, pmi_i, TRUE, FALSE, &cds_flags, &dm );
cds_flags |= CDS_TEST;
cds_rc = ChangeDisplaySettings( &dm, cds_flags );
if( cds_rc != 0)
{
// The driver does not support this mode even though it is in the mode table.
// Mark the mode as unsupported and go ahead and add the ModeX mode.
DPF( 3, "Mode %d not supported (%dx%dx%d), rc = %d, marking invalid", i,
pmi_i->dwWidth, pmi_i->dwHeight, pmi_i->dwBPP,
cds_rc );
pmi_i->wFlags |= DDMODEINFO_UNSUPPORTED;
}
else
{
// Don't add the ModeX mode, the driver supports a linear mode.
hasmode[j] = TRUE;
}
}
}
}
/*
* count how many new modes we need
*/
newmodecnt = 0;
for( j=0;j<NUM_MODEX_MODES; j++ )
{
if( !hasmode[j] )
{
newmodecnt++;
}
}
/*
* create new struct
*/
if( newmodecnt > 0 )
{
pmi = MemAlloc( (newmodecnt + pdrv->dwNumModes) * sizeof( DDHALMODEINFO ) );
if( pmi != NULL )
{
memcpy( pmi, pdrv->lpModeInfo, pdrv->dwNumModes * sizeof( DDHALMODEINFO ) );
for( j=0;j<NUM_MODEX_MODES; j++ )
{
if( !hasmode[j] )
{
DPF( 1, "Adding ModeX mode %ldx%ldx%ld",
ddmiModeXModes[j].dwWidth,
ddmiModeXModes[j].dwHeight,
ddmiModeXModes[j].dwBPP );
pmi[ pdrv->dwNumModes ] = ddmiModeXModes[j];
pdrv->dwNumModes++;
}
}
MemFree( pdrv->lpModeInfo );
pdrv->lpModeInfo = pmi;
}
}
} /* AddModeXModes */
#ifdef WIN95
BOOL MonitorCanHandleMode( DWORD width, DWORD height, WORD refreshRate )
{
DWORD max_monitor_x;
DWORD min_refresh;
DWORD max_refresh;
max_monitor_x = (DWORD)DD16_GetMonitorMaxSize(1);
if( ( max_monitor_x != 0 ) && ( width > max_monitor_x ) )
{
DPF(3, "Mode's width greater than monitor maximum width (%d)", max_monitor_x);
return FALSE;
}
if( refreshRate == 0 )
{
// default refresh rate specified, no need to verify it
return TRUE;
}
// a refresh rate was specified, we'd better make sure the monitor can handle it
if(DD16_GetMonitorRefreshRateRanges(1, (int)width, (int) height, &min_refresh, &max_refresh))
{
if( (min_refresh != 0) && (refreshRate < min_refresh) )
{
DPF(3, "Requested refresh rate < monitor's minimum refresh rate (%d)", min_refresh);
return FALSE;
}
if( (max_refresh != 0) && (refreshRate > max_refresh) )
{
DPF(3, "Requested refresh rate > monitor's maximum refresh rate (%d)", max_refresh);
return FALSE;
}
}
// The monitor likes it.
return TRUE;
}
#else
BOOL MonitorCanHandleMode( DWORD width, DWORD height, WORD refreshRate )
{
return TRUE;
}
#endif
/*
* setSurfaceDescFromMode
*/
static void setSurfaceDescFromMode(
LPDDHALMODEINFO pmi,
LPDDSURFACEDESC pddsd )
{
memset( pddsd, 0, sizeof( DDSURFACEDESC ) );
pddsd->dwSize = sizeof( DDSURFACEDESC );
pddsd->dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT |
DDSD_PITCH | DDSD_REFRESHRATE;
pddsd->dwHeight = pmi->dwHeight;
pddsd->dwWidth = pmi->dwWidth;
pddsd->lPitch = pmi->lPitch;
pddsd->dwRefreshRate = (DWORD)pmi->wRefreshRate;
#ifdef WINNT
// on NT, a refresh rate of 1 means adapter default. We expose
// this to the application as a refresh rate of 0 which just means
// pick a default refresh rate.
if( pddsd->dwRefreshRate == 1 )
{
pddsd->dwRefreshRate = 0;
}
#endif
pddsd->ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
pddsd->ddpfPixelFormat.dwFlags = DDPF_RGB;
pddsd->ddpfPixelFormat.dwRGBBitCount = (DWORD)pmi->dwBPP;
if( pmi->wFlags & DDMODEINFO_PALETTIZED )
{
pddsd->ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8;
}
else
{
pddsd->ddpfPixelFormat.dwRBitMask = pmi->dwRBitMask;
pddsd->ddpfPixelFormat.dwGBitMask = pmi->dwGBitMask;
pddsd->ddpfPixelFormat.dwBBitMask = pmi->dwBBitMask;
pddsd->ddpfPixelFormat.dwRGBAlphaBitMask = pmi->dwAlphaBitMask;
}
} /* setSurfaceDescFromMode */
#ifdef WINNT
/*
* ModeChanged
*
* This function always calls FetchDirectDrawData. It's necessary in those cases'
* where the focus changed but was handled by calling NT's DdDisableAllSurfaces
* which doesn't bump the display uniqueness value, which makes ModeChangedOnENTERDDRAW
* return without doing anything, so we'd never restore the ddraw object.
*/
BOOL NTModeChanged(LPDDRAWI_DIRECTDRAW_GBL pdrv)
{
DWORD oldorig=pdrv->dwModeIndexOrig;
DPF(4,"NTModeChanged called");
uDisplaySettingsUnique=DdQueryDisplaySettingsUniqueness();
if (NULL == FetchDirectDrawData( pdrv, TRUE, 0 ))
return FALSE;
pdrv->dwModeIndexOrig=oldorig;
return TRUE;
}
/*
* ModeChangedOnENTERDDRAW
*
* This function is called via the ENTERDDRAW macro to check whether the mode
* has changed. If it has, we update the driver object and the mode uniqueness.
*/
void ModeChangedOnENTERDDRAW(void)
{
LPDDRAWI_DIRECTDRAW_INT pdrv_int;
LPDDRAWI_DIRECTDRAW_GBL pdrv;
if ( DdQueryDisplaySettingsUniqueness() == uDisplaySettingsUnique )
return;
/*
* we don't want the helper coming and resetting a driver object which it doesn't
* own and getting registered with the Kernel and all that other crap that could
* happen
*/
if (dwHelperPid==GetCurrentProcessId())
{
DPF(4,"Ignoring a mode change in ddhelp's process");
return;
}
DPF(4,"ModeChangedOnENTERDDRAW uniqueness changed");
pdrv_int = lpDriverObjectList;
if (pdrv_int)
{
if (pdrv_int->lpLcl->lpGbl)
{
NTModeChanged(pdrv_int->lpLcl->lpGbl);
return;
}
}
}
#endif //winnt
#undef DPF_MODNAME
#define DPF_MODNAME "GetDisplayMode"
/*
* DD_GetDisplayMode
*/
HRESULT DDAPI DD_GetDisplayMode(
LPDIRECTDRAW lpDD,
LPDDSURFACEDESC lpSurfaceDesc )
{
LPDDRAWI_DIRECTDRAW_INT this_int;
LPDDRAWI_DIRECTDRAW_LCL this_lcl;
LPDDRAWI_DIRECTDRAW_GBL this;
LPDDHALMODEINFO pmi;
ENTER_DDRAW();
TRY
{
this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
if( !VALID_DIRECTDRAW_PTR( this_int ) )
{
LEAVE_DDRAW();
return DDERR_INVALIDOBJECT;
}
this_lcl = this_int->lpLcl;
this = this_lcl->lpGbl;
if( !VALIDEX_DDSURFACEDESC_PTR( lpSurfaceDesc ) )
{
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
if( this->dwModeIndex == DDUNSUPPORTEDMODE)
{
DPF_ERR( "Driver is in an unsupported mode" );
LEAVE_DDRAW();
return DDERR_UNSUPPORTEDMODE;
}
pmi = &this->lpModeInfo[ this->dwModeIndex ];
setSurfaceDescFromMode( pmi, lpSurfaceDesc );
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
DPF_ERR( "Exception encountered validating parameters" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
LEAVE_DDRAW();
return DD_OK;
} /* DD_GetDisplayMode */
#undef DPF_MODNAME
#define DPF_MODNAME "SetDisplayMode"
/*
* bumpPriority
*/
static DWORD bumpPriority( void )
{
DWORD oldclass;
HANDLE hprocess;
hprocess = GetCurrentProcess();
oldclass = GetPriorityClass( hprocess );
SetPriorityClass( hprocess, HIGH_PRIORITY_CLASS );
return oldclass;
} /* bumpPriority */
/*
* restorePriority
*/
static void restorePriority( DWORD oldclass )
{
HANDLE hprocess;
hprocess = GetCurrentProcess();
SetPriorityClass( hprocess, oldclass );
} /* restorePriority */
#if 0
static char szClassName[] = "DirectDrawFullscreenWindow";
static HWND hWndTmp;
static HCURSOR hSaveClassCursor;
static HCURSOR hSaveCursor;
static LONG lWindowLong;
static RECT rWnd;
#define OCR_WAIT_DEFAULT 102
/*
* curtainsUp
*/
void curtainsUp( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl )
{
HCURSOR hcursor= (HCURSOR)LoadImage(NULL,MAKEINTRESOURCE(OCR_WAIT_DEFAULT),IMAGE_CURSOR,0,0,0);
if( (pdrv_lcl->hWnd != 0) && IsWindow( (HWND) pdrv_lcl->hWnd ) )
{
lWindowLong = GetWindowLong( (HWND) pdrv_lcl->hWnd, GWL_EXSTYLE );
SetWindowLong( (HWND) pdrv_lcl->hWnd, GWL_EXSTYLE, lWindowLong |
(WS_EX_TOOLWINDOW) );
hSaveClassCursor = (HCURSOR) GetClassLong( (HWND) pdrv_lcl->hWnd, GCL_HCURSOR );
SetClassLong( (HWND) pdrv_lcl->hWnd, GCL_HCURSOR, (LONG) hcursor );
GetWindowRect( (HWND) pdrv_lcl->hWnd, (LPRECT) &rWnd );
SetWindowPos( (HWND) pdrv_lcl->hWnd, NULL, 0, 0,
10000, 10000,
SWP_NOZORDER | SWP_NOACTIVATE );
SetForegroundWindow( (HWND) pdrv_lcl->hWnd );
}
else
{
WNDCLASS cls;
pdrv_lcl->hWnd = 0;
cls.lpszClassName = szClassName;
cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
cls.hInstance = hModule;
cls.hIcon = NULL;
cls.hCursor = hcursor;
cls.lpszMenuName = NULL;
cls.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
cls.lpfnWndProc = (WNDPROC)DefWindowProc;
cls.cbWndExtra = 0;
cls.cbClsExtra = 0;
RegisterClass(&cls);
DPF( 3, "*** CREATEWINDOW" );
hWndTmp = CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW,
szClassName, szClassName,
WS_POPUP|WS_VISIBLE, 0, 0, 10000, 10000,
NULL, NULL, hModule, NULL);
DPF( 3, "*** BACK FROM CREATEWINDOW, hwnd=%08lx", hWndTmp );
if( hWndTmp != NULL)
{
SetForegroundWindow( hWndTmp );
}
}
hSaveCursor = SetCursor( hcursor );
} /* curtainsUp */
/*
* curtainsDown
*/
void curtainsDown( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl )
{
if( (pdrv_lcl->hWnd != 0) && IsWindow( (HWND) pdrv_lcl->hWnd ) )
{
SetWindowLong( (HWND) pdrv_lcl->hWnd, GWL_EXSTYLE, lWindowLong );
SetClassLong( (HWND) pdrv_lcl->hWnd, GCL_HCURSOR, (LONG) hSaveClassCursor );
SetCursor( hSaveCursor );
SetWindowPos( (HWND) pdrv_lcl->hWnd, NULL,
rWnd.left, rWnd.top,
rWnd.right-rWnd.left,
rWnd.bottom-rWnd.top,
SWP_NOZORDER | SWP_NOACTIVATE );
}
else
{
SetCursor( hSaveCursor );
pdrv_lcl->hWnd = 0;
if( hWndTmp != NULL )
{
DestroyWindow( hWndTmp );
UnregisterClass( szClassName, hModule );
}
}
hWndTmp = NULL;
} /* curtainsDown */
#endif
/*
* fetchModeXData
*/
static LPDDRAWI_DIRECTDRAW_GBL fetchModeXData(
LPDDRAWI_DIRECTDRAW_GBL pdrv,
LPDDHALMODEINFO pmi )
{
DDHALINFO ddhi;
LPDDRAWI_DIRECTDRAW_GBL new_pdrv;
DDPIXELFORMAT dpf;
extern dwFakeFlags;
/*
* initialize the DDHALINFO struct
*/
memset( &ddhi, 0, sizeof( ddhi ) );
ddhi.dwSize = sizeof( ddhi );
/*
* capabilities supported (none)
*/
ddhi.ddCaps.dwCaps = 0;
ddhi.ddCaps.dwFXCaps = 0;
ddhi.ddCaps.dwCKeyCaps = 0;
ddhi.ddCaps.ddsCaps.dwCaps = 0;
/*
* pointer to primary surface
*/
ddhi.vmiData.fpPrimary = 0xbad00bad;
/*
* build mode and pixel format info
*/
ddhi.vmiData.dwDisplayHeight = pmi->dwHeight;
ddhi.vmiData.dwDisplayWidth = pmi->dwWidth;
ddhi.vmiData.lDisplayPitch = pmi->lPitch;
BuildPixelFormat( pmi, &dpf );
ddhi.vmiData.ddpfDisplay = dpf;
/*
* fourcc code information
*/
ddhi.ddCaps.dwNumFourCCCodes = 0;
ddhi.lpdwFourCC = NULL;
/*
* Fill in heap info
*/
ddhi.vmiData.dwNumHeaps = 0;
ddhi.vmiData.pvmList = NULL;
/*
* required alignments of the scanlines of each kind of memory
* (DWORD is the MINIMUM)
*/
ddhi.vmiData.dwOffscreenAlign = sizeof( DWORD );
ddhi.vmiData.dwTextureAlign = sizeof( DWORD );
ddhi.vmiData.dwZBufferAlign = sizeof( DWORD );
/*
* callback functions
*/
ddhi.lpDDCallbacks = NULL;
ddhi.lpDDSurfaceCallbacks = NULL;
ddhi.lpDDPaletteCallbacks = NULL;
/*
* create the driver object
*/
new_pdrv = DirectDrawObjectCreate( &ddhi, TRUE, pdrv );
DPF(6,"MODEX driver object's display is %dx%d, pitch is %d", ddhi.vmiData.dwDisplayHeight,ddhi.vmiData.dwDisplayWidth,ddhi.vmiData.lDisplayPitch);
if( new_pdrv != NULL )
{
new_pdrv->dwFlags |= DDRAWI_MODEX;
if( new_pdrv->dwPDevice != 0 )
{
new_pdrv->dwPDevice = 0;
new_pdrv->lpwPDeviceFlags = (WORD *)&dwFakeFlags;
}
}
DPF( 3, "ModeX DirectDraw object created" );
DPF( 3, " width=%ld, height=%ld, %ld bpp",
new_pdrv->vmiData.dwDisplayWidth,
new_pdrv->vmiData.dwDisplayHeight,
new_pdrv->vmiData.ddpfDisplay.dwRGBBitCount );
DPF( 3, " lDisplayPitch = %ld", new_pdrv->vmiData.lDisplayPitch );
return new_pdrv;
} /* fetchModeXData */
/*
* stopModeX
*/
static void stopModeX( LPDDRAWI_DIRECTDRAW_GBL pdrv )
{
DPF( 5, "***************** Turning off ModeX *****************" );
#ifdef WIN95
ModeX_RestoreMode();
#else
DdSetModeX(pdrv,0);
#endif
pdrv->dwFlags &= ~DDRAWI_MODEX;
DPF( 5, "**************** DONE Turning off ModeX **************" );
} /* stopModeX */
/*
* SetDisplayMode
*/
HRESULT SetDisplayMode(
LPDDRAWI_DIRECTDRAW_LCL this_lcl,
DWORD modeidx,
BOOL force,
BOOL useRefreshRate)
{
DWORD rc;
DDHAL_SETMODEDATA smd;
LPDDHAL_SETMODE smfn;
LPDDHAL_SETMODE smhalfn;
LPDDHALMODEINFO pmi;
BOOL inexcl;
BOOL emulation;
LPDDRAWI_DIRECTDRAW_GBL this;
DWORD oldclass;
BOOL use_modex;
BOOL was_modex;
DWORD real_modeidx;
/*
* Signify that the app at least tried to set a mode.
* Redrawing of the desktop will only happen if this flag is set.
*/
this_lcl->dwLocalFlags |= DDRAWILCL_MODEHASBEENCHANGED;
this = this_lcl->lpGbl;
/*
* don't allow if surfaces open
*/
if( !force )
{
if( this->dwSurfaceLockCount > 0 )
{
DPF_ERR( "Can't switch modes with locked surfaces!" );
return DDERR_SURFACEBUSY;
}
}
if( modeidx == DDUNSUPPORTEDMODE )
{
DPF_ERR( "Trying to set to an unsupported mode" );
return DDERR_UNSUPPORTEDMODE;
}
/*
* is our current mode a disp dib mode?
*/
was_modex = FALSE;
if( this->dwModeIndex != DDUNSUPPORTEDMODE )
{
if( this->lpModeInfo[ this->dwModeIndex ].wFlags & DDMODEINFO_MODEX )
{
was_modex = TRUE;
}
}
/*
* is the new mode a mode x mode
*/
pmi = &this->lpModeInfo[ modeidx ];
if( pmi->wFlags & DDMODEINFO_MODEX )
{
DPF( 1, "Mode %ld is a ModeX mode", modeidx);
use_modex = TRUE;
}
else
{
use_modex = FALSE;
}
/*
* don't re-set the mode to the same one...
* NOTE: we ALWAYS set the mode in emulation on Win95 since our index could be wrong
*/
#ifdef WINNT
if( modeidx == this->dwModeIndex )
{
DPF( 2, "%08lx: Current Mode match: %ldx%ld, %dbpp", GetCurrentProcessId(),
pmi->dwWidth, pmi->dwHeight, pmi->dwBPP );
if( this->dwFlags & DDRAWI_DISPLAYDRV )
{
RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE |
RDW_ALLCHILDREN );
}
return DD_OK;
}
#else
if( modeidx == this->dwModeIndex && !(this->dwFlags & DDRAWI_NOHARDWARE) )
{
DPF( 2, "%08lx: Current Mode match: %ldx%ld, %dbpp", GetCurrentProcessId(),
pmi->dwWidth, pmi->dwHeight, pmi->dwBPP );
return DD_OK;
}
#endif
DPF( 5, "***********************************************" );
DPF( 5, "*** SETDISPLAYMODE: %ldx%ld, %dbpp", pmi->dwWidth, pmi->dwHeight, pmi->dwBPP );
DPF( 5, "*** dwModeIndex (current) = %ld", this->dwModeIndex );
DPF( 5, "*** modeidx (new) = %ld", modeidx );
DPF( 5, "*** use_modex = %ld", use_modex );
DPF( 5, "*** was_modex = %ld", was_modex );
DPF( 5, "***********************************************" );
/*
* check if in exclusive mode
*/
inexcl = (this->lpExclusiveOwner == this_lcl);
/*
* check bpp
*/
if( (this->dwFlags & DDRAWI_DISPLAYDRV) && !force )
{
if( (this->lpModeInfo[this->dwModeIndex].dwBPP !=
this->lpModeInfo[modeidx].dwBPP) ||
((this->lpModeInfo[this->dwModeIndex].dwBPP ==
this->lpModeInfo[modeidx].dwBPP) && use_modex ) )
{
if( !inexcl || !(this->dwFlags & DDRAWI_FULLSCREEN) )
{
DPF_ERR( "Can't change BPP if not in exclusive fullscreen mode" );
return DDERR_NOEXCLUSIVEMODE;
}
}
}
/*
* see if we need to shutdown modex mode
*/
if( was_modex )
{
stopModeX( this );
}
/*
* see if we need to set a modex mode
*/
if( use_modex )
{
DWORD i;
LPDDHALMODEINFO tmp_pmi;
real_modeidx = modeidx;
for( i=0;i<this->dwNumModes;i++ )
{
tmp_pmi = &this->lpModeInfo[ i ];
if( (tmp_pmi->dwWidth == 640) &&
(tmp_pmi->dwHeight == 480) &&
(tmp_pmi->dwBPP == 8) &&
(tmp_pmi->wFlags & DDMODEINFO_PALETTIZED) )
{
DPF( 5, "MODEX: Setting to 640x480x8 first (index=%ld)", i );
modeidx = i;
break;
}
}
if( i == this->dwNumModes )
{
DPF( 1, "Mode not supported" );
return DDERR_GENERIC;
}
}
/*
* get the driver to set the new mode...
*/
#ifdef WIN95
if( ( this->dwFlags & DDRAWI_DISPLAYDRV ) ||
( this->dwFlags & DDRAWI_NOHARDWARE ) ||
( this_lcl->lpDDCB->cbDDCallbacks.SetMode == NULL ) )
#else
if (1) //always use mySetDisplayMode for NT
#endif
{
smfn = this_lcl->lpDDCB->HELDD.SetMode;
smhalfn = smfn;
emulation = TRUE;
DPF( 3, "Calling HEL SetMode" );
}
else
{
smhalfn = this_lcl->lpDDCB->cbDDCallbacks.SetMode;
smfn = this_lcl->lpDDCB->HALDD.SetMode;
emulation = FALSE;
}
if( smhalfn != NULL )
{
DWORD oldmode;
BOOL didsetmode;
/*
* set the mode if this isn't a modex mode, or if it is a modex
* mode but wasn't one before
*/
if( !use_modex || (use_modex && !was_modex) )
{
smd.SetMode = smhalfn;
smd.lpDD = this;
smd.dwModeIndex = modeidx;
smd.inexcl = inexcl;
smd.useRefreshRate = useRefreshRate;
oldclass = bumpPriority();
DOHALCALL( SetMode, smfn, smd, rc, emulation );
restorePriority( oldclass );
didsetmode = TRUE;
}
else
{
rc = DDHAL_DRIVER_HANDLED;
smd.ddRVal = DD_OK;
didsetmode = FALSE;
}
if( rc == DDHAL_DRIVER_HANDLED )
{
if( smd.ddRVal == DD_OK )
{
oldmode = this->dwModeIndexOrig; // save original mode index
if( didsetmode )
{
#ifdef WINNT
uDisplaySettingsUnique=DdQueryDisplaySettingsUniqueness();
#endif
FetchDirectDrawData( this, TRUE, 0 );
#ifndef WINNT
this->dwModeIndex = modeidx;
this_lcl->dwPreferredMode = modeidx;
#else
this_lcl->dwPreferredMode = this->dwModeIndex;
#endif
DPF(9,"Preferred mode index is %d, desired mode is %d",this_lcl->dwPreferredMode,modeidx);
this->dwModeIndexOrig = oldmode;
}
/*
* now set modex mode
*/
if( use_modex )
{
extern void HELStopDCI( void );
DPF( 5, "********************** Setting MODEX MODE **********************" );
HELStopDCI();
#ifdef WIN95
ModeX_SetMode( (UINT)pmi->dwWidth, (UINT)pmi->dwHeight);
#else
DdSetModeX(this,(ULONG) pmi->dwHeight);
//DPF(6,"HAL CreateSurface is %08x after DdSetModeX");
{
BOOL bNewMode;
if (!DdReenableDirectDrawObject(this,&bNewMode))
{
DPF_ERR("After MODEX, call to DdReenableDirectDrawObject failed!");
return DDERR_UNSUPPORTED;
}
}
#endif
/*
* ModeX now active, program our driver object and return
*/
#ifdef WINNT
uDisplaySettingsUnique=DdQueryDisplaySettingsUniqueness();
fetchModeXData( this, pmi );
this_lcl->lpDDCB = this->lpDDCBtmp;
#else
fetchModeXData( this, pmi );
#endif
this->dwModeIndex = real_modeidx;
this_lcl->dwPreferredMode = real_modeidx;
this->dwModeIndexOrig = oldmode;
DPF( 5, "********************** Done Setting MODEX MODE **********************" );
return DD_OK;
}
}
return smd.ddRVal;
}
}
return DDERR_UNSUPPORTED;
} /* SetDisplayMode */
/*
* DD_SetDisplayMode
*/
HRESULT DDAPI DD_SetDisplayMode(
LPDIRECTDRAW lpDD,
DWORD dwWidth,
DWORD dwHeight,
DWORD dwBPP )
{
DPF(9,"DD1 setdisplay mode called");
return DD_SetDisplayMode2(lpDD,dwWidth,dwHeight,dwBPP,0,0);
} /* DD_SetDisplayMode */
/*
* DD_SetDisplayMode2
*/
HRESULT DDAPI DD_SetDisplayMode2(
LPDIRECTDRAW lpDD,
DWORD dwWidth,
DWORD dwHeight,
DWORD dwBPP,
DWORD dwRefreshRate,
DWORD dwFlags)
{
LPDDRAWI_DIRECTDRAW_INT this_int;
LPDDRAWI_DIRECTDRAW_LCL this_lcl;
LPDDRAWI_DIRECTDRAW_GBL this;
int i;
int j;
LPDDHALMODEINFO pmi;
HRESULT ddrval;
int iChosenMode;
WORD wChosenRefresh;
DWORD dwNumberOfTempModes;
#ifdef WINNT
WORD wCurrentRefresh=0;
DWORD dwCurrentWidth=0;
#endif
typedef struct
{
DDHALMODEINFO mi;
int iIndex;
}TEMP_MODE_LIST;
TEMP_MODE_LIST * pTempList=0;
ENTER_DDRAW();
TRY
{
this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
if( !VALID_DIRECTDRAW_PTR( this_int ) )
{
LEAVE_DDRAW();
return DDERR_INVALIDOBJECT;
}
this_lcl = this_int->lpLcl;
this = this_lcl->lpGbl;
/*
* no flags defined right now
*/
if( dwFlags )
{
DPF_ERR( "Invalid flags specified" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
/*
* don't allow change if surfaces are locked
*/
if( this->dwSurfaceLockCount )
{
DPF_ERR( "Surfaces are locked, can't switch the mode" );
LEAVE_DDRAW();
return DDERR_SURFACEBUSY;
}
/*
* don't allow change if some other process has exclusive mode
*/
if( (this->lpExclusiveOwner != NULL) &&
(this->lpExclusiveOwner != this_lcl ) )
{
DPF_ERR( "Can't change mode; exclusive mode not owned" );
LEAVE_DDRAW();
return DDERR_NOEXCLUSIVEMODE;
}
#ifdef WINNT
/*
* Get the current refresh rate, if we have one.
*/
if( 0xFFFFFFFFUL != this->dwModeIndex )
{
wCurrentRefresh = this->lpModeInfo[ this->dwModeIndex ].wRefreshRate;
dwCurrentWidth = this->lpModeInfo[ this->dwModeIndex ].dwWidth;
}
#endif
/*
* Modes are now chosen in a brain-dead 3-step process:
* -Build a temporary list of modes which match the desired spatial and color resolutions
* -Sort this list into ascending refresh rate order.
* -Select from this list the rate which best matches what we want.
*/
/*
* Step 1. Build a list of modes which match the desired spatial and color resolutions
*/
pTempList = (TEMP_MODE_LIST*) MemAlloc(this->dwNumModes * sizeof(TEMP_MODE_LIST));
if (0 == pTempList)
{
LEAVE_DDRAW();
return DDERR_OUTOFMEMORY;
}
/*
* On NT, some cards will enumerate only one refresh rate choice for each
* resolution, and that choice will be the hardware default rate.
*/
dwNumberOfTempModes=0;
for(i = 0;i <(int) (this->dwNumModes);i++)
{
pmi = &this->lpModeInfo[i];
if( (pmi->dwWidth == dwWidth) &&
(pmi->dwHeight == dwHeight) &&
((DWORD)pmi->dwBPP == dwBPP) &&
((pmi->wFlags & DDMODEINFO_UNSUPPORTED) == 0))
{
pTempList[dwNumberOfTempModes].mi = *pmi;
pTempList[dwNumberOfTempModes].iIndex = i;
#ifdef WINNT
/*
* The app can specify a refresh rate of zero for "don't care",
* Since on NT default refresh rates are specified by '1' in the
* mode list, we'll translate 1 to 0 in the temporary list.
*/
if (pmi->wRefreshRate <= 1)
{
pTempList[dwNumberOfTempModes].mi.wRefreshRate = 0;
}
#endif
dwNumberOfTempModes++;
}
}
if (0 == dwNumberOfTempModes)
{
MemFree(pTempList);
LEAVE_DDRAW();
DPF( 0,"Mode not found... No match amongst available spatial and color resolutions (wanted %dx%dx%d)",dwWidth,dwHeight,dwBPP );
return DDERR_INVALIDMODE;
}
for(i=0;i<(int)dwNumberOfTempModes;i++)
DPF(9,"Copied mode list element %d:%dx%dx%d@%d",i,
pTempList[i].mi.dwWidth,
pTempList[i].mi.dwHeight,
pTempList[i].mi.dwBPP,
pTempList[i].mi.wRefreshRate);
/*
* Step 2. Sort list into ascending refresh order
* Bubble sort
* Note this does nothing if there's only one surviving mode.
*/
for (i=0;i<(int)dwNumberOfTempModes;i++)
{
for (j=(int)dwNumberOfTempModes-1;j>i;j--)
{
if (pTempList[i].mi.wRefreshRate > pTempList[j].mi.wRefreshRate)
{
TEMP_MODE_LIST temp = pTempList[i];
pTempList[i] = pTempList[j];
pTempList[j] = temp;
}
}
}
for(i=0;i<(int)dwNumberOfTempModes;i++)
DPF(9,"Sorted mode list element %d:%dx%dx%d@%d",i,
pTempList[i].mi.dwWidth,
pTempList[i].mi.dwHeight,
pTempList[i].mi.dwBPP,
pTempList[i].mi.wRefreshRate);
/*
* Step 3. Find the rate we're looking for.
* There are three cases.
* 1:Looking for a specific refresh
* 2a:Not looking for a specific refresh and stepping down in spatial resolution
* 2a:Not looking for a specific refresh and stepping up in spatial resolution
*/
iChosenMode = -1;
if (dwRefreshRate)
{
/* case 1 */
DPF(9,"App wants rate of %d",dwRefreshRate);
for (i=0;i<(int)dwNumberOfTempModes;i++)
{
/*
* We'll never match a zero (hardware default) rate here,
* but if there's only one rate which has refresh=0
* the app will never ask for a non-zero rate, because it will
* never have seen one at enumerate time.
*/
if ( (DWORD) (pTempList[i].mi.wRefreshRate) == dwRefreshRate )
{
iChosenMode=pTempList[i].iIndex;
break;
}
}
}
else
{
#if 0 //def WINNT
/* case 2. a or b? */
if (dwWidth <= dwCurrentWidth)
{
/*
* Case 2a: Going down in spatial resolution, so ascend the rates, looking for the highest
* rate which does not exceed the current rate. If there's no such rate, grab the lowest
* of all the rates (all of which are greater than the current rate).
* Start with the first (lowest rate possible):
*/
iChosenMode = pTempList[0].iIndex;
for (i=0;i< (int) dwNumberOfTempModes;i++)
{
if ( pTempList[i].mi.wRefreshRate > wCurrentRefresh )
{
/*
* Found a rate greater than the current. This and all later rates are not wanted
* (unless we already chose it by default by assigning iChosenMode to the first in the list).
*/
if ( 0 != this->lpModeInfo[iChosenMode].wRefreshRate )
{
/*
* If the last mode we found was a hardware default, then
* we need to choose the next one. If we got here, then
* the last mode was _not_ a HDR, and we can safely choose it.
*/
break;
}
}
iChosenMode = pTempList[i].iIndex;
}
}
else
#endif
{
/*
* Case 2b: Going up in spatial resolution, so just pick the lowest rate (earliest in list)
* which isn't a hardware default, unless no such rate exists.
*/
iChosenMode=pTempList[0].iIndex;
#if 0
for (i=0;i< (int) dwNumberOfTempModes;i++)
{
if ( pTempList[i].mi.wRefreshRate != 0 )
{
break;
}
iChosenMode = pTempList[i].iIndex;
}
#endif
}
}
if (-1 == iChosenMode)
{
MemFree(pTempList);
LEAVE_DDRAW();
DPF( 0,"Mode not found... No match amongst available refresh rates (wanted %dx%dx%d@%d)",dwWidth,dwHeight,dwBPP,dwRefreshRate);
return DDERR_INVALIDMODE;
}
MemFree(pTempList);
pmi = &this->lpModeInfo[iChosenMode];
DPF(9,"Desired width:%d, current width:%d. Current refresh:%d, chosen refresh %d",
dwWidth,
dwCurrentWidth,
wCurrentRefresh,
this->lpModeInfo[iChosenMode].wRefreshRate);
/*
* only allow ModeX modes if the cooplevel is ok
*/
if( (pmi->wFlags & DDMODEINFO_MODEX) && !(this_lcl->dwLocalFlags & DDRAWILCL_ALLOWMODEX) )
{
LEAVE_DDRAW();
DPF( 0,"must set DDSCL_ALLOWMODEX to use ModeX modes" );
return DDERR_INVALIDMODE;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
DPF_ERR( "Exception encountered validating parameters" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
// see if the monitor likes it
if( !(pmi->wFlags & DDMODEINFO_MODEX) && !MonitorCanHandleMode(pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate) )
{
// Monitor doesn't like it
DPF_ERR("Mode not compatible with monitor");
return DDERR_INVALIDMODE;
}
/*
* set the display mode, and pay attention to refresh rate if we were asked to.
* Always pay attention to rate on NT.
* NOTE!!! This is a very slight change from what we did in released DX2!!!
* - This function is now called from DD_SetDisplayMode with a refresh rate of 0,
* so we check for that circumstance and use it to say to the driver wether
* or not to pay attention to the refresh rate. Fine. However, now when
* someone calls DD_SetDisplayMode2 with a refresh rate of 0, we tell
* the driver to ignore the rate, when before we were telling the driver
* to force to some rate we found in the mode table (which would have been
* the first mode which matched resolution in the list... probably the lowest
* refresh rate).
*/
#if 1 //def WIN95
if (0 == dwRefreshRate)
ddrval = SetDisplayMode( this_lcl, iChosenMode, FALSE, FALSE );
else
#endif
ddrval = SetDisplayMode( this_lcl, iChosenMode, FALSE, TRUE );
LEAVE_DDRAW();
return ddrval;
} /* DD_SetDisplayMode2 */
#undef DPF_MODNAME
#define DPF_MODNAME "RestoreDisplayMode"
/*
* RestoreDisplayMode
*
* For use by DD_RestoreDisplayMode & internally.
* Must be called with driver lock taken
*/
HRESULT RestoreDisplayMode( LPDDRAWI_DIRECTDRAW_LCL this_lcl, BOOL force )
{
DWORD rc;
DDHAL_SETMODEDATA smd;
BOOL inexcl;
DWORD pid;
LPDDHAL_SETMODE smfn;
LPDDHAL_SETMODE smhalfn;
BOOL emulation;
LPDDRAWI_DIRECTDRAW_GBL this;
DWORD oldclass;
BOOL was_modex;
this = this_lcl->lpGbl;
DPF(9,"Restoring Display mode to index %d, %dx%dx%d@%d",this->dwModeIndexOrig,
this->lpModeInfo[this->dwModeIndexOrig].dwWidth,
this->lpModeInfo[this->dwModeIndexOrig].dwHeight,
this->lpModeInfo[this->dwModeIndexOrig].dwBPP,
this->lpModeInfo[this->dwModeIndexOrig].wRefreshRate);
if (0 == (this_lcl->dwLocalFlags & DDRAWILCL_MODEHASBEENCHANGED) )
{
/*
* This app never made a mode change, so we ignore the restore, in case someone switch desktop
* modes while playing a movie in a window, for instance. We do it before the redraw window
* so that we don't flash icons when a windowed app exits.
*/
DPF( 2, "Mode was never changed by this app" );
return DD_OK;
}
/*
* we ALWAYS set the mode in emulation on Win95 since our index could be wrong
*/
#ifdef WINNT
if (this->dwModeIndex == this->dwModeIndexOrig)
{
DPF( 2, "Mode wasn't changed" );
RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
return DD_OK;
}
#else
if( ( (this->dwModeIndex == this->dwModeIndexOrig) &&
!(this->dwFlags & DDRAWI_NOHARDWARE) ) || (this->lpModeInfo==NULL) )
{
DPF( 2, "Mode wasn't changed" );
RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
return DD_OK;
}
#endif
DPF( 1, "In RestoreDisplayMode" );
pid = GetCurrentProcessId();
/*
* don't allow mode change if surfaces are locked
*/
if( !force )
{
if( this->dwSurfaceLockCount > 0 )
{
DPF( 0, "Can't switch modes with locked surfaces!" );
return DDERR_SURFACEBUSY;
}
}
/*
* see if we're in exclusive mode
*/
if( force )
{
inexcl = TRUE;
}
else
{
inexcl = (this->lpExclusiveOwner == this_lcl);
}
/*
* check bpp
*/
if( this->lpModeInfo[ this->dwModeIndex ].wFlags & DDMODEINFO_MODEX )
{
was_modex = TRUE;
}
else
{
was_modex = FALSE;
}
/*
* turn off modex first...
*/
if( was_modex )
{
stopModeX( this );
}
/*
* get the driver to restore the mode...
*/
#ifdef WIN95
if( ( this->dwFlags & DDRAWI_DISPLAYDRV ) ||
( this->dwFlags & DDRAWI_NOHARDWARE ) ||
( this_lcl->lpDDCB->cbDDCallbacks.SetMode == NULL ) )
#else
if (1) //always use hel for nt
#endif
{
smfn = this_lcl->lpDDCB->HELDD.SetMode;
smhalfn = smfn;
emulation = TRUE;
}
else
{
smhalfn = this_lcl->lpDDCB->cbDDCallbacks.SetMode;
smfn = this_lcl->lpDDCB->HALDD.SetMode;
emulation = FALSE;
}
if( smhalfn != NULL )
{
smd.SetMode = smhalfn;
smd.lpDD = this;
#ifdef WIN95
smd.dwModeIndex = (DWORD) -1;
#else
/*
* If we allow the HEL to set the desktop to what's in the registry,
* we'll possibly end up with a mode index that was different to what
* we originally thought it was, so we force a return to the mode we
* were in when the direct draw object was created, which has to match
* the GDI desktop.
*/
smd.dwModeIndex = this->dwModeIndexOrig;
#endif
smd.inexcl = inexcl;
smd.useRefreshRate = TRUE;
oldclass = bumpPriority();
DOHALCALL( SetMode, smfn, smd, rc, emulation );
restorePriority( oldclass );
if( rc == DDHAL_DRIVER_HANDLED )
{
if( smd.ddRVal == DD_OK )
{
DPF( 3, "RestoreDisplayMode: Process %08lx Mode = %ld", GETCURRPID(), this->dwModeIndex );
#ifdef WINNT
uDisplaySettingsUnique=DdQueryDisplaySettingsUniqueness();
#endif
FetchDirectDrawData( this, TRUE, 0 );
if( this->dwFlags & DDRAWI_DISPLAYDRV )
{
DPF(4,"Redrawing all windows");
RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE |
RDW_ALLCHILDREN );
}
}
return smd.ddRVal;
}
}
return DDERR_UNSUPPORTED;
} /* RestoreDisplayMode */
/*
* DD_RestoreDisplayMode
*
* restore mode
*/
HRESULT DDAPI DD_RestoreDisplayMode( LPDIRECTDRAW lpDD )
{
LPDDRAWI_DIRECTDRAW_INT this_int;
LPDDRAWI_DIRECTDRAW_LCL this_lcl;
LPDDRAWI_DIRECTDRAW_GBL this;
HRESULT ddrval;
ENTER_DDRAW();
TRY
{
this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
if( !VALID_DIRECTDRAW_PTR( this_int ) )
{
LEAVE_DDRAW();
return DDERR_INVALIDOBJECT;
}
this_lcl = this_int->lpLcl;
this = this_lcl->lpGbl;
/*
* switching to the same mode?
*/
if( this->dwModeIndex == this->dwModeIndexOrig )
{
LEAVE_DDRAW();
return DD_OK;
}
/*
* don't allow change if some other process has exclusive mode
*/
if( (this->lpExclusiveOwner != NULL) &&
(this->lpExclusiveOwner != this_lcl ) )
{
DPF_ERR( "Can't change mode; exclusive mode owned" );
LEAVE_DDRAW();
return DDERR_NOEXCLUSIVEMODE;
}
/*
* don't allow change if surfaces are locked
*/
if( this->dwSurfaceLockCount )
{
DPF_ERR( "Surfaces are locked, can't switch the mode" );
LEAVE_DDRAW();
return DDERR_SURFACEBUSY;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
DPF_ERR( "Exception encountered validating parameters" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
ddrval = RestoreDisplayMode( this_lcl, FALSE );
if( ddrval == DD_OK )
{
this_lcl->dwPreferredMode = this->dwModeIndex;
DPF( 1, "Preferred mode is now %ld", this_lcl->dwPreferredMode );
}
LEAVE_DDRAW();
return ddrval;
} /* DD_RestoreDisplayMode */
#undef DPF_MODNAME
#define DPF_MODNAME "EnumDisplayModes"
/*
* DD_EnumDisplayModes
*/
HRESULT DDAPI DD_EnumDisplayModes(
LPDIRECTDRAW lpDD,
DWORD dwFlags,
LPDDSURFACEDESC lpDDSurfaceDesc,
LPVOID lpContext,
LPDDENUMMODESCALLBACK lpEnumCallback )
{
LPDDRAWI_DIRECTDRAW_INT this_int;
LPDDRAWI_DIRECTDRAW_LCL this_lcl;
LPDDRAWI_DIRECTDRAW_GBL this;
DWORD rc;
DDSURFACEDESC ddsd;
LPDDHALMODEINFO pmi;
int i, j;
BOOL inexcl;
BOOL bUseRefreshRate;
ENTER_DDRAW();
TRY
{
this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
if( !VALID_DIRECTDRAW_PTR( this_int ) )
{
LEAVE_DDRAW();
return DDERR_INVALIDOBJECT;
}
this_lcl = this_int->lpLcl;
this = this_lcl->lpGbl;
if( lpDDSurfaceDesc != NULL )
{
if( !VALID_DDSURFACEDESC_PTR(lpDDSurfaceDesc) )
{
DPF_ERR( "Invalid surface description" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
}
if ( dwFlags & ~DDEDM_VALID)
{
DPF_ERR( "Invalid flags") ;
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
if( !VALIDEX_CODE_PTR( lpEnumCallback ) )
{
DPF_ERR( "Invalid enum. callback routine" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
DPF_ERR( "Exception encountered validating parameters" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
/*
* see if we're in exclusive mode
*/
inexcl = (this->lpExclusiveOwner == this_lcl);
/*
* go through all possible modes...
*/
for( i=0;i<(int)this->dwNumModes;i++ )
{
pmi = &this->lpModeInfo[i];
/*
* check to see if this is a duplicate mode
*/
for (j=0; j<i; j++)
{
// if we find a duplicate, break out early
if( (this->lpModeInfo[j].dwHeight == pmi->dwHeight) &&
(this->lpModeInfo[j].dwWidth == pmi->dwWidth) &&
(this->lpModeInfo[j].dwBPP == pmi->dwBPP) )
{
// basic mode matches, what about refresh rate?
if( dwFlags & DDEDM_REFRESHRATES )
{
// if refresh rate is not unique then the modes match
if( this->lpModeInfo[j].wRefreshRate == pmi->wRefreshRate )
{
DPF(1, "matched: %d %d", this->lpModeInfo[j].wRefreshRate, pmi->wRefreshRate);
break;
}
// unique refresh rate and the app cares, the modes don't match
}
else
{
// the app doesn't care about refresh rates
break;
}
}
}
if( j != i)
{
// broke out early, mode i is not unique, move on to the next one.
continue;
}
/*
* check if surface description matches mode
*/
if ( lpDDSurfaceDesc )
{
if( lpDDSurfaceDesc->dwFlags & DDSD_HEIGHT )
{
if( lpDDSurfaceDesc->dwHeight != pmi->dwHeight )
{
continue;
}
}
if( lpDDSurfaceDesc->dwFlags & DDSD_WIDTH )
{
if( lpDDSurfaceDesc->dwWidth != pmi->dwWidth )
{
continue;
}
}
if( lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT )
{
if( lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount != pmi->dwBPP )
{
continue;
}
}
if( lpDDSurfaceDesc->dwFlags & DDSD_REFRESHRATE )
{
bUseRefreshRate = TRUE;
if( lpDDSurfaceDesc->dwRefreshRate != (DWORD)pmi->wRefreshRate )
{
continue;
}
}
else
{
bUseRefreshRate = FALSE;
}
}
#ifdef WIN95
/*
* see if driver will allow this
*/
if( (this->dwFlags & DDRAWI_DISPLAYDRV) &&
!(pmi->wFlags & DDMODEINFO_MODEX) )
{
DWORD cds_flags;
DEVMODE dm;
int cds_rc;
makeDEVMODE( this, pmi, inexcl, bUseRefreshRate, &cds_flags, &dm );
cds_flags |= CDS_TEST;
cds_rc = ChangeDisplaySettings( &dm, cds_flags );
if( cds_rc != 0 )
{
if( bUseRefreshRate )
{
DPF( 3, "Mode %d not supported (%ldx%ldx%ld rr=%d), rc = %d", i,
pmi->dwWidth, pmi->dwHeight, pmi->dwBPP, pmi->wRefreshRate, cds_rc );
}
else
{
DPF( 3, "Mode %d not supported (%ldx%ldx%ld), rc = %d", i,
pmi->dwWidth, pmi->dwHeight, pmi->dwBPP, cds_rc );
}
continue;
}
if( !MonitorCanHandleMode( pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate ) )
{
DPF( 3, "Monitor can't handle mode %d: (%ldx%ld rr=%d)", i,
pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate);
continue;
}
}
if( (this->dwFlags & DDRAWI_DISPLAYDRV) &&
(pmi->wFlags & DDMODEINFO_MODEX) &&
!(this_lcl->dwLocalFlags & DDRAWILCL_ALLOWMODEX) )
{
DPF( 3, "skipping ModeX mode" );
continue;
}
#endif
/*
* invoke callback with surface desc.
*/
setSurfaceDescFromMode( pmi, &ddsd );
/*
* Hardware default rates on NT are signified as 1Hz. We translate this to
* 0Hz for DDraw apps. At SetDisplayMode time, 0Hz is translated back to 1Hz.
*/
if(0==(dwFlags & DDEDM_REFRESHRATES))
{
ddsd.dwRefreshRate = 0;
}
rc = lpEnumCallback( &ddsd, lpContext );
if( rc == 0 )
{
break;
}
}
LEAVE_DDRAW();
return DD_OK;
} /* DD_EnumDisplayModes */