JPEGView/Source/C/MiscellaneousUtils.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
15 KiB
C

/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information. */
/* Contact email: mac@aarongiles.com */
/*********************************************************/
#if THINK_C
#include "THINK.Header"
#elif applec
#pragma load ":Headers:MPW.Header"
#elif __MWERKS__
//#include "MW.Header"
#else
#include "JPEGView.h"
#endif
/*
* Local variables:
* lTimeInstalled = count of the number of times the task record has been installed
* lTimeTask = Time Manager task record for calculating elapsed times
*
*/
static short gTimeInstalled = 0;
static long gStartTicks;
static Boolean HandleAbortMouseDown(EventRecord *theEvent);
static Boolean HandleAbortKeyDown(EventRecord *theEvent);
/*
* CheckAbort()
*
* Purpose: Scans the event queue for an aborting keypress
* Inputs: none
* Returns: true if we should abort
*
*/
Boolean CheckAbort(JVDrawParamsHandle theParams)
{
static long gLastTime = 0;
static short gCount = 0;
Boolean aborted = false, QDxInstalled;
ImageHandle theImage;
EventRecord theEvent;
EvQElPtr eventPtr;
short sleepTime;
Point newPoint;
// get the proper sleep time: according to preferences if in foreground, or the
// maximum if we're in the background or running as a screen saver
if (gInBackground || gScreenSaver ||
gThePrefs.backgroundTime == bgMaximal) sleepTime = kSleepTime;
else if (gThePrefs.backgroundTime == bgMinimal) sleepTime = 0;
else sleepTime = 3;
// if we're in screen saver mode, make sure we're frontmost
if (gScreenSaver) EnsureFrontmost();
// if we're not in the background, ensure that we get at least 2 ticks of continuous
// operation before giving up a full amount of time to others
if (!gInBackground && (TickCount() - gLastTime) < 2) sleepTime = 0;
PushPort();
MySetPort((CGrafPtr)FrontWindow());
QDxInstalled = GetQDxDispatchPatchState();
// get the next event; if sleepTime is zero, check event availability first
if (sleepTime || EventAvail(everyEvent, &theEvent)) {
// if we're in screen saver mode, and the mouse moved, quit immediately
newPoint = GlobalMouse();
if (gSlideShow && gScreenSaver &&
(abs(newPoint.h - gScreenSaverPoint.h) > 2 ||
abs(newPoint.v - gScreenSaverPoint.v) > 2)) {
SendQuitApplication();
aborted = true;
}
// otherwise, handle any pending events normally
else while (WaitNextEvent(everyEvent - highLevelEventMask, &theEvent, sleepTime, nil)) {
// dispatch the event as appropriate
switch (theEvent.what) {
case mouseDown:
aborted = HandleAbortMouseDown(&theEvent);
break;
case keyDown:
if (theEvent.message == kCreator) break;
case autoKey:
aborted = HandleAbortKeyDown(&theEvent);
break;
case updateEvt:
if (theImage = FindImage((WindowPtr)theEvent.message)) {
if (gDrawing && theImage == gDrawing &&
theParams && (*theParams)->on.port) {
aborted = true;
MySetPort((CGrafPtr)(*theImage)->window);
BeginUpdate((*theImage)->window);
UnionRgn((*theImage)->update, (*theImage)->window->visRgn, (*theImage)->update);
EndUpdate((*theImage)->window);
(*theImage)->flags |= ifNeedToRedraw;
} else DeferImageUpdate(theImage);
} else HandleUpdateEvent(&theEvent);
break;
case activateEvt:
HandleActivateEvent(&theEvent);
break;
case osEvt:
HandleOSEvent(&theEvent);
break;
}
StartSpinning();
// if we got a pending button, abort (unless it's during offscreen draw of
// user-controlled slide show)
if (gPendingButton != -1)
if (gPendingButton != kForwardButton ||
(theParams && (*theParams)->on.port))
aborted = true;
}
} else {
if (!(gCount = (gCount + 1) & 0x1f) && !gInBackground)
PPostEvent(keyDown, kCreator, &eventPtr);
}
SetQDxDispatchPatchState(QDxInstalled);
PopPort();
if (sleepTime) gLastTime = TickCount();
return aborted;
}
static Boolean HandleAbortMouseDown(EventRecord *theEvent)
{
Boolean aborted = false;
// if we're in screen saver mode, always abort
if (gSlideShow && gScreenSaver) {
SendQuitApplication();
return true;
}
// handle dialog events properly; if button 3 was hit on the progress dialog,
// we abort the drawing
if (IsDialogEvent(theEvent)) {
DialogPtr theDialog;
short itemHit;
StopSpinning(&qd.arrow);
if (DialogSelect(theEvent, &theDialog, &itemHit) &&
GetWRefCon(theDialog) == kProgressDialogID &&
itemHit == progressCancel) aborted = true;
// otherwise, do it the hard way....
} else {
WindowPtr theWindow;
short thePart = FindWindow(theEvent->where, &theWindow);
// if a slide show is happening and the mouse was clicked in a
// non-floating window, toggle the visible state of the slide show controls
if (gSlideShow && WindowKind(theWindow) != floatingWindowKind) {
theWindow = GetSlideControlsWindow();
if (!theWindow) {
if (OpenSlideControls() == noErr)
ChangeActive(GetSlideControlsWindow());
} else CloseSlideControls();
// otherwise, track dragging and menus as normal; check specially for clicks in
// the slide show controls floating window, and beep about everything else
} else {
switch (thePart) {
case inDrag:
StopSpinning(&qd.arrow);
HandleDragClick(theEvent, theWindow);
break;
case inMenuBar:
StopSpinning(&qd.arrow);
if (gMenuVisible) HandleMenuClick(theEvent);
break;
case inGrow:
case inContent:
if (theWindow == GetSlideControlsWindow()) {
StopSpinning(&qd.arrow);
HandleSlideControlsClick(theEvent->where, theEvent->modifiers, false);
break;
}
default:
SysBeep(1);
break;
}
}
}
return aborted;
}
static Boolean HandleAbortKeyDown(EventRecord *theEvent)
{
uchar theChar = theEvent->message & charCodeMask;
Boolean aborted = false;
DialogPtr theDialog;
for (theDialog = FWFrontWindow(); theDialog; theDialog = NextWindow(theDialog))
if (GetWRefCon(theDialog) == kProgressDialogID) break;
// if we're in screen saver mode, always abort
if (gSlideShow && gScreenSaver) {
SendQuitApplication();
return true;
}
// for cmd-0, cmd-`, and cmd-\, dispatch to the standard menu handler;
// if cmd-. set the proper abort flag
if ((theEvent->modifiers & cmdKey) && theChar != '.') {
if (theChar == '0' || theChar == '`' || theChar == '\\' ||
theChar == 'Q' || theChar == 'q') {
HandleMenuChoice(PowerMenuKey(theEvent->message, theEvent->modifiers,
GetMHandle(rFileMenu)));
if (gDone) aborted = true;
}
}
// if escape, set the proper abort flag
else if (((theEvent->modifiers & cmdKey) && theChar == '.') || theChar == kEscapeChar) {
// if the we're in a slide show & the stop button is disabled, simply abort
if (gSlideShow == kPaused && GetSlideControlsWindow() &&
GetSlideControlButton(kStopButton) == disabled) aborted = 0x4d;
else if (gSlideShow) HandleSlideControlsKey(theChar, theEvent->modifiers, false);
else aborted = 0x4d;
// if we're in a slide show, pass the key through the controls handler
} else if (gSlideShow) HandleSlideControlsKey(theChar, theEvent->modifiers, false);
if (aborted == 0x4d && theDialog) {
PushPort();
MySetPort((CGrafPtr)theDialog);
HandleDialogCancelKey(theDialog);
aborted = true;
PopPort();
}
return aborted;
}
/*
* StartTimer()
*
* Purpose: Starts a Time Manager task to calculate an elapsed time
* Inputs: none
* Returns: nothing
*
*/
void StartTimer(void)
{
if (++gTimeInstalled != 1) return;
gStartTicks = TickCount();
}
/*
* StopTimer()
*
* Purpose: Stops the Time Manager task to calculate an elapsed time
* Inputs: none
* Returns: the elapsed time, in milliseconds
*
*/
long StopTimer(void)
{
if (--gTimeInstalled) return 0L;
return ((TickCount() - gStartTicks) * 1000L / 60L);
}
/*
* DirName(dirID, vRefNum, s)
*
* Purpose: Returns the name of the directory given by the dirID and vRefNum
* Inputs: dirID = the directory ID of the directory
* vRefNum = the vRef of the directory
* s = a pointer to a string to hold the final name
* Returns: s
*
*/
char *DirName(long dirID, short vRefNum, char *s)
{
Str255 directoryName;
CInfoPBRec block;
*s = 0;
block.dirInfo.ioNamePtr = directoryName;
block.dirInfo.ioDrDirID = block.dirInfo.ioDrParID = dirID;
block.dirInfo.ioVRefNum = vRefNum;
block.dirInfo.ioFDirIndex = -1;
if (PBGetCatInfo(&block, false) == noErr) {
if (directoryName[0]) BlockMove(directoryName, s, directoryName[0] + 1);
else s[0] = 0;
} else s[0] = 0;
return s;
}
/*
* GetDirectoryID(dirID, vRefNum)
*
* Purpose: Gets the dirID of the given directory
* Inputs: theSpec = pointer to the directory spec
* theID = pointer to a long to store the ID
* Returns: an OSErr describing what went wrong
*
*/
OSErr GetDirectoryID(FSSpec *theSpec, long *theID)
{
CInfoPBRec block;
Str255 fileName;
OSErr theErr;
block.hFileInfo.ioNamePtr = fileName;
BlockMove(theSpec->name, fileName, *theSpec->name + 1);
block.hFileInfo.ioVRefNum = theSpec->vRefNum;
block.hFileInfo.ioFDirIndex = 0;
block.hFileInfo.ioDirID = theSpec->parID;
theErr = PBGetCatInfo(&block, false);
if (theErr != noErr) return theErr;
if (!(block.hFileInfo.ioFlAttrib & 0x10)) return errNotADirectory;
*theID = block.dirInfo.ioDrDirID;
return theErr;
}
/*
* GetFullPath(theSpec, thePath)
*
* Purpose: Gets the full pathname from a given FSSpec
* Inputs: theSpec = pointer to the directory spec
* thePath = pointer to a handle to receive the path
* Returns: an OSErr describing what went wrong
*
*/
OSErr GetFullPath(FSSpec *theSpec, Handle *thePath)
{
OSErr theErr = noErr;
Boolean isDirectory;
long size, tempID;
Str255 dirName;
DirInfo block;
theErr = GetDirectoryID(theSpec, &tempID);
isDirectory = (theErr == noErr);
*thePath = NewHandle(size = *theSpec->name);
if (*thePath) {
BlockMove(&theSpec->name[1], **thePath, *theSpec->name);
block.ioDrParID = theSpec->parID;
block.ioNamePtr = dirName;
do {
block.ioVRefNum = theSpec->vRefNum;
block.ioFDirIndex = -1;
block.ioDrDirID = block.ioDrParID;
theErr = PBGetCatInfo((CInfoPBPtr)&block, false);
if (theErr != noErr) {
if (isDirectory) return noErr;
break;
}
SetHandleSize(*thePath, size + 1 + *dirName);
theErr = MemError();
if (theErr != noErr) break;
BlockMove(**thePath, **thePath + *dirName + 1, size);
size += 1 + *dirName;
BlockMove(&dirName[1], **thePath, *dirName);
*(**thePath + *dirName) = ':';
} while (block.ioDrDirID != 2);
} else theErr = memFullErr;
if ((theErr != noErr) && *thePath) {
DisposeHandle(*thePath);
*thePath = nil;
}
return theErr;
}
/*
* ForceFolderUpdate(dirID, vRefNum)
*
* Purpose: Forces the Finder to update the directory information of the given folder
* Inputs: dirID = the directory ID of the directory
* vRefNum = the vRef of the directory
* Returns: nothing
*
*/
void ForceFolderUpdate(long dirID, short vRefNum)
{
CInfoPBRec block;
block.hFileInfo.ioCompletion = nil;
block.hFileInfo.ioNamePtr = nil;
block.hFileInfo.ioVRefNum = vRefNum;
block.hFileInfo.ioDirID = dirID;
block.hFileInfo.ioFDirIndex = -1;
PBGetCatInfo(&block, false);
GetDateTime(&block.dirInfo.ioDrMdDat);
PBSetCatInfo(&block, false);
}
/*
* AddString(theString, theAddition)
*
* Purpose: Appends theAddition, a pascal string, to the pascal string theString
* Inputs: theString = the destination string in pascal format
* theAddition = the text of the addition
* Returns: nothing
*
*/
void AddString(StringPtr theString, StringPtr theAddition)
{
BlockMove((uchar *)theAddition + 1, theString + theString[0] + 1, *theAddition);
*theString += *theAddition;
}
/*
* AddCString(theString, theAddition, length)
*
* Purpose: Appends theAddition, a C string of length length, to the pascal string
* theString
* Inputs: theString = the destination string in pascal format
* theAddition = the text of the addition
* length = the length of the addition
* Returns: nothing
*
*/
void AddCString(StringPtr theString, char *theAddition, int length)
{
BlockMove(theAddition, theString + theString[0] + 1, length);
*theString += length;
}
/*
* AddNumber(theString, theNum)
*
* Purpose: Appends an ASCII representation of theNum to the pascal string theString
* Inputs: theString = the destination string in pascal format
* theNum = the number to append
* Returns: nothing
*
*/
void AddNumber(StringPtr theString, long theNum)
{
Str255 tempNum, theAddition;
int i;
NumToString(theNum, tempNum);
*theAddition = 0;
for (i = 1; i <= *tempNum; i++) {
AddChar(theAddition, tempNum[i]);
if ((*tempNum > 4) && (*tempNum != i) && (((*tempNum - i) % 3) == 0))
AddChar(theAddition, gThousandsSep);
}
AddString(theString, theAddition);
}
void StuffNumber(StringPtr theString, short theItem, long theNum)
{
Str32 tempNum, fixedNum;
StringPtr src, dst;
short j;
NumToString(theNum, tempNum);
src = &tempNum[1];
dst = &fixedNum[1];
*fixedNum = *tempNum;
for (j = 1; j <= *tempNum; j++) {
*dst++ = *src++;
if ((*tempNum > 4) && (*tempNum != j) && (((*tempNum - j) % 3) == 0))
*dst++ = gThousandsSep, (*fixedNum)++;
}
StuffString(theString, theItem, fixedNum);
}
void StuffNumber0(StringPtr theString, short theItem, long theNum, short theLength)
{
Str32 tempNum;
NumToString(theNum, tempNum);
while (*tempNum < theLength) {
BlockMove(&tempNum[1], &tempNum[2], 30);
tempNum[1] = '0';
(*tempNum)++;
}
StuffString(theString, theItem, tempNum);
}
void StuffDepth(StringPtr theString, short theItem, short theDepth)
{
Str32 tempNum;
if (theDepth > 32) theDepth -= 32;
if (theDepth <= 8) NumToString(1L << theDepth, tempNum);
else if (theDepth == 16)
BlockMove(gString[strThousands], tempNum, *gString[strThousands] + 1);
else BlockMove(gString[strMillions], tempNum, *gString[strMillions] + 1);
StuffString(theString, theItem, tempNum);
}
void StuffString(StringPtr theString, short theItem, StringPtr addString)
{
Str255 tempStr;
StringPtr src = &theString[1], dst = &tempStr[1], num = &addString[1];
short i, j, len = *theString;
theItem += '0';
for (i = 0; i < len; i++) {
if ((*src == '~') && (*(src+1) == theItem)) break;
else *dst++ = *src++;
}
if (*src != '~') return;
num = &addString[1];
for (j = 0; j < *addString; j++) *dst++ = *num++;
src += 2, i += 2;
for ( ; i < len; i++) *dst++ = *src++;
*tempStr = len + *addString - 2;
BlockMove(tempStr, theString, *tempStr + 1);
}
/*
* GlobalMouse()
*
* Purpose: Gets the global coordinates of the mouse
* Inputs: none
* Returns: the mouse location in global coordinates
*
*/
Point GlobalMouse(void)
{
Point thePoint;
PushPort();
MySetPort(nil);
GetMouse(&thePoint);
LocalToGlobal(&thePoint);
PopPort();
return thePoint;
}