mac-rom/Toolbox/DisplayMgr/DisplayMgrUtils.c
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

1338 lines
43 KiB
C

/*
File: DisplayMgrUtils.c
Contains: Contains utility routines for Display Manager
Written by: Ian Hendry
Copyright: © 1993 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<11> 11/5/93 IH Sync with Excelsior.
<SM10> 10/10/93 IH Sync with Excelsior.
<9> 9/10/93 IH Fix cursor bug in horror ROMs and SuperMario..
<8> 8/26/93 IH #1108969 <KON>: Move Display Manager Apple event define to
Displays.h.
<7> 8/16/93 IH #1099391 <KON>: Fix apple event notification. Move some
utilities from DisplayMgr.c to here.
<6> 8/4/93 IH #1101633,1098397,1101795,1101636,1102280 <KON>: Fix 1102280:
return new device rect from declROM. Also bail gracefully if
there is no slot for a given gDevice.
<5> 6/25/93 IH Fix decl ROM lookup. (searched one level too far). It still
worked, but I'm not sure why.
<4> 6/22/93 IH Fix code to get timing information from DeclROM.
<3> 6/1/93 IH Add Utility call to timing mode info from Decl ROM.
<2> 5/28/93 IH #1081805,1086363: Add activeOnly booleans for
DMGetFirstScreenDevice and DMGetNextScreenDevice. Added some
warnings and comments for future development.
<1> 4/8/93 IH first checked in
*/
#ifndef __APPLEEVENTS__
#include <AppleEvents.h>
#endif
#ifndef __GESTALTEQU__
#include <GestaltEqu.h>
#endif
#ifndef __MENUS__
#include <Menus.h>
#endif
#ifndef __PROCESSES__
#include <Processes.h>
#endif
#ifndef __QDOFFSCREEN__
#include <QDOffscreen.h>
#endif
#ifndef __RESOURCES__
#include <Resources.h>
#endif
#ifndef __RETRACE__
#include <Retrace.h>
#endif
#ifndef __TOOLUTILS__
#include <ToolUtils.h> // Might want to get rid of "HiWord" and then I don't need this
#endif
#ifndef __SYSEQU__
#include <SysEqu.h>
#endif
#ifndef __ERRORS__
#include <Errors.h>
#endif
#ifndef __PALETTES__
#include <Palettes.h>
#endif
#ifndef __SLOTS__
#include <Slots.h>
#endif
#ifndef __VIDEO__
#include <Video.h>
#endif
#ifndef __ROMDEFS__
#include <ROMDefs.h>
#endif
#ifndef __DEVICES__
#include <Devices.h>
#endif
#ifndef __MENUMGRPRIV__
#include "MenuMgrPriv.h"
#endif
#ifndef __PALETTESPRIV__
#include "PalettesPriv.h"
#endif
#ifndef __PROCESSESPRIV__
#include "ProcessesPriv.h"
#endif
#ifndef __DATA__
#include "Data.h" // Needs a better way to get the PEntry struct (now in {Sources}ProcessMgr:Data.h
#endif
#ifndef __DISPLAYS__
#include "Displays.h"
#endif
#ifndef __DISPLAYSPRIV__
#include "DisplaysPriv.h"
#endif
#ifndef __EXPANDMEMPRIV__
#include "ExpandMemPriv.h"
#endif
Boolean IsActiveScreenDevice(GDHandle theDevice,Boolean activeOnly)
{
// Check to see that the device is non-nil
// Has a driver (i.e., non-zero refNum)
// and that it is a screen device
// and either that we do not care if it is active only or that it is active now
return( ( nil != theDevice ) &&
( 0 != (*theDevice)->gdRefNum ) &&
( TestDeviceAttribute(theDevice, mainScreen) || TestDeviceAttribute(theDevice, screenDevice) ) &&
( !activeOnly || TestDeviceAttribute(theDevice, screenActive)) );
}
/* GetActiveScreenDeviceCount() returns either number of active screen (if activeOnly is set true), or it
// returns the total number screen devices (if activeOnly is false).
*/
unsigned short
GetActiveScreenDeviceCount(
Boolean activeOnly)
{ GDHandle gDevice = DMGetFirstScreenDevice(activeOnly);
unsigned short activeScreenDeviceCount = 0;
while (nil != gDevice)
{ if (IsActiveScreenDevice(gDevice,activeOnly))
activeScreenDeviceCount++;
gDevice = DMGetNextScreenDevice(gDevice,activeOnly);
}
return(activeScreenDeviceCount);
}
GDHandle FindMaxCoverageDevice(const Rect* windowRect)
// Find the device with most area of the window
// Should we return nil if there is no intersection or should we return MainDevice?
//
// What about alerts and modals? They need to go completely on the screen (not just partially).
// How do I tell if a dialog has a title bar?
{
Rect checkRect; // Used to check whether the window intersects the device
Rect tempRect; // Rectangle of intersection between window and rect
unsigned long tempArea; // Temp coverage
unsigned long maxArea = 0; // Max coverage so far
GDHandle maxDevice = nil; // In case there is NO intersection with a device
GDHandle checkDevice = DMGetFirstScreenDevice(true); // Start to walk device list
while( checkDevice )
{
checkRect = (*checkDevice)->gdRect;
if( SectRect(&checkRect,windowRect,&tempRect) ) // Does rect hit device?
{
tempArea = (tempRect.right-tempRect.left)*(tempRect.bottom-tempRect.top);
if( tempArea > maxArea )
{
maxArea = tempArea;
maxDevice = checkDevice;
}
}
checkDevice = DMGetNextScreenDevice(checkDevice,true);
}
return(maxDevice);
}
GDHandle FindClosestDevice(const Rect* windowRect)
// MUST RETURN A DEVICE!!
{
Rect checkRect; // Used to check whether the window intersects the device
register long minDistanceSqrd = 0x7FFFFFFF; // Minimum Distance so far
register long testDistanceSqrd;
register long displayRadiusSqrd;
long displayX,displayY;
long xDist,yDist;
register GDHandle minDevice = GetMainDevice(); // In case there is NO intersection with a device
register GDHandle checkDevice = DMGetFirstScreenDevice(true); // Start to walk device list
while( checkDevice )
{
checkRect = (*checkDevice)->gdRect;
// We will be measuring distance from the center of the monitors to
// the center of the window.
//
// This may mean we favor small monitors (because the distance to their
// centers is smaller). I can always change it.
//
// We do not really want to spent a lot of time getting this just right
// so we adjust the size of the monitor
// from the distance.
xDist = (checkRect.left+checkRect.right)/2 - (windowRect->left+windowRect->right)/2;
yDist = (checkRect.top+checkRect.bottom)/2 - (windowRect->top+windowRect->bottom)/2;
displayX = checkRect.right - checkRect.left;
displayY = checkRect.bottom - checkRect.top;
displayRadiusSqrd = ( (checkRect.right - checkRect.left)*(checkRect.right - checkRect.left) +
(checkRect.bottom - checkRect.top)*(checkRect.bottom - checkRect.top) ) / 4;
displayRadiusSqrd = 0;
testDistanceSqrd = xDist*xDist + yDist*yDist - displayRadiusSqrd;
if( testDistanceSqrd < minDistanceSqrd )
{
minDistanceSqrd = testDistanceSqrd;
minDevice = checkDevice;
}
checkDevice = DMGetNextScreenDevice(checkDevice,true);
}
return(minDevice);
}
void GetWindowGlobalRegion(WindowPeek theWindow,RgnHandle windowRgn,Point *structOffset, Boolean isMovable,Boolean hasStructRgn)
{
Point portOffset;
Rect windowRect;
// Design Issue - Windows in hidden layers have empty structure regions
// Getting the struct window directly gets a better judge of the actual window position but
// it means window movement may be different depending on whether it is hidden.
//
if( hasStructRgn ) // When a layer is hidden, window regions are empty
{
UnionRgn( theWindow->strucRgn,theWindow->contRgn,windowRgn);
structOffset->v = (*theWindow->contRgn)->rgnBBox.top - (*theWindow->strucRgn)->rgnBBox.top;
structOffset->h = (*theWindow->contRgn)->rgnBBox.left - (*theWindow->strucRgn)->rgnBBox.left;
}
else
{
// In this case, we are not sure how big the structRgn of the window is because it is hidden.
// Therefore we have to guess.
//
// We guess the rect of the port with room for a titlebar
//
if( isMovable )
structOffset->v = kDefaultTitleBarHeight;
else structOffset->v = 0;
structOffset->h = 0;
windowRect = theWindow->port.portRect;
// DANGER - in resolution independent QD, the pixmap bounds are adjusted for the resolution of the device.
//
if( DM__IsColorPort( &theWindow->port ) )
portOffset = *(Point *)&(*((CGrafPtr )&theWindow->port)->portPixMap)->bounds.top;
else portOffset = *(Point *)&theWindow->port.portBits.bounds.top;
OffsetRect(&windowRect,-portOffset.h,-portOffset.v);
if( isMovable )
{
windowRect.top -= kDefaultTitleBarHeight; // Guess at window title height
windowRect.left -= kDefaultTitleBarHeight; // Guess at window title height
}
RectRgn(windowRgn,&windowRect);
// DANGER -- add more checks for known WDEFs. Are Truth WDEFs ever going to ship?
// If so they we need to handle them. Perhaps we need to keep the offsets in globals somewhere
// so I do not have to alter the code.
}
}
Rect *LocalPinRectToRect(register Rect *r,register Rect *pinRect)
{
register short dx,dv;
dx = pinRect->right - r->right;
if (dx<0) { r->left += dx; r->right += dx; }
else
{
dx = pinRect->left - r->left;
if (dx>0) { r->left += dx; r->right += dx; }
}
dv = pinRect->bottom - r->bottom;
if (dv<0) { r->top += dv; r->bottom += dv; }
else
{
dv = pinRect->top - r->top;
if (dv>0) { r->top += dv; r->bottom += dv; }
}
return r;
}
/*
Boolean TestFlagBit(unsigned long flagLong,short flagBit)
{
return( 0 != (flagLong & (1<<flagBit)) )
}
void SetFlagBit(unsigned long *flagLong,short flagBit)
{
flagLong |= (1<<flagBit);
}
*/
OSErr CheckExpandMem(Boolean allocateIfNeeded)
{
ExpandMemPtr newExpandMem = nil; // Set to non-nil if we need it
ExpandMemPtr savedExpandMem = GetExpandMem(); // How is expandmem now?
if( ((Ptr )-1) == savedExpandMem ) // -1 means not installed (we check for nil next)
savedExpandMem = nil;
if( nil == savedExpandMem || GetExpandMemVersion() < emCurVersion )
{
if( allocateIfNeeded )
newExpandMem = (ExpandMemPtr )NewPtrSysClear(sizeof(ExpandMemRec));
if( nil == newExpandMem )
{
SysError(dsMemFullErr); // Get error code and croak
return(memFullErr); // In case some Macsbug user wants to keep going, return an error
}
}
if( nil != newExpandMem ) // If we allocated a new expandmem, then install it
{
if( savedExpandMem ) // We blockmove if we have a source
BlockMove((Ptr )savedExpandMem,(Ptr )newExpandMem,savedExpandMem->emSize);
newExpandMem->emVersion = emCurVersion; // Just to be safe, I will make sure new ExpandMem is
newExpandMem->emSize = sizeof(ExpandMemRec); // completely correct before replacing the old ExpandMem
(*((ExpandMemPtr *)ExpandMem)) = newExpandMem; // Replace the old ExpandMem vector
if( savedExpandMem ) // If we allocated a newExpandMem,
DisposePtr( (Ptr )savedExpandMem ); // Then get rid of the old ExpandMem.
}
return( noErr );
}
OSErr GetGDeviceVideoMode(GDHandle theDevice,VDSwitchInfoPtr videoMode,Boolean* driverHasGetCurMode)
{
OSErr getModeErr;
CntrlParam pBlock;
AuxDCEHandle theDCE;
*driverHasGetCurMode = true;
pBlock.ioNamePtr = nil;
pBlock.ioCRefNum = (*theDevice)->gdRefNum;
pBlock.csCode = cscGetCurMode;
*(Ptr *)&pBlock.csParam[0] = (Ptr )videoMode;
getModeErr = PBStatusSync((ParmBlkPtr )&pBlock);
if( statusErr == getModeErr ) // If the call is not implemented in the driver, then fill it out by hand
{
*driverHasGetCurMode = false; // Mark that this driver does not support get video mode
theDCE = (AuxDCEHandle )GetDCtlEntry( (*theDevice)->gdRefNum );
if( theDCE )
{
videoMode->csMode = (*theDevice)->gdMode;
videoMode->csData = (unsigned char )(*theDCE)->dCtlSlotId;
videoMode->csPage = 0; // What should I set this to?
videoMode->csBaseAddr = (Ptr )(*theDCE)->dCtlDevBase;
videoMode->csReserved = 0;
getModeErr = noErr;
}
}
return(getModeErr);
}
OSErr SwitchVideoMode(GDHandle theDevice,VDSwitchInfoPtr newMode)
{
OSErr switchModeErr;
CntrlParam pBlock;
pBlock.ioNamePtr = nil;
pBlock.ioCRefNum = (*theDevice)->gdRefNum;
pBlock.csCode = cscSwitchMode;
*(Ptr *)&pBlock.csParam[0] = (Ptr )newMode;
HideCursor();
switchModeErr = PBControlSync((ParmBlkPtr )&pBlock);
DMMoveCursor(nil,nil);
ShowCursor();
return(switchModeErr);
}
OSErr GetDisplayConnection(GDHandle theDevice,VDDisplayConnectInfoPtr connectInfo)
{
OSErr connectionErr;
CntrlParam pBlock;
pBlock.ioNamePtr = nil;
pBlock.ioCRefNum = (*theDevice)->gdRefNum;
pBlock.csCode = cscGetConnection;
*(Ptr *)&pBlock.csParam[0] = (Ptr )connectInfo;
connectionErr = PBStatusSync((ParmBlkPtr )&pBlock);
return(connectionErr);
}
OSErr GetTimingMode(GDHandle theDevice,VDTimingInfoPtr timingInfo)
{
OSErr connectionErr;
CntrlParam pBlock;
pBlock.ioNamePtr = nil;
pBlock.ioCRefNum = (*theDevice)->gdRefNum;
pBlock.csCode = cscGetModeTiming;
*(Ptr *)&pBlock.csParam[0] = (Ptr )timingInfo;
connectionErr = PBStatusSync((ParmBlkPtr )&pBlock);
return(connectionErr);
}
Boolean DisplayHasMenu(GDHandle aDevice)
// Needs to change to support multiple menu bars.
{
// DANGER -- should we only check for hasAuxMenuBar (ie hasMenuBar)?
// Should we move this flag into internal data structures?
// Should we have a global that tell us so I don't have to change the code?
return( TestDeviceAttribute(aDevice, mainScreen) || TestDeviceAttribute(aDevice, hasAuxMenuBar) );
}
pascal OSErr DM_GetBestDepthModeInfo(GDHandle theDevice,VDSwitchInfoPtr modeInfo,unsigned long depthMode,short* bestDepth, Rect* modeRect)
//
// Return the mode number (128-133 or so) for the some depth
// or zero if no such mode available.
// This routine should be patched if we ever stop using the slot manager.
//
// depthMode = 0 => current device depth
// depthMode < 128 => Special constant (for now depth only)
// depthMode >=128 => Actual mode requested
{
SpBlock slotBlock;
Ptr savedSlotInfoPtr;
VPBlockPtr videoParams;
OSErr slotError;
OSErr modeInfoError;
unsigned char walkModes;
short depthSoFar = 0;
unsigned short theSlot;
unsigned short theID;
unsigned short theExtDev = 0,
tempExtDev;
Rect rectSoFar;
modeInfoError = GetDeviceSlotInfo(theDevice,&theSlot,&theID,&tempExtDev);
SetRect(&rectSoFar,0,0,0,0);
if( noErr == modeInfoError )
{
if( 0 == depthMode ) // Special case if depthmode is zero, then look for current depth
depthMode = (*(*theDevice)->gdPMap)->pixelSize;
if( 0 == modeInfo->csData )
{
modeInfo->csData = theID;
theExtDev = tempExtDev;
}
slotBlock.spParamData = (1<<fall)+(1<<foneslot); // Search only the specified slot and search all resources (even disabled)
slotBlock.spSlot = theSlot; // Which slot
slotBlock.spID = modeInfo->csData; // Funtional sResource ID if new screen mode
slotBlock.spExtDev = theExtDev; // Why - because you always do (although it seems to work even setting it to different values)
// slotBlock.spCategory = catDisplay; // We want only display sResources
// slotBlock.spCType = typeVideo; // We want only video sResources from the display card
// slotBlock.spDrvrSW = drSwApple; // We want only video sResources for an apple driver
// slotBlock.spTBMask = 1; // ignore spDrvrHW
// slotError = SGetTypeSRsrc(&slotBlock); // Find the slot resource DOES NOT WORK FOR THIS -- always gets next resource
// This is very lame if you happen to be trying to set to the last
// sResource (and then you get an error). I could try something fancy
// like setting the search bit (in case anyone ever pays attention to it)
// and subtracting one from the spID, but that is gross.
slotError = SGetSRsrc(&slotBlock); // Find the slot resource
if( noErr == slotError && // If I cannot use SGetTypeSRsrc, then I need to check my work.
(slotBlock.spCategory != catDisplay || slotBlock.spCType != typeVideo || slotBlock.spDrvrSW != drSwApple))
slotError = paramErr;
else
savedSlotInfoPtr = slotBlock.spsPointer; // Save the functional sResource table
if( noErr == slotError )
{
if ( 128 > depthMode ) // Search by depth
{
walkModes = 0x80; // Start looking for video parameters at 0x80;
while( walkModes != endOfList ) // Walk ALL the vidParams (even past holes)
{
slotBlock.spID = walkModes; // Look at walkModes
slotBlock.spsPointer = savedSlotInfoPtr; // Start at the functional sResource table
if( noErr == SFindStruct(&slotBlock) ) // Did I find a video mode?
{
slotBlock.spID = mVidParams; // Look for mVid parameters in the video mode
if( noErr == SGetBlock(&slotBlock) ) // Did I find them?
{
videoParams = (VPBlockPtr )slotBlock.spResult;
if( depthMode == videoParams->vpPixelSize ) // Is the video is the same depth?
{
depthSoFar = videoParams->vpPixelSize;
modeInfo->csMode = walkModes; // If so, we got what we came for
rectSoFar = videoParams->vpBounds;
modeInfoError = noErr; // We have a solution
break; // Go home with this mode
}
else // Otherwise update the closest mode
{
if( 0 == modeInfo->csMode || // If we have no candidate or this is closer to our desired depth
(depthSoFar < videoParams->vpPixelSize) && (depthMode > videoParams->vpPixelSize) )
{
// Best fit so far.
// We are going for as deep as possible without overshooting the old depth
// DANGER: this will screw up would be if the first entry was deeper than our desired depth
depthSoFar = videoParams->vpPixelSize; // Save where we are so far
modeInfo->csMode = walkModes; // Take this mode as a candidate
rectSoFar = videoParams->vpBounds; // Get the rect too
modeInfoError = noErr; // We have a candidate
}
}
DisposePtr((Ptr )videoParams); // SGetBlock always returns a pointer
videoParams = 0; // Zero it just to be paranoid
}
}
walkModes++;
}
if( videoParams ) // Did we exit loop with break?
DisposePtr((Ptr )videoParams); // If so then we leaked.
}
else // Search for real ID....
{
modeInfo->csMode = depthMode;
slotBlock.spID = depthMode; // Look at depthMode
slotBlock.spsPointer = savedSlotInfoPtr; // Start at the functional sResource table
if( noErr == SFindStruct(&slotBlock) ) // Did I find a video mode?
{
slotBlock.spID = mVidParams; // Look for mVid parameters in the video mode
if( noErr == SGetBlock(&slotBlock) ) // Did I find them?
{
videoParams = (VPBlockPtr )slotBlock.spResult;
depthSoFar = videoParams->vpPixelSize;
rectSoFar = videoParams->vpBounds;
DisposePtr((Ptr )videoParams); // SGetBlock always returns a pointer
videoParams = 0; // Zero it just to be paranoid
}
}
}
}
}
if( bestDepth )
*bestDepth = depthSoFar;
if( modeRect )
*modeRect = rectSoFar;
return(modeInfoError);
}
OSErr GetDeviceSlotInfo(GDHandle theDevice,unsigned short* theSlot,unsigned short* theID, unsigned short* theExtDev)
{
OSErr getSlotError;
short gdRefNum;
AuxDCEHandle theDCE;
if( theSlot ) *theSlot = 0;
if( theID ) *theID = 0;
if( theExtDev ) *theExtDev = 0;
getSlotError = unitEmptyErr;
gdRefNum = (*theDevice)->gdRefNum;
if( gdRefNum )
{
theDCE = *((*(AuxDCEHandle **)UTableBase) - (1+gdRefNum));
if( theDCE )
{
if( theSlot ) *theSlot = (*theDCE)->dCtlSlot;
if( theID ) *theID = (unsigned char )(*theDCE)->dCtlSlotId;
if( theExtDev ) *theExtDev = (*theDCE)->dCtlExtDev;
getSlotError = noErr;
}
}
return(getSlotError);
}
OSErr GetTimingFromDecl(GDHandle theDevice,short displayType,VDTimingInfoPtr declTiming)
{
#pragma unused(displayType);
SpBlock slotBlock;
OSErr slotError;
unsigned short theSlot;
slotError = GetDeviceSlotInfo(theDevice,&theSlot,nil,nil);
if( noErr == slotError )
{
declTiming->csTimingFormat = kDeclROMtables;
slotBlock.spParamData = (1<<foneslot); // Search only the specified slot and search only enalbed resources
slotBlock.spSlot = theSlot; // Which slot
slotBlock.spID = 0; // Funtional sResource ID if new screen mode
slotBlock.spExtDev = 0; // Why - because you always do (although it seems to work even setting it to different values)
slotBlock.spCategory = catBoard; // We want only baord sResources
slotBlock.spCType = typeBoard; // We want only baord sResources
slotBlock.spDrvrSW = 0; // We want do not care about this
slotBlock.spDrvrHW = 0; // We want do not care about this
slotBlock.spTBMask = 3; // ignore spDrvrHW && spDrvrHW
slotError = SGetTypeSRsrc(&slotBlock); // Find the slot resource WORKS FOR THIS -- always gets next resource
// We are searching for the first board sResource.
if( noErr == slotError )
{
slotBlock.spID = 0x7B;
slotError = SFindStruct(&slotBlock); // Look for video parameters in sVidAuxParams
if( noErr == slotError ) // Did I find a video parameters?
{
slotBlock.spID = declTiming->csTimingMode;
slotError == SReadLong(&slotBlock); // Look for timing mode
if( noErr == slotError )
declTiming->csTimingData = slotBlock.spResult; // Zero it just to be paranoid
}
}
}
return(slotError);
}
OSErr ConvertDisplayConfigToAERecord(DisplayConfigPtr displayConfig,AERecord* configList)
{
//
// displayConfig must be locked.
// configList must be locked returned complete of null.
//
OSErr convertError;
convertError = AECreateList(nil,0,true,configList);
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDMConfigVersion, typeLongInteger, (Ptr )&displayConfig->configVersion, sizeof(displayConfig->configVersion) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDMConfigFlags, typeLongInteger, (Ptr )&displayConfig->configFlags, sizeof(displayConfig->configFlags) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDMConfigReserved, typeLongInteger, (Ptr )&displayConfig->configReserved, sizeof(displayConfig->configReserved) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDisplayID, typeLongInteger, (Ptr )&displayConfig->displayID, sizeof(displayConfig->displayID) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDisplayComponent, typeLongInteger, (Ptr )&displayConfig->displayComponent, sizeof(displayConfig->displayComponent) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDisplayDevice, typeLongInteger, (Ptr )&displayConfig->displayDevice, sizeof(displayConfig->displayDevice) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDisplayFlags, typeLongInteger, (Ptr )&displayConfig->displayFlags, sizeof(displayConfig->displayFlags) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDisplayMode, typeLongInteger, (Ptr )&displayConfig->displayMode, sizeof(displayConfig->displayMode) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDisplayModeReserved, typeLongInteger, (Ptr )&displayConfig->displayModeReserved, sizeof(displayConfig->displayModeReserved) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDisplayReserved, typeLongInteger, (Ptr )&displayConfig->displayReserved, sizeof(displayConfig->displayReserved) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDeviceFlags, typeShortInteger, (Ptr )&displayConfig->deviceFlags, sizeof(displayConfig->deviceFlags) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDeviceDepthMode, typeLongInteger, (Ptr )&displayConfig->deviceDepthMode, sizeof(displayConfig->deviceDepthMode) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyDeviceRect, typeQDRectangle, (Ptr )&displayConfig->deviceRect, sizeof(displayConfig->deviceRect) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapRect, typeQDRectangle, (Ptr )&displayConfig->pixMapRect, sizeof(displayConfig->pixMapRect) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapHResolution, typeFixed, (Ptr )&displayConfig->pixMapHResolution, sizeof(displayConfig->pixMapHResolution) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapVResolution, typeFixed, (Ptr )&displayConfig->pixMapVResolution, sizeof(displayConfig->pixMapVResolution) );
// if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapAlignment, typeLongInteger, (Ptr )&displayConfig->pixMapAlignment, sizeof(displayConfig->pixMapAlignment) ); // be ready for res-ind QD
// if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapReserved, typeLongInteger, (Ptr )&displayConfig->pixMapResReserved, sizeof(displayConfig->pixMapResReserved) ); // be ready for res-ind QD
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapPixelType, typeShortInteger, (Ptr )&displayConfig->pixMapPixelType, sizeof(displayConfig->pixMapPixelType) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapPixelSize, typeShortInteger, (Ptr )&displayConfig->pixMapPixelSize, sizeof(displayConfig->pixMapPixelSize) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapCmpCount, typeShortInteger, (Ptr )&displayConfig->pixMapCmpCount, sizeof(displayConfig->pixMapCmpCount) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapCmpSize, typeShortInteger, (Ptr )&displayConfig->pixMapCmpSize, sizeof(displayConfig->pixMapCmpSize) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapReserved, typeLongInteger, (Ptr )&displayConfig->pixMapReserved, sizeof(displayConfig->pixMapReserved) );
if( noErr == convertError ) convertError = AEPutKeyPtr( configList,keyPixMapColorTableSeed, typeLongInteger, (Ptr )&displayConfig->pixMapColorTableSeed, sizeof(displayConfig->pixMapColorTableSeed) );
if( noErr != convertError )
AEDisposeDesc(configList);
return(convertError);
}
OSErr BuildDisplayConfigHandle(DisplayConfigHdl *displayConfigs,short *displayCount)
{
DisplayConfigRec tempConfig;
short localDisplayCount;
DisplayConfigHdl localDisplayConfigs;
short displayIndex;
GDHandle walkDisplay = DMGetFirstScreenDevice(false);
OSErr buildError;
buildError = DMSetDisplayID(nil,0); // Make sure all current displays have displayIDs
if( noErr == buildError )
{
while( walkDisplay )
{
localDisplayCount++;
walkDisplay = DMGetNextScreenDevice(walkDisplay,false);
}
localDisplayConfigs = (DisplayConfigHdl )NewHandleClear( sizeof(DisplayConfigRec)*localDisplayCount );
buildError = MemError();
}
if( noErr != buildError )
{
localDisplayCount = 0;
localDisplayConfigs = nil;
}
else
{
displayIndex = 0;
walkDisplay = DMGetFirstScreenDevice(false);
while( walkDisplay ) // Walk the displays and fill in the display configuration information
{
GetDisplayConfig(walkDisplay,&tempConfig); // Get the config
(*localDisplayConfigs)[displayIndex++] = tempConfig; // Copy config to handle
walkDisplay = DMGetNextScreenDevice(walkDisplay,false);
}
}
*displayCount = localDisplayCount; // Return the corrct followers
*displayConfigs = localDisplayConfigs; // Set the followers
return(buildError);
}
static short PartitionDisplayConfigs(DisplayConfigPtr configArray,short leftBound, short rightBound)
{
DisplayConfigRec tempDisplayConfigs;
short keyIndex;
short leftIndex;
short rightIndex;
keyIndex = rightBound--;
leftIndex = leftBound;
rightIndex = rightBound;
while( leftIndex < rightIndex )
{
while( (leftIndex < rightBound) && (configArray[leftIndex].displayID < configArray[keyIndex].displayID) )
leftIndex++;
while( (leftBound < rightIndex) && (configArray[keyIndex].displayID < configArray[rightIndex].displayID) )
rightIndex--;
if( (leftIndex < rightIndex) )
{
tempDisplayConfigs = configArray[rightIndex];
configArray[rightIndex] = configArray[leftIndex];
configArray[leftIndex] = tempDisplayConfigs;
}
}
if( configArray[keyIndex].displayID < configArray[leftIndex].displayID )
{
tempDisplayConfigs = configArray[keyIndex];
configArray[keyIndex] = configArray[leftIndex];
configArray[leftIndex] = tempDisplayConfigs;
keyIndex = leftIndex; // Return the left index
}
return(keyIndex);
}
static void SortDisplayConfigs(DisplayConfigPtr configArray,short startSort,short endSort)
{
short splitIndex;
if( startSort < endSort )
{
splitIndex = PartitionDisplayConfigs(configArray,startSort,endSort);
SortDisplayConfigs(configArray,0,splitIndex-1);
SortDisplayConfigs(configArray,splitIndex+1,endSort);
}
}
void InitAEDesc(AEDesc* theDesc)
{
theDesc->descriptorType = typeNull;
theDesc->dataHandle = nil;
}
OSErr BuildNotificationAppleEvent(DisplaysStateHdl displayState,AERecord* notifyRecord)
{
OSErr buildError = noErr;
short newIndex = 0;
short oldIndex = 0;
short oldDisplayCount = (*displayState)->displayCount;
DisplayConfigHdl oldDisplayConfigs = (*displayState)->displayConfigs;
short newDisplayCount;
DisplayConfigHdl newDisplayConfigs;
DisplayIDType newID,oldID,workingID;
AERecord oldConfigDesc,newConfigDesc;
AERecord displayDesc;
AERecord notifyDesc;
InitAEDesc(&notifyDesc); // Init this because we use it if something goes wrong
InitAEDesc(&displayDesc); // Init this just to be sure
buildError = BuildDisplayConfigHandle(&newDisplayConfigs,&newDisplayCount);
if( noErr == buildError )
{
SortDisplayConfigs(*newDisplayConfigs,0,newDisplayCount-1);
SortDisplayConfigs(*oldDisplayConfigs,0,oldDisplayCount-1);
#if DEBUG_DISPLAY_CODE
{
short countCheck = oldDisplayCount;
DisplayConfigPtr configCheck = *oldDisplayConfigs;
while( countCheck-- )
{
if( countCheck && configCheck[countCheck].displayID < configCheck[countCheck-1].displayID )
DMDebugStr("\p Sort 1 failed");
}
}
{
short countCheck = newDisplayCount;
DisplayConfigPtr configCheck = *newDisplayConfigs;
while( countCheck-- )
{
if( countCheck && configCheck[countCheck].displayID < configCheck[countCheck-1].displayID )
DMDebugStr("\p Sort 2 failed");
}
}
#endif
if( noErr == buildError )
buildError = AECreateList(nil,0,true,&notifyDesc); // Create list for display descriptors (keyed by displayID)
//
// Both lists are sorted, so we can merge them together.
//
while( (noErr == buildError) && ((oldIndex < oldDisplayCount) || (newIndex < newDisplayCount)) )
{
DisplayConfigRec tempDisplayConfig;
buildError = AECreateList(nil,0,true,&displayDesc); // Pairs of display pre and post (except for added displays)
InitAEDesc(&newConfigDesc);
InitAEDesc(&oldConfigDesc);
oldID = (*oldDisplayConfigs)[oldIndex].displayID;
newID = (*newDisplayConfigs)[newIndex].displayID;
if( (oldID == newID) && (oldIndex < oldDisplayCount) && (newIndex < newDisplayCount) ) // Build Before/After Event
{
workingID = oldID;
tempDisplayConfig = (*oldDisplayConfigs)[oldIndex++];
buildError = ConvertDisplayConfigToAERecord(&tempDisplayConfig, &oldConfigDesc);
if( noErr == buildError )
{
tempDisplayConfig = (*newDisplayConfigs)[newIndex++];
buildError = ConvertDisplayConfigToAERecord(&tempDisplayConfig, &newConfigDesc);
}
}
else if( (newIndex >= newDisplayCount) || // if we are at the end of the new displays all the remaining displays must be old
((oldIndex < oldDisplayCount) && (oldID < newID)) ) // Build deleted display event
{
DMDebugStr("\p Deleted Display");
workingID = oldID;
tempDisplayConfig = (*oldDisplayConfigs)[oldIndex++];
buildError = ConvertDisplayConfigToAERecord(&tempDisplayConfig, &oldConfigDesc);
}
else // Build new display event
{
DMDebugStr("\p Added Display");
workingID = newID;
tempDisplayConfig = (*newDisplayConfigs)[newIndex++];
buildError = ConvertDisplayConfigToAERecord(&tempDisplayConfig, &newConfigDesc);
}
if( noErr == buildError )
buildError = AEPutKeyDesc(&displayDesc,keyDisplayOldConfig,&oldConfigDesc);
if( noErr == buildError )
buildError = AEPutKeyDesc(&displayDesc,keyDisplayNewConfig,&newConfigDesc);
if( noErr == buildError )
buildError = AEPutKeyDesc(&notifyDesc,workingID,&displayDesc);
AEDisposeDesc(&oldConfigDesc);
AEDisposeDesc(&newConfigDesc);
AEDisposeDesc(&displayDesc);
}
if( noErr != buildError ) // If we got an error, then pass an empty event
AEDisposeDesc(&notifyDesc); // Just so there is SOME notification
}
*notifyRecord = notifyDesc;
return(buildError);
}
pascal OSErr DM_GetGDeviceByDisplayID(DisplayIDType displayID, GDHandle* displayDevice, Boolean failToMain)
{
OSErr getDeviceError = kDMDisplayNotFoundErr;
DisplayManagerGlobalsPtr dmGlobals = GetDMGlobalsPtr();
DisplayInfoPtr displayWalk = *dmGlobals->fDisplayTable;
short displayCount = dmGlobals->fDisplayCount;
*displayDevice = nil;
if( dmGlobals )
{
while(displayCount--)
{
if( displayID == displayWalk->displayID )
{
*displayDevice = displayWalk->displayDevice;
getDeviceError = noErr;
break;
}
displayWalk++;
}
if( nil == *displayDevice && failToMain)
*displayDevice = GetMainDevice();
}
else
getDeviceError = kDMSWNotInitializedErr;
return(getDeviceError);
}
pascal OSErr DM_GetDisplayIDByGDevice(GDHandle displayDevice, DisplayIDType *displayID, Boolean failToMain)
{
OSErr getDeviceError = kDMDisplayNotFoundErr;
DisplayManagerGlobalsPtr dmGlobals = GetDMGlobalsPtr();
DisplayInfoPtr displayWalk = *dmGlobals->fDisplayTable;
short displayCount = dmGlobals->fDisplayCount;
*displayID = nil;
if( dmGlobals )
{
while(displayCount--)
{
if( displayDevice == displayWalk->displayDevice )
{
*displayID = displayWalk->displayID;
getDeviceError = noErr;
break;
}
displayWalk++;
}
if( nil == *displayID && failToMain)
{
GDHandle mainDevice = GetMainDevice();
getDeviceError = DMGetDisplayIDByGDevice(GetMainDevice(), displayID, false);
}
}
else
getDeviceError = kDMSWNotInitializedErr;
return(getDeviceError);
}
DisplayInfoPtr DM_GetDisplayInfoByGDevice(GDHandle displayDevice,Boolean failToMain)
// Warning: DM_GetDisplayInfoByGDevice returns a pointer into an unlocked handle
// do not move memory.
{
DisplayInfoPtr displayInfo = nil;
DisplayManagerGlobalsPtr dmGlobals = GetDMGlobalsPtr();
if( displayDevice && dmGlobals && dmGlobals->fDisplayTable && dmGlobals->fDisplayCount )
{
short displayCount = dmGlobals->fDisplayCount;
DisplayInfoPtr walkdisplays = *dmGlobals->fDisplayTable;
while(displayCount--)
{
if( walkdisplays->displayDevice == displayDevice )
{
displayInfo = walkdisplays;
break;
}
walkdisplays++;
}
}
if( (nil == displayInfo) && failToMain )
{
GDHandle theMainDevice = GetMainDevice();
if( theMainDevice != displayDevice )
displayInfo = DM_GetDisplayInfoByGDevice(theMainDevice,false);
}
return(displayInfo);
}
DisplayInfoPtr DM_GetDisplayInfoByDisplayID(DisplayIDType displayID,Boolean failToMain)
{
// Warning: DM_GetDisplayInfoByDisplayID returns a pointer into an unlocked handle
// do not move memory.
DisplayInfoPtr displayInfo = nil;
DisplayManagerGlobalsPtr dmGlobals = GetDMGlobalsPtr();
if( dmGlobals && dmGlobals->fDisplayTable && dmGlobals->fDisplayCount )
{
short displayCount = dmGlobals->fDisplayCount;
DisplayInfoPtr walkdisplays = *dmGlobals->fDisplayTable;
while(displayCount--)
{
if( walkdisplays->displayID == displayID )
{
displayInfo = walkdisplays;
break;
}
walkdisplays++;
}
}
if( (nil == displayInfo) && failToMain )
displayInfo = DM_GetDisplayInfoByGDevice(GetMainDevice(),false);
return(displayInfo);
}
pascal OSErr DM_SwapDevices(GDHandle device1, GDHandle device2)
{
OSErr swapError = paramErr;
DisplayInfoPtr displayInfo1 = DM_GetDisplayInfoByGDevice(device1,false);
DisplayInfoPtr displayInfo2 = DM_GetDisplayInfoByGDevice(device2,false);
// Warning: DM_GetDisplayInfoByGDevice returns a pointer into an unlocked handle
// do not move memory.
if( displayInfo1 && displayInfo2 )
{
displayInfo1->displayDevice = device2;
displayInfo2->displayDevice = device1;
swapError = noErr;
}
return(swapError);
}
OSErr DM_SetDisplayInfoByDisplayID(DisplayInfoPtr newDisplayInfo)
{
OSErr setInfoError = noErr;
DisplayManagerGlobalsPtr dmGlobals = GetDMGlobalsPtr();
DisplayInfoPtr currentDisplayInfo = DM_GetDisplayInfoByDisplayID(newDisplayInfo->displayID,false);
if(currentDisplayInfo)
*currentDisplayInfo = *newDisplayInfo;
else
{
if( dmGlobals )
{
if( dmGlobals->fDisplayTable )
SetHandleSize( (Handle )dmGlobals->fDisplayTable,sizeof(DisplayInfoRec)*(dmGlobals->fDisplayCount+1) );
else dmGlobals->fDisplayTable = (DisplayInfoHdl )NewHandleSysClear(sizeof(DisplayInfoRec));
setInfoError = MemError();
if( noErr == setInfoError )
(*dmGlobals->fDisplayTable)[dmGlobals->fDisplayCount++] = *newDisplayInfo;
}
}
return(setInfoError);
}
OSErr DM_DeleteDisplayInfoByDisplayID(DisplayIDType displayID)
{
OSErr setInfoError = noErr;
DisplayManagerGlobalsPtr dmGlobals = GetDMGlobalsPtr();
DisplayInfoPtr currentDisplayInfo = DM_GetDisplayInfoByDisplayID(displayID,false);
if(currentDisplayInfo)
{
long offset = (long )(char *)currentDisplayInfo-(long )*dmGlobals->fDisplayTable;
Handle mungeee = (Handle )dmGlobals->fDisplayTable;
DMDebugStr("\p About to munge data string");
Munger(mungeee,offset,nil,sizeof(DisplayInfoRec),(Ptr)-1,0);
}
return(setInfoError);
}
void InitNewDisplayInfo( DisplayIDType displayID,
ComponentInstance displayComponent,
GDHandle displayDevice,
unsigned long displayFlags,
unsigned long displayReserved,
DisplayInfoPtr newdisplayInfo)
{
if( 0 == displayID )
displayID = GetDMGlobalsPtr()->fDisplayNextID++;
newdisplayInfo->displayID = displayID;
newdisplayInfo->displayComponent = displayComponent;
newdisplayInfo->displayDevice = displayDevice;
newdisplayInfo->displayFlags = displayFlags;
newdisplayInfo->displayReserved = displayReserved;
}
void GetDisplayConfig(GDHandle displayDevice,DisplayConfigPtr displayConfig)
{
PixMapHandle displayPixMap;
DisplayInfoPtr displayInfo;
DisplayInfoRec saveDisplayInfo;
VDSwitchInfoRec videoMode;
Boolean hasGetCurMode;
if( displayDevice )
{
displayInfo = DM_GetDisplayInfoByGDevice(displayDevice,false);
if( displayInfo )
saveDisplayInfo = *displayInfo; // Gotten from unlocked handle, so I make a copy
}
if( displayDevice && displayInfo )
{
displayPixMap = (*displayDevice)->gdPMap;
if( noErr == GetGDeviceVideoMode(displayDevice,&videoMode,&hasGetCurMode) )
{
displayConfig->displayMode = videoMode.csData; // Functional sResource (for NuBus)
displayConfig->displayModeReserved = videoMode.csReserved; // Reserved mode info
}
displayConfig->configVersion = kDMConfigLatestVersion;
displayConfig->configFlags = 0;
displayConfig->configReserved = 0;
displayConfig->displayID = saveDisplayInfo.displayID;
displayConfig->displayComponent = saveDisplayInfo.displayComponent;
displayConfig->displayDevice = saveDisplayInfo.displayDevice;
displayConfig->displayFlags = saveDisplayInfo.displayFlags;
// displayConfig->displayMode; // filled above
// displayConfig->displayModeReserved; // filled above
displayConfig->displayReserved = 0;
// Information about the display state
displayConfig->deviceFlags = (*displayDevice)->gdFlags; // Reserved
displayConfig->deviceDepthMode = (*displayDevice)->gdMode; // Functional sResource (for NuBus)
displayConfig->deviceRect = (*displayDevice)->gdRect;
displayConfig->pixMapRect = (*displayPixMap)->bounds;
displayConfig->pixMapHResolution = (*displayPixMap)->hRes;
displayConfig->pixMapVResolution = (*displayPixMap)->vRes;
displayConfig->pixMapAlignment = 0; // be ready for res-ind QD
displayConfig->pixMapResReserved = 0;
displayConfig->pixMapPixelType = (*displayPixMap)->pixelType;
displayConfig->pixMapPixelSize = (*displayPixMap)->pixelSize;
displayConfig->pixMapCmpCount = (*displayPixMap)->cmpCount;
displayConfig->pixMapCmpSize = (*displayPixMap)->cmpSize;
displayConfig->pixMapReserved = 0;
displayConfig->pixMapColorTableSeed = (*(*displayPixMap)->pmTable)->ctSeed;
}
else // We have no device handle, so we just slam everything
{
char* zeroWalker = (char*)displayConfig;
short zeroCounter = sizeof(DisplayConfigRec);
while(zeroCounter--)
*zeroWalker++ = 0;
}
}
#if DEBUG_DISPLAY_CODE
/*----------------------------------------------------------------------
| Determine if the stack builds up or down
|
| Formerly, this peeked at the values on the stack; now it just
| checks the address of the parameters.
----------------------------------------------------------------------*/
static short StackDirection( short one, short two, short three )
{
if( &three > &two ) return( 1 );
if( &one > &two ) return( -1 );
DebugStr( "\pStackDirection didn't work" );
return( 0 );
}
/*----------------------------------------------------------------------
| Convert a long to a hexadecimal ascii string. The string
| pointer provided is advanced past the last character converted.
----------------------------------------------------------------------*/
static void InsertHexNumberInPstr( Str255 pstr, unsigned long number )
{
unsigned long highDigits;
long n;
highDigits = number >> 4;
if( highDigits )
InsertHexNumberInPstr( pstr, highDigits );
n = (unsigned char) (number & 0x0F);
pstr[++pstr[0]] = (unsigned char) ( n > 9 ? 'A' + (n - 10) : n + '0' );
}
/*----------------------------------------------------------------------
| This routine takes a source string, a destination string and
| an array of long integers. The source string contains exactly
| one tilde character ("~") for every element in the array of
| longs. The source string is copied to the destination string; in
| the process, every tilde is replaced with a hexadecimal
| representation of one of the items from the array.
----------------------------------------------------------------------*/
static void BuildNumberPstr( Str255 pSrc, Str255 pDest, long *number )
{
short index = 0;
unsigned char len = pSrc[0];
short i = 1;
pDest[0] = 0;
while( len-- )
{
if( pSrc[i] == '~' )
{
InsertHexNumberInPstr( pDest, number[index] );
index += StackDirection( 1, 2, 3 );
}
else if( pSrc[i] == '@' )
{
char* t = (char*) (&number[index]);
pDest[++pDest[0]] = t[0];
pDest[++pDest[0]] = t[1];
pDest[++pDest[0]] = t[2];
pDest[++pDest[0]] = t[3];
index += StackDirection( 1, 2, 3 );
}
else
{
pDest[++pDest[0]] = pSrc[i];
}
++i;
}
}
#endif
void BuildMessage( Str255 msg, Str255 pstr, long number, ... )
{
#if DEBUG_DISPLAY_CODE
BuildNumberPstr( pstr, msg, &number );
#else
#pragma unused(pstr, msg, number)
#endif
}