/*------------------------------------------------------------------------------ # # MacOSª Sample Code # # Written by: Eric Anderson # AppleLink: ERIC3 # AOL: ERICTHREE # # Display Manager sample code # # RequestVideo # # RequestVideo.c - C Code # # Copyright © 1995 Apple Computer, Inc. # All rights reserved. # # 5/31/95 ewa Added RVGetCurrentVideoSetting and RVConfirmVideoRequest routines # to make it easy to revert back to where you came from and to give # the user a chance to confirm the new setting if the new mode was # valid (ie: the card supports it) but not safe (the monitor may not). # 5/24/95 ewa Give the kAllValidModesBit requestFlags option for safe only or all # valid resolution timings. # # # # Components: PlayVideo.c # RequestVideo.c # RequestVideo.h # RequestVideo.rsrc # # RequestVideo demonstrates the usage of the Display Manager introduced # with the PowerMacs and integrated into the system under System 7.5. With # the RequestVideo sample code library, developers will be able to explore # the Display Manager API by changing bit depth and screen resolution on # multisync displays on built-in, NuBus, and PCI based video. Display Manager 1.0 # is built into the Systems included with the first PowerMacs up through System 7.5. # Display Manager 2.0 is included with the release of the new PCI based PowerMacs, # and will be included in post 7.5 System Software releases. # # It is a good idea to reset the screen(s) to the original setting before exit # since the call to RVSetVideoAsScreenPrefs() may not do the right thing under # Display Manager 1.0 with certain video drivers. # # For information on the use of this sample code, please the documentation in the Read Me file ------------------------------------------------------------------------------*/ #include "RequestVideo.h" // Internal includes #include #include #include #include #include #include #include #include #include #include #include //-------------------------------------------------------------- // // Internal defines, structs, typedefs, and routine declarations // //-------------------------------------------------------------- #define KMonoDev 0 // false (handy definitions for gdDevType settings) #define kColorDev 1 // true #define char_Enter 0x03 // for our filter proc #define char_Return 0x0D // #define iRevertItem 1 // User buttons #define iConfirmItem 2 // #define kSecondsToConfirm 8 // seconds before confirm dialog is taken down #define rConfirmSwtchAlrt 2735 // ID of alert dialog 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 { VDTimingInfoRec displayModeTimingInfo; // Contains timing flags and such unsigned long depthBlockCount; // How many depths available for a particular timing DepthInfo *depthBlocks; // Array of DepthInfo }; typedef struct ListIteratorDataRec ListIteratorDataRec; void GetRequestTheDM1Way ( VideoRequestRecPtr requestRecPtr, GDHandle walkDevice); void GetRequestTheDM2Way ( VideoRequestRecPtr requestRecPtr, GDHandle walkDevice, DMDisplayModeListIteratorUPP myModeIteratorProc, DMListIndexType theDisplayModeCount, DMListType *theDisplayModeList); pascal void ModeListIterator ( void *userData, DMListIndexType itemIndex, DMDisplayModeListEntryPtr displaymodeInfo); Boolean FindBestMatch ( VideoRequestRecPtr requestRecPtr, short bitDepth, unsigned long horizontal, unsigned long vertical); void GravitateMonitors (void); pascal Boolean ConfirmAlertFilter (DialogPtr dlg, EventRecord *evt, short *itemHit); Handle myHACK = 0; //-------------------------------------------------------------- // // Implementation of sample code // //-------------------------------------------------------------- OSErr RVSetVideoRequest (VideoRequestRecPtr requestRecPtr) { GDHandle aMonitor; Boolean displayMgrPresent; unsigned long displayMgrVersion; OSErr err; Boolean isColor; long value = 0; Gestalt(gestaltDisplayMgrVers, (long*)&displayMgrVersion); Gestalt(gestaltDisplayMgrAttr,&value); displayMgrPresent=value&(1<displayMode && requestRecPtr->depthMode) { if (requestRecPtr->availBitDepth == 1) // Based on avail bit depth, isColor = KMonoDev; // set the device to a mono device, or else isColor = kColorDev; // set the device to a color device SetDeviceAttribute(requestRecPtr->screenDevice,gdDevType,isColor); // see how many monitors we have, aMonitor will be nil if we have only one. aMonitor = DMGetFirstScreenDevice (dmOnlyActiveDisplays); // get the first guy aMonitor = DMGetNextScreenDevice ( aMonitor, dmOnlyActiveDisplays ); // get the next guy if (nil == aMonitor || displayMgrVersion >= 0x00020000) { // only call DMSetDisplayMode if we have one monitor or DM2.0 is installed // since DM1.0 does not automatically gravitate monitors and our gravitate code // is not implemented. err = DMSetDisplayMode( requestRecPtr->screenDevice, // GDevice requestRecPtr->displayMode, // DM1.0 uses this &requestRecPtr->depthMode, // DM1.0 uses this (unsigned long) &(requestRecPtr->switchInfo), // DM2.0 uses this rather than displayMode/depthMode combo myHACK); if (noErr == err) { // Do the monitor gravitate here if we are using a version less than DM2.0 if (displayMgrVersion < 0x00020000) GravitateMonitors (); } else if (kDMDriverNotDisplayMgrAwareErr == err) { // DM not supported by driver, so all we can do is set the bit depth err = SetDepth (requestRecPtr->screenDevice, requestRecPtr->depthMode, gdDevType, isColor); } } else { // we have more than one monitor and DM1.0 is installed, so all we can do is set the bit depth err = SetDepth (requestRecPtr->screenDevice, requestRecPtr->depthMode, gdDevType, isColor); } return (err); // we did try to set the request } } return (-1); // return a generic error } OSErr HackSetRequest (VideoRequestRecPtr requestRecPtr) { DMBeginConfigureDisplays(&myHACK); return RVSetVideoRequest(requestRecPtr); } OSErr HackRestoreRequest (VideoRequestRecPtr requestRecPtr) { OSErr ret; ret = RVSetVideoRequest(requestRecPtr); DMEndConfigureDisplays(myHACK); return ret; } OSErr RVGetCurrentVideoSetting (VideoRequestRecPtr requestRecPtr) { unsigned long displayMgrVersion; OSErr error = paramErr; CntrlParam pBlock; VDSwitchInfoRec switchInfo; AuxDCEHandle theDCE; VDSwitchInfoRec videoMode; requestRecPtr->availBitDepth = 0; // init to default - you can do it if it is important to you requestRecPtr->availHorizontal = 0; requestRecPtr->availVertical = 0; requestRecPtr->availFlags = 0; requestRecPtr->displayMode = -1; requestRecPtr->depthMode = -1; requestRecPtr->switchInfo.csMode = 0; requestRecPtr->switchInfo.csData = 0; requestRecPtr->switchInfo.csPage = 0; requestRecPtr->switchInfo.csBaseAddr = 0; requestRecPtr->switchInfo.csReserved = 0; Gestalt(gestaltDisplayMgrVers, (long*)&displayMgrVersion); if (requestRecPtr->screenDevice) { if (displayMgrVersion >= 0x00020000) { // get the info the DM 2.0 way error = DMGetDisplayMode(requestRecPtr->screenDevice, &switchInfo); if (noErr == error) { requestRecPtr->depthMode = switchInfo.csMode; requestRecPtr->displayMode = switchInfo.csData; requestRecPtr->switchInfo.csMode = switchInfo.csMode; requestRecPtr->switchInfo.csData = switchInfo.csData; } return (error); // we (maybe) set the world back to a known setting } 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 = (*(requestRecPtr->screenDevice))->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((*(requestRecPtr->screenDevice))->gdRefNum); if( theDCE ) { videoMode.csData = (unsigned char)(*theDCE)->dCtlSlotId; videoMode.csMode = (*(requestRecPtr->screenDevice))->gdMode; error = noErr; } } if (noErr == error) // Set our data { requestRecPtr->displayMode = videoMode.csData; requestRecPtr->depthMode = videoMode.csMode; requestRecPtr->switchInfo.csMode = videoMode.csMode; requestRecPtr->switchInfo.csData = videoMode.csData; } return (error); // we (maybe) set the world back to a known setting } } return (-1); } OSErr RVRequestVideoSetting (VideoRequestRecPtr requestRecPtr) { 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<screenDevice) // user wants a specifc device? { walkDevice = requestRecPtr->screenDevice; suppliedGDevice = true; } else { 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) 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 GetRequestTheDM2Way (requestRecPtr, 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 GetRequestTheDM1Way (requestRecPtr, walkDevice); } } } while ( !suppliedGDevice && nil != (walkDevice = DMGetNextScreenDevice ( walkDevice, dmOnlyActiveDisplays )) ); // go until no more gdevices if( myModeIteratorProc ) DisposeRoutineDescriptor(myModeIteratorProc); return (noErr); // we were able to get the look for a match } return (-1); // return a generic error } void GetRequestTheDM1Way (VideoRequestRecPtr requestRecPtr, 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<requestFlags & 1<vpBounds.bottom; // left and top are usually zero width = vpData->vpBounds.right; if (FindBestMatch (requestRecPtr, vpData->vpPixelSize, vpData->vpBounds.right, vpData->vpBounds.bottom)) { requestRecPtr->screenDevice = walkDevice; requestRecPtr->availBitDepth = vpData->vpPixelSize; requestRecPtr->availHorizontal = vpData->vpBounds.right; requestRecPtr->availVertical = vpData->vpBounds.bottom; requestRecPtr->displayMode = displayMode; requestRecPtr->depthMode = depthMode; requestRecPtr->switchInfo.csMode = depthMode; // fill in for completeness requestRecPtr->switchInfo.csData = displayMode; requestRecPtr->switchInfo.csPage = 0; requestRecPtr->switchInfo.csBaseAddr = 0; requestRecPtr->switchInfo.csReserved = 0; if (switchFlags & 1<availFlags = 0; // mode safe else requestRecPtr->availFlags = 1<displayModeTimingInfo = *displaymodeInfo->displayModeTimingInfo; // now get the DMDepthInfo info 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 GetRequestTheDM2Way ( VideoRequestRecPtr requestRecPtr, GDHandle walkDevice, DMDisplayModeListIteratorUPP myModeIteratorProc, DMListIndexType theDisplayModeCount, DMListType *theDisplayModeList) { short jCount; short kCount; ListIteratorDataRec searchData; searchData.depthBlocks = nil; // get the mode lists for this GDevice for (jCount=0; jCountrequestFlags & 1<screenDevice = walkDevice; requestRecPtr->availBitDepth = searchData.depthBlocks[kCount].depthVPBlock.vpPixelSize; requestRecPtr->availHorizontal = searchData.depthBlocks[kCount].depthVPBlock.vpBounds.right; requestRecPtr->availVertical = searchData.depthBlocks[kCount].depthVPBlock.vpBounds.bottom; // now set the important info for DM to set the display requestRecPtr->depthMode = searchData.depthBlocks[kCount].depthSwitchInfo.csMode; requestRecPtr->displayMode = searchData.depthBlocks[kCount].depthSwitchInfo.csData; requestRecPtr->switchInfo = searchData.depthBlocks[kCount].depthSwitchInfo; if (searchData.displayModeTimingInfo.csTimingFlags & 1<availFlags = 0; // mode safe else requestRecPtr->availFlags = 1<displayMode && ( (horizontal >= requestRecPtr->reqHorizontal && vertical >= requestRecPtr->reqVertical) || !(requestRecPtr->requestFlags & 1<reqBitDepth || !(requestRecPtr->requestFlags & 1<reqHorizontal && vertical == requestRecPtr->reqVertical && bitDepth == requestRecPtr->reqBitDepth) || !(requestRecPtr->requestFlags & 1<requestFlags & 1<availBitDepth != requestRecPtr->reqBitDepth ) && ( ( bitDepth > requestRecPtr->availBitDepth && bitDepth <= requestRecPtr->reqBitDepth ) || !(requestRecPtr->requestFlags & 1<availBitDepth < requestRecPtr->reqBitDepth && bitDepth > requestRecPtr->availBitDepth ) && ( (horizontal == requestRecPtr->reqHorizontal && vertical == requestRecPtr->reqVertical && bitDepth == requestRecPtr->reqBitDepth) || !(requestRecPtr->requestFlags & 1<reqHorizontal - horizontal)) <= abs((requestRecPtr->reqHorizontal - requestRecPtr->availHorizontal)) && abs((requestRecPtr->reqVertical - vertical)) <= abs((requestRecPtr->reqVertical - requestRecPtr->availVertical)) ) { // now we have a smaller or equal delta // if (h or v greater/equal to request or kMaximizeRes not set) if ( (horizontal >= requestRecPtr->reqHorizontal && vertical >= requestRecPtr->reqVertical) || !(requestRecPtr->requestFlags & 1<availBitDepth == bitDepth || !(requestRecPtr->requestFlags & 1<reqBitDepth || !(requestRecPtr->requestFlags & 1<availHorizontal != horizontal || requestRecPtr->availVertical != vertical) || (requestRecPtr->availBitDepth < requestRecPtr->reqBitDepth && bitDepth > requestRecPtr->availBitDepth) || (bitDepth == requestRecPtr->reqBitDepth) ) && ( (horizontal == requestRecPtr->reqHorizontal && vertical == requestRecPtr->reqVertical && bitDepth == requestRecPtr->reqBitDepth) || !(requestRecPtr->requestFlags & 1<