JPEGView/Source/C/SlideShow.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
30 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 "SlideShow.h"
//=====================================================================================
// Constants local to this module
//=====================================================================================
enum {
kEndSlideShow = -1,
kAdvanceSlide = -2,
kReloadSlide = -3,
kReverseSlide = -4
};
//=====================================================================================
// Global variables local to this module
//=====================================================================================
static Boolean gSlideWarned = false, gStatsHidden, gColorsHidden, gCommentsHidden;
static ImageHandle gSlideNextImage = nil;
static WindowPtr gSlideBackWindow = nil;
static SlideHandle gSlideNext = nil;
static SlideHandle gSlideRoot = nil;
static long gSlideTimer = 0L;
static long gSlideCount = 0L;
//=====================================================================================
// Prototypes for functions local to this module
//=====================================================================================
static void OpenSlideBackWindow(void);
static SlideHandle NewSlide(Boolean memory, FSSpec *spec);
static void DisposeSlide(SlideHandle theSlide);
static SlideHandle LastSlide(void);
static SlideHandle PreviousSlide(SlideHandle theSlide);
static SlideHandle DisplayedSlide(void);
static void ShuffleSlides(void);
static ImageHandle LoadSlideFromMem(void);
static ImageHandle LoadSlideFromDisk(void);
static ImageHandle HandleLoadError(OSErr theErr, StringPtr fileName);
static Boolean WarnSlideShowMemory(void);
//=====================================================================================
// void OpenSlideBackWindow(void)
//
// Creates and displays the background window for the slide show.
//
// External calls: GetDeepMonitor, PushPort, MySetPort, FullScreen, PopPort
//=====================================================================================
static void OpenSlideBackWindow(void)
{
MonitorHandle deepMonitor;
PaletteHandle thePalette;
deepMonitor = GetDeepMonitor(true);
thePalette = SystemPalette((*deepMonitor)->depth <= 8 ? (*deepMonitor)->depth : 8);
PushPort();
MySetPort(nil);
FullScreen(gMainMonitor);
gSlideBackWindow = FWGetNewCWindow(rFullImageWindow, (Ptr)gSlideBackWindow, (WindowPtr)-1);
SizeWindow(gSlideBackWindow, Width(&(*GetGrayRgn())->rgnBBox),
Height(&(*GetGrayRgn())->rgnBBox), true);
FWMoveWindow(gSlideBackWindow, (*GetGrayRgn())->rgnBBox.left, (*GetGrayRgn())->rgnBBox.top, true);
SetPalette(gSlideBackWindow, thePalette, true);
ActivatePalette(gSlideBackWindow);
MySetPort((CGrafPtr)gSlideBackWindow);
SetOrigin((*GetGrayRgn())->rgnBBox.left, (*GetGrayRgn())->rgnBBox.top);
FWShowWindow(gSlideBackWindow);
DrawSlideBackWindow();
PopPort();
}
//=====================================================================================
// WindowPtr GetSlideBackWindow(void)
//
// Returns a pointer to the slide backdrop window.
//
// External calls: GetDeepMonitor, PushPort, MySetPort, FullScreen, PopPort
//=====================================================================================
extern WindowPtr GetSlideBackWindow(void)
{
return gSlideBackWindow;
}
//=====================================================================================
// void CloseSlideBackWindow(void)
//
// Closes the slide backdrop window.
//
// External calls: none
//=====================================================================================
extern void CloseSlideBackWindow(void)
{
if (gSlideBackWindow) {
PushPort();
MySetPort(nil);
FWDisposeWindow(gSlideBackWindow);
DeallocateWindow(gSlideBackWindow);
gSlideBackWindow = nil;
if (!AnotherFull(nil)) NormalScreen(gMainMonitor);
PopPort();
}
}
//=====================================================================================
// void DrawSlideBackWindow(void)
//
// Draws a JPEGView icon in the center of each screen.
//
// External calls: none
//=====================================================================================
extern void DrawSlideBackWindow(void)
{
MonitorHandle theMonitor;
Rect theRect;
for (theMonitor = gMainMonitor; theMonitor; theMonitor = (*theMonitor)->next) {
theRect = (*theMonitor)->rect;
theRect.left += (Width(&theRect) - 32) / 2;
theRect.top += (Height(&theRect) - 32) / 2;
theRect.right = theRect.left + 32;
theRect.bottom = theRect.top + 32;
PlotIconSuite(&theRect, atAbsoluteCenter, ttNone, gIconSuite);
}
}
//=====================================================================================
// void ResetSlideTimer(void)
//
// Resets the slide timer, maintained by HandleSlideNullEvent.
//
// External calls: none
//=====================================================================================
extern void ResetSlideTimer(void)
{
gSlideTimer = TickCount();
}
//=====================================================================================
// void HandleSlideNullEvent(void)
//
// Handles null events while a slide show is active.
//
// External calls: none
//=====================================================================================
extern void HandleSlideNullEvent(void)
{
ulong newCount = TickCount();
EvQElPtr theEvent;
Boolean advance;
// if we're in screen saver mode, make sure the mouse didn't move
if (gScreenSaver) {
Point newMouse = GlobalMouse();
if (abs(newMouse.h - gScreenSaverPoint.h) > 2 ||
abs(newMouse.v - gScreenSaverPoint.v) > 2) {
SendQuitApplication();
return;
}
}
// if we're automatic, enable the play button here
if (!(*gSlideOptions)->userControl && GetSlideControlButton(kForwardButton) == disabled) {
SetSlideControlButton(kForwardButton, standard);
DrawSlideControlsWindow();
}
// if the slide show is paused, don't do this bit
if (gSlideShow == kPaused) return;
if ((*gSlideOptions)->userControl)
SetSlideControlsText(gString[strSlideReady], gNullString, gNullString, gNullString);
// if the timer isn't up yet, and we're in the foreground, post a fake
// key down event to prevent screen savers from kicking in
else if (((newCount - gSlideTimer) / kClockFreq) <= (*gSlideOptions)->delay &&
!gInBackground) {
Str32 theCount;
PPostEvent(keyDown, kCreator, &theEvent);
NumToString((*gSlideOptions)->delay - (newCount - gSlideTimer) / kClockFreq, theCount);
SetSlideControlsText(gString[strSlideDelaying], theCount, gNullString, gNullString);
return;
}
// if we're under user control, or if we're paused
if ((*gSlideOptions)->userControl || gSlideShow == kPaused) return;
// otherwise, reset the slide timer, draw this slide and then start loading the next
gSlideTimer = newCount;
do {
advance = false;
gSlideShow = NextSlide(&advance);
if (gSlideShow) gSlideShow = LoadSlide(&advance);
} while (advance && gSlideShow);
}
//=====================================================================================
// SlideHandle NewSlide(Boolean memory, FSSpec *spec)
//
// Creates a new slide handle and appends it to the beginning of the linked list.
//
// External calls: none
//=====================================================================================
static SlideHandle NewSlide(Boolean memory, FSSpec *spec)
{
long theSize = sizeof(SlideItem);
SlideHandle theSlide;
if (!IsMemAvailable(sizeof(SlideItem))) return nil;
if (gSlideRoot) {
for (theSlide = gSlideRoot; (*theSlide)->next; theSlide = (*theSlide)->next);
theSlide = (*theSlide)->next = (SlideHandle)NewHandle(sizeof(SlideItem));
} else
theSlide = gSlideRoot = (SlideHandle)NewHandle(sizeof(SlideItem));
if (theSlide) {
(*theSlide)->next = nil;
(*theSlide)->mem = memory;
(*theSlide)->spec = *spec;
gSlideCount++;
}
return theSlide;
}
//=====================================================================================
// void DisposeSlide(SlideHandle theSlide)
//
// Removes a slide handle from the linked list.
//
// External calls: none
//=====================================================================================
static void DisposeSlide(SlideHandle theSlide)
{
Boolean found = false;
SlideHandle tempSlide;
if (theSlide != gSlideRoot) {
for (tempSlide = gSlideRoot;
tempSlide && ((*tempSlide)->next != theSlide);
tempSlide = (*tempSlide)->next);
if (tempSlide) (*tempSlide)->next = (*theSlide)->next;
} else
gSlideRoot = (*gSlideRoot)->next;
DisposeHandle((Handle)theSlide);
gSlideCount--;
}
//=====================================================================================
// SlideHandle PreviousSlide(SlideHandle theSlide)
//
// Returns the slide in the list previous to the given slide.
//
// External calls: none
//=====================================================================================
static SlideHandle LastSlide(void)
{
SlideHandle theSlide;
if (!gSlideRoot) return nil;
for (theSlide = gSlideRoot; (*theSlide)->next; theSlide = (*theSlide)->next);
return theSlide;
}
static SlideHandle PreviousSlide(SlideHandle theSlide)
{
SlideHandle slide;
if (!theSlide || theSlide == gSlideRoot || theSlide == (SlideHandle)kEndSlideShow)
return LastSlide();
for (slide = gSlideRoot; slide; slide = (*slide)->next)
if ((*slide)->next == theSlide) return slide;
return nil;
}
static SlideHandle DisplayedSlide(void)
{
SlideHandle theSlide = PreviousSlide(gSlideNext);
ImageHandle theImage = FrontImage();
short imageIndex;
if (!theImage) return nil;
imageIndex = GetDocumentIndex((*theImage)->window);
do {
if ((*theSlide)->mem) {
if ((*theSlide)->spec.vRefNum == imageIndex) return theSlide;
} else
if (SameFile(&(*theImage)->file, &(*theSlide)->spec)) return theSlide;
theSlide = PreviousSlide(theSlide);
} while (theSlide != gSlideNext);
return nil;
}
//=====================================================================================
// void PointToPreviousSlide(void)
//
// Backs up the gSlideNext pointer by the specified count.
//
// External calls: none
//=====================================================================================
extern void PointToPreviousSlide(void)
{
SlideHandle currentSlide = DisplayedSlide();
ImageHandle frontImage = FrontImage();
if (currentSlide) {
if ((*currentSlide)->next == gSlideNext || (*(*currentSlide)->next)->next == gSlideNext)
gSlideNext = PreviousSlide(currentSlide);
else if (gSlideNext != gSlideRoot) gSlideNext = PreviousSlide(gSlideNext);
else SysBeep(1);
} else SysBeep(1);
if (gSlideNextImage && gSlideNextImage != frontImage)
DoCloseWindow((*gSlideNextImage)->window, false);
gSlideNextImage = nil;
}
//=====================================================================================
// void InitSlideShow(void)
//
// Initializes a new slide show; does not properly set up for a resumed slide show.
//
// External calls: none
//=====================================================================================
extern void InitSlideShow(void)
{
ImageHandle theImage;
WindowPtr theWindow;
Boolean advance;
FSSpec theSpec;
gSlideShow = false;
// if we're doing a memory-based slide show, generate the slide entries here
if (!gSlideRoot && (*gSlideOptions)->fromMemory)
for (theImage = gImageRoot; theImage; theImage = (*theImage)->next) {
theSpec.vRefNum = GetDocumentIndex((*theImage)->window);
NewSlide(true, &theSpec);
}
// if for some reason we have no slides, signal the error and return
if (!gSlideCount) {
MinorError(errNoImagesFound);
MyInvalMenuBar();
return;
}
// if we are to hide the floating windows, do it now
gStatsHidden = gCommentsHidden = gColorsHidden = false;
if ((*gSlideOptions)->hideWindoids) {
if (theWindow = GetStatWindow()) gStatsHidden = true, CloseStats();
if (theWindow = GetCommentsWindow()) gCommentsHidden = true, CloseComments();
if (theWindow = GetColorsWindow()) gColorsHidden = true, CloseColors();
}
// if the slide background window has not been opened, we allocate and open it now
if (!gSlideBackWindow && (gSlideBackWindow = AllocateWindow())) OpenSlideBackWindow();
// set up the slide control buttons ahead of time here
SetSlideControlButton(kReverseButton, disabled);
SetSlideControlButton(kStopButton, standard);
SetSlideControlButton(kPauseButton, standard);
SetSlideControlButton(kForwardButton, standard);
// if this is user-controlled, pop up the controls window now
if (!(*gSlideOptions)->hideControls && OpenSlideControls() == noErr)
ChangeActive(GetSlideControlsWindow());
// if this is a disk-based slide show, close all other open images
if (!(*gSlideOptions)->fromMemory)
while (gImageRoot)
DoCloseWindow((*LastImage())->window, false);
// reset all the appropriate variables, then load, draw, and load the second slide
if ((*gSlideOptions)->random) ShuffleSlides();
gSlideNextImage = nil;
gSlideWarned = false;
gSlideNext = gSlideRoot;
gSlideShow = true;
advance = false;
if (gSlideShow = LoadSlide(&advance)) {
do {
advance = false;
gSlideShow = NextSlide(&advance);
if (gSlideShow) gSlideShow = LoadSlide(&advance);
} while (advance && gSlideShow);
}
// if we got shoved in the background, start in the paused state
if (gInBackground && !gScreenSaver) {
Boolean dummy;
gSlideShow = PauseSlideShow(&dummy);
}
}
//=====================================================================================
// void ReinitSlideShow(PrefsData *oldPrefs)
//
// Initializes a new slide show; does not properly set up for a resumed slide show.
//
// External calls: none
//=====================================================================================
extern void ReinitSlideShow(SlideOptionsPtr oldOptions)
{
WindowPtr theWindow;
if (oldOptions->hideWindoids != (*gSlideOptions)->hideWindoids) {
if ((*gSlideOptions)->hideWindoids) {
if (theWindow = GetStatWindow()) gStatsHidden = true, CloseStats();
if (theWindow = GetCommentsWindow()) gCommentsHidden = true, CloseComments();
if (theWindow = GetColorsWindow()) gColorsHidden = true, CloseColors();
} else {
if (gStatsHidden && OpenStats() == noErr) ChangeActive(GetStatWindow());
if (gCommentsHidden && OpenComments() == noErr) ChangeActive(GetCommentsWindow());
if (gColorsHidden && OpenColors() == noErr) ChangeActive(GetColorsWindow());
}
}
if (oldOptions->hideControls != (*gSlideOptions)->hideControls) {
if (!(*gSlideOptions)->hideControls && OpenSlideControls() == noErr)
ChangeActive(GetSlideControlsWindow());
else if ((*gSlideOptions)->hideControls && GetSlideControlsWindow())
CloseSlideControls();
}
gPendingButton = kForwardButton;
}
//=====================================================================================
// void AddSlideDir(FSSpec *spec)
//
// Adds a given file or directory to the list of slides to be displayed, recognizing
// the request for recursive directory scans.
//
// External calls: none
//=====================================================================================
extern OSErr AddSlideDir(FSSpec *spec, Boolean recursive, ICMProgressProcRecordPtr theProg,
LoopCheckPtr loopList)
{
FSSpec dirSpec = *spec, theSpec;
Boolean isFolder, wasAliased;
OSErr theErr = noErr;
LoopCheck thisDir;
CInfoPBRec block;
Str255 fileName;
long dir;
if (ResolveAliasFile(&dirSpec, true, &isFolder, &wasAliased) != noErr) return noErr;
if (isFolder) {
theErr = GetDirectoryID(&dirSpec, &dir);
if (theErr != noErr) return noErr;
thisDir.prev = loopList;
thisDir.vRefNum = dirSpec.vRefNum;
thisDir.dirID = dir;
while (loopList) {
if (loopList->vRefNum == dirSpec.vRefNum && loopList->dirID == dir)
return noErr;
loopList = loopList->prev;
}
UpdateParamText(gString[strScanningDirectory], gNullString, gNullString, spec->name);
} else {
if (!NewSlide(false, &dirSpec)) return memFullErr;
return noErr;
}
block.hFileInfo.ioNamePtr = fileName;
block.hFileInfo.ioFDirIndex = 1;
block.hFileInfo.ioVRefNum = dirSpec.vRefNum;
block.hFileInfo.ioDirID = dir;
if (theProg && (OSErr)CallICMProgressProc(theProg->progressProc,
codecProgressUpdatePercent, kIndefProgress,
theProg->progressRefCon) == codecAbortErr)
return codecAbortErr;
while (PBGetCatInfo(&block, false) == noErr && theErr == noErr) {
KeepSpinning();
FSMakeFSSpec(dirSpec.vRefNum, dir, fileName, &theSpec);
if (ResolveAliasFile(&theSpec, true, &isFolder, &wasAliased) == noErr) {
if (isFolder) {
if (recursive) {
theErr = AddSlideDir(&theSpec, (*gSlideOptions)->recursive, theProg, &thisDir);
if (theErr != noErr) break;
}
} else if ((*gSlideOptions)->allFiles) {
short theFile, fileType;
if (FSpOpenDF(&theSpec, fsRdPerm, &theFile) == noErr) {
fileType = IDImage(theFile, &theSpec);
FSClose(theFile);
if (fileType != kInvalidType)
if (!NewSlide(false, &theSpec)) {
theErr = memFullErr;
break;
}
}
} else if (ValidType(block.hFileInfo.ioFlFndrInfo.fdType))
if (!NewSlide(false, &theSpec)) {
theErr = memFullErr;
break;
}
if (!(block.hFileInfo.ioFDirIndex & 0x0f))
if (theProg && (OSErr)CallICMProgressProc(theProg->progressProc,
codecProgressUpdatePercent, kIndefProgress,
theProg->progressRefCon) == codecAbortErr)
return codecAbortErr;
}
block.hFileInfo.ioFDirIndex++;
block.hFileInfo.ioDirID = dir;
}
return theErr;
}
//=====================================================================================
// void CleanUpSlideShow(void)
//
// Cleans up for when the slide show is completely finished.
//
// External calls: none
//=====================================================================================
extern void CleanUpSlideShow(void)
{
ImageHandle theImage, nextImage;
short choice = 0;
while (gSlideRoot) DisposeSlide(gSlideRoot);
if (GetSlideControlsWindow()) CloseSlideControls();
if (GetSlideBackWindow()) CloseSlideBackWindow();
gSlideShow = false;
if (!(*gSlideOptions)->fromMemory)
for (theImage = gImageRoot; theImage; theImage = nextImage) {
nextImage = (*theImage)->next;
if (theImage != FrontImage())
DoCloseWindow((*theImage)->window, gThePrefs.restoreColors);
}
if ((*gSlideOptions)->hideWindoids) {
if (gStatsHidden && OpenStats() == noErr) ChangeActive(GetStatWindow());
if (gCommentsHidden && OpenComments() == noErr) ChangeActive(GetCommentsWindow());
if (gColorsHidden && OpenColors() == noErr) ChangeActive(GetColorsWindow());
}
for (theImage = gImageRoot; theImage; theImage = (*theImage)->next)
if (GWTempMem(theImage)) KillGWorld(theImage);
EnableMenus();
if (theImage = FrontImage()) (*theImage)->flags &= ~ifAborted;
}
//=====================================================================================
// void ShuffleSlides(void)
//
// Shuffles the linked list of slides in a pseudo-random order.
//
// External calls: none
//=====================================================================================
static void ShuffleSlides(void)
{
SlideHandle theSlide, tempSlide;
long i, j, k;
for (i = 0; i < (gSlideCount * 4); i++) {
j = ((ushort)Random()) % gSlideCount;
if (j > 0) {
for (theSlide = gSlideRoot, k = 1; (k < j) && theSlide; k++)
theSlide = (*theSlide)->next;
if (theSlide) {
tempSlide = (*theSlide)->next;
(*theSlide)->next = (*tempSlide)->next;
(*tempSlide)->next = gSlideRoot;
gSlideRoot = tempSlide;
}
}
}
}
//=====================================================================================
// void LoadSlide(void)
//
// Loads the next slide, skipping over any that cause errors.
//
// External calls: none
//=====================================================================================
extern Boolean LoadSlide(Boolean *advance)
{
SlideHandle theSlide;
// loop until we get a good slide
while (!gSlideNextImage) {
if (!(*gSlideOptions)->userControl) ObscureCursor();
// enable the reverse button if we're not loading the first two slides
if (gSlideNext != gSlideRoot &&
(theSlide = DisplayedSlide()) && theSlide != gSlideRoot)
SetSlideControlButton(kReverseButton, standard);
else SetSlideControlButton(kReverseButton, disabled);
// load the next slide, either from memory, or from disk
if ((*gSlideNext)->mem) gSlideNextImage = LoadSlideFromMem();
else gSlideNextImage = LoadSlideFromDisk();
// if we've ended the show, clean up and return false
if (gSlideNextImage == (ImageHandle)kEndSlideShow) {
CleanUpSlideShow();
return false;
// if we're supposed to advance forward one, set the flag
} else if (gSlideNextImage == (ImageHandle)kAdvanceSlide) {
gSlideNextImage = nil;
*advance = true;
}
// if we're supposed to reload the current slide, skip this next part
if (gSlideNextImage == (ImageHandle)kReloadSlide) {
gSlideNextImage = nil;
*advance = true;
// if we're backing up, back gSlideNext up one and reload, skipping next
} else if (gSlideNextImage == (ImageHandle)kReverseSlide) {
gSlideNextImage = nil;
PointToPreviousSlide();
*advance = true;
// save the handle to the current slide, and find the next one, restarting
// and reshuffling as appropriate
} else {
theSlide = gSlideNext;
if (!(gSlideNext = (*gSlideNext)->next)) {
if (!(*gSlideOptions)->repeat) {
if (gSlideNextImage) {
gSlideNext = (SlideHandle)kEndSlideShow;
return true;
} else {
EndSlideShow();
CleanUpSlideShow();
return false;
}
} else {
if ((*gSlideOptions)->random) ShuffleSlides();
gSlideNext = gSlideRoot;
}
}
// if we got an unprocessed forward arrow, set the advance flag
if (gPendingButton == kForwardButton) {
*advance = true;
gPendingButton = -1;
}
// if there was an error in setting up the last slide, kill it from the list
if (!gSlideNextImage) {
if (gSlideNext == theSlide) {
gSlideNext = (*gSlideNext)->next;
if (!gSlideNext && gSlideRoot == theSlide) {
CleanUpSlideShow();
EndSlideShow();
return false;
} else if (!gSlideNext) gSlideNext = gSlideRoot;
}
DisposeSlide(theSlide);
}
}
}
return true;
}
//=====================================================================================
// ImageHandle LoadSlideFromMem(void)
//
// Sets up the next slide for an in-memory slide show.
//
// External calls: FindImage, IndexedDocument, DoSetWindowFull
//=====================================================================================
static ImageHandle LoadSlideFromMem(void)
{
ImageHandle theImage;
OSErr theErr = noErr;
theImage = FindImage(IndexedDocument((*gSlideNext)->spec.vRefNum));
if (!Full(theImage)) theErr = DoSetWindowFull((*theImage)->window, true);
if (theErr == noErr) return theImage;
if (!(*gSlideOptions)->noErrors) HandleAEError(theErr, errNoDrawMemory, (*theImage)->file.name);
return nil;
}
//=====================================================================================
// ImageHandle LoadSlideFromDisk(SlideHandle theSlide)
//
// Sets up the next slide for a disk-based slide show; returns nil if the image failed
// to load; returns (ImageHandle)-1 if the slide show should end.
//
// External calls: GetOpenDefaults, DoOpenDocument, StopSpinning, HandleAEError
//=====================================================================================
static ImageHandle LoadSlideFromDisk(void)
{
DescType openScreen, openFull, openPalette, drawQuality;
FSSpec theSpec = (*gSlideNext)->spec;
ImageHandle theImage;
OSErr theErr;
do {
SetSlideControlsText(gString[strSlideLoading], theSpec.name, gNullString, gNullString);
GetOpenDefaults(&openScreen, &openFull, &openPalette, &drawQuality);
StartSpinning();
theErr = DoOpenDocument(&theSpec, true, openScreen, kAEOFAlways,
gThePrefs.expandSmall, true, openPalette, drawQuality,
(*gSlideOptions)->offscreen, (*gSlideOptions)->autoComments,
gThePrefs.autoFix, gThePrefs.changeCreator);
StopSpinning(&qd.arrow);
if (theErr == noErr) {
for (theImage = gImageRoot, gSlideNextImage = nil; theImage;
theImage = (*theImage)->next)
if (SameFile(&(*theImage)->file, &theSpec)) return theImage;
} else theImage = HandleLoadError(theErr, theSpec.name);
} while (theImage == (ImageHandle)kReloadSlide);
return theImage;
}
//=====================================================================================
// ImageHandle HandleLoadError(OSErr theErr)
//
// Handles errors that occur during a load; abort errors are assumed to be the result
// of the user pressing a control button.
//
// External calls: GetOpenDefaults, DoOpenDocument, StopSpinning, HandleAEError
//=====================================================================================
static ImageHandle HandleLoadError(OSErr theErr, StringPtr fileName)
{
Boolean advance;
switch (theErr) {
case codecAbortErr:
if (gDone) return (ImageHandle)kEndSlideShow;
else if (gPendingButton != -1) {
short button = gPendingButton;
gPendingButton = -1;
if (button == kPauseButton || button == kHideButton) {
gSlideShow = (button == kPauseButton) ? PauseSlideShow(&advance) :
HideSlideShow(&advance);
if (!gSlideShow) return (ImageHandle)kEndSlideShow;
else return (ImageHandle)kReloadSlide;
} else if (button == kForwardButton)// && (*gSlideOptions)->userControl)
return (ImageHandle)kAdvanceSlide;
else if (button == kStopButton) return (ImageHandle)kEndSlideShow;
else if (button == kReverseButton) return (ImageHandle)kReverseSlide;
}
break;
case memFullErr:
if (WarnSlideShowMemory()) return (ImageHandle)kEndSlideShow;
break;
default:
if (!(*gSlideOptions)->noErrors) HandleAEError(theErr, errNoLoadMemory, fileName);
break;
}
return nil;
}
//=====================================================================================
// Boolean WarnSlideShowMemory(void)
//
// Display the warning about not being able to see all slides due to low memory.
//
// External calls: PushPort, MySetPort, StopSpinning, CenterAlert, PopPort
//=====================================================================================
static Boolean WarnSlideShowMemory(void)
{
short choice;
ShowCursor();
if (!gSlideWarned && !(*gSlideOptions)->noErrors) {
gSlideWarned = true;
PushPort();
MySetPort(nil);
StopSpinning(&qd.arrow);
choice = FWCautionAlert(CenterAlert(rSlideMemAlert), gGenericFilter);
PopPort();
if (choice == 3 || choice == kDialogCancel) return true;
}
return false;
}
//=====================================================================================
// Boolean EndSlideShow(void)
//
// Display the "Slide show has ended" alert.
//
// External calls: PushPort, MySetPort, StopSpinning, CenterAlert, PopPort
//=====================================================================================
extern Boolean EndSlideShow(void)
{
ShowCursor();
if (!gSlideRoot) {
MinorError(errNoImagesFound);
MyInvalMenuBar();
} else {
PushPort();
MySetPort(nil);
StopSpinning(&qd.arrow);
FWNoteAlert(CenterAlert(rEndSlidesAlert), gGenericFilter);
PopPort();
}
return false;
}
//=====================================================================================
// Boolean NextSlide(void)
//
// Switches to the next slide and forces it to be drawn.
//
// External calls: ChangeActive, DoCloseWindow, UpdateImage
//=====================================================================================
extern Boolean NextSlide(Boolean *advance)
{
ImageHandle loadErrorResult;
OSErr theErr;
// if no slide is ready tell the caller to advance
if (!gSlideNextImage) *advance = true;
// otherwise, process & draw the next slide
else {
// obscure the cursor unless it's under user control
if (!(*gSlideOptions)->userControl && !GetSlideControlsWindow()) ObscureCursor();
// bring the next window to the front
ChangeActive((*gSlideNextImage)->window);
// if we're doing a disk-based slide show, close all other images
if (!(*gSlideRoot)->mem) {
ImageHandle oldImage, nextImage;
for (oldImage = gImageRoot; oldImage; oldImage = nextImage) {
nextImage = (*oldImage)->next;
if (oldImage != gSlideNextImage)
DoCloseWindow((*oldImage)->window, gThePrefs.restoreColors);
}
}
// handle the update immediately, so we can begin loading the next guy; we
// do this in a loop so that if we get a pause/resume sequence, we can redraw
// the image
do {
SetSlideControlsText(gString[strSlideDrawing], (*gSlideNextImage)->file.name,
gNullString, gNullString);
theErr = UpdateImage(gSlideNextImage);
ResetSlideTimer();
// clear out the next slide pointer and handle any error conditions
if (theErr != noErr) {
loadErrorResult = HandleLoadError(theErr, nil);
if (loadErrorResult == (ImageHandle)kAdvanceSlide) *advance = true;
else if (loadErrorResult == (ImageHandle)kEndSlideShow) {
CleanUpSlideShow();
return false;
} else if (loadErrorResult == (ImageHandle)kReverseSlide) {
PointToPreviousSlide();
*advance = true;
}
} else loadErrorResult = nil;
if (loadErrorResult != (ImageHandle)kReloadSlide) gSlideNextImage = nil;
} while (loadErrorResult == (ImageHandle)kReloadSlide);
}
// if we hit the end of the slide show, end it now
if (!(*gSlideOptions)->repeat && DisplayedSlide() == LastSlide()) {
SetSlideControlButton(kForwardButton, disabled);
DrawSlideControlsWindow();
EndSlideShow();
CleanUpSlideShow();
return false;
}
return true;
}