JPEGView/Source/C/JPEGViewEventHandlers.c
Aaron Giles 92bdb55672 JPEGView 3.3 for Macintosh
These are the sources for the final official release of JPEGView for the
Mac, back in 1994.
2015-02-05 00:18:10 -08:00

1 line
16 KiB
C

/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information. */
/* Contact email: mac@aarongiles.com */
/*********************************************************/
//=====================================================================================
// Generic includes for Macintosh headers
//=====================================================================================
#if THINK_C
#include "THINK.Header"
#elif applec
#pragma load ":Headers:MPW.Header"
#elif __MWERKS__
//#include "MW.Header"
#else
#include "JPEGView.h"
#endif
//=====================================================================================
// Includes specific to this module
//=====================================================================================
#include "JPEGViewEventHandlers.h"
//=====================================================================================
// Prototypes for functions local to this module
//=====================================================================================
static OSErr DrawToDummyPort(ImageHandle theImage, Rect *srcRect, Rect *dstRect);
static PicHandle MyOpenCPicture(Rect *dstRect, ImageHandle theImage);
static Boolean WasDesktop(FSSpec *spec, Boolean recursive, ICMProgressProcRecordPtr theProg,
OSErr *theErr);
//=====================================================================================
// pascal OSErr HandleQuantize(AppleEvent *theEvent, AppleEvent *reply, long refCon)
//=====================================================================================
// Handles the quantize image AppleEvent, from the JPEGView suite.
//=====================================================================================
extern pascal OSErr HandleQuantize(AppleEvent *theEvent, AppleEvent *reply, long refCon)
{
#if applec
#pragma unused(refCon)
#endif
ObjectTokenHandle theToken;
PaletteHandle thePalette;
CTabHandle theColors;
ImageHandle theImage;
OSErr theErr = noErr;
AEDesc theObject;
long numColors;
AEBegin();
theErr = AEExtractObject(theEvent, keyDirectObject, &theObject);
if (theErr == noErr) {
theErr = AEExtractLong(theEvent, keyColorCount, &numColors);
if (theErr == noErr) {
theToken = (ObjectTokenHandle)theObject.dataHandle;
if (theObject.descriptorType == cImage) {
if ((*theToken)->count == 1) {
theImage = FindImage((WindowPtr)(*theToken)->object[0]);
StartSpinning();
theErr = DoQuantize(theImage, numColors, &thePalette, nil);
StopSpinning(&qd.arrow);
if (theErr == noErr) {
if (theColors = (CTabHandle)NewHandle(4)) {
Palette2CTab(thePalette, theColors);
HLock((Handle)theColors);
if (reply->dataHandle)
theErr = AEPutParamPtr(reply, keyAEResult, typeColorTable, (void *)*theColors, GetHandleSize((Handle)theColors));
DisposeHandle((Handle)theColors);
} else theErr = memFullErr;
DisposePalette(thePalette);
}
} else theErr = errAENotASingleObject;
} else theErr = errAECantHandleClass;
}
AEDisposeDesc(&theObject);
}
AEEnd();
return theErr;
}
//=====================================================================================
// pascal OSErr HandleSlideShow(AppleEvent *theEvent, AppleEvent *reply, long refCon)
//=====================================================================================
// Handles the JPEGView slide show AppleEvent, from the JPEGView suite.
//=====================================================================================
extern pascal OSErr HandleSlideShow(AppleEvent *theEvent, AppleEvent *reply, long refCon)
{
#if applec
#pragma unused(reply, refCon)
#endif
long theLong, theCount, theIndex, actualSize;
DescType theType, theKey;
NestedProgress theProc = { { nil, 0 }, 0, 0L, 0L, false };
ICMProgressProcRecordPtr progPtr = (ICMProgressProcRecordPtr)&theProc;
OSErr theErr = noErr;
Boolean theBoolean;
FSSpec theFile;
AEDesc theList;
theProc.prog.progressProc = gGenericProgress;
theProc.prog.progressRefCon = (long)&theProc;
if (gSlideShow) return noErr;
AEBegin();
theErr = AEExtractLong(theEvent, keyDelay, &theLong);
if (theErr == noErr) (*gSlideOptions)->delay = theLong;
theErr = AEExtractBoolean(theEvent, keyFilenames, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->fileNames = theBoolean;
theErr = AEExtractBoolean(theEvent, keyFromDisk, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->fromMemory = !theBoolean;
theErr = AEExtractBoolean(theEvent, keyIgnoreErrors, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->noErrors = theBoolean;
theErr = AEExtractBoolean(theEvent, keyImportFiles, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->allFiles = theBoolean;
theErr = AEExtractBoolean(theEvent, keyRandom, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->random = theBoolean;
theErr = AEExtractBoolean(theEvent, keyRepeat, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->repeat = theBoolean;
theErr = AEExtractBoolean(theEvent, keyScanRecursive, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->recursive = theBoolean;
theErr = AEExtractBoolean(theEvent, keyUserControl, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->userControl = theBoolean;
theErr = AEExtractBoolean(theEvent, keyOffscreen, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->offscreen = theBoolean;
theErr = AEExtractBoolean(theEvent, keyAutoComments, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->autoComments = theBoolean;
theErr = AEExtractBoolean(theEvent, keyHideWindoids, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->hideWindoids = theBoolean;
theErr = AEExtractBoolean(theEvent, keyHideControls, &theBoolean);
if (theErr == noErr) (*gSlideOptions)->hideControls = theBoolean;
theErr = AEExtractBoolean(theEvent, keyScreenSaver, &theBoolean);
if (theErr == noErr) gScreenSaver = theBoolean;
else gScreenSaver = false;
if (gScreenSaver) gScreenSaverPoint = GlobalMouse();
theErr = AEGetParamDesc(theEvent, keyDirectObject, typeAEList, &theList);
if (theErr == noErr) {
if (!(*gSlideOptions)->fromMemory) {
StartSpinning();
theErr = AECountItems(&theList, &theCount);
if (theErr == noErr) {
ParamText(gString[strScanningDirectory], gNullString, gNullString, gNullString);
if (progPtr)
CallICMProgressProc(progPtr->progressProc, codecProgressOpen, kIndefProgress, progPtr->progressRefCon);
for (theIndex = 1; theIndex <= theCount; theIndex++) {
if (theErr != noErr) break;
theErr = AEGetNthPtr(&theList, theIndex, typeFSS, &theKey, &theType, (void *)&theFile, sizeof(FSSpec), &actualSize);
if (theErr == noErr) {
if (gScreenSaver) gSlideShow = true;
if (!WasDesktop(&theFile, (*gSlideOptions)->recursive, progPtr, &theErr))
theErr = AddSlideDir(&theFile, (*gSlideOptions)->recursive, progPtr, nil);
if (gScreenSaver) gSlideShow = false;
} else theErr = errAEBadListItem;
}
if (progPtr)
CallICMProgressProc(progPtr->progressProc, codecProgressClose, kIndefProgress, progPtr->progressRefCon);
} else theErr = errAEWrongDataType;
}
if (theErr == noErr) {
InitSlideShow();
gIntError = noErr;
} else CleanUpSlideShow();
AEDisposeDesc(&theList);
StopSpinning(&qd.arrow);
}
AEEnd();
return theErr;
}
//=====================================================================================
// pascal OSErr HandleCopy(AppleEvent *theEvent, AppleEvent *reply, long refCon)
//=====================================================================================
// Handles the Copy AppleEvent, from the Miscellaneous Events suite.
//=====================================================================================
extern pascal OSErr HandleCopy(AppleEvent *theEvent, AppleEvent *reply, long refCon)
{
#if applec
#pragma unused(theEvent, reply, refCon)
#endif
OSErr theErr;
AEBegin();
theErr = DoCopy();
AEEnd();
return theErr;
}
extern OSErr DoCopy(void)
{
ImageHandle theImage = FrontImage();
Boolean dontDispose = false;
OSErr theErr = noErr;
PicHandle thePict;
if (theImage) {
theErr = GetSelectedPICT(theImage, &thePict);
if (theErr == noErr) {
if (!thePict) {
thePict = (PicHandle)(*theImage)->data;
dontDispose = true;
}
ZeroScrap();
UnloadScrap();
HLock((Handle)thePict);
PutScrap(GetHandleSize((Handle)thePict), kPICTType, StripAddress((Ptr)*thePict));
if (!dontDispose) DisposeHandle((Handle)thePict);
} else if (theErr == codecAbortErr) theErr = noErr;
} else theErr = errAEEventFailed;
return theErr;
}
extern OSErr GetSelectedPICT(ImageHandle theImage, PicHandle *thePicture)
{
Rect srcRect, dstRect;
OSErr theErr = noErr;
CGrafPort dummyPort;
if (AntsHaveSelection((*theImage)->ants)) SelRectToCropRect(theImage, &srcRect);
else srcRect = (*theImage)->crect;
if (EqualRect(&srcRect, &(*theImage)->grect) && (*theImage)->format->inType == kPICTType) {
*thePicture = nil;
return noErr;
}
dstRect = srcRect;
OffsetRect(&dstRect, -dstRect.left, -dstRect.top);
OpenCPort(&dummyPort);
RectRgn(dummyPort.visRgn, &dstRect);
ClipRect(&dstRect);
PushPort();
MySetPort(&dummyPort);
*thePicture = MyOpenCPicture(&dstRect, theImage);
if (*thePicture) {
theErr = DrawToDummyPort(theImage, &srcRect, &dstRect);
ClosePicture();
if (!Width(&(**thePicture)->picFrame) && !Height(&(**thePicture)->picFrame)) theErr = memFullErr;
if (theErr != noErr) DisposeHandle((Handle)*thePicture), *thePicture = nil;
} else theErr = memFullErr;
PopPort();
CloseCPort(&dummyPort);
return theErr;
}
//=====================================================================================
// PicHandle MyOpenCPicture(Rect *dstRect, ImageHandle theImage)
//=====================================================================================
// Opens up a color picture, in preparation for copying. We use a simple algorithm to
// figure out whether to use application or temporary memory, in order to maximize the
// likelihood that we'll be able to succeed.
//=====================================================================================
static PicHandle MyOpenCPicture(Rect *dstRect, ImageHandle theImage)
{
Size estSize = (((long)Height(&(*theImage)->grect) * (long)Width(&(*theImage)->grect) * (long)(*theImage)->depth) >> 3) * 3L / 4L;
Size grow, tempMax = TempMaxMem(&grow), appMax = MaxMem(&grow);
THz oldZone = GetZone(), tempZone;
Boolean inTempMem = true;
OpenCPicParams theParams;
OSErr theErr = noErr;
PicHandle thePict;
// set up the OpenCPicture parameters
theParams.srcRect = *dstRect;
theParams.hRes = theParams.vRes = 0x480000L;
theParams.version = -2;
theParams.reserved1 = theParams.reserved2 = 0;
// allocate a handle in temp memory, and retrieve the temporary zone from that
thePict = (PicHandle)TempNewHandle(4, &theErr);
if (thePict) {
tempZone = HandleZone((Handle)thePict);
DisposeHandle((Handle)thePict);
}
// some simple logic to determine if we should use app or temp memory
if (!HasVirtualMemory() && (estSize < appMax || estSize > tempMax)) inTempMem = false;
// open the picture
if (inTempMem) SetZone(tempZone);
thePict = OpenCPicture(&theParams);
SetZone(oldZone);
return thePict;
}
//=====================================================================================
// OSErr DrawToDummyPort(ImageHandle theImage, Rect *srcRect, Rect *dstRect)
//=====================================================================================
// Actually does the drawing of the image to the dummy port. Of course, the dummy port
// has been set up to bottleneck all the drawing into a picture, so nothing actually
// gets drawn.
//=====================================================================================
static OSErr DrawToDummyPort(ImageHandle theImage, Rect *srcRect, Rect *dstRect)
{
NestedProgress progProc = { { nil, 0 }, 0, 0L, 0x10000L, false };
short oldBackgroundTime = gThePrefs.backgroundTime;
Rect boundsRect = (*theImage)->grect;
JVDrawParamsHandle theParams;
OSErr theErr = noErr;
progProc.prog.progressProc = gGenericProgress;
// hack: Finder doesn't seem to like it if we give any apps time during
// the drag process, so we force 0 sleep time and checking with
// EventAvail
gThePrefs.backgroundTime = bgMinimal;
// allocate and initialize the drawing parameters
if (theParams = NewDrawParams(&boundsRect, iqMedium, false, &progProc, (*theImage)->privateData)) {
SetUpDrawPort(theParams, kOnscreenPort, (CGrafPtr)qd.thePort, srcRect, dstRect, false);
// preflight the drawing here and save the port
KeepSpinning();
theErr = PreflightDrawing(theParams);
PushPort();
if (theErr == noErr) {
// point to the dummy drawing port and start the inner progress proc
MySetPort((*theParams)->dummy);
UpdateParamText(gString[strCopying], gNullString, gNullString, (*theImage)->file.name);
CallICMProgressProc((*theParams)->progress.prog.progressProc, codecProgressOpen, 0L,
(*theParams)->progress.prog.progressRefCon);
// now do the drawing, either from the offscreen GWorld...
if ((*theImage)->gworld && GWOrigSize(theImage))
CopyGWorldToGWorld((*theImage)->gworld, (*theParams)->dummy, &(*theImage)->gworld->portRect,
&(*theImage)->gworld->portRect, srcCopy, nil);
// or from the image directly
else theErr = (*theImage)->format->draw((*theImage)->data, theParams);
// clean up our drawing, checking for missed aborts
if (theErr == noErr) theErr = PostflightDrawing(theParams);
else PostflightDrawing(theParams);
// if we were aborted, tell the printer so, and close the inner prog.
CallICMProgressProc((*theParams)->progress.prog.progressProc, codecProgressClose, 0L,
(*theParams)->progress.prog.progressRefCon);
KeepSpinning();
}
PopPort();
DisposeHandle((Handle)theParams);
}
gThePrefs.backgroundTime = oldBackgroundTime;
return theErr;
}
extern OSErr DoSlideShow(void)
{
NestedProgress theProg = { { nil, 0 }, 0, 0L, 0L, false };
ICMProgressProcRecordPtr progPtr = (ICMProgressProcRecordPtr)&theProg;
OSErr theErr = noErr;
FSSpec theSpec;
if (!(*gSlideOptions)->fromMemory) {
theProg.prog.progressProc = gGenericProgress;
theProg.prog.progressRefCon = (long)&theProg;
UpdateParamText(gString[strScanningDirectory], gNullString, gNullString, gNullString);
CallICMProgressProc(theProg.prog.progressProc, codecProgressOpen, kIndefProgress, theProg.prog.progressRefCon);
theErr = GetSlideSpec(&theSpec);
if (theErr == noErr)
if (!WasDesktop(&theSpec, (*gSlideOptions)->recursive, progPtr, &theErr))
theErr = AddSlideDir(&theSpec, (*gSlideOptions)->recursive, progPtr, nil);
CallICMProgressProc(theProg.prog.progressProc, codecProgressClose, kIndefProgress, theProg.prog.progressRefCon);
}
if (theErr == noErr) InitSlideShow();
else {
CleanUpSlideShow();
if (theErr == noErr) MinorError(errNoMemory);
}
return theErr;
}
static Boolean WasDesktop(FSSpec *spec, Boolean recursive, ICMProgressProcRecordPtr theProg,
OSErr *theErr)
{
HParamBlockRec params;
FSSpec theSpec;
OSErr err;
err = GetDeskFolderSpec(&theSpec, spec->vRefNum);
if (err != noErr || !SameFile(&theSpec, spec)) return false;
params.volumeParam.ioVolIndex = 1;
params.volumeParam.ioCompletion = nil;
params.volumeParam.ioNamePtr = theSpec.name;
while (PBHGetVInfo(&params, false) == noErr && *theErr == noErr) {
if (recursive) err = FSMakeFSSpec(params.ioParam.ioVRefNum, 2, "\p", &theSpec);
else err = GetDeskFolderSpec(&theSpec, params.volumeParam.ioVRefNum);
if (err == noErr) err = AddSlideDir(&theSpec, recursive, theProg, nil);
if (err == memFullErr || err == codecAbortErr) *theErr = err;
params.volumeParam.ioVolIndex++;
}
}