Demonstration Program
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// Files2.h
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
//
// This program demonstrates:
//
// ¥ The use of Navigation Services rather than the Standard File Package to display
// Open, Save, and Choose a Folder dialog boxes.
//
// ¥ The use of Navigation Services rather than the Dialog Manager to display Save
// Changes and Discard Changes alert boxes.
//
// ¥ Application-defined file handling functions associated with:
//
// ¥ The user invoking the File menu Open., Close, Save, Save As., Revert to Saved,
// and Quit commands of a typical application.
//
// ¥ Handling of the required Apple events Open Application, Re-open Application,
// Open Documents and Quit Application.
//
// These functions are essentially the same as those in the demonstration program
// Files1 except that the safe-save methodology used in Files1 is not used, all
// saves being direct to the target file.
//
// To keep the code not specifically related to files and file-handling to a minimum, an
// item is included in the Demonstration menu which allows the user to simulate
// "touching" a window (that is, modifying the contents of the associated document).
// Choosing the first menu item in this menu sets the window-touched flag in the window's
// document structure to true and draws the text "WINDOW TOUCHED" in the window in a
// large font size, this latter so that the user can keep track of which windows have
// been "touched".
//
// This program is also, in part, an extension of the demonstration program Windows2 in
// that it also demonstrates certain file-related Window Manager features introduced with
// the Mac OS 8.5 Window Manager. These features are:
//
// ¥ Window proxy icons.
//
// ¥ Window path pop-up menus.
//
// Those sections of the source code relating to these features is identified with /////
// at the right of each line.
//
// The program utilises the following resources:
//
// ¥ An 'MBAR' resource, and 'MENU' resources for Apple, File, Edit and Demonstration
// menus (preload, non-purgeable).
//
// ¥ A 'WIND' resource (purgeable) (initially not visible).
//
// ¥ A 'STR ' resource containing the "missing application name" string, which is copied
// to all document files created by the program.
//
// ¥ 'STR#' resources (purgeable) containing error strings, the application's name (for
// certain Navigation Services functions), and a message string for the Choose a
// Folder dialog box.
//
// ¥ A 'kind' resource (purgeable) describing file types, which is used by Navigation
// Services to build the native file types section of the Show pop-up menu in the
// Open dialog box.
//
// ¥ An 'open' resource (purgeable) containing the file type list for the Open dialog
// box.
//
// ¥ A 'pnot' and associated 'PICT' resource (both purgeable), which provide the preview
// for the PICT file.
//
// ¥ The 'BNDL' resource (non-purgeable), 'FREF' resources (non-purgeable), signature
// resource (non-purgeable), and icon family resources (purgeable), required to
// support the built application.
//
// ¥ A 'SIZE' resource with the acceptSuspendResumeEvents, isHighLevelEventAware, and
// is32BitCompatible flags set (non-purgeable).
//
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// ............................................................................. includes
#include <Appearance.h>
#include <AERegistry.h>
#include <Devices.h>
#include <Folders.h>
#include <Gestalt.h> /////
#include <Navigation.h>
#include <Resources.h>
#include <Sound.h>
#include <ToolUtils.h>
// ............................................................................. typedefs
typedef struct
{
TEHandle editStrucHdl;
PicHandle pictureHdl;
SInt16 fileRefNum;
FSSpec fileFSSpec;
AliasHandle aliasHdl; /////
Boolean windowTouched;
} docStructure, *docStructurePointer, **docStructureHandle;
typedef StandardFileReply *standardFileReplyPtr;
// .............................................................................. defines
#define mApple 128
#define iAbout 1
#define mFile 129
#define iNew 1
#define iOpen 2
#define iClose 4
#define iSave 5
#define iSaveAs 6
#define iRevert 7
#define iQuit 12
#define mDemonstration 131
#define iTouchWindow 1
#define iChooseAFolderDialog 3
#define rNewWindow 128
#define rMenubar 128
#define rRevertAlert 128
#define rCloseFileAlert 129
#define rCustomOpenDialog 130
#define iPopupItem 10
#define rSelectDirectoryDialog 131
#define iSelectButton 10
#define rErrorStrings 128
#define eInstallHandler 1000
#define eMaxWindows 1001
#define eFileIsOpen opWrErr
#define eNoNavServices 1002
#define eCantFindFinderProcess 1003 /////
#define rMiscStrings 129
#define sApplicationName 1
#define sChooseAFolder 2
#define rOpenResource 128
#define kMaxWindows 10
#define MAXLONG 0x7FFFFFFF
#define MIN(a,b) ((a) < (b) ? (a) : (b))
// .................................................................. function prototypes
void main (void);
void eventLoop (void);
void doInitManagers (void);
void doInstallAEHandlers (void);
void doEvents (EventRecord *);
void doMouseDown (EventRecord *);
void doBringFinderToFront (void); /////
OSErr doFindProcess (OSType,OSType,ProcessSerialNumber *); /////
void doUpdate (EventRecord *);
void doMenuChoice (SInt32);
void doFileMenu (SInt16);
void doAdjustMenus (void);
void doErrorAlert (SInt16);
void doCopyPString (Str255,Str255);
void doConcatPStrings (Str255,Str255);
void doTouchWindow (void);
void doSynchroniseFiles (void); /////
pascal OSErr doOpenAppEvent (AppleEvent *,AppleEvent *,SInt32);
pascal OSErr doReopenAppEvent (AppleEvent *,AppleEvent *,SInt32);
pascal OSErr doOpenDocsEvent (AppleEvent *,AppleEvent *,SInt32);
pascal OSErr doQuitAppEvent (AppleEvent *,AppleEvent *,SInt32);
OSErr doHasGotRequiredParams (AppleEvent *);
OSErr doNewCommand (void);
OSErr doOpenCommand (void);
OSErr doCloseCommand (NavAskSaveChangesAction);
OSErr doSaveCommand (void);
OSErr doSaveAsCommand (void);
OSErr doRevertCommand (void);
OSErr doQuitCommand (NavAskSaveChangesAction);
OSErr doNewDocWindow (Boolean,OSType);
OSErr doOpenFile (FSSpec,OSType);
OSErr doReadTextFile (WindowPtr);
OSErr doReadPictFile (WindowPtr);
OSErr doCloseFile (WindowPtr,docStructureHandle,NavAskSaveChangesAction);
OSErr doWriteFile (WindowPtr,Boolean);
OSErr doWriteTextData (WindowPtr,SInt16);
OSErr doWritePictData (WindowPtr,SInt16);
OSErr doCopyResources (WindowPtr);
OSErr doCopyAResource (ResType,SInt16,SInt16,SInt16);
pascal void navEventFunction (NavEventCallbackMessage,NavCBRecPtr,NavCallBackUserData);
OSErr doChooseAFolderDialog (FSSpec *);
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// Files2.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// ............................................................................. includes
#include "Files2.h"
// ..................................................................... global variables
Boolean gMacOS85Present = false; /////
Boolean gDone;
Boolean gInBackground;
AEEventHandlerUPP doOpenAppEventUPP;
AEEventHandlerUPP doReopenAppEventUPP;
AEEventHandlerUPP doOpenDocsEventUPP;
AEEventHandlerUPP doQuitAppEventUPP;
SInt16 gAppResFileRefNum;
extern SInt16 gCurrentNumberOfWindows;
extern Rect gDestRect,gViewRect;
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× main
void main(void)
{
OSErr osError; /////
SInt32 response; /////
Handle menubarHdl;
MenuHandle menuHdl;
// .................................................................initialise managers
doInitManagers();
// ....................................... check whether Mac OS 8.5 or later is present
osError = Gestalt(gestaltSystemVersion,&response); /////
/////
if(osError == noErr && response >= 0x00000850) /////
gMacOS85Present = true; /////
// ............................. check for Navigation Services, and pre-load (optional)
if(NavServicesAvailable())
NavLoad();
else
doErrorAlert(eNoNavServices);
// ................................. create routine decriptors for Apple event handlers
doOpenAppEventUPP = NewAEEventHandlerProc((ProcPtr) doOpenAppEvent);
doReopenAppEventUPP = NewAEEventHandlerProc((ProcPtr) doReopenAppEvent);
doOpenDocsEventUPP = NewAEEventHandlerProc((ProcPtr) doOpenDocsEvent);
doQuitAppEventUPP = NewAEEventHandlerProc((ProcPtr) doQuitAppEvent);
// ........................... set application's resource fork as current resource file
gAppResFileRefNum = CurResFile();
// .......................................................... set up menu bar and menus
menubarHdl = GetNewMBar(rMenubar);
if(menubarHdl == NULL)
doErrorAlert(MemError());
SetMenuBar(menubarHdl);
DrawMenuBar();
menuHdl = GetMenuHandle(mApple);
if(menuHdl == NULL)
doErrorAlert(MemError());
else
AppendResMenu(menuHdl,'DRVR');
// .............................................. install required Apple event handlers
doInstallAEHandlers();
// ................................................................... enter event loop
eventLoop();
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× eventLoop
void eventLoop(void)
{
EventRecord eventStructure;
gDone = false;
while(!gDone)
{
if(WaitNextEvent(everyEvent,&eventStructure,MAXLONG,NULL))
doEvents(&eventStructure);
#if TARGET_CPU_PPC /////
else /////
if(gMacOS85Present) /////
doSynchroniseFiles(); /////
#endif /////
}
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doInitManagers
void doInitManagers(void)
{
MaxApplZone();
MoreMasters();
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(NULL);
InitCursor();
FlushEvents(everyEvent,0);
RegisterAppearanceClient();
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doInstallAEHandlers
void doInstallAEHandlers(void)
{
OSErr osError;
osError = AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,doOpenAppEventUPP,
0L,false);
if(osError != noErr) doErrorAlert(eInstallHandler);
osError = AEInstallEventHandler(kCoreEventClass,kAEReopenApplication,
doReopenAppEventUPP,0L,false);
if(osError != noErr) doErrorAlert(eInstallHandler);
osError = AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,doOpenDocsEventUPP,
0L,false);
if(osError != noErr) doErrorAlert(eInstallHandler);
osError = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,doQuitAppEventUPP,
0L,false);
if(osError != noErr) doErrorAlert(eInstallHandler);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doEvents
void doEvents(EventRecord *eventStrucPtr)
{
SInt8 charCode;
switch(eventStrucPtr->what)
{
case kHighLevelEvent:
AEProcessAppleEvent(eventStrucPtr);
break;
case mouseDown:
doMouseDown(eventStrucPtr);
break;
case keyDown:
case autoKey:
charCode = eventStrucPtr->message & charCodeMask;
if((eventStrucPtr->modifiers & cmdKey) != 0)
{
doAdjustMenus();
doMenuChoice(MenuEvent(eventStrucPtr));
}
break;
case updateEvt:
doUpdate(eventStrucPtr);
break;
case osEvt:
switch((eventStrucPtr->message >> 24) & 0x000000FF)
{
case suspendResumeMessage:
gInBackground = (eventStrucPtr->message & resumeFlag) == 0;
break;
}
HiliteMenu(0);
break;
}
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMouseDown
void doMouseDown(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
SInt16 partCode;
OSStatus osStatus; /////
Boolean handled = false; /////
SInt32 itemSelected; /////
partCode = FindWindow(eventStrucPtr->where,&windowPtr);
switch(partCode)
{
case inMenuBar:
doAdjustMenus();
doMenuChoice(MenuSelect(eventStrucPtr->where));
break;
case inContent:
if(windowPtr != FrontWindow())
SelectWindow(windowPtr);
break;
case inGoAway:
if(TrackGoAway(windowPtr,eventStrucPtr->where) == true)
doCloseCommand(kNavSaveChangesClosingDocument);
break;
#if TARGET_CPU_PPC /////
case inProxyIcon: /////
osStatus = TrackWindowProxyDrag(windowPtr,eventStrucPtr->where); /////
if(osStatus == errUserWantsToDragWindow) /////
handled = false; /////
else if(osStatus == noErr) /////
handled = true; /////
#endif /////
case inDrag: /////
#if TARGET_CPU_PPC /////
if(gMacOS85Present) /////
{ /////
if(!handled) /////
{ /////
if(IsWindowPathSelectClick(windowPtr,eventStrucPtr)) /////
{ /////
if(WindowPathSelect(windowPtr,NULL,&itemSelected) == noErr) /////
{ /////
if(LoWord(itemSelected) > 1) /////
doBringFinderToFront(); /////
} /////
/////
handled = true; /////
} /////
} /////
if(!handled) /////
DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds); /////
} /////
else /////
#endif /////
DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);
break;
}
}
#if TARGET_CPU_PPC /////
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doBringFinderToFront
void doBringFinderToFront(void) /////
{ /////
ProcessSerialNumber finderProcess; /////
/////
if(doFindProcess('MACS','FNDR',&finderProcess) == noErr) /////
SetFrontProcess(&finderProcess); /////
else /////
doErrorAlert(eCantFindFinderProcess); /////
} /////
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFindProcess
OSErr doFindProcess(OSType creator,OSType type,ProcessSerialNumber *outProcSerNo)
{ /////
ProcessSerialNumber procSerialNo; /////
ProcessInfoRec procInfoStruc; /////
OSErr osError = 0; /////
/////
procSerialNo.highLongOfPSN = 0; /////
procSerialNo.lowLongOfPSN = kNoProcess; /////
/////
procInfoStruc.processInfoLength = sizeof(ProcessInfoRec); /////
procInfoStruc.processName = NULL; /////
procInfoStruc.processAppSpec = NULL; /////
procInfoStruc.processLocation = NULL; /////
/////
while(true) /////
{ /////
osError = GetNextProcess(&procSerialNo); /////
if(osError != noErr) /////
break; /////
/////
osError = GetProcessInformation(&procSerialNo,&procInfoStruc); /////
if(osError != noErr) /////
break; /////
if((procInfoStruc.processSignature == creator) && /////
(procInfoStruc.processType == type)) /////
break; /////
} /////
/////
*outProcSerNo = procSerialNo; /////
/////
return osError; /////
} /////
#endif /////
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doUpdate
void doUpdate(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
docStructureHandle docStrucHdl;
GrafPtr oldPort;
Rect destRect;
windowPtr = (WindowPtr) eventStrucPtr->message;
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
GetPort(&oldPort);
SetPort(windowPtr);
BeginUpdate(windowPtr);
if((*docStrucHdl)->pictureHdl)
{
destRect = (*(*docStrucHdl)->pictureHdl)->picFrame;
OffsetRect(&destRect,170,54);
HLock((Handle) (*docStrucHdl)->pictureHdl);
DrawPicture((*docStrucHdl)->pictureHdl,&destRect);
HUnlock((Handle) (*docStrucHdl)->pictureHdl);
}
else if((*docStrucHdl)->editStrucHdl)
{
HLock((Handle) (*docStrucHdl)->editStrucHdl);
TEUpdate(&gDestRect,(*docStrucHdl)->editStrucHdl);
HUnlock((Handle) (*docStrucHdl)->editStrucHdl);
}
if((*docStrucHdl)->windowTouched)
{
TextSize(48);
MoveTo(30,170);
DrawString("\pWINDOW TOUCHED");
TextSize(12);
}
EndUpdate((WindowPtr)eventStrucPtr->message);
SetPort(oldPort);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMenuChoice
void doMenuChoice(SInt32 menuChoice)
{
SInt16 menuID, menuItem;
Str255 itemName;
SInt16 daDriverRefNum;
OSErr osError;
FSSpec fileSpec;
Rect theRect;
Str255 theString, numberString;
menuID = HiWord(menuChoice);
menuItem = LoWord(menuChoice);
if(menuID == 0)
return;
switch(menuID)
{
case mApple:
GetMenuItemText(GetMenuHandle(mApple),menuItem,itemName);
daDriverRefNum = OpenDeskAcc(itemName);
break;
case mFile:
doFileMenu(menuItem);
break;
case mDemonstration:
if(menuItem == iTouchWindow)
doTouchWindow();
else if(menuItem == iChooseAFolderDialog)
{
if((osError = doChooseAFolderDialog(&fileSpec)) && osError != userCanceledErr)
doErrorAlert(osError);
else
{
if(FrontWindow())
{
SetPort(FrontWindow());
TextSize(10);
SetRect(&theRect,0,271,600,300);
EraseRect(&theRect);
if(osError != userCanceledErr)
{
doCopyPString(fileSpec.name,theString);
doConcatPStrings(theString, "\p Volume Reference Number: ");
NumToString((SInt32) fileSpec.vRefNum,numberString);
doConcatPStrings(theString,numberString);
doConcatPStrings(theString, "\p Parent Directory ID: ");
NumToString((SInt32) fileSpec.parID,numberString);
doConcatPStrings(theString,numberString);
MoveTo(10,290);
DrawString(theString);
}
}
}
}
break;
}
HiliteMenu(0);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFileMenu
void doFileMenu(SInt16 menuItem)
{
OSErr osError;
switch(menuItem)
{
case iNew:
if(osError = doNewCommand())
doErrorAlert(osError);
break;
case iOpen:
if(osError = doOpenCommand())
doErrorAlert(osError);
break;
case iClose:
if((osError = doCloseCommand(kNavSaveChangesClosingDocument)) &&
osError != kNavAskSaveChangesCancel)
doErrorAlert(osError);
break;
case iSave:
if(osError = doSaveCommand())
doErrorAlert(osError);
break;
case iSaveAs:
if(osError = doSaveAsCommand())
doErrorAlert(osError);
break;
case iRevert:
if(osError = doRevertCommand())
doErrorAlert(osError);
break;
case iQuit:
if((osError = doQuitCommand(kNavSaveChangesQuittingApplication)) &&
osError != kNavAskSaveChangesCancel)
doErrorAlert(osError);
if(osError != kNavAskSaveChangesCancel)
{
NavUnload();
gDone = true;
}
break;
}
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doAdjustMenus
void doAdjustMenus(void)
{
MenuHandle menuHdl;
WindowPtr windowPtr;
docStructureHandle docStrucHdl;
windowPtr = FrontWindow();
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
menuHdl = GetMenuHandle(mFile);
if(gCurrentNumberOfWindows > 0)
{
menuHdl = GetMenuHandle(mFile);
EnableItem(menuHdl,iClose);
if((*docStrucHdl)->windowTouched)
{
EnableItem(menuHdl,iSave);
EnableItem(menuHdl,iRevert);
}
else
{
DisableItem(menuHdl,iSave);
DisableItem(menuHdl,iRevert);
}
EnableItem(menuHdl,iSaveAs);
menuHdl = GetMenuHandle(mDemonstration);
if((*docStrucHdl)->windowTouched == false)
EnableItem(menuHdl,iTouchWindow);
else
DisableItem(menuHdl,iTouchWindow);
}
else
{
menuHdl = GetMenuHandle(mFile);
DisableItem(menuHdl,iClose);
DisableItem(menuHdl,iSave);
DisableItem(menuHdl,iSaveAs);
DisableItem(menuHdl,iRevert);
menuHdl = GetMenuHandle(mDemonstration);
DisableItem(menuHdl,iTouchWindow);
}
DrawMenuBar();
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doErrorAlert
void doErrorAlert(SInt16 errorCode)
{
AlertStdAlertParamRec paramRec;
Str255 errorString, theString;
SInt16 itemHit;
paramRec.movable = true;
paramRec.helpButton = false;
paramRec.filterProc = NULL;
paramRec.defaultText = (StringPtr) kAlertDefaultOKText;
paramRec.cancelText = NULL;
paramRec.otherText = NULL;
paramRec.defaultButton = kAlertStdAlertOKButton;
paramRec.cancelButton = 0;
paramRec.position = kWindowDefaultPosition;
if(errorCode == eInstallHandler)
GetIndString(errorString,rErrorStrings,1);
else if(errorCode == eMaxWindows)
GetIndString(errorString,rErrorStrings,2);
else if(errorCode == eFileIsOpen)
GetIndString(errorString,rErrorStrings,3);
else if(errorCode == eNoNavServices)
GetIndString(errorString,rErrorStrings,4);
else if(errorCode == eCantFindFinderProcess)
GetIndString(errorString,rErrorStrings,5);
else
{
GetIndString(errorString,rErrorStrings,6);
NumToString((SInt32) errorCode,theString);
doConcatPStrings(errorString,theString);
}
if(errorCode != memFullErr && errorCode != eNoNavServices)
StandardAlert(kAlertCautionAlert,errorString,NULL,¶mRec,&itemHit);
else
{
StandardAlert(kAlertStopAlert,errorString,NULL,¶mRec,&itemHit);
ExitToShell();
}
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCopyPString
void doCopyPString(Str255 sourceString,Str255 destinationString)
{
SInt16 stringLength;
stringLength = sourceString[0];
BlockMove(sourceString + 1,destinationString + 1,stringLength);
destinationString[0] = stringLength;
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doConcatPStrings
void doConcatPStrings(Str255 targetString,Str255 appendString)
{
SInt16 appendLength;
appendLength = MIN(appendString[0],255 - targetString[0]);
if(appendLength > 0)
{
BlockMoveData(appendString+1,targetString+targetString[0]+1,(SInt32) appendLength);
targetString[0] += appendLength;
}
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doTouchWindow
void doTouchWindow(void)
{
WindowPtr windowPtr;
docStructureHandle docStrucHdl;
windowPtr = FrontWindow();
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
SetPort(windowPtr);
TextSize(48);
MoveTo(30,170);
DrawString("\pWINDOW TOUCHED");
TextSize(12);
(*docStrucHdl)->windowTouched = true;
#if TARGET_CPU_PPC /////
if(gMacOS85Present) /////
SetWindowModified(windowPtr,true); /////
#endif /////
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSynchroniseFiles
#if TARGET_CPU_PPC /////
void doSynchroniseFiles(void) /////
{ /////
UInt32 currentTicks; /////
WindowPtr windowPtr; /////
SInt16 trashVRefNum; /////
SInt32 trashDirID; /////
static UInt32 nextSynchTicks = 0; /////
docStructureHandle docStrucHdl; /////
Boolean aliasChanged; /////
AliasHandle aliasHdl; /////
FSSpec newFSSpec; /////
OSErr osError; /////
/////
currentTicks = TickCount(); /////
windowPtr = FrontNonFloatingWindow(); /////
/////
if(currentTicks > nextSynchTicks) /////
{ /////
while(windowPtr != NULL) /////
{ /////
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr); /////
/////
if(docStrucHdl != NULL) /////
{ /////
if((*docStrucHdl)->aliasHdl == NULL) /////
break; /////
/////
aliasChanged = false; /////
aliasHdl = (*docStrucHdl)->aliasHdl; /////
ResolveAlias(NULL,aliasHdl,&newFSSpec,&aliasChanged); /////
/////
if(aliasChanged) /////
{ /////
(*docStrucHdl)->fileFSSpec = newFSSpec; /////
SetWTitle(windowPtr,newFSSpec.name); /////
} /////
/////
osError = FindFolder(kOnSystemDisk,kTrashFolderType,kDontCreateFolder, /////
&trashVRefNum,&trashDirID); /////
/////
if(osError == noErr) /////
{ /////
do /////
{ /////
if(newFSSpec.parID == fsRtParID) /////
break; /////
/////
if((newFSSpec.vRefNum == trashVRefNum) && (newFSSpec.parID == trashDirID))
{ /////
FSClose((*docStrucHdl)->fileRefNum); /////
if((*docStrucHdl)->editStrucHdl) /////
TEDispose((*docStrucHdl)->editStrucHdl); /////
if((*docStrucHdl)->pictureHdl) /////
KillPicture((*docStrucHdl)->pictureHdl); /////
DisposeHandle((Handle) docStrucHdl); /////
DisposeWindow(windowPtr); /////
gCurrentNumberOfWindows --; /////
break; /////
} /////
} while(FSMakeFSSpec(newFSSpec.vRefNum,newFSSpec.parID,"\p",&newFSSpec) == noErr);
} /////
} /////
/////
windowPtr = GetNextWindow(windowPtr); /////
} /////
/////
nextSynchTicks = currentTicks + 15; /////
} /////
} /////
#endif /////
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOpenAppEvent
pascal OSErr doOpenAppEvent(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefCon)
{
OSErr osError;
osError = doHasGotRequiredParams(appEvent);
if(osError == noErr)
osError = doNewCommand();
return(osError);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doReopenAppEvent
pascal OSErr doReopenAppEvent(AppleEvent *appEvent,AppleEvent *reply,
SInt32 handlerRefCon)
{
OSErr osError;
osError = doHasGotRequiredParams(appEvent);
if(osError == noErr)
if(!FrontWindow())
osError = doNewCommand();
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOpenDocsEvent
pascal OSErr doOpenDocsEvent(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
{
FSSpec fileSpec;
AEDescList docList;
OSErr osError, ignoreErr;
SInt32 index, numberOfItems;
Size actualSize;
AEKeyword keyWord;
DescType returnedType;
FInfo fileInfo;
osError = AEGetParamDesc(appEvent,keyDirectObject,typeAEList,&docList);
if(osError == noErr)
{
osError = doHasGotRequiredParams(appEvent);
if(osError == noErr)
{
AECountItems(&docList,&numberOfItems);
if(osError == noErr)
{
for(index=1;index<=numberOfItems;index++)
{
osError = AEGetNthPtr(&docList,index,typeFSS,&keyWord,&returnedType,
(Ptr) &fileSpec,sizeof(fileSpec),&actualSize);
if(osError == noErr)
{
osError = FSpGetFInfo(&fileSpec,&fileInfo);
if(osError == noErr)
{
if(osError = doOpenFile(fileSpec,fileInfo.fdType))
doErrorAlert(osError);
}
}
else
doErrorAlert(osError);
}
}
}
else
doErrorAlert(osError);
ignoreErr = AEDisposeDesc(&docList);
}
else
doErrorAlert(osError);
return(osError);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doQuitAppEvent
pascal OSErr doQuitAppEvent(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
{
OSErr osError;
osError = doHasGotRequiredParams(appEvent);
if(osError == noErr)
{
while(FrontWindow())
{
osError = doCloseCommand(kNavSaveChangesQuittingApplication);
if(osError != noErr && osError != kNavAskSaveChangesCancel)
doErrorAlert(osError);
if(osError == kNavAskSaveChangesCancel)
return;
}
}
NavUnload();
gDone = true;
return(osError);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doHasGotRequiredParams
OSErr doHasGotRequiredParams(AppleEvent *appEvent)
{
DescType returnedType;
Size actualSize;
OSErr osError;
osError = AEGetAttributePtr(appEvent,keyMissedKeywordAttr,typeWildCard,&returnedType,
NULL,0,&actualSize);
if(osError == errAEDescNotFound)
return(noErr);
else if(osError == noErr)
return(errAEParamMissed);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// NewOpenCloseSave.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// ............................................................................. includes
#include "Files2.h"
// ..................................................................... global variables
WindowPtr gWindowPtr;
SInt16 gCurrentNumberOfWindows = 0;
Rect gDestRect,gViewRect;
extern SInt16 gAppResFileRefNum;
extern Boolean gMacOS85Present; /////
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doNewCommand
OSErr doNewCommand(void)
{
OSErr osError;
OSType documentType = 'TEXT';
osError = doNewDocWindow(true,documentType);
#if TARGET_CPU_PPC /////
if(gMacOS85Present) /////
{ /////
if(osError == noErr) /////
SetWindowProxyCreatorAndType(gWindowPtr,'kBkB','TEXT',kOnSystemDisk); /////
} /////
#endif /////
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOpenCommand
OSErr doOpenCommand(void)
{
NavDialogOptions dialogOptions;
NavTypeListHandle fileTypeListHdl = NULL;
NavEventUPP navEventFunctionUPP;
OSErr osError = noErr;
NavReplyRecord navReplyStruc;
AEDesc resultDesc;
SInt32 index, count;
FSSpec fileSpec;
FInfo fileInfo;
OSType documentType;
NavGetDefaultDialogOptions(&dialogOptions);
GetIndString((unsigned char*) &dialogOptions.clientName,rMiscStrings,sApplicationName);
fileTypeListHdl = (NavTypeListHandle) GetResource('open',rOpenResource);
navEventFunctionUPP = NewNavEventProc((ProcPtr) navEventFunction);
osError = NavGetFile(NULL,&navReplyStruc,&dialogOptions,navEventFunctionUPP,NULL,NULL,
fileTypeListHdl,0);
DisposeRoutineDescriptor(navEventFunctionUPP);
if(navReplyStruc.validRecord && osError == noErr)
{
if(osError == noErr)
{
osError = AECountItems(&(navReplyStruc.selection),&count);
for(index=1;index<=count;index++)
{
resultDesc.dataHandle = 0L;
if((osError = AEGetNthDesc(&(navReplyStruc.selection),index,typeFSS,NULL,
&resultDesc)) == noErr)
{
BlockMoveData(*resultDesc.dataHandle,&fileSpec,sizeof(FSSpec));
if((osError = FSpGetFInfo(&fileSpec,&fileInfo)) == noErr)
{
documentType = fileInfo.fdType;
osError = doOpenFile(fileSpec,documentType);
}
AEDisposeDesc(&resultDesc);
}
}
}
NavDisposeReply(&navReplyStruc);
}
if(fileTypeListHdl != NULL)
ReleaseResource((Handle) fileTypeListHdl);
if(osError == userCanceledErr)
osError = noErr;
return(osError);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCloseCommand
OSErr doCloseCommand(NavAskSaveChangesAction action)
{
WindowPtr windowPtr;
SInt16 windowKind;
docStructureHandle docStrucHdl;
OSErr osError = noErr;
windowPtr = FrontWindow();
windowKind = ((WindowPeek) windowPtr)->windowKind;
switch(windowKind)
{
case kApplicationWindowKind:
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
osError = doCloseFile(windowPtr,docStrucHdl,action);
if(osError == kNavAskSaveChangesCancel)
return(kNavAskSaveChangesCancel);
else if(osError == noErr)
{
DisposeWindow(windowPtr);
gCurrentNumberOfWindows --;
}
break;
case kDialogWindowKind:
// Hide or close modeless dialog, as required.
break;
}
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSaveCommand
OSErr doSaveCommand(void)
{
WindowPtr windowPtr;
docStructureHandle docStrucHdl;
OSErr osError = noErr;
windowPtr = FrontWindow();
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
if((*docStrucHdl)->fileRefNum)
{
osError = doWriteFile(windowPtr,false);
SetPort(windowPtr);
EraseRect(&windowPtr->portRect);
InvalRect(&windowPtr->portRect);
}
else
osError = doSaveAsCommand();
#if TARGET_CPU_PPC /////
if(gMacOS85Present) /////
{ /////
if(osError == noErr) /////
SetWindowModified(windowPtr,false); /////
} /////
#endif /////
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSaveAsCommand
OSErr doSaveAsCommand(void)
{
NavDialogOptions dialogOptions;
WindowPtr windowPtr;
docStructureHandle docStrucHdl;
NavEventUPP navEventFunctionUPP;
OSType fileType;
OSErr osError = noErr;
NavReplyRecord navReplyStruc;
AEDesc resultDesc;
FSSpec fileSpec;
SInt16 fileRefNum;
NavGetDefaultDialogOptions(&dialogOptions);
windowPtr = FrontWindow();
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
GetWTitle(windowPtr,dialogOptions.savedFileName);
GetIndString((unsigned char*) &dialogOptions.clientName,rMiscStrings,sApplicationName);
navEventFunctionUPP = NewNavEventProc((ProcPtr) navEventFunction);
if((*docStrucHdl)->editStrucHdl)
fileType = 'TEXT';
else if((*docStrucHdl)->pictureHdl)
fileType = 'PICT';
osError = NavPutFile(NULL,&navReplyStruc,&dialogOptions,navEventFunctionUPP,
fileType,'kBkB',NULL);
DisposeRoutineDescriptor(navEventFunctionUPP);
if(navReplyStruc.validRecord && osError == noErr)
{
resultDesc.dataHandle = 0L;
if((osError = AEGetNthDesc(&(navReplyStruc.selection),1,typeFSS,NULL,&resultDesc))
== noErr)
{
BlockMoveData(*resultDesc.dataHandle,&fileSpec,sizeof(FSSpec));
if(!navReplyStruc.replacing)
{
osError = FSpCreate(&fileSpec,'kBkB',fileType,navReplyStruc.keyScript);
if(osError != noErr)
{
AEDisposeDesc(&resultDesc);
NavDisposeReply(&navReplyStruc);
return(osError);
}
}
(*docStrucHdl)->fileFSSpec = fileSpec;
if((*docStrucHdl)->fileRefNum != 0)
{
osError = FSClose((*docStrucHdl)->fileRefNum);
(*docStrucHdl)->fileRefNum = 0;
}
if(osError == noErr)
osError = FSpOpenDF(&(*docStrucHdl)->fileFSSpec,fsRdWrPerm,&fileRefNum);
if(osError == noErr)
{
(*docStrucHdl)->fileRefNum = fileRefNum;
SetWTitle(windowPtr,fileSpec.name);
#if TARGET_CPU_PPC /////
if(gMacOS85Present) /////
{ /////
SetPort(windowPtr); /////
SetWindowProxyFSSpec(windowPtr,&fileSpec); /////
GetWindowProxyAlias(windowPtr,&((*docStrucHdl)->aliasHdl)); /////
SetWindowModified(windowPtr,false); /////
} /////
#endif /////
osError = doWriteFile(windowPtr,!navReplyStruc.replacing);
}
AEDisposeDesc(&resultDesc);
NavCompleteSave(&navReplyStruc,kNavTranslateInPlace);
}
NavDisposeReply(&navReplyStruc);
}
SetPort(windowPtr);
EraseRect(&windowPtr->portRect);
InvalRect(&windowPtr->portRect);
if(osError == userCanceledErr)
osError = noErr;
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doRevertCommand
OSErr doRevertCommand(void)
{
NavEventUPP navEventFunctionUPP;
WindowPtr windowPtr;
docStructureHandle docStrucHdl;
Str255 fileName;
NavDialogOptions dialogOptions;
NavAskSaveChangesResult reply;
OSErr osError = noErr;
navEventFunctionUPP = NewNavEventProc((ProcPtr) navEventFunction);
windowPtr = FrontWindow();
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
SetPort(windowPtr);
GetWTitle(windowPtr,fileName);
BlockMoveData(fileName,dialogOptions.savedFileName,fileName[1]);
osError = NavAskDiscardChanges(&dialogOptions,&reply,navEventFunctionUPP,0);
if(reply == kNavAskDiscardChanges)
{
EraseRect(&windowPtr->portRect);
if((*docStrucHdl)->editStrucHdl)
{
osError = doReadTextFile(windowPtr);
}
else if((*docStrucHdl)->pictureHdl)
{
KillPicture((*docStrucHdl)->pictureHdl);
(*docStrucHdl)->pictureHdl = NULL;
osError = doReadPictFile(windowPtr);
}
(*docStrucHdl)->windowTouched = false;
#if TARGET_CPU_PPC /////
if(gMacOS85Present) /////
SetWindowModified(windowPtr,false); /////
#endif /////
InvalRect(&windowPtr->portRect);
}
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doQuitCommand
OSErr doQuitCommand(NavAskSaveChangesAction action)
{
OSErr osError = noErr;
while(FrontWindow())
{
osError = doCloseCommand(action);
if(osError != noErr)
return(osError);
}
return(osError);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doNewDocWindow
OSErr doNewDocWindow(Boolean showWindow,OSType documentType)
{
docStructureHandle docStrucHdl;
if(gCurrentNumberOfWindows == kMaxWindows)
return(eMaxWindows);
if(!(gWindowPtr = GetNewCWindow(rNewWindow,NULL,(WindowPtr)-1)))
return(MemError());
SetPort(gWindowPtr);
if(!(docStrucHdl = (docStructureHandle) NewHandle(sizeof(docStructure))))
{
DisposeWindow(gWindowPtr);
return(MemError());
}
SetWRefCon(gWindowPtr,(SInt32) docStrucHdl);
(*docStrucHdl)->editStrucHdl = NULL;
(*docStrucHdl)->pictureHdl = NULL;
(*docStrucHdl)->fileRefNum = 0;
(*docStrucHdl)->windowTouched = false;
(*docStrucHdl)->aliasHdl = NULL; /////
if(documentType == 'TEXT')
{
gDestRect = gWindowPtr->portRect;
InsetRect(&gDestRect,6,6);
gViewRect = gDestRect;
MoveHHi((Handle) docStrucHdl);
HLock((Handle) docStrucHdl);
if(!((*docStrucHdl)->editStrucHdl = TENew(&gDestRect,&gViewRect)))
{
DisposeWindow(gWindowPtr);
DisposeHandle((Handle) docStrucHdl);
return(MemError());
}
HUnlock((Handle) docStrucHdl);
}
if(showWindow)
ShowWindow(gWindowPtr);
gCurrentNumberOfWindows ++;
return(noErr);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOpenFile
OSErr doOpenFile(FSSpec fileSpec,OSType documentType)
{
OSErr osError;
SInt16 fileRefNum;
docStructureHandle docStrucHdl;
if(osError = doNewDocWindow(false,documentType))
return(osError);
SetWTitle(gWindowPtr,fileSpec.name);
if(osError = FSpOpenDF(&fileSpec,fsRdWrPerm,&fileRefNum))
{
DisposeWindow(gWindowPtr);
gCurrentNumberOfWindows --;
return(osError);
}
docStrucHdl = (docStructureHandle) GetWRefCon(gWindowPtr);
(*docStrucHdl)->fileRefNum = fileRefNum;
(*docStrucHdl)->fileFSSpec = fileSpec;
if(documentType == 'TEXT')
{
if(osError = doReadTextFile(gWindowPtr))
return(osError);
}
else if(documentType == 'PICT')
{
if(osError = doReadPictFile(gWindowPtr))
return(osError);
}
#if TARGET_CPU_PPC /////
if(gMacOS85Present) /////
{ /////
SetWindowProxyFSSpec(gWindowPtr,&fileSpec); /////
GetWindowProxyAlias(gWindowPtr,&((*docStrucHdl)->aliasHdl)); /////
SetWindowModified(gWindowPtr,false); /////
} /////
#endif /////
ShowWindow(gWindowPtr);
return(noErr);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCloseFile
OSErr doCloseFile(WindowPtr windowPtr,docStructureHandle docStrucHdl,
NavAskSaveChangesAction action)
{
NavAskSaveChangesResult reply = 0;
NavEventUPP navEventFunctionUPP;
NavDialogOptions dialogOptions;
Str255 fileName;
OSErr osError;
if((*docStrucHdl)->windowTouched)
{
GetWTitle(windowPtr,fileName);
BlockMoveData(fileName,dialogOptions.savedFileName,fileName[0]+1);
navEventFunctionUPP = NewNavEventProc((ProcPtr) navEventFunction);
osError = NavAskSaveChanges(&dialogOptions,action,&reply,navEventFunctionUPP,0);
DisposeRoutineDescriptor(navEventFunctionUPP);
if(reply == kNavAskSaveChangesCancel)
return((OSErr) reply);
else if(reply == kNavAskSaveChangesSave)
{
if(osError = doSaveCommand())
return(osError);
}
}
if((*docStrucHdl)->fileRefNum != 0)
{
if(!(osError = FSClose((*docStrucHdl)->fileRefNum)))
{
osError = FlushVol(NULL,(*docStrucHdl)->fileFSSpec.vRefNum);
(*docStrucHdl)->fileRefNum = 0;
}
}
if((*docStrucHdl)->editStrucHdl)
TEDispose((*docStrucHdl)->editStrucHdl);
if((*docStrucHdl)->pictureHdl)
KillPicture((*docStrucHdl)->pictureHdl);
DisposeHandle((Handle) docStrucHdl);
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doWriteFile
OSErr doWriteFile(WindowPtr windowPtr,Boolean newFile)
{
docStructureHandle docStrucHdl;
OSErr osError;
SInt32 fileRefNum;
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
fileRefNum = (*docStrucHdl)->fileRefNum;
if((*docStrucHdl)->editStrucHdl)
osError = doWriteTextData(windowPtr,fileRefNum);
else if((*docStrucHdl)->pictureHdl)
osError = doWritePictData(windowPtr,fileRefNum);
if(osError == noErr)
if(newFile)
osError = doCopyResources(windowPtr);
return(osError);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doReadTextFile
OSErr doReadTextFile(WindowPtr windowPtr)
{
docStructureHandle docStrucHdl;
SInt16 fileRefNum;
TEHandle textEditHdl;
SInt32 numberOfBytes;
Handle textBuffer;
OSErr osError;
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
fileRefNum = (*docStrucHdl)->fileRefNum;
textEditHdl = (*docStrucHdl)->editStrucHdl;
(*textEditHdl)->txSize = 10;
(*textEditHdl)->lineHeight = 15;
SetFPos(fileRefNum,fsFromStart,0);
GetEOF(fileRefNum,&numberOfBytes);
if(numberOfBytes > 32767)
numberOfBytes = 32767;
if(!(textBuffer = NewHandle((Size) numberOfBytes)))
return(MemError());
osError = FSRead(fileRefNum,&numberOfBytes,*textBuffer);
if(osError == noErr || osError == eofErr)
{
MoveHHi(textBuffer);
HLockHi(textBuffer);
TESetText(*textBuffer,numberOfBytes,(*docStrucHdl)->editStrucHdl);
HUnlock(textBuffer);
DisposeHandle(textBuffer);
}
else
return(osError);
return(noErr);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doReadPictFile
OSErr doReadPictFile(WindowPtr windowPtr)
{
docStructureHandle docStrucHdl;
SInt16 fileRefNum;
SInt32 numberOfBytes;
OSErr osError;
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
fileRefNum = (*docStrucHdl)->fileRefNum;
GetEOF(fileRefNum,&numberOfBytes);
SetFPos(fileRefNum,fsFromStart,512);
numberOfBytes -= 512;
if(!((*docStrucHdl)->pictureHdl = (PicHandle) NewHandle(numberOfBytes)))
return(MemError());
osError = FSRead(fileRefNum,&numberOfBytes,*(*docStrucHdl)->pictureHdl);
if(osError == noErr || osError == eofErr)
return(noErr);
else
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doWriteTextData
OSErr doWriteTextData(WindowPtr windowPtr,SInt16 tempFileRefNum)
{
docStructureHandle docStrucHdl;
TEHandle textEditHdl;
Handle editText;
SInt32 numberOfBytes;
SInt16 volRefNum;
OSErr osError;
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
textEditHdl = (*docStrucHdl)->editStrucHdl;
editText = (*textEditHdl)->hText;
numberOfBytes = (*textEditHdl)->teLength;
osError = SetFPos(tempFileRefNum,fsFromStart,0);
if(osError == noErr)
osError = FSWrite(tempFileRefNum,&numberOfBytes,*editText);
if(osError == noErr)
osError = SetEOF(tempFileRefNum,numberOfBytes);
if(osError == noErr)
osError = GetVRefNum(tempFileRefNum,&volRefNum);
if(osError == noErr)
osError = FlushVol(NULL,volRefNum);
if(osError == noErr)
(*docStrucHdl)->windowTouched = false;
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doWritePictData
OSErr doWritePictData(WindowPtr windowPtr,SInt16 tempFileRefNum)
{
docStructureHandle docStrucHdl;
PicHandle pictureHdl;
SInt32 numberOfBytes, dummyData;
SInt16 volRefNum;
OSErr osError;
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
pictureHdl = (*docStrucHdl)->pictureHdl;
numberOfBytes = 512;
dummyData = 0;
osError = SetFPos(tempFileRefNum,fsFromStart,0);
if(osError == noErr)
osError = FSWrite(tempFileRefNum,&numberOfBytes,&dummyData);
numberOfBytes = GetHandleSize((Handle) (*docStrucHdl)->pictureHdl);
if(osError == noErr)
{
HLock((Handle) (*docStrucHdl)->pictureHdl);
osError = FSWrite(tempFileRefNum,&numberOfBytes,*(*docStrucHdl)->pictureHdl);
HUnlock((Handle) (*docStrucHdl)->pictureHdl);
}
if(osError == noErr)
osError = SetEOF(tempFileRefNum,512 + numberOfBytes);
if(osError == noErr)
osError = GetVRefNum(tempFileRefNum,&volRefNum);
if(osError == noErr)
osError = FlushVol(NULL,volRefNum);
if(osError == noErr)
(*docStrucHdl)->windowTouched = false;
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCopyResources
OSErr doCopyResources(WindowPtr windowPtr)
{
docStructureHandle docStrucHdl;
OSType fileType;
OSErr osError;
SInt16 fileRefNum;
docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
if((*docStrucHdl)->editStrucHdl)
fileType = 'TEXT';
else if((*docStrucHdl)->pictureHdl)
fileType = 'PICT';
FSpCreateResFile(&(*docStrucHdl)->fileFSSpec,'kBkB',fileType,smSystemScript);
osError = ResError();
if(osError == noErr)
fileRefNum = FSpOpenResFile(&(*docStrucHdl)->fileFSSpec,fsRdWrPerm);
if(fileRefNum > 0)
{
osError = doCopyAResource('STR ',-16396,gAppResFileRefNum,fileRefNum);
if(fileType == 'PICT')
{
doCopyAResource('pnot',128,gAppResFileRefNum,fileRefNum);
doCopyAResource('PICT',128,gAppResFileRefNum,fileRefNum);
}
}
else
osError = ResError();
if(osError == noErr)
CloseResFile(fileRefNum);
osError = ResError();
return(osError);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCopyAResource
OSErr doCopyAResource(ResType resourceType,SInt16 resourceID,SInt16 sourceFileRefNum,
SInt16 destFileRefNum)
{
Handle sourceResourceHdl;
Str255 sourceResourceName;
ResType ignoredType;
SInt16 ignoredID;
UseResFile(sourceFileRefNum);
sourceResourceHdl = GetResource(resourceType,resourceID);
if(sourceResourceHdl != NULL)
{
GetResInfo(sourceResourceHdl,&ignoredID,&ignoredType,sourceResourceName);
DetachResource(sourceResourceHdl);
UseResFile(destFileRefNum);
AddResource(sourceResourceHdl,resourceType,resourceID,sourceResourceName);
if(ResError() == noErr)
UpdateResFile(destFileRefNum);
}
ReleaseResource(sourceResourceHdl);
return(ResError());
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× navEventFunction
pascal void navEventFunction(NavEventCallbackMessage callBackSelector,
NavCBRecPtr callBackParms,NavCallBackUserData callBackUD)
{
WindowPtr windowPtr;
windowPtr = (WindowPtr) callBackParms->eventData.eventDataParms.event->message;
switch(callBackSelector)
{
case kNavCBEvent:
switch(callBackParms->eventData.eventDataParms.event->what)
{
case updateEvt:
if(((WindowPeek) windowPtr)->windowKind != kDialogWindowKind)
doUpdate((EventRecord *) callBackParms->eventData.eventDataParms.event);
break;
}
break;
}
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// ChooseAFolderDialog.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// ............................................................................. includes
#include "Files2.h"
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doChooseAFolderDialog
OSErr doChooseAFolderDialog(FSSpec *theFileSpec)
{
NavDialogOptions dialogOptions;
NavEventUPP navEventFunctionUPP;
OSErr osError;
NavReplyRecord navReplyStruc;
FSSpec fileSpec;
AEDesc resultDesc;
osError = NavGetDefaultDialogOptions(&dialogOptions);
GetIndString(dialogOptions.message,rMiscStrings,sChooseAFolder);
navEventFunctionUPP = NewNavEventProc((ProcPtr) navEventFunction);
osError = NavChooseFolder(NULL,&navReplyStruc,&dialogOptions,navEventFunctionUPP,NULL,0);
DisposeRoutineDescriptor(navEventFunctionUPP);
if((navReplyStruc.validRecord) && (osError == noErr))
{
if((osError = AECoerceDesc(&(navReplyStruc.selection),typeFSS,&resultDesc)) == noErr)
{
BlockMoveData(*resultDesc.dataHandle,&fileSpec,sizeof(FSSpec));
FSMakeFSSpec(fileSpec.vRefNum,fileSpec.parID,fileSpec.name,theFileSpec);
}
AEDisposeDesc(&resultDesc);
NavDisposeReply(&navReplyStruc);
}
return(osError);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
Demonstration Program Comments
Note 1: Navigation Services requires Mac OS 7.5.do5 or later and Appearance Manager
1.0.1 or later. The Navigation Services shared library must be installed in the
Extensions folder. On 680x0 systems, OpenTransportLib68K 1.3 or later must be installed
in the Extensions folder.
Note 2: In addition to demonstrating Navigation Services, this program also demonstrates
window proxy icons and window path pop-up menus. (See Chapter 4B - More on Windows - Mac
OS 8.5 Window Managager.) Comments pertaining to these aspects of the demonstration
appear in blue.
When the program is run, the user should:
* Exercise the File menu by opening the supplied TEXT and PICT files, saving those
files, saving those files under new names, closing files, opening the new files,
attempting to open files which are already open, attempting to save files to new
files with existing names, making open windows "touched" by choosing the first item
in the Demonstration menu, reverting to the saved versions of files associated with
"touched" windows, choosing Quit when "touched" and non-" touched" windows are open,
and so on.
* Choose, via the Show pop-up menu button, the file types required to be displayed in
the Open dialog.
* Choose the Choose a Folder item from the Demonstration menu to display the Choose a
Folder dialog, and choose a folder using the Choose button at the bottom of the
dialog. (The name of the chosen folder will be drawn in the bottom-left corner of
the front window.)
* With either PICT Document or TEXT Document open:
* With the chap16b-demo folder open so that the document's Finder icon is visible,
drag the window proxy icon to the desktop or to another open folder, noting that
the Finder icon moves to the latter. Then choose Touch Window from the
Demonstration menu to simulate unsaved changes to the document. Note that the
proxy icon changes to the disabled state. Then save the file, proving the
correct operation of the file synchronisation function. Note that, after the
save, the window proxy icon changes back to the enabled state.
* Command-click the window's title to display the window path pop-up menu, choose
a folder from the menu, and note that the Finder is brought to the foreground
and the chosen folder opens.
The program may be run from within CodeWarrior to demonstrate responses to the File menu
commands and the Choose a Folder dialog.
The built application, together with the supplied TEXT and PICT files, may be used to
demonstrate the additional aspect of integrating the receipt of required Apple events
with the overall file handling mechanism. To prove the correct handling of the required
Apple events, the user should:
* Open the application by double-clicking the application icon, noting that a new
document window is opened after the application is launched and the Open Application
event is received.
* Double click on a document icon, or select one or more document icons and either drag
those icons to the application icon or choose Open from the Finder's File menu,
noting that the application is launched and the selected files are opened when the
Open Documents event is received.
* Close all windows and double-click the application icon, noting that the application
responds to the Re-open Application event by opening a new window.
* With several documents open, some with "touched" windows, choose Restart or Shut Down
from the Finder's Special menu (thus invoking a Quit Application event), noting that,
for "touched" windows, the Save Changes alert box is presented asking the user
whether the file should be saved before the shutdown process proceeds.
Files2.h
#typedef
Each window created by the program will have an associated document structure, accessed
via the window structure's refCon field. The docStructure structure will be used for
document structures.
The editStrucHdl field will be assigned a handle to a TextEdit edit structure ('TEXT'
files). The pictureHdl field will be assigned a handle to a Picture structure ('PICT'
files). The fileRefNum and fileFSSpec fields will be assigned the file reference number
and the file system specification structure of the file associated with the window. The
windowTouched field will be set to true when a window has been made "touched", that is,
when the associated document in memory has been modified by the user.
When a file is opened, the aliasHdl field will be assigned a handle to a structure of
type AliasRecord, which contains the alias data for the file.
#define
After the usual constants relating to menus, windows, and alert boxes are established,
additional constants are established a 'STR#' resource containing error strings, four
specific error conditions, a 'STR#' resource containing the application's name and the
message string for the Choose a Folder dialog box, and the 'open' resource containing the
file types list. kMaxWindows is used to limit the number of windows the user can open.
Files2.c
Files.c is simply the basic "engine" which supports the demonstration. There is little
in this file which has not featured in previous demonstration programs.
Global Variables
gMacOS85Present will be assigned true if Mac OS 8.5 or later is present. (Because
window proxy icons and window path pop-up menus are supported only under Mac OS 8.5 or
later, the associated source code will be bypassed if Mac OS 8.5 or later is not
present.)
gAppResFileRefNum will be assigned the file reference number of the application's
resource fork.
main
The call to Gestalt determines whether Mac OS 8.5 or later is present.
The call to NavServicesAvailable determines whether the Navigation Services shared
library is installed and running on the user's system. If it is, NavLoad is called to
load the library, otherwise, an error alert is presented and the program terminates.
(The call to NavLoad is optional. If the call is not made, the Navigation Services
shared library will not load until your application calls a Navigation Services function,
and will unload after the call completes. If the NavLoad call is made, you must call the
NavUnload function before quitting so as to release the reserved memory.)
Routine descriptors for the required Apple events (less the Print Documents event) are
created and a call is made to the application-defined function which installs the
handlers. Also, the file reference number of the application's resource fork (which is
opened automatically at application launch) is assigned to the global variable
gAppResFileRefNum.
EventLoop
If the compilation is for PowerPC (Mac OS 8.5 does not run on 680x0 Macintoshes) and
if Mac OS 8.5 or later is present, the application-defined function doSynchroniseFiles
is called. (See File Synchronisation Function at Chapter 4B - More on Windows - Mac OS
8.5 Window Manager.)
doInstallAEHandlers
doInstallAEHandlers installs handlers for the Open Application, Re-Open Application, Open
Documents, and Quit Application events. (Note that, so as to avoid the necessity to
include application-defined printing functions in this program, a handler for the Print
Documents event is not included in this demonstration.)
doMouseDown
Note that, in the inGoAway case, the constant kNavSaveChangesClosingDocument is passed in
the call to doCloseCommand. This affects the text in the Save Changes alert box.
The inProxyIcon and inDrag cases recognise that a mouse-down in the proxy icon region can
mean that the user wishes to drag the proxy icon (icon enabled), drag the window (icon
disabled) or display the window path pop-up menu (Command key down, icon enabled or
disabled).
If the proxy icon is enabled and the mouse-down is in the proxy icon,
TrackWindowProxyDrag handles all aspects of the proxy icon drag process while the user
drags the icon and returns noErr, in which case the local variable handled is assigned
true and execution drops through to the break at the bottom of the inDrag case.
If TrackWindowProxyDrag returns errUserWantsToDragWindow, the user is either dragging
the window (proxy icon is disabled) or displaying the window path pop-up menu. In this
case, the local variable handled is assigned false and execution falls through to the
IsWindowPathSelectClick call inside the inDrag case.
IsWindowPathSelectClick reports whether the mouse-down should activate the window path
pop-up menu. If this call returns true, WindowPathSelect displays the pop-up menu,
returning the item selected in the third parameter. If the menu item chosen is not
the title of the window itself, the application-defined function doBringFinderToFront
is called to make the Finder the frontmost process, thus ensuring that the window being
opened will be visible. The local variable handled is then set to true so that
DragWindow will not be called.
If IsWindowPathSelectClick returns false, DragWindow is called to take control of the
dragging operation.
doBringFinderToFront
doBringFinderToFront is called from the inDrag case in doMouseDown. It makes the
Finder the frontmost process.
The call to the application-defined function doFindProcess gets the process serial
number of the Finder, which is then passed in a call to SetFrontProcess.
doFindProcess
doFindProcess is called by doBringFinderToFront to get the process serial number of
the Finder.
The first two lines initialise the fields of a process serial number structure so that
the search starts from kNoProcess. The next block initialises the fields of a process
information structure which, amongst other things, contains fields for the signature
(creator) and file type of the application file. (The search is for the signature
(creator) 'MACS' and the type 'FNDR'.)
Within the while loop, GetNextProcess is called to get the process serial number of the
next process. The call to GetProcessInformation gets information about this process
into the process information structure. The processSignature and processType fields of
process information structure are then examined. If they equal 'MACS' and 'FNDR'
respectively, the while loop exits and the process serial number is assigned to the
formal parameter outProcSerNo.
doUpdate
doUpdate performs such window updating as is necessary for the satisfactory execution of
the demonstration aspects of the program.
doMenuChoice
If the Choose a Folder item in the Demonstration menu is chosen, the application-defined
function which presents the Choose a Folder dialog box is called. This function returns
userCanceledErr if the user clicked the Cancel push button in the dialog box. If an
error other than userCanceledErr is returned, an error alert box is presented and the
else block is bypassed.
The doChooseAFolderDialog function fills in the file system specification structure whose
address is passed in its parameter. If a window is open, a rectangle in the bottom
corner of the front window is erased and, if the user did not click the Cancel push
button, the chosen folder's name, volume reference number, and parent directory ID are
extracted from the file system specification structure and drawn in the bottom of the
window.
doFileMenu
At the iClose case, kNavSaveChangesClosingDocument is passed in the call to
doCloseCommand. This affects the wording in the Save Changes alert box. If
doCloseCommand returns an error, and if that error is not kNavAskSaveChangesCancel (the
user clicked the Cancel push button in the Save Changes alert box), an error alert box is
presented.
At the iQuit case, kNavSaveChangesQuittingApplication is passed in the call to
doQuitCommand. This affects the wording in the Save Changes alert box. If doQuitCommand
returns an error, and if that error is not kNavAskSaveChangesCancel (the user clicked the
Cancel push button in the Save Changes alert box), an error alert box is presented. If
kNavAskSaveChangesCancel was not returned, NavUnload is called to release the memory
reserved for the Navigation Services shared library, and gDone is set to true to cause
program termination.
doErrorAlert
doErrorAlert handles errors, invoking an appropriate alert box (caution or stop) advising
of the nature of the problem by error code number or straight text. Note that the program
will only be terminated if the Navigation Services library is not installed and running,
or in the case of the memFullErr error (no more space in the application heap).
doTouchWindow
doTouchWindow is called when the user chooses the Touch Window item in the Demonstration
menu. Changing the content of the in-memory version of a file is only simulated in this
program. The text "WINDOW TOUCHED" is drawn in window and the windowTouched field of the
document structure is set to true.
If Mac OS 8.5 is present (meaning that window proxy icons are implemented),
SetWindowModified is called with true passed in the modified parameter. This causes
the proxy icon to appear in the disabled state, indicating that the window has unsaved
changes.
doSynchroniseFiles
doSynchroniseFiles is called from the main event loop whenever a null event is
received. It synchronises the file data for the application's document windows. (See
File Synchronisation Function at Chapter 4B - More on Windows - Mac OS 8.5 Window
Manager.)
currentTicks is assigned the number of ticks since system startup. As will be seen,
currentTicks will be used to ensure that synchronisations only occur every quarter
second (15 ticks). WindowPtr is assigned a pointer to the front non-floating window.
If 15 ticks have elapsed since the last synchronisation, the outer if block executes.
The while loop walks the window list (see the call to GetNextWindow at the bottom of
the loop) looking for associated files whose locations have changed. When the last
window in the list has been examined, the loop exits.
Within the while loop, GetWRefCon is called to retrieve the handle to the window's
document structure.
If the aliasHdl field of the window's document structure contains NULL, the window does
not yet have a file associated with it, in which case execution falls through to the
next iteration of the while loop and the next window is examined.
If the window has an associated file, the handle to the associated alias structure,
which contains the alias data for the file, is retrieved. ResolveAlias is then called
to perform a search for the target of the alias, returning the file system
specification for the target file in the third parameter. After identifying the
target, ResolveAlias compares some key information about the target with the
information in the alias structure. If the information differs, ResolveAlias updates
the alias structure to match the target and sets the aliasChanged parameter to true.
If the aliasChanged parameter is set to true, meaning that the location of the file has
changed, the fileFSSpec field of the window's document structure is assigned the file
system specification structure returned by ResolveAlias. Since it is also possible
that the user has renamed the file, SetWTitle is called to set the window's title to
the filename contained in the name field of the file system specification structure
returned by ResolveAlias.
The next task is to determine whether the user has moved the file to the trash or to a
folder in the trash, in which case the document must be closed.
FindFolder is called to get the volume reference number and parent directory ID of the
trash folder.
The do/while loop walks up the parent folder hierarchy to the root folder. At the
first line in the do/while loop, if the root folder has been reached (fsRtParID is the
parent ID of the root directory), the file is not in the trash, in which case the loop
exits at that point. At the next if statement, the volume reference number and parent
directory ID of the file are compared with the volume reference number and directory ID
of the trash. If they match, the file is closed, its associated memory is disposed of,
and the window is disposed of.
The bottom line of the do/while loop effects the walk up the parent directory
hierarchy, FSMakeFSSpec creates a file system specification structure from the current
contents of the vRefNum and parID fields of newFSSPec. Since newFSSpec is also the
target, the parID field is "filled in" again, at every iteration of the loop, with the
parent ID of the directory passed in the second parameter of the FSMakeFSSpec call.
doOpenAppEvent, doOpenDocsEvent, and doQuitAppEvent
The handlers for the required Apple events are es |