Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Application.cp
/*------------------------------------------------------------------------------------------ |
Program: CPlusTESample 2.0 |
File: Application.cp |
Uses: Application.h |
Document.h |
by Andrew Shebanow |
of Apple Macintosh Developer Technical Support |
Copyright © 1989-1990 Apple Computer, Inc. |
All rights reserved. |
------------------------------------------------------------------------------------------*/ |
// Mac Includes |
#define OBSOLETE |
// for ClrAppFiles(), CountAppFiles(), GetAppFiles() et. all. |
#ifndef __TYPES__ |
#include <Types.h> |
#endif |
#ifndef __QUICKDRAW__ |
#include <QuickDraw.h> |
#endif |
#ifndef __FONTS__ |
#include <Fonts.h> |
#endif |
#ifndef __EVENTS__ |
#include <Events.h> |
#endif |
#ifndef __CONTROLS__ |
#include <Controls.h> |
#endif |
#ifndef __WINDOWS__ |
#include <Windows.h> |
#endif |
#ifndef __RESOURCES__ |
#include <Resources.h> |
#endif |
#ifndef __MENUS__ |
#include <Menus.h> |
#endif |
#ifndef __TEXTEDIT__ |
#include <TextEdit.h> |
#endif |
#ifndef __DIALOGS__ |
#include <Dialogs.h> |
#endif |
#ifndef __MENUS__ |
#include <Menus.h> |
#endif |
#ifndef __DEVICES__ |
#include <Devices.h> |
#endif |
#ifndef __EVENTS__ |
#include <Events.h> |
#endif |
#ifndef __SCRAP__ |
#include <Scrap.h> |
#endif |
#ifndef __TOOLUTILS__ |
#include <ToolUtils.h> |
#endif |
#ifndef __MEMORY__ |
#include <Memory.h> |
#endif |
#ifndef __SEGLOAD__ |
#include <SegLoad.h> |
#endif |
#ifndef __FILES__ |
#include <Files.h> |
#endif |
#ifndef __OSUTILS__ |
#include <OSUtils.h> |
#endif |
#ifndef __TRAPS__ |
#include <Traps.h> |
#endif |
#ifndef __APPLICATION__ |
#include "Application.h" |
#endif |
#ifndef __DOCUMENT__ |
#include "Document.h" |
#endif |
// OSEvent is the event number of the suspend/resume and mouse-moved events sent |
// by MultiFinder. Once we determine that an event is an osEvent, we look at the |
// high byte of the message sent to determine which kind it is. To differentiate |
// suspend and resume events we check the resumeMask bit. |
const short kOsEvent = app4Evt; // event used by MultiFinder |
const short kSuspendResumeMessage = 0x01; // high byte of suspend/resume event message |
const short kClipConvertMask = 0x02; // bit of message field clip conversion |
const short kResumeMask = 0x01; // bit of message field for resume vs. suspend |
const short kMouseMovedMessage = 0xFA; // high byte of mouse-moved event message |
extern "C" { |
// from MPW standard library |
void _DataInit(); // sets up A5 globals |
}; |
// useful state checking Boolean |
Boolean gHaveColorQD; |
// just as "normal" global variables that are declared extern in |
// header files must still be declared somewhere in order to reserve |
// space, static class variables must also be declared outside of |
// the class definition. The syntax is confusing, but then, thats |
// what makes C++ so ***interesting***. |
OSType TApplication::fCreator; |
TApplication::TApplication(OSType creator) |
{ |
SysEnvRec envRec; |
long stkNeeded; |
long heapSize; |
// initialize Mac Toolbox components |
InitGraf((Ptr) &qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(NULL); |
InitCursor(); |
// Unload data segment: note that _DataInit must not be in Main! |
UnloadSeg((ProcPtr) _DataInit); |
// ignore the error returned from SysEnvirons; even if an error occurred, |
// the SysEnvirons glue will fill in the SysEnvRec |
(void) SysEnvirons(curSysEnvVers, &envRec); |
// Are we running on a 128K ROM machine or better??? |
if (envRec.machineType < 0) |
BigBadError(kErrStrings,eWrongMachine); // if not, alert & quit |
gHaveColorQD = envRec.hasColorQD; |
// if we need more stack space, get it now |
stkNeeded = StackNeeded(); |
if (stkNeeded > StackSpace()) |
{ |
// new address is heap size + current stack - needed stack |
SetApplLimit((Ptr) ((long) GetApplLimit() - stkNeeded + StackSpace())); |
} |
// Check for minimum heap size |
heapSize = (long) GetApplLimit() - (long) ApplicationZone(); |
if (heapSize < HeapNeeded()) |
BigBadError(kErrStrings,eSmallSize); |
// expand the heap so new code segments load at the top |
MaxApplZone(); |
// allocate an empty document list |
fDocList = new TDocumentList; |
// check to see if WaitNextEvent is implemented |
fHaveWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap); |
// initialize our class variables |
fCurDoc = nil; |
fDone = false; |
fInBackground = false; |
fMouseRgn = nil; |
fWhichWindow = nil; |
fCreator = creator; |
} |
void TApplication::EventLoop() |
{ |
int gotEvent; |
EventRecord tEvt; |
SetUp(); // call setup routine |
DoIdle(); // do idle once |
while (!fDone) |
{ |
// always set up fWhichWindow before doing anything |
fWhichWindow = FrontWindow(); |
if (fWhichWindow != nil) |
{ |
// see if window belongs to a document |
fCurDoc = fDocList->FindDoc(fWhichWindow); |
// make sure we always draw into correct window |
SetPort(fWhichWindow); |
} |
else fCurDoc = nil; |
DoIdle(); // call idle time handler |
if (fHaveWaitNextEvent) |
gotEvent = WaitNextEvent(everyEvent, &tEvt, SleepVal(), fMouseRgn); |
else |
{ |
SystemTask(); |
gotEvent = GetNextEvent(everyEvent, &tEvt); |
} |
fTheEvent = tEvt; |
// if we got a real event, process it |
if (gotEvent) |
ProcessEvent(); |
AdjustCursor(); |
} |
} |
void TApplication::ProcessEvent() |
{ |
// make sure alert is loaded in memory BEFORE we do any event |
// processing. This is necessary since the alert for the case |
// when we need to display an out of memory alert. |
// CouldAlert(rUserAlert); |
TRY |
{ |
AdjustCursor(); |
switch (fTheEvent.what) |
{ |
case mouseDown: |
DoMouseDown(); |
break; |
case mouseUp: |
DoMouseUp(); |
break; |
case keyDown: |
case autoKey: |
DoKeyDown(); |
break; |
case updateEvt: |
DoUpdateEvt(); |
break; |
case diskEvt: |
DoDiskEvt(); |
break; |
case activateEvt: |
DoActivateEvt(); |
break; |
case kOsEvent: |
DoOSEvent(); |
break; |
default: |
break; |
} |
} |
RECOVER |
{ |
AlertUser((short) gFailMessage, gFailError); |
// don't let error bubble up any farther |
goto doneEvent; |
} |
ENDTRY |
doneEvent: |
return; |
} |
void TApplication::DoKeyDown() |
{ |
char key; |
long mResult; |
key = (char) (fTheEvent.message & charCodeMask); |
if ((fTheEvent.modifiers & cmdKey) && (fTheEvent.what == keyDown)) |
{ |
// only do command keys if we are not autokeying |
AdjustMenus(); // make sure menus are up to date |
mResult = MenuKey(key); |
if (mResult != 0) // if it wasn't a menu key, pass it through |
{ |
DoMenuCommand(HiWord(mResult), LoWord(mResult)); |
return; |
} |
} |
if (fCurDoc != nil) |
{ |
EventRecord tEvt; |
// we copy event record so that we don't pass reference to object field |
tEvt = fTheEvent; |
fCurDoc->DoKeyDown(&tEvt); |
} |
} |
void TApplication::DoActivateEvt() |
{ |
// event record contains window ptr |
fWhichWindow = (WindowPtr) fTheEvent.message; |
// see if window belongs to a document |
fCurDoc = fDocList->FindDoc(fWhichWindow); |
SetPort(fWhichWindow); |
if (fCurDoc != nil) |
fCurDoc->DoActivate((fTheEvent.modifiers & activeFlag) != 0); |
} |
void TApplication::DoUpdateEvt() |
{ |
// event record contains window ptr |
fWhichWindow = (WindowPtr) fTheEvent.message; |
// see if window belongs to a document |
fCurDoc = fDocList->FindDoc(fWhichWindow); |
SetPort(fWhichWindow); |
if (fCurDoc != nil) |
fCurDoc->DoUpdate(); |
} |
// NOTE: we use an anonymous parameter here so that the compiler |
// doesn't warn us about it being unused. Since we give it a name |
// in the class definition, we still know what its used for. |
void TApplication::DoSuspend(Boolean) |
{ |
if (fCurDoc != nil) |
fCurDoc->DoActivate(!fInBackground); |
} |
void TApplication::DoResume(Boolean) |
{ |
if (fCurDoc != nil) |
fCurDoc->DoActivate(!fInBackground); |
} |
void TApplication::DoOSEvent() |
{ |
Boolean doConvert; |
unsigned char evType; |
// is it a multifinder event? |
evType = (unsigned char) (fTheEvent.message >> 24) & 0x00ff; |
switch (evType) { // high byte of message is type of event |
case kMouseMovedMessage: |
DoIdle(); // mouse-moved is also an idle event |
break; |
case kSuspendResumeMessage: |
doConvert = (fTheEvent.message & kClipConvertMask) != 0; |
fInBackground = (fTheEvent.message & kResumeMask) == 0; |
if (fInBackground) |
DoSuspend(doConvert); |
else DoResume(doConvert); |
break; |
} |
} |
void TApplication::DoMouseDown() |
{ |
long mResult; |
short partCode; |
WindowPtr tWind; |
EventRecord tEvt; |
// gotta watch those object field dereferences |
partCode = FindWindow(fTheEvent.where, &tWind); |
fWhichWindow = tWind; |
tEvt = fTheEvent; |
switch (partCode) |
{ |
case inSysWindow: |
DoMouseInSysWindow(); |
break; |
case inMenuBar: |
AdjustMenus(); |
mResult = MenuSelect(tEvt.where); |
if (mResult != 0) |
DoMenuCommand(HiWord(mResult),LoWord(mResult)); |
break; |
case inGoAway: |
DoGoAway(); |
break; |
case inDrag: |
DoDrag(); |
break; |
case inGrow: |
if (fCurDoc != nil) |
fCurDoc->DoGrow(&tEvt); |
break; |
case inZoomIn: |
case inZoomOut: |
if ((TrackBox(fWhichWindow, tEvt.where, partCode)) && |
(fCurDoc != nil)) |
fCurDoc->DoZoom(partCode); |
break; |
case inContent: |
// If window is not in front, make it so |
if ( fWhichWindow != FrontWindow() ) |
SelectWindow(fWhichWindow); |
else if (fCurDoc != nil) |
fCurDoc->DoContent(&tEvt); |
break; |
} |
} |
void TApplication::DoDrag() |
{ |
DragWindow(fWhichWindow, fTheEvent.where, &qd.screenBits.bounds); |
} |
void TApplication::DoGoAway() |
{ |
if (TrackGoAway(fWhichWindow, fTheEvent.where)) |
{ |
if (fCurDoc != nil) |
{ |
if (fCurDoc->DoClose(true, yesResult, false) != cancelResult) |
{ |
fDocList->RemoveDoc(fCurDoc); |
delete fCurDoc; |
} |
} |
else CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind); |
// make sure our current document/window references are valid |
fWhichWindow = FrontWindow(); |
if (fWhichWindow != nil) |
{ |
fCurDoc = fDocList->FindDoc(fWhichWindow); |
SetPort(fWhichWindow); |
} |
else fCurDoc = nil; |
} |
} |
void TApplication::ProcessArgs() |
{ |
short message, numFiles, curFile; |
AppFile fileInfo; |
/* count the files */ |
CountAppFiles(&message,&numFiles); |
if (numFiles == 0) |
{ |
// create a single empty document |
DoNew(); |
return; |
} |
for (curFile = 1; curFile <= numFiles; curFile++) |
{ |
/* get file info */ |
GetAppFiles(curFile,&fileInfo); |
/* open/print the file */ |
if (message != appPrint) |
{ |
TRY |
{ |
OpenADoc(fileInfo.vRefNum,0,fileInfo.fName,fileInfo.fType); |
} |
RECOVER |
{ |
goto processNextFile; |
} |
ENDTRY |
} |
processNextFile: |
/* clear finder arg for this file */ |
ClrAppFiles(curFile); |
} |
} |
void TApplication::DoQuit(Boolean askUser, YNCResult defaultResult) |
{ |
while (true) |
{ |
fWhichWindow = FrontWindow(); |
if (fWhichWindow == nil) |
break; |
fCurDoc = fDocList->FindDoc(fWhichWindow); |
if (fCurDoc != nil) |
{ |
// if the user cancels the quit |
if (fCurDoc->DoClose(askUser, defaultResult, true) == cancelResult) |
return; |
else |
{ |
fDocList->RemoveDoc(fCurDoc); |
delete fCurDoc; |
} |
} |
else CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind); |
// make sure we aren't in an infinite loop. This could occur |
// if the CloseDeskAcc was failing for some reason. |
if (FrontWindow() == fWhichWindow) |
{ |
// send the window to the back of the list. |
// if the FrontWindow is still the same, we will exit |
// the loop. Otherwise, we let the loop keep running so |
// that we have a chance to close our other windows |
// cleanly |
SendBehind(fWhichWindow, nil); |
if (FrontWindow() == fWhichWindow) |
break; |
} |
} |
fDone = true; |
fWhichWindow = nil; |
fCurDoc = nil; |
} |
Boolean TApplication::TrapAvailable(short tNumber,TrapType tType) |
{ |
// Check and see if the trap exists. On 64K ROM machines, tType will be ignored. |
return NGetTrapAddress(tNumber, tType) != NGetTrapAddress(_Unimplemented, ToolTrap); |
} |
void TApplication::WDToDirID(short wdRefNum, short& vRefNum, long& dirID) |
{ |
const short kRootDirID = 2; |
long junk; |
OSErr err = GetWDInfo(wdRefNum,&vRefNum,&dirID,&junk); |
if (err != noErr) |
{ |
vRefNum = wdRefNum; // if GetVol doesn't return valid vRefNum/dirID pair, |
dirID = kRootDirID; // use wdRefNum as a vRefNum and use root for dirID |
} |
} |
void AlertUser(short errResID, short errCode) |
{ |
Str255 messageStr; |
// if we have a hilited menu, turn it off before displaying alert |
HiliteMenu(0); |
if (errResID != 0) |
{ |
GetIndString(messageStr, errResID, errCode); |
ParamText(messageStr, "\p", "\p", "\p"); |
} |
else |
{ |
// we need to lookup the error in our table |
LookupErrorString(errCode,kSysErrStrings,messageStr); |
ParamText(messageStr, "\p", "\p", "\p"); |
} |
SetCursor(&qd.arrow); |
(void) Alert(rUserAlert, (ModalFilterProcPtr) nil); |
} |
void BigBadError(short errResID, short errCode) |
{ |
AlertUser(errResID,errCode); |
ExitToShell(); |
} |
Boolean LookupErrorString(short value, short resID, StringPtr str) |
{ |
struct ErrRecord { |
short lowErr; |
short highErr; |
short index; |
}; |
typedef struct ErrRecord* ErrRecordPtr; |
Handle table; |
ErrRecordPtr pEntry; |
unsigned long tableOffset; |
long lenTab; |
int strID; |
// start with an empty string |
str[0] = 0; |
table = GetResource('errs', resID); |
if (!table) |
{ |
lenTab = (long) (GetHandleSize((Handle) table) / sizeof(ErrRecord)); |
strID = 0; |
tableOffset = 0; |
for (long i = 1; i <= lenTab; i++) |
{ |
pEntry = (ErrRecordPtr) ((unsigned long) *table) + tableOffset; |
if (pEntry->lowErr == 0) |
strID = pEntry->index; |
else if ((pEntry->lowErr <= value) && (value <= pEntry->highErr)) |
{ |
if (pEntry->index > 0) |
GetIndString(str, strID, pEntry->index); |
return true; |
} |
tableOffset += sizeof(ErrRecord); |
} |
} |
return false; |
} |
// That's all, folks... |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14