/* Copyright (c) 2017, Computer History Museum All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "icon.h" #define FILE_NUM 62 /* Copyright (c) 1994 by QUALCOMM Incorporated */ #pragma segment Icon OSErr DT1GetIcon(short dtRef,OSType creator,OSType type,short iconType, Ptr data, short size); pascal Handle ICacheGetter(ResType theType,ICacheHandle ich); /********************************************************************** * PlotIconFromICache - plot an icon from a cache **********************************************************************/ OSErr PlotIconFromICache(ICacheHandle ich,IconTransformType transform,Rect *inRect) { if (ich) return (PlotIconSuite(inRect,atAbsoluteCenter,transform,(*ich)->cache)); else return (fnfErr); } /********************************************************************** * Names2Icon - turn names into an icon **********************************************************************/ short Names2Icon(PStr baseName,PStr modifierNames) { short id = 0; Str255 wholeName; Handle resH; OSType junk; PCopy(wholeName,modifierNames); PSCat(wholeName,baseName); SetResLoad(False); if (!(resH = GetNamedResource('icns',wholeName))) if (!(resH = GetNamedResource('icns',baseName))) if (!(resH = GetNamedResource('ICN#',wholeName))) if (!(resH = GetNamedResource('ICN#',baseName))) ; SetResLoad(True); if (!resH) return(0); GetResInfo(resH,&id,&junk,wholeName); return(id); } /********************************************************************** * ICacheToRgn - turn an icon cache into a region **********************************************************************/ OSErr ICacheToRgn(ICacheHandle ich,Rect *inRect,RgnHandle rgn) { if (ich) return (IconSuiteToRgn(rgn,inRect,atAbsoluteCenter,(*ich)->cache)); else return (fnfErr); } /********************************************************************** * ICacheGetter - all the work **********************************************************************/ pascal Handle ICacheGetter(ResType theType,ICacheHandle ich) { OSErr err = noErr; Handle data,resH; typedef struct {short dtType; short size; OSType suiteType;} IconDesc, *IconDescPtr, **IconDescHandle; IconDescPtr idp; short dtRef; static IconDesc descList[] = { kLargeIcon, kLargeIconSize, large1BitMask, kLarge4BitIcon, kLarge4BitIconSize, large4BitData, kLarge8BitIcon, kLarge8BitIconSize, large8BitData, kSmallIcon, kSmallIconSize, small1BitMask, kSmall4BitIcon, kSmall4BitIconSize, small4BitData, kSmall8BitIcon, kSmall8BitIconSize, small8BitData }; idp = descList + sizeof(descList)/sizeof(IconDesc) - 1; // last item! while ( idp >= descList && idp->suiteType != theType ) idp--; if ( idp < descList ) return NULL; ASSERT ( idp->suiteType == theType ); if (data = NuHandle(idp->size)) { /* * if we haven't found the right desktop file yet, find it now */ if (!(*ich)->dtRefValid) { // Find the correct desktop file short volIndex; short vRef; for (volIndex=1;!IndexVRef(volIndex,&vRef);volIndex++) if (!DTRef(vRef,&dtRef)) if (!DT1GetIcon(dtRef,(*ich)->creator,(*ich)->type,idp->dtType,LDRef(data),idp->size)) { // Found it here (*ich)->dtRef = dtRef; (*ich)->dtRefValid = true; break; } } else if ((*ich)->dtRef) err = DT1GetIcon((*ich)->dtRef,(*ich)->creator,(*ich)->type,idp->dtType,LDRef(data),idp->size); UL(data); /* * did we fail? */ if (err || !(*ich)->dtRef) { // no icon // if that's because we didn't find the app, return generic icon // or, if we did find the app but for some reason its icons are damaged, // return generic icon if asking for the B&W icon, since that icon // should always be present if ((!(*ich)->dtRef || theType==large1BitMask) && (resH=GetResource(theType,(*ich)->type=='APPL' ? genericApplicationIconResource:genericDocumentIconResource))) BMD(*resH,*data,idp->size); else ZapHandle(data); /* failure */ } } return(data); } /********************************************************************** * GetICache - find (or create) the icon cache entry for a type and creator **********************************************************************/ ICacheHandle GetICache(OSType type,OSType creator) { ICacheHandle ich; ICacheType ic; DECLARE_UPP(ICacheGetter,IconGetter); /* * is it there already? */ if (ich=FindICache(type,creator)) return(ich); /* * not there. gotta make it */ if (ich=NewH(ICacheType)) { Zero(ic); INIT_UPP(ICacheGetter,IconGetter); if (!MakeIconCache(&ic.cache,ICacheGetterUPP,ich)) { ic.magic = 'iCaC'; ic.type = type; ic.creator = creator; **ich = ic; LL_Push(ICache,ich); } else ZapHandle(ich); } return(ich); } #pragma segment Icon /********************************************************************** * FindICache - find the icon cache entry for a type and creator **********************************************************************/ ICacheHandle FindICache(OSType type,OSType creator) { ICacheHandle ich; for (ich=ICache;ich;ich=(*ich)->next) { if ((*ich)->type==type && (*ich)->creator==creator) break; } return(ich); } /********************************************************************** * DisposeICache - dispose of an entry in the ICache * returns non-zero if bytes were disposed of **********************************************************************/ long DisposeICache(ICacheHandle ich) { if (ich) { /* * pop it from the list */ LL_Remove(ICache,ich,(ICacheHandle)); /* * nuke the icon cache */ DisposeIconSuite((*ich)->cache,True); /* * and now the whole thing */ ZapHandle(ich); /* * found one! */ return(1); } return(0); } /************************************************************************ * DTGetIconInfo - get icon info ************************************************************************/ OSErr DTGetIconInfo(short dtRef,OSType creator, short index,OSType *type) { DTPBRec pb; short err; pb.ioCompletion = nil; pb.ioDTRefNum = dtRef; pb.ioIndex = index; pb.ioFileCreator = creator; if (err=PBDTGetIconInfo(&pb,False)) return(err); *type = pb.ioFileType; return(pb.ioResult); } /************************************************************************ * DT1GetIcon - find an icon for a creator ************************************************************************/ OSErr DT1GetIcon(short dtRef,OSType creator,OSType type,short iconType, Ptr data, short size) { DTPBRec pb; short err; Str63 appName; Zero(pb); pb.ioNamePtr = appName; pb.ioDTRefNum = dtRef; pb.ioFileCreator = creator; pb.ioFileType = type; pb.ioDTBuffer = data; pb.ioIconType = iconType; pb.ioDTReqCount = size; if (err=PBDTGetIcon(&pb,False)) return(err); return(pb.ioResult); } /********************************************************************** * NamedIconCalc - calc where things go in a named icon **********************************************************************/ void NamedIconCalc(Rect *inRect,PStr name,short hIndent,short vIndent,Rect *iconR,Point *textP) { short hi = RectHi(*inRect); short wi = RectWi(*inRect); Rect inner = *inRect; short iHi; short txFont = GetPortTextFont(GetQDGlobalsThePort()); short txSize = GetPortTextSize(GetQDGlobalsThePort()); InsetRect(&inner,hIndent,vIndent); if (hi<14+2*vIndent) { /* * no icons */ short lead = GetLeading(txFont,txSize); short descent = GetDescent(txFont,txSize); SetPt(textP,inner.left,inner.bottom - (inner.bottom-inner.top-lead)/2 - descent); SetRect(iconR,0,0,0,0); } else { if (hi<32+2*vIndent) { /* * small icons */ iHi = hi-2*vIndent; iHi = MIN(iHi,16); SetRect(iconR,0,0,iHi,iHi); CenterRectIn(iconR,&inner); if (wi>30) { OffsetRect(iconR,inner.left-iconR->left,0); textP->h = iconR->right + INSET; textP->v = iconR->top + GetLeading(txFont,txSize); } else textP->h = textP->v = 0; } else { SetRect(iconR,0,0,32,32); if (hi>40) { TopCenterRectIn(iconR,&inner); textP->v = iconR->bottom + GetAscent(txFont,txSize); textP->h = inRect->left + (RectWi(*inRect)-StringWidth(name))/2; textP->h = MAX(textP->h,inRect->left+hIndent); hi = (RectHi(inner)-(textP->v+FontDescent-inner.top))/2; if (hi<0) hi = (RectHi(inner)-32)/2; if (hi>0) { textP->v += hi; OffsetRect(iconR,0,hi); } } else { CenterRectIn(iconR,&inner); textP->h = textP->v = 0; } } } } /********************************************************************** * DupIconSuite - copy all the data out of an icon suite **********************************************************************/ OSErr DupIconSuite(Handle fromSuite,Handle *toSuite,Boolean reuseSuite) { OSErr err = noErr; Handle data, oldData; OSType types[] = { large1BitMask, large4BitData, large8BitData, small1BitMask, small4BitData, small8BitData, mini1BitMask, mini4BitData, mini8BitData }; short index; if (!fromSuite) return(fnfErr); if (!reuseSuite) *toSuite = nil; if (*toSuite || !(err=NewIconSuite(toSuite))) for (index=sizeof(types)/sizeof(OSType);!err && index--;) { if (!GetIconFromSuite(&data,fromSuite,types[index]) && data && // GetIconFromSuite may return no err even when there is no icon available !(err=MyHandToHand(&data))) { oldData = nil; if (reuseSuite && !GetIconFromSuite(&oldData,*toSuite,types[index]) && oldData) ZapHandle(oldData); err = AddIconToSuite(data,*toSuite,types[index]); } else if (reuseSuite && !GetIconFromSuite(&oldData,*toSuite,types[index]) && oldData) ZapHandle(oldData); } if (err && !reuseSuite) { if (*toSuite) DisposeIconSuite(*toSuite,True); } else SetSuiteLabel(*toSuite,GetSuiteLabel(fromSuite)); return(err); } /********************************************************************** * FSpGetCustomIconSuite - get a custom icon, if a file has one **********************************************************************/ Handle FSpGetCustomIconSuite(FSSpecPtr spec,short dataSelector) { short iconRes, oldResFile = CurResFile(); Handle rIconSuite, theIcon = nil; OSErr err; // open the file iconRes = FSpOpenResFile(spec,fsRdPerm); if (iconRes != -1) { // read in the icon err = GetIconSuite(&rIconSuite, kCustomIconResource, dataSelector); if (rIconSuite && *rIconSuite && (err==noErr)) { err = DupIconSuite(rIconSuite, &theIcon, false); if (err == noErr) { HNoPurge(theIcon); } } CloseResFile(iconRes); } UseResFile(oldResFile); return theIcon; } /********************************************************************** * DupDeskIconSuite - copy all the data out of an icon suite **********************************************************************/ OSErr DupDeskIconSuite(OSType type, OSType creator,Handle *toSuite) { OSErr err = noErr; Handle data; OSType types[] = { large1BitMask, large4BitData, large8BitData, small1BitMask, small4BitData, small8BitData }; short index; ICacheHandle ich = NewZH(ICacheType); DECLARE_UPP(ICacheGetter,IconGetter); if (!ich) return(fnfErr); *toSuite = nil; (*ich)->type = type; (*ich)->creator = creator; INIT_UPP(ICacheGetter,IconGetter); if (!(err=NewIconSuite(toSuite))) for (index=sizeof(types)/sizeof(OSType);!err && index--;) if ((data=ICacheGetter(types[index],ich)) && // GetIconFromSuite may return no err even when there is no icon available !(err=MyHandToHand(&data))) err = AddIconToSuite(data,*toSuite,types[index]); if (err) { if (*toSuite) DisposeIconSuite(*toSuite,True); *toSuite = nil; } return(err); } /************************************************************************ * PlotTinyIconAtPenID - plot a very small icon as though it were a character * Icon is small icon, scaled ************************************************************************/ void PlotTinyIconAtPenID(IconTransformType transform,short icon) { Rect tempR; Point penLoc; GetPortPenLocation(GetQDGlobalsThePort(),&penLoc); SetRect(&tempR,penLoc.h,penLoc.v-8,penLoc.h+8,penLoc.v); PlotIconID(&tempR,atNone,transform,icon); Move(12,0); } /************************************************************************ * PlotTinyULIconAtPenID - plot a very small icon as though it were a character * Icon lives in UL corner of small icon ************************************************************************/ void PlotTinyULIconAtPenID(IconTransformType transform,short icon) { Rect tempR; RgnHandle newClip = NewRgn(); RgnHandle oldClip; if (newClip) { Point penLoc; GetPortPenLocation(GetQDGlobalsThePort(),&penLoc); SetRect(&tempR,penLoc.h,penLoc.v-8,penLoc.h+8,penLoc.v); RectRgn(newClip,&tempR); oldClip = SavePortClipRegion(GetQDGlobalsThePort()); SetPortClipRegion(GetQDGlobalsThePort(),newClip); SectRgn(newClip,oldClip,newClip); tempR.bottom = tempR.top+16; tempR.right = tempR.left+16; PlotIconID(&tempR,atNone,transform,icon); RestorePortClipRegion(GetQDGlobalsThePort(),oldClip); DisposeRgn(newClip); } Move(12,0); } /************************************************************************ * RefreshRGBIcon - refresh a color icon ************************************************************************/ OSErr RefreshRGBIcon(short id,RGBColor *color,short template,Boolean *changed) { Str31 nameShdBe; Str255 nameIs; Handle res; long type; OSErr err = noErr; Boolean addIt = false; Handle maskSuite = nil; SetResLoad(false); res=Get1Resource('ICN#',id); if (!res && !(err=ResError())) err = resNotFound; /* if ( !res ) { err = ResError (); if ( !err ) err = resNotFound; } */ SetResLoad(true); if (err==resNotFound) addIt = true; else { GetResInfo(res,&id,&type,nameIs); Color2String(nameShdBe,color); addIt = !StringSame(nameShdBe,nameIs); } if (addIt) { if (template) GetIconSuite(&maskSuite, template, svAllAvailableData); err = RGBColorToIconFamily(color,id,nameShdBe,true,maskSuite); if (maskSuite) DisposeIconSuite(maskSuite,false); } if (changed) *changed = addIt && !err; return(err); } #ifdef LABEL_ICONS #define kicl8Size 1024 #define kics8Size 256 #define kicm8Size 192 #define kicl4Size 512 #define kics4Size 128 #define kicm4Size 96 #define kICNSize 256 #define kicnSize 64 #define kicmSize 48 OSErr RGBColorToNBitIcon( RGBColor* theColor, short bitDepth, short iconID, ConstStr255Param name, Boolean overWrite, Handle maskSuite ); OSErr GetNBitColors( short bitDepth, RGBColor* theColor, Byte maskIndex, Byte* colorIndex, Byte* compIndex, Boolean computeComposite ); void BuildNBitIconFromMask( Handle icon, Handle mask, Byte colorIndex, Byte compIndex, short bitDepth, short size ); OSErr RGBColorToIconFamily( RGBColor* theColor, short iconID, ConstStr255Param name, Boolean overWrite, Handle maskSuite ) { OSErr theErr; theErr = RGBColorToNBitIcon( theColor, 1, iconID, name, overWrite, maskSuite ); if( theErr ) return( theErr ); theErr = RGBColorToNBitIcon( theColor, 4, iconID, name, overWrite, maskSuite ); if( theErr ) return( theErr ); theErr = RGBColorToNBitIcon( theColor, 8, iconID, name, overWrite, maskSuite ); if( theErr ) return( theErr ); return( noErr ); } OSErr RGBColorToNBitIcon( RGBColor* theColor, short bitDepth, short iconID, ConstStr255Param name, Boolean overWrite, Handle maskSuite ) { enum { depth8, depth4, depth1 }; enum { large, small, mini, numIconSizes }; OSErr theErr; short tmpSize; Byte colorIndex, maskIndex=0, compIndex=0; short depthIndex, i; Handle icons[numIconSizes], masks[numIconSizes], tmpRes, mask; static struct IconInfo{ short depth; long type[numIconSizes]; short size[numIconSizes]; } iconInfo[] = { depth8, {kLarge8BitData, kSmall8BitData, kMini8BitData}, {kicl8Size, kics8Size, kicm8Size}, depth4, {kLarge4BitData, kSmall4BitData, kMini4BitData}, {kicl4Size, kics4Size, kicm4Size}, depth1, {kLarge1BitMask, kSmall1BitMask, kMini1BitMask}, {kICNSize, kicnSize, kicmSize } }; switch( bitDepth ) { case 8: depthIndex = depth8; break; case 4: depthIndex = depth4; break; case 1: depthIndex = depth1; break; default: return( paramErr ); break; } if( maskSuite ) { for( i=0; ired )/2; tmpRGB.green = ( tmpRGB.green + theColor->green )/2; tmpRGB.blue = ( tmpRGB.blue + theColor->blue )/2; *compIndex = Color2Index( &tmpRGB ); } SetGWorld( oldPort, oldGD ); DisposeGWorld( offscreenGWorld ); return( theErr ); } void BuildNBitIconFromMask( Handle icon, Handle mask, Byte colorIndex, Byte compIndex, short bitDepth, short size ) { short i, j; Byte byteVal; if( mask ) { switch( bitDepth ) { case 1: //bit by bit... for( i=0; i