Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
DisplayVideo.c
/* |
File: DisplayVideo.c |
Description:DisplayVideo will display all info about all video modes supported |
by each installed video card with their attached monitor. The purpose |
of this code is to provide a sample of how developers can discover the |
bit depths and timings of multisync displays. |
Author: EWA |
Copyright: Copyright: © 1995-1999 by Apple Computer, Inc. |
all rights reserved. |
Disclaimer: You may incorporate this sample code into your applications without |
restriction, though the sample code has been provided "AS IS" and the |
responsibility for its operation is 100% yours. However, what you are |
not permitted to do is to redistribute the source as "DSC Sample Code" |
after having made changes. If you're going to re-distribute the source, |
we require that you make it clear in the source that the code was |
descended from Apple Sample Code, but that you've made changes. |
Change History (most recent first): |
6/24/99 Updated for Metrowerks Codewarror Pro 2.1(KG) |
1/28/97 Updated source for Metrowerks CodeWarrior 11 Fixed up |
formatting and generally made things nicer(EWA) |
5/24/95 New today(EWA) |
*/ |
#include <Dialogs.h> |
#include <Devices.h> |
#include <Displays.h> |
#include <Errors.h> |
#include <FixMath.h> |
#include <fp.h> |
#include <Gestalt.h> |
#include <Memory.h> |
#include <Palettes.h> |
#include <PLStringFuncs.h> |
#include <QuickDraw.h> |
#include <ROMDefs.h> |
#include <Slots.h> |
#include <StdIO.h> |
#include <Video.h> |
#include <TextUtils.h> |
#include <Strings.h> |
#include <DriverServices.h> |
#include <stdlib.h> |
//-------------------------------------------------------------- |
// |
// Internal defines, structs, typedefs, and routine declarations |
// |
//-------------------------------------------------------------- |
struct DepthInfo { |
VDSwitchInfoRec depthSwitchInfo; // This is the switch mode to choose this timing/depth |
VPBlock depthVPBlock; // VPBlock (including size, depth and format) |
}; |
typedef struct DepthInfo DepthInfo; |
struct ListIteratorDataRec { |
unsigned long displayModeFlags; // |
VDSwitchInfoRec displayModeSwitchInfo; // |
VDResolutionInfoRec displayModeResolutionInfo; // |
VDTimingInfoRec displayModeTimingInfo; // Contains timing flags and such |
unsigned long depthBlockCount; // How many depths available for a particular timing |
DepthInfo *depthBlocks; // Array of DepthInfo |
Str255 displayModeName; // name of the timing mode |
}; |
typedef struct ListIteratorDataRec ListIteratorDataRec; |
void PrintCurrentVideoSetting (GDHandle walkDevice); |
void DisplayVideoSettings (void); |
void PrintAvailableVideoSettingsDM1 (GDHandle walkDevice); |
void PrintAvailableVideoSettingsDM2 (GDHandle walkDevice, |
DMDisplayModeListIteratorUPP myModeIteratorProc, |
DMListIndexType theDisplayModeCount, |
DMListType *theDisplayModeList); |
pascal void ModeListIterator ( void *userData, |
DMListIndexType itemIndex, |
DMDisplayModeListEntryPtr displaymodeInfo); |
// routine implementations |
void main(void) |
{ |
DisplayVideoSettings (); |
} |
//-------------------------------------------------------------- |
// |
// Implementation of sample code |
// |
//-------------------------------------------------------------- |
void PrintCurrentVideoSetting (GDHandle walkDevice) |
{ |
unsigned long displayMgrVersion; |
OSErr error = paramErr; |
CntrlParam pBlock; |
VDSwitchInfoRec switchInfo; |
AuxDCEHandle theDCE; |
VDSwitchInfoRec videoMode; |
Gestalt(gestaltDisplayMgrVers, (long*)&displayMgrVersion); |
if (displayMgrVersion >= 0x00020000) |
{ // get the info the DM 2.0 way |
error = DMGetDisplayMode(walkDevice, &switchInfo); |
if (noErr == error) |
{ |
printf ("Current Settings DM2 - displayMode: %d, depthMode: %d\n", switchInfo.csData, switchInfo.csMode); |
} |
return; |
} |
else |
{ // get the info the DM 1.0 way |
videoMode.csMode = -1; // init to bogus value |
videoMode.csData = -1; // init to bogus value |
pBlock.ioNamePtr = nil; |
pBlock.ioCRefNum = (*(walkDevice))->gdRefNum; |
pBlock.csCode = cscGetCurMode; |
*(Ptr *)&pBlock.csParam[0] = (Ptr)&videoMode; |
error = PBStatusSync((ParmBlkPtr )&pBlock); // ask the driver first....since we trust it the most |
if ( noErr == error && ((-1 == videoMode.csMode) || (-1 == videoMode.csData)) ) |
error = statusErr; |
if (noErr != error) // if the driver has no clue fill it videoMode by hand as a last resort |
{ |
theDCE = (AuxDCEHandle)GetDCtlEntry((*(walkDevice))->gdRefNum); |
if( theDCE ) |
{ |
videoMode.csData = (unsigned char)(*theDCE)->dCtlSlotId; |
videoMode.csMode = (*(walkDevice))->gdMode; |
error = noErr; |
} |
} |
if (noErr == error) |
{ |
printf ("Current Settings DM1 - displayMode: %d, depthMode: %d\n", videoMode.csData, videoMode.csMode); |
} |
return; |
} |
} |
void DisplayVideoSettings (void) |
{ |
Boolean displayMgrPresent; |
short iCount = 0; // just a counter of GDevices we have seen |
DMDisplayModeListIteratorUPP myModeIteratorProc = nil; // for DM2.0 searches |
SpBlock spBlock; |
Boolean suppliedGDevice; |
DisplayIDType theDisplayID; // for DM2.0 searches |
DMListIndexType theDisplayModeCount; // for DM2.0 searches |
DMListType theDisplayModeList; // for DM2.0 searches |
long value = 0; |
GDHandle walkDevice = nil; // for everybody |
Gestalt(gestaltDisplayMgrAttr,&value); |
displayMgrPresent=value&(1<<gestaltDisplayMgrPresent); |
displayMgrPresent=displayMgrPresent && (SVersion(&spBlock)==noErr); // need slot manager |
if (displayMgrPresent) // and Display Manager |
{ |
walkDevice = DMGetFirstScreenDevice (dmOnlyActiveDisplays); // for everybody |
suppliedGDevice = false; |
myModeIteratorProc = NewDMDisplayModeListIteratorProc(ModeListIterator); // for DM2.0 searches |
// Note that we are hosed if somebody changes the gdevice list behind our backs while we are iterating.... |
// ...now do the loop if we can start |
if( walkDevice && myModeIteratorProc) do // start the search |
{ |
iCount++; // GDevice we are looking at (just a counter) |
printf("=================================================\n"); |
printf("GDevice #%d (0x%X) at location (%d,%d).\n",iCount, *walkDevice, (long )(*walkDevice)->gdRect.left, (long )(*walkDevice)->gdRect.top); |
printf("=================================================\n\n"); |
PrintCurrentVideoSetting (walkDevice); |
if( noErr == DMGetDisplayIDByGDevice( walkDevice, &theDisplayID, false ) ) // DM1.0 does not need this, but it fits in the loop |
{ |
theDisplayModeCount = 0; // for DM2.0 searches |
if (noErr == DMNewDisplayModeList(theDisplayID, 0, 0, &theDisplayModeCount, &theDisplayModeList) ) |
{ |
// search NuBus & PCI the new kool way through Display Manager 2.0 |
// printf("\nAvailable Video Settings DM2.0 way\n"); |
PrintAvailableVideoSettingsDM2 (walkDevice, myModeIteratorProc, theDisplayModeCount, &theDisplayModeList); |
DMDisposeList(theDisplayModeList); // now toss the lists for this gdevice and go on to the next one |
} |
else |
{ |
// search NuBus only the old disgusting way through the slot manager |
printf("\nAvailable Video Settings DM1.0 way\n"); |
PrintAvailableVideoSettingsDM1 (walkDevice); |
} |
} |
printf("\n\n\n"); |
} while ( !suppliedGDevice && nil != (walkDevice = DMGetNextScreenDevice ( walkDevice, dmOnlyActiveDisplays )) ); // go until no more gdevices |
if( myModeIteratorProc ) |
DisposeRoutineDescriptor(myModeIteratorProc); |
return; |
} |
} |
void PrintAvailableVideoSettingsDM1 (GDHandle walkDevice) |
{ |
AuxDCEHandle myAuxDCEHandle; |
unsigned long depthMode; |
unsigned long displayMode; |
OSErr error; |
OSErr errorEndOfTimings; |
short height; |
short jCount = 0; |
Boolean modeOk; |
SpBlock spAuxBlock; |
SpBlock spBlock; |
unsigned long switchFlags; |
VPBlock *vpData; |
short width; |
myAuxDCEHandle = (AuxDCEHandle) GetDCtlEntry((**walkDevice).gdRefNum); |
spBlock.spSlot = (**myAuxDCEHandle).dCtlSlot; |
spBlock.spID = (**myAuxDCEHandle).dCtlSlotId; |
spBlock.spExtDev = (**myAuxDCEHandle).dCtlExtDev; |
spBlock.spHwDev = 0; // we are going to get this pup |
spBlock.spParamData = 1<<foneslot; // this slot, enabled, and it better be here. |
spBlock.spTBMask = 3; // don't have constants for this yet |
errorEndOfTimings = SGetSRsrc(&spBlock); // get the spDrvrHW so we know the ID of this puppy. This is important |
// since some video cards support more than one display, and the spDrvrHW |
// ID can, and will, be used to differentiate them. |
if ( noErr == errorEndOfTimings ) |
{ |
// reinit the param block for the SGetTypeSRsrc loop, keep the spDrvrHW we just got |
spBlock.spID = 0; // start at zero, |
spBlock.spTBMask = 2; // 0b0010 - ignore DrvrSW - why ignore the SW side? Is it not important for video? |
spBlock.spParamData = (1<<fall) + (1<<foneslot) + (1<<fnext); // 0b0111 - this slot, enabled or disabled, so we even get 640x399 on Blackbird |
spBlock.spCategory=catDisplay; |
spBlock.spCType=typeVideo; |
errorEndOfTimings = SGetTypeSRsrc(&spBlock); // but only on 7.0 systems, not a problem since we require DM1.0 |
// now, loop through all the timings for this GDevice |
if ( noErr == errorEndOfTimings ) do |
{ |
// now, loop through all possible depth modes for this timing mode |
displayMode = (unsigned char)spBlock.spID; // "timing mode, ie:resource ref number" |
for (jCount = firstVidMode; jCount<= sixthVidMode; jCount++) |
{ |
depthMode = jCount; // vid mode |
error = DMCheckDisplayMode(walkDevice,displayMode,depthMode,&switchFlags,0,&modeOk); |
// only if the mode okay |
if (noErr == error && modeOk) |
{ |
// have a good displayMode/depthMode combo - now lets look inside |
spAuxBlock = spBlock; // don't ruin the iteration spBlock!! |
spAuxBlock.spID = depthMode; // vid mode |
error=SFindStruct(&spAuxBlock); // get back a new spsPointer |
if (noErr == error) // keep going if no errorÉ |
{ |
spAuxBlock.spID = 0x01; // mVidParams request |
error=SGetBlock (&spAuxBlock); // use the new spPointer and get back...a NewPtr'ed spResult |
if (noErr == error) // Ékeep going if no errorÉ |
{ // We have data! lets have a look |
vpData = (VPBlock*)spAuxBlock.spResult; |
height = vpData->vpBounds.bottom; // left and top are usually zero |
width = vpData->vpBounds.right; |
// print screen data |
printf("\nTiming Mode: %d\n", displayMode); |
printf("Depth Mode: %d, Depth: %d, Resolution: %dH x %dV\n", |
depthMode, |
vpData->vpPixelSize, |
vpData->vpBounds.right, |
vpData->vpBounds.bottom); |
printf("Components per Pixel: %d, bits per Component: %d\n", |
vpData->vpCmpCount, |
vpData->vpCmpSize); |
printf("Switch flags:\n"); |
if (switchFlags & 1<<kNoSwitchConfirmBit) |
printf(" Confirmation not required,\n"); |
else |
printf(" Confirmation required,\n"); |
if (switchFlags & 1<<kDepthNotAvailableBit) |
printf(" Current depth not available in this mode,\n"); |
else |
printf(" Current depth available in this mode,\n"); |
if (switchFlags & 1<<kShowModeBit) |
printf(" Always shown,\n"); |
else |
printf(" Not always shown,\n"); |
if (switchFlags & 1<<kModeNotResizeBit) |
printf(" Not resizeable,\n"); |
else |
printf(" Resizeable\n"); |
if (spAuxBlock.spResult) DisposePtr ((Ptr)spAuxBlock.spResult); // toss this puppy when done |
} |
} |
} |
} |
// go around again, looking for timing modes for this GDevice |
spBlock.spTBMask = 2; // ignore DrvrSW |
spBlock.spParamData = (1<<fall) + (1<<foneslot) + (1<<fnext); // next resource, this slot, whether enabled or disabled |
errorEndOfTimings = SGetTypeSRsrc(&spBlock); // and get the next timing mode |
} while ( noErr == errorEndOfTimings ); // until the end of this GDevice |
} |
} |
pascal void ModeListIterator(void *userData, DMListIndexType, DMDisplayModeListEntryPtr displaymodeInfo) |
{ |
unsigned long depthCount; |
short iCount; |
ListIteratorDataRec *myIterateData = (ListIteratorDataRec*) userData; |
DepthInfo *myDepthInfo; |
// printf ("\n now in ModeListIterator\n"); |
// set display data in a round about way |
// Set the basics |
myIterateData->displayModeFlags = displaymodeInfo->displayModeFlags; // Info on this particular display mode |
myIterateData->displayModeSwitchInfo = *displaymodeInfo->displayModeSwitchInfo; // not needed - depth info has this per depth |
myIterateData->displayModeResolutionInfo = *displaymodeInfo->displayModeResolutionInfo; // refresh rate, pixels/lines at max depth |
myIterateData->displayModeTimingInfo = *displaymodeInfo->displayModeTimingInfo; // to get the flags on timing mode |
PStrCopy ((StringPtr)&myIterateData->displayModeName, (ConstStr255Param)*displaymodeInfo->displayModeName); // the name of the mode |
// now get the DMDepthInfo into memory we own |
depthCount = displaymodeInfo->displayModeDepthBlockInfo->depthBlockCount; |
myDepthInfo = (DepthInfo*)NewPtrClear(depthCount * sizeof(DepthInfo)); |
// set the info for the caller |
myIterateData->depthBlockCount = depthCount; |
myIterateData->depthBlocks = myDepthInfo; |
// and fill out all the entries |
if (depthCount) for (iCount=0; iCount < depthCount; iCount++) |
{ |
myDepthInfo[iCount].depthSwitchInfo = |
*displaymodeInfo->displayModeDepthBlockInfo->depthVPBlock[iCount].depthSwitchInfo; |
myDepthInfo[iCount].depthVPBlock = |
*displaymodeInfo->displayModeDepthBlockInfo->depthVPBlock[iCount].depthVPBlock; |
} |
} |
void PrintAvailableVideoSettingsDM2 (GDHandle walkDevice, |
DMDisplayModeListIteratorUPP myModeIteratorProc, |
DMListIndexType theDisplayModeCount, |
DMListType *theDisplayModeList) |
{ |
short jCount; |
short kCount; |
ListIteratorDataRec searchData; |
double_t refreshRate; |
unsigned long switchFlags; |
Boolean modeOk; |
OSErr error; |
searchData.depthBlocks = nil; |
// get the mode lists for this GDevice |
// printf ("\n about to start DMGetIndexedDisplayModeFromList loop\n"); |
for (jCount=0; jCount<theDisplayModeCount; jCount++) // get info on all the resolution timings |
{ |
DMGetIndexedDisplayModeFromList(*theDisplayModeList, jCount, 0, myModeIteratorProc, &searchData); |
// printf ("\n just did a DMGetIndexedDisplayModeFromList\n"); |
// only if the mode is valid |
// if (searchData.displayModeTimingInfo.csTimingFlags & 1<<kModeValid) |
{ |
// for all the depths for this resolution timing (mode)... |
printf("\nTiming mode: %d (or 0x%X) named Ò%sÓ\n", |
searchData.depthBlocks[0].depthSwitchInfo.csData, |
searchData.depthBlocks[0].depthSwitchInfo.csData, |
P2CStr(searchData.displayModeName)); |
refreshRate = Fix2X (searchData.displayModeResolutionInfo.csRefreshRate); |
refreshRate = round (refreshRate); |
if (refreshRate == 0) |
printf ("Refresh rate: 0 (not defined in displayModeResolutionInfo.csRefreshRate)\n"); |
else |
printf ("Refresh rate: %g\n", refreshRate); |
if (searchData.displayModeResolutionInfo.csResolutionFlags & 1<<kResolutionHasMultipleDepthSizes) |
printf("DisplayMode has different H&V per bit depth\n"); |
else |
printf("DisplayMode does not have different H&V per bit depth\n"); |
{ |
char tempArr[6]; |
ResType* tempPtr = (ResType* )&tempArr[0]; // Make a convenient ptr to assign the restype |
*tempPtr = searchData.displayModeTimingInfo.csTimingFormat; // contents of string are the resType |
tempArr[4] = 0; // null temp the string |
printf("Timing format: Ò%sÓ. Timing csData %d\n", tempArr, searchData.displayModeTimingInfo.csTimingData); |
} |
printf("Available depths:\n"); |
if (searchData.depthBlockCount) for (kCount = 0; kCount < searchData.depthBlockCount; kCount++) |
{ |
// print all the timing information |
printf(" Depth: %d, Depth mode: 0x%X, Resolution: %dH x %dV\n", |
searchData.depthBlocks[kCount].depthVPBlock.vpPixelSize, |
searchData.depthBlocks[kCount].depthSwitchInfo.csMode, |
searchData.depthBlocks[kCount].depthVPBlock.vpBounds.right, |
searchData.depthBlocks[kCount].depthVPBlock.vpBounds.bottom); |
// printf("Components per Pixel: %d, bits per Component: %d\n", |
// searchData.depthBlocks[kCount].depthVPBlock.vpCmpCount, |
// searchData.depthBlocks[kCount].depthVPBlock.vpCmpSize); |
} |
error = DMCheckDisplayMode(walkDevice, |
searchData.depthBlocks[0].depthSwitchInfo.csData, |
searchData.depthBlocks[0].depthSwitchInfo.csMode, |
&switchFlags, |
0, |
&modeOk); |
if (noErr == error && modeOk) |
{ |
printf("Switch flags = 0x%X\n", switchFlags); |
if (switchFlags & 1<<kNoSwitchConfirmBit) |
printf(" Confirmation not required,\n"); |
else |
printf(" Confirmation required,\n"); |
if (switchFlags & 1<<kDepthNotAvailableBit) |
printf(" Current depth not available in this mode,\n"); |
else |
printf(" Current depth available in this mode,\n"); |
if (switchFlags & 1<<kShowModeBit) |
printf(" Always shown,\n"); |
else |
printf(" Not always shown,\n"); |
if (switchFlags & 1<<kModeNotResizeBit) |
printf(" Not resizeable,\n"); |
else |
printf(" Resizeable\n"); |
} |
// timing flags |
printf("Timing flags = 0x%X\n",searchData.displayModeTimingInfo.csTimingFlags); |
if (searchData.displayModeTimingInfo.csTimingFlags & 1<<kModeValid) |
printf(" Valid,\n",searchData.displayModeTimingInfo.csTimingFlags); |
else |
printf(" Invalid,\n",searchData.displayModeTimingInfo.csTimingFlags); |
if (searchData.displayModeTimingInfo.csTimingFlags & 1<<kModeSafe) |
printf(" Safe,\n"); |
else |
printf(" Unsafe,\n"); |
if (searchData.displayModeTimingInfo.csTimingFlags & 1<<kModeDefault) |
printf(" Default,\n"); |
else |
printf(" Not default,\n"); |
if (searchData.displayModeTimingInfo.csTimingFlags & 1<<kModeShowNow) |
printf(" Always shown,\n"); |
else |
printf(" Not always shown,\n"); |
if (searchData.displayModeTimingInfo.csTimingFlags & 1<<kModeNotResize) |
printf(" Not resizeable,\n"); |
else |
printf(" Resizeable,\n"); |
if (searchData.displayModeTimingInfo.csTimingFlags & 1<<kModeRequiresPan) |
printf(" Requires pan.\n"); |
else |
printf(" No pan.\n"); |
// mode flags |
printf("Mode flags = 0x%X\n",searchData.displayModeFlags); |
if (searchData.displayModeFlags & 1<<0) |
printf(" Stripped,\n"); |
else |
printf(" Not Stripped,\n"); |
} |
if (searchData.depthBlocks) |
{ |
DisposePtr ((Ptr)searchData.depthBlocks); // toss for this timing mode of this gdevice |
searchData.depthBlocks = nil; // init it just so we know |
} |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14