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.
SimpleText.c
/* |
** File: SimpleText.c |
** |
** Contains: SimpleText - a simple document editing application for shipping |
** with system software. |
** |
** Version: SimpleText 1.4 or later |
** |
** Copyright 1993-1999 Apple Computer. All rights reserved. |
** |
** You may incorporate this sample code into your applications without |
** restriction, though the sample code has been provided "AS IS" and the |
** responsibility for its operation is 100% yours. However, what you are |
** not permitted to do is to redistribute the source as "DSC Sample Code" |
** after having made changes. If you're going to re-distribute the source, |
** we require that you make it clear in the source that the code was |
** descended from Apple Sample Code, but that you've made changes. |
*/ |
#include "MacIncludes.h" |
#include <ImageCompression.h> // for CustomGetFilePreview |
#include <Threads.h> |
#define CompilingMain=1 |
#include "SimpleText.h" |
#include "Clipboard.h" |
#include "ExtendPrintRecord.h" |
#include "ScriptablePrinting.h" |
// -------------------------------------------------------------------------------------------------------------- |
// FORWARD DECLARES |
// -------------------------------------------------------------------------------------------------------------- |
OSErr DoActivate(WindowRef pWindow, Boolean activating); |
OSErr DoCommand(WindowRef pWindow, short commandID, long menuResult); |
OSErr DoKeyEvent(WindowRef pWindow, EventRecord * pEvent, Boolean processPageControls); |
Boolean CommandToIDs(short commandID, short * menuID, short *itemID); |
void AdjustMenus(WindowRef pWindow, Boolean editDialogs, Boolean forceTitlesOn); |
// -------------------------------------------------------------------------------------------------------------- |
// GLOBAL VARIABLES |
// -------------------------------------------------------------------------------------------------------------- |
EventRecord gEvent; // currently pending event |
Boolean gAllDone; // true if the application is the in process of terminating |
MachineInfoRec gMachineInfo; // info about abilities and options installed on this machine |
short gApplicationResFile; // resource fork of application |
RgnHandle gCursorRgn; // region to control the cursor apearence |
AGRefNum gAGRefNum = -1; // AppleGuide database which is open |
FSSpec gAGSpec; // where to find our database |
AGCoachRefNum gAGCoachRefNum = -1; // coach handler refNum |
FontMappingHandle gFontMappingList = nil; // list of font mappings |
ThreadID gFontThread; // thread that builds font menu |
ThreadID gAGThread; // thread that looks for AppleGuide database |
ThreadID gStarterThread; // starts our other threads for us |
Boolean gDontYield; // whether our threads should yield |
void* gThreadResults; // scratch space for thread results |
// These variables are for the find/replace commands |
Str255 gFindString = "\p", gReplaceString = "\p"; |
Boolean gWrapAround = false, gCaseSensitive = false; |
// Metrowerks MWCRuntime.lib defines qd for us on PPC, and their |
// __runtime module does under the 68K case. OTOH, neither SC nor |
// MrC give us qd for free, so we need it there. I'm still not |
// certain which way to go for the ThinkC or Symantec PPC case. |
#if !defined(__MWERKS__) |
// QuickDraw globals |
QDGlobals qd; |
#endif |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
static pascal Boolean AlertFilter(DialogRef theDialog, EventRecord *theEvent, short *itemHit) |
{ |
if (theEvent->what == activateEvt && (DialogRef) theEvent->message == theDialog) |
{ |
SetDialogDefaultItem(theDialog, 1); |
} |
if (StdFilterProc(theDialog, theEvent, itemHit)) |
return true; |
// Pass updates through (Activates are tricky...was mucking with Apple menu & thereby |
// drastically changing how the system handles the menu bar during our alert) |
if (theEvent->what == updateEvt /* || theEvent->what == activateEvt */ ) |
{ |
HandleEvent(theEvent); |
} |
return false; |
} // AlertFilter |
void ConductErrorDialog(OSErr error, short commandID, short alertType) |
{ |
long foundError; // The error, converted to a number |
short stringIndex; // Index into the strings |
Str255 errorText; // the error in a string format |
// Start with no error so far |
foundError = 0; |
// Start with the first string |
stringIndex = 1; |
// Loop until we find an error string |
errorText[0] = 0; |
do |
{ |
// Get the string, and convert it to a number |
GetIndString(errorText, kErrorBaseID + commandID, stringIndex); |
if (errorText[0] == 0) |
break; |
StringToNum(errorText, &foundError); |
// If we reach the last string, or we match the error code |
if ((foundError == 0) || |
(foundError == error)) |
{ |
// Get the text string for this error |
GetIndString(errorText, kErrorBaseID + commandID, stringIndex+1); |
} |
else |
{ |
// Otherwise, make us continue until we get a string |
errorText[0] = 0; |
} |
// Advance so we get the next string number |
stringIndex += 2; |
} while (errorText[0] == 0); // errorText[0] == 0 |
if (errorText[0] != 0) |
{ |
DialogRef dPtr; |
short hit; |
SetCursor(&qd.arrow); |
ParamText(errorText, "\p", "\p", "\p"); |
#if !GENERATINGPOWERPC |
if (gMachineInfo.theEnvirons.systemVersion < 0x0700) |
{ |
short ** hDialog; |
hDialog = (short**) GetResource('DLOG', kErrorBaseID + alertType); |
(*hDialog)[4] = dBoxProc; |
dPtr = GetNewDialog(kErrorBaseID + alertType, nil, (WindowRef)-1); |
do |
{ |
ModalDialog(nil, &hit); |
} while (hit != ok); |
DisposeDialog(dPtr); |
} |
else |
{ |
dPtr = GetNewDialog(kErrorBaseID + alertType, nil, (WindowRef)-1); |
SetDialogDefaultItem(dPtr, ok); |
BeginMovableModal(); |
do |
{ |
MovableModalDialog(nil, &hit); |
} while (hit != ok); |
DisposeDialog(dPtr); |
EndMovableModal(); |
} |
#else |
dPtr = GetNewDialog(kErrorBaseID + alertType, nil, (WindowRef)-1); |
SetDialogDefaultItem(dPtr, ok); |
BeginMovableModal(); |
do |
{ |
MovableModalDialog(nil, &hit); |
} while (hit != ok); |
DisposeDialog(dPtr); |
EndMovableModal(); |
#endif |
} |
} // ConductErrorDialog |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
static void MovableModalMenus(DialogRef dPtr, short *pItem, long menuResult) |
{ |
short iCut, iCopy, iClear, iPaste; |
short editMenu; |
short menuItem = menuResult & 0xFFFF; |
// find out where edit menus are |
CommandToIDs(cCut, &editMenu, &iCut); |
CommandToIDs(cCopy, &editMenu, &iCopy); |
CommandToIDs(cClear, &editMenu, &iClear); |
CommandToIDs(cPaste, &editMenu, &iPaste); |
HiliteMenu(0); |
switch (menuResult >> 16) |
{ |
case mApple: |
{ |
Str255 tempString; |
GetMenuItemText(GetMenuHandle(menuResult>>16), menuItem, tempString); |
OpenDeskAcc(tempString); |
} |
break; |
case mEdit: |
{ |
short type; |
Handle item; |
Rect box; |
short editField = GetDialogKeyboardFocusItem(dPtr); |
// return typed item, if it isn't disabled |
GetDialogItem(dPtr, editField, &type, &item, &box); |
if ((type & itemDisable) == 0) |
*pItem = editField; |
if (menuItem == iCut) |
{ |
DialogCut(dPtr); |
ZeroScrap(); |
TEToScrap(); |
} |
if (menuItem == iCopy) |
{ |
DialogCopy(dPtr); |
ZeroScrap(); |
TEToScrap(); |
} |
if (menuItem == iClear) |
DialogDelete(dPtr); |
if (menuItem == iPaste) |
DialogPaste(dPtr); |
} |
break; |
} |
} // MovableModalMenus |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
void MovableModalDialog(ModalFilterProcPtr filterProc, short *pItem) |
/* |
Call this as you would ModalDialog, when the dialog is moveable |
modal. |
However, first call BeginMovableModal, and afterwards (after |
disposing of dialog) call EndMovableModal. |
*/ |
{ |
GrafPtr curPort; |
DialogRef dPtr = FrontWindow(); |
*pItem = 0; |
if (dPtr) |
{ |
GetPort(&curPort); |
SetPort(dPtr); |
do |
{ |
WaitNextEvent(mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask + updateMask + activMask + osMask, |
&gEvent, 0, nil); |
// call the filter proc |
if ( (filterProc) && ((*filterProc) (dPtr, &gEvent, pItem)) ) |
break; |
// call the basic filtering |
if (StdFilterProc(dPtr, &gEvent, pItem)) |
break; |
// handle keyboard |
if ((gEvent.what == keyDown) && (gEvent.modifiers & cmdKey)) |
{ |
MovableModalMenus(dPtr, pItem, MenuKey(gEvent.message & charCodeMask)); |
break; |
} |
// handle clicks and drags |
if (gEvent.what == mouseDown) |
{ |
WindowRef whichWindow; |
short part = FindWindow(gEvent.where, &whichWindow); |
// menu bar events |
if (part == inMenuBar) |
{ |
MovableModalMenus(dPtr, pItem, MenuSelect(gEvent.where)); |
break; |
} |
// check for outside of our window |
if (!PtInRgn(gEvent.where, ((WindowPeek)dPtr)->strucRgn)) |
{ |
SysBeep(1); |
gEvent.what = nullEvent; |
} |
// drag the window around |
if ( (part == inDrag) && (whichWindow == dPtr) ) |
{ |
Rect tempRect = (**GetGrayRgn()).rgnBBox; |
DragWindow(GetDialogWindow(dPtr), gEvent.where, &tempRect); |
gEvent.what = nullEvent; |
} |
} |
// check with standard dialog stuff |
{ |
DialogRef tempDialog; |
if ( IsDialogEvent(&gEvent) && DialogSelect(&gEvent, &tempDialog, pItem) ) |
break; |
} |
// handle updates |
if (gEvent.what == updateEvt) |
{ |
HandleEvent(&gEvent); |
break; |
} |
} while (true); |
SetPort(curPort); |
} |
} // MovableModalDialog |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
void BeginMovableModal(void) |
{ |
DialogRef dPtr = FrontWindow(); |
WindowRef nextWindow = GetNextWindow(dPtr); |
if (nextWindow) |
DoActivate(nextWindow, false); |
AdjustMenus(GetDialogWindow(dPtr), (GetDialogKeyboardFocusItem(dPtr) > 0), false); |
} // BeginMovableModal |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
void EndMovableModal(void) |
{ |
WindowRef nextWindow = FrontWindow(); |
AdjustMenus(nextWindow, true, false); |
if (nextWindow) |
DoActivate(nextWindow, true); |
} // EndMovableModal |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
short ConductFindOrReplaceDialog(short dialogID) |
{ |
DialogRef dPtr; |
short hit; |
dPtr = GetNewDialog(dialogID, nil, (WindowRef)-1); |
if (dPtr) |
{ |
short kind; |
Rect box; |
Handle item; |
// standard default behavior |
SetDialogDefaultItem(dPtr, ok); |
SetDialogCancelItem (dPtr, cancel); |
SetDialogTracksCursor(dPtr, true); |
// Find string |
GetDialogItem(dPtr, iFindEdit, &kind, &item, &box); |
SetDialogItemText(item, gFindString); |
// check boxes |
GetDialogItem(dPtr, iCaseSensitive, &kind, &item, &box); |
SetControlValue((ControlRef)item, gCaseSensitive); |
GetDialogItem(dPtr, iWrapAround, &kind, &item, &box); |
SetControlValue((ControlRef)item, gWrapAround); |
if (dialogID == kReplaceWindowID) |
{ |
// Replace string |
GetDialogItem(dPtr, iReplaceEdit, &kind, &item, &box); |
SetDialogItemText(item, gReplaceString); |
} |
// select the search text by default |
SelectDialogItemText(dPtr, iFindEdit, 0, 32767); |
// and away we go! |
ShowWindow(GetDialogWindow(dPtr)); |
BeginMovableModal(); |
do |
{ |
MovableModalDialog(nil, &hit); |
switch (hit) |
{ |
case iCaseSensitive: |
case iWrapAround: |
GetDialogItem(dPtr, hit, &kind, &item, &box); |
SetControlValue((ControlRef)item, 1-GetControlValue((ControlRef)item)); |
break; |
} |
} while ( (hit != ok) && (hit != cancel) && (hit != iReplaceAll) ); |
if (hit != cancel) |
{ |
// Find string |
GetDialogItem(dPtr, iFindEdit, &kind, &item, &box); |
GetDialogItemText(item, gFindString); |
// check boxes |
GetDialogItem(dPtr, iCaseSensitive, &kind, &item, &box); |
gCaseSensitive = GetControlValue((ControlRef)item); |
GetDialogItem(dPtr, iWrapAround, &kind, &item, &box); |
gWrapAround = GetControlValue((ControlRef)item); |
if (dialogID == kReplaceWindowID) |
{ |
// Replace string |
GetDialogItem(dPtr, iReplaceEdit, &kind, &item, &box); |
GetDialogItemText(item, gReplaceString); |
} |
} |
DisposeDialog(dPtr); |
EndMovableModal(); |
} |
return(hit); |
} // ConductFindOrReplaceDialog |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
void SetWatchCursor(void) |
{ |
CursHandle theWatch; |
theWatch = GetCursor(watchCursor); |
if (theWatch) |
{ |
char oldState; |
oldState = HGetState((Handle) theWatch); |
HLock((Handle) theWatch); |
SetCursor(*theWatch); |
HSetState((Handle) theWatch, oldState); |
} |
} // SetWatchCursor |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
void LongRectToRect(LongRect* longRect, Rect *rect) |
{ |
rect->top = longRect->top; |
rect->left = longRect->left; |
rect->bottom = longRect->bottom; |
rect->right = longRect->right; |
} // LongRectToRect |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
void RectToLongRect(Rect *rect, LongRect *longRect) |
{ |
longRect->top = rect->top; |
longRect->left = rect->left; |
longRect->bottom = rect->bottom; |
longRect->right = rect->right; |
} // RectToLongRect |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
#ifndef ff |
#define ff(x) (x << 16) |
#endif |
void GetPICTRectangleAt72dpi(PicHandle hPicture, Rect *pictureRect) |
{ |
typedef struct FixedRect { |
Fixed left; |
Fixed top; |
Fixed right; |
Fixed bottom; |
} FixedRect; |
typedef struct { |
Picture pictInfo; |
unsigned short versionOp; // 0x1101 |
Byte opCodes[1]; |
} PICTHeaderVer1; |
typedef struct { |
Picture pictInfo; |
unsigned short versionOp; // 0x0011 |
unsigned short versionOp2; // 0x02ff |
unsigned short headerOp; // 0x0c00 |
unsigned short version; // 0xffff |
unsigned short version2; // 0xffff |
FixedRect pictBounds; |
unsigned long reserved; |
unsigned short opCodes[1]; |
} PICTHeaderVer2; |
typedef struct { |
Picture pictInfo; |
unsigned short versionOp; // 0x0011 |
unsigned short versionOp2; // 0x02ff |
unsigned short headerOp; // 0x0c00 |
unsigned short version; // 0xfffe |
unsigned short reserved; // 0x0000 |
Fixed hRes; |
Fixed vRes; |
Rect pictBounds; |
unsigned long reserved2; |
unsigned short opCodes[1]; |
} PICTHeaderVer2Ext; |
const Fixed seventyTwo = 0x480000; |
Fixed hRes, vRes; |
PICTHeaderVer1* pPict = (PICTHeaderVer1*) *hPicture; |
hRes = vRes = seventyTwo; // assume 72 dpi, Fixed |
if (pPict->versionOp == 0x0011) |
{ |
// Version 2 PICT |
PICTHeaderVer2* pPict2 = (PICTHeaderVer2*) pPict; |
if (pPict2->version == 0xfffe) |
{ |
// Extended Version 2 |
PICTHeaderVer2Ext* pPict2ext = (PICTHeaderVer2Ext*) pPict; |
hRes = pPict2ext->hRes; |
vRes = pPict2ext->vRes; |
} |
} |
hRes = FixDiv(hRes, seventyTwo); |
vRes = FixDiv(vRes, seventyTwo); |
pictureRect->left = Fix2Long(FixDiv( ff((**hPicture).picFrame.left), hRes )); |
pictureRect->right = Fix2Long(FixDiv( ff((**hPicture).picFrame.right), hRes )); |
pictureRect->top = Fix2Long(FixDiv( ff((**hPicture).picFrame.top), vRes )); |
pictureRect->bottom = Fix2Long(FixDiv( ff((**hPicture).picFrame.bottom), vRes )); |
} // GetPICTRectangleAt72dpi |
#undef ff |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
static WindowDataPtr GetWindowInfo(WindowRef pWindow) |
{ |
WindowDataPtr result = nil; |
if ( |
(pWindow) && |
(GetWindowKind(pWindow) == userKind) |
) |
result = (WindowDataPtr) GetWRefCon(pWindow); |
return result; |
} // GetWindowInfo |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Utility |
static short ZeroStringSub(Str255 destString, Str255 subStr) |
// returns number of substitutions performed |
{ |
OSErr anErr; |
Handle destHandle = nil; |
Handle subHandle = nil; |
short count = 0; |
anErr = PtrToHand(&destString[1], &destHandle, destString[0]); |
if (anErr == noErr) |
{ |
anErr = PtrToHand(&subStr[1], &subHandle, subStr[0]); |
if (anErr == noErr) |
{ |
count = ReplaceText(destHandle, subHandle, "\p^0"); // error or # of substitutions |
destString[0] = GetHandleSize(destHandle); |
BlockMoveData(*destHandle, &destString[1], destString[0]); |
} |
} |
DisposeHandle(destHandle); |
DisposeHandle(subHandle); |
if (count < 0) |
count = 0; // change error code into count = 0 substitutions |
return count; |
} // ZeroStringSub |
// -------------------------------------------------------------------------------------------------------------- |
// SEARCH/REPLACE UTILITY FUNCTIONS |
// -------------------------------------------------------------------------------------------------------------- |
static Boolean IsThisTheString( |
Ptr p, // pointer to check |
Str255 searchString, // string to check for |
Boolean isCaseSensitive) // case sensitive check or not |
/* |
Returns true if the supplied string is at the specified offset. |
Otherwise returns false. |
*/ |
{ |
Boolean returnValue = false; |
if (isCaseSensitive) |
returnValue = ( IUMagString(p, &searchString[1], searchString[0], searchString[0]) == 0 ); |
else |
returnValue = ( IUMagIDString(p, &searchString[1], searchString[0], searchString[0]) == 0 ); |
return(returnValue); |
} // IsThisTheString |
// -------------------------------------------------------------------------------------------------------------- |
Boolean PerformSearch( |
Handle h, // handle to search |
long start, // offset to begin with |
Str255 searchString, // string to search for |
Boolean isCaseSensitive, // case sensitive search |
Boolean isBackwards, // search backwards from starting point |
Boolean isWraparound, // wrap search around from end->begining |
long * pNewStart, // returned new selection start |
long * pNewEnd) // returned new selection end |
/* |
Performs a search on the supplied handle, starting at the provided |
offset. Returns the new selection start and end values, and true |
if the search is successful. Otherwise it returns false. |
*/ |
{ |
char flags; |
Ptr startPtr; |
Ptr endPtr; |
Ptr searchPtr; |
Boolean foundIt = false; |
flags = HGetState(h); |
HLock(h); |
// back up one when searching backwards, or we'll hit every time on the current |
// character |
if (isBackwards) |
{ |
if (start != 0) |
{ |
--start; |
} |
else |
{ |
if (isWraparound) |
start = GetHandleSize(h); |
else |
return(false); |
} |
} |
// determine the bounds of the searching |
startPtr = (*h) + start; |
if ( isWraparound ) |
{ |
if (isBackwards) |
{ |
// go backwards until just after the start, or begining of |
// document is start is the end |
if (start == GetHandleSize(h)) |
endPtr = *h; |
else |
endPtr = startPtr + 1; |
} |
else |
{ |
// go forwards until just before the start, or to the end |
// of the document is the start is already the begining |
if (start == 0) |
endPtr = *h + GetHandleSize(h); |
else |
endPtr = startPtr - 1; |
} |
} |
else |
{ |
if (isBackwards) |
{ |
// go back until hit begining of document |
endPtr = *h-1; |
} |
else |
{ |
// go forward until hit end of document |
endPtr = *h + GetHandleSize(h); |
} |
} |
searchPtr = startPtr; |
while (searchPtr != endPtr) |
{ |
if (IsThisTheString(searchPtr, searchString, isCaseSensitive)) |
{ |
foundIt = true; |
*pNewStart = searchPtr - *h; |
*pNewEnd = *pNewStart + searchString[0]; |
break; |
} |
if (isBackwards) |
--searchPtr; |
else |
++searchPtr; |
if (isWraparound) |
{ |
if (searchPtr < *h) |
searchPtr = *h + GetHandleSize(h); |
if (searchPtr > *h + GetHandleSize(h)) |
searchPtr = *h; |
} |
} |
HSetState(h, flags); |
return(foundIt); |
} // PerformSearch |
// -------------------------------------------------------------------------------------------------------------- |
// SELECTION UTILITY ROUTINES |
// -------------------------------------------------------------------------------------------------------------- |
void DrawSelection(WindowDataPtr pData, Rect *pSelection, short * pPhase, Boolean bumpPhase) |
{ |
if (!EmptyRect(pSelection) ) |
{ |
RgnHandle oldClip = NewRgn(); |
Pattern aPattern; |
Rect newClip; |
if ( |
(bumpPhase) && |
(MOVESELECTION(TickCount()) ) |
) |
{ |
if ((++(*pPhase)) > 7 ) |
*pPhase = 1; |
} |
// setup for drawing in this window |
SetPort((GrafPtr) pData); |
GetClip(oldClip); |
PenMode(notPatXor); |
// offset the draw area (SetOrigin a must to preserve pattern appearence) |
// and the clip area to avoid stepping on the scroll bars |
SetOrigin(GetControlValue(pData->hScroll), GetControlValue(pData->vScroll)); |
newClip = pData->contentRect; |
OffsetRect(&newClip, GetControlValue(pData->hScroll), GetControlValue(pData->vScroll)); |
ClipRect(&newClip); |
// do the draw |
GetIndPattern(&aPattern, kPatternListID, (*pPhase)+1); |
PenPat(&aPattern); |
FrameRect(pSelection); |
SetOrigin(0, 0); |
// restore the old port settings |
SetClip(oldClip); |
DisposeRgn(oldClip); |
PenNormal(); |
} |
} // DrawSelection |
// -------------------------------------------------------------------------------------------------------------- |
OSErr SelectContents(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent, Rect *pSelection, Rect *pContent, short *pPhase) |
{ |
OSErr anErr = noErr; |
Point clickPoint = pEvent->where; |
Point currentPoint; |
Boolean didJustScroll; |
ControlRef theControl; |
GlobalToLocal(&clickPoint); |
if (FindControl(clickPoint, pWindow, &theControl) == 0) |
{ |
// move the click point into the proper range |
clickPoint.h += GetControlValue(pData->hScroll); |
clickPoint.v += GetControlValue(pData->vScroll); |
// if the shift key is held down then the selection starts from |
// a preexisting point such that we are doing an expand/contract |
// of the original selection |
if (pEvent->modifiers & shiftKey) |
{ |
if (clickPoint.h < pSelection->right) |
clickPoint.h = pSelection->right; |
else |
clickPoint.h = pSelection->left; |
if (clickPoint.v < pSelection->bottom) |
clickPoint.v = pSelection->bottom; |
else |
clickPoint.v = pSelection->top; |
} |
while (StillDown()) |
{ |
// get the current mouse |
GetMouse(¤tPoint); |
didJustScroll = false; |
// scroll contents if needed |
{ |
short deltaH = 0; |
short deltaV = 0; |
if (currentPoint.h < 0) |
deltaH = pData->hScrollAmount; |
if (currentPoint.h > qd.thePort->portRect.right) |
deltaH = -pData->hScrollAmount; |
if (currentPoint.v < 0) |
deltaV = pData->vScrollAmount; |
if (currentPoint.v > qd.thePort->portRect.bottom) |
deltaV = -pData->vScrollAmount; |
if ( (deltaH != 0) || (deltaV != 0) ) |
{ |
if (deltaH) |
SetControlAndClipAmount(pData->hScroll, &deltaH); |
if (deltaV) |
SetControlAndClipAmount(pData->vScroll, &deltaV); |
DoScrollContent(pWindow, pData, deltaH, deltaV); |
didJustScroll = true; |
} |
} |
// map mouse into proper range |
currentPoint.h += GetControlValue(pData->hScroll); |
currentPoint.v += GetControlValue(pData->vScroll); |
// clip to the document size |
if (currentPoint.h < 0) |
currentPoint.h = 0; |
if (currentPoint.v < 0) |
currentPoint.v = 0; |
if (currentPoint.h > pContent->right) |
currentPoint.h = pContent->right; |
if (currentPoint.v > pContent->bottom) |
currentPoint.v = pContent->bottom; |
// draw the new selection if it is time or we are about to |
// exit this loop |
if ((MOVESELECTION(TickCount())) || (!Button()) || (didJustScroll) ) |
{ |
// first, erase any old selection we might have had |
DrawSelection(pData, pSelection, pPhase, false); |
// make a rectangle out of the two points |
pSelection->left = Min(currentPoint.h, clickPoint.h); |
pSelection->right = Max(currentPoint.h, clickPoint.h); |
pSelection->top = Min(currentPoint.v, clickPoint.v); |
pSelection->bottom = Max(currentPoint.v, clickPoint.v); |
// draw the new selection |
DrawSelection(pData, pSelection, pPhase, true); |
} |
} |
// we handled the selection |
anErr = eActionAlreadyHandled; |
} |
return(anErr); |
} // SelectContents |
// -------------------------------------------------------------------------------------------------------------- |
void DragAndDropArea(WindowRef pWindow, WindowDataPtr pData, EventRecord* event, Rect *pFrameRect) |
{ |
RgnHandle hilightRgn; |
Rect r; |
DragReference theDrag; |
OSErr anErr = noErr; |
if (NewDrag(&theDrag) == noErr) |
{ |
if (pData->pDragAddFlavors) |
anErr = (*(pData->pDragAddFlavors)) (pWindow, pData, theDrag); |
if (anErr == noErr) |
{ |
Rect globalRect = *pFrameRect; |
hilightRgn = NewRgn(); |
LocalToGlobal(&TopLeft(globalRect)); |
LocalToGlobal(&BotRight(globalRect)); |
RectRgn(hilightRgn, &globalRect); |
SetDragItemBounds(theDrag, 1, &r); |
// turn the region from a fill into a frame |
{ |
RgnHandle tempRgn = NewRgn(); |
CopyRgn(hilightRgn, tempRgn); |
InsetRgn(tempRgn, 1, 1); |
DiffRgn(hilightRgn, tempRgn, hilightRgn); |
DisposeRgn(tempRgn); |
} |
TrackDrag(theDrag, event, hilightRgn); |
DisposeDrag(theDrag); |
DisposeRgn(hilightRgn); |
} |
} |
} // DragAndDropArea |
// -------------------------------------------------------------------------------------------------------------- |
// WINDOW UTILITY ROUTINES |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static void CalculateGrowIcon(WindowDataPtr pData, Rect * location) |
{ |
if (pData->vScroll) |
location->top = (**pData->vScroll).contrlRect.bottom; |
else |
{ |
if (pData->hScroll) |
location->top = (**pData->hScroll).contrlRect.top; |
else |
location->top = pData->theWindow.port.portRect.bottom - 15; |
} |
if (pData->hScroll) |
location->left = (**pData->hScroll).contrlRect.right; |
else |
{ |
if (pData->vScroll) |
location->left = (**pData->vScroll).contrlRect.left; |
else |
location->left = pData->theWindow.port.portRect.right - 15; |
} |
location->right = location->left + 16; |
location->bottom = location->top + 16; |
} // CalculateGrowIcon |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
OSErr AdjustScrollBars(WindowRef pWindow, |
Boolean moveControls, // might the controls have moved? |
Boolean didResize, // did we just resize the window? |
Boolean *needInvalidate) // does the caller need to invalidate contents as a result? |
{ |
OSErr anErr = noErr; |
LongRect docRect; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
Rect growIconRect; |
if (needInvalidate) |
*needInvalidate = false; |
if (pData) |
{ |
short oldHMax, oldVMax; |
short oldHValue, oldVValue; |
// cache current values, we'll force an update if we needed to change em! |
if (pData->hScroll) |
{ |
oldHMax = GetControlMaximum(pData->hScroll); |
oldHValue = GetControlValue(pData->hScroll); |
} |
if (pData->vScroll) |
{ |
oldVMax = GetControlMaximum(pData->vScroll); |
oldVValue = GetControlValue(pData->vScroll); |
} |
// if we have a grow box but not all controls we have to invalidate the grow bar areas |
// by caclulating them |
if ( (didResize) && (pData->hasGrow) ) |
{ |
// if we regrow without any scroll bars, we need to update the content area |
if ( (needInvalidate) && (pData->hScroll == nil) && (pData->vScroll == nil) ) |
*needInvalidate = true; |
// invalidate old grow bar areas |
if (pData->vScroll == nil) |
{ |
growIconRect = GetWindowPort(pWindow)->portRect; |
growIconRect.left = pData->contentRect.right; |
InvalRect(&growIconRect); |
} |
if (pData->hScroll == nil) |
{ |
growIconRect = GetWindowPort(pWindow)->portRect; |
growIconRect.top = pData->contentRect.bottom; |
InvalRect(&growIconRect); |
} |
// invalidate new grow bar areas |
if (pData->vScroll == nil) |
{ |
growIconRect = GetWindowPort(pWindow)->portRect; |
growIconRect.left = growIconRect.right - kScrollBarSize; |
InvalRect(&growIconRect); |
} |
if (pData->hScroll == nil) |
{ |
growIconRect = GetWindowPort(pWindow)->portRect; |
growIconRect.top = growIconRect.bottom - kScrollBarSize; |
InvalRect(&growIconRect); |
} |
} |
// if the controls need moving, recalculate the visible area |
if (moveControls) |
{ |
pData->contentRect = GetWindowPort(pWindow)->portRect; |
if ((pData->hScroll) || (pData->hasGrow) ) |
pData->contentRect.bottom -= kScrollBarSize; |
if ((pData->vScroll) || (pData->hasGrow) ) |
pData->contentRect.right -= kScrollBarSize; |
} |
// before doing anything, make the controls invisible |
if (pData->hScroll) |
(**pData->hScroll).contrlVis = 0; |
if (pData->vScroll) |
(**pData->vScroll).contrlVis = 0; |
// based on document and visiable area, adjust possible control values |
if ( (pData->pGetDocumentRect) && ((pData->hScroll) || (pData->vScroll)) ) |
{ |
// let the object calc the size and content if it wishes to |
anErr = (*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, false); |
if (anErr == noErr) |
{ |
short amountOver; |
short newMax; |
amountOver = (docRect.right - docRect.left) - (pData->contentRect.right - pData->contentRect.left); |
if ( |
(pData->hScroll) && |
(amountOver > 0) |
) |
newMax = amountOver; |
else |
newMax = 0; |
if (pData->hScroll) |
{ |
if (GetControlValue(pData->hScroll) > newMax) |
{ |
if (needInvalidate) |
*needInvalidate = true; |
} |
SetControlMaximum(pData->hScroll, newMax); |
} |
amountOver = (docRect.bottom - docRect.top) - (pData->contentRect.bottom - pData->contentRect.top); |
if ( |
(pData->vScroll) && |
(amountOver > 0) |
) |
newMax = amountOver; |
else |
newMax = 0; |
if (pData->vScroll) |
{ |
if (GetControlValue(pData->vScroll) > newMax) |
{ |
if (needInvalidate) |
*needInvalidate = true; |
} |
SetControlMaximum(pData->vScroll, newMax); |
} |
} |
} |
// then, if the controls need moving, we move them and inval the old |
// and new locations |
if (moveControls) |
{ |
// if we have grow box we invalidate the old grow location |
if ( pData->hasGrow) |
{ |
CalculateGrowIcon(pData, &growIconRect); |
InvalRect(&growIconRect); |
} |
if (pData->hScroll) |
{ |
short widthAdjust; |
if ((pData->vScroll) || (pData->hasGrow)) |
widthAdjust = -kGrowScrollAdjust; |
else |
widthAdjust = -1; |
growIconRect = (**pData->hScroll).contrlRect; |
InvalRect(&growIconRect); |
MoveControl(pData->hScroll, pData->hScrollOffset-1, GetWindowPort(pWindow)->portRect.bottom - kScrollBarSize); |
SizeControl(pData->hScroll, (GetWindowPort(pWindow)->portRect.right - |
GetWindowPort(pWindow)->portRect.left) + widthAdjust - pData->hScrollOffset, |
16); |
growIconRect = (**pData->hScroll).contrlRect; |
InvalRect(&growIconRect); |
} |
if (pData->vScroll) |
{ |
short heightAdjust; |
if ((pData->hScroll) || (pData->hasGrow)) |
heightAdjust = -kGrowScrollAdjust; |
else |
heightAdjust = -1; |
growIconRect = (**pData->vScroll).contrlRect; |
InvalRect(&growIconRect); |
MoveControl(pData->vScroll, GetWindowPort(pWindow)->portRect.right - kScrollBarSize, pData->vScrollOffset-1); |
SizeControl(pData->vScroll, 16, |
(GetWindowPort(pWindow)->portRect.bottom - |
GetWindowPort(pWindow)->portRect.top) + heightAdjust - pData->vScrollOffset); |
growIconRect = (**pData->vScroll).contrlRect; |
InvalRect(&growIconRect); |
} |
// if we have scroll bars, update the grow icon |
if ( pData->hasGrow ) |
{ |
CalculateGrowIcon(pData, &growIconRect); |
InvalRect(&growIconRect); |
} |
} |
// let the document adjust anything it needs to |
if (pData->pAdjustSize) |
anErr = (*(pData->pAdjustSize)) (pWindow, pData, &didResize); |
if ((didResize) && (needInvalidate)) |
*needInvalidate = true; |
if ( ((WindowPeek) pWindow)->hilited ) |
{ |
// after doing something, make the controls visible |
if (pData->hScroll) |
{ |
if ((oldHMax != GetControlMaximum(pData->hScroll)) || (oldHValue != GetControlValue(pData->hScroll)) ) |
ShowControl(pData->hScroll); |
else |
(**pData->hScroll).contrlVis = 0xFF; |
} |
if (pData->vScroll) |
{ |
if ((oldVMax != GetControlMaximum(pData->vScroll)) || (oldVValue != GetControlValue(pData->vScroll)) ) |
ShowControl(pData->vScroll); |
else |
(**pData->vScroll).contrlVis = 0xFF; |
} |
} |
} |
return anErr; |
} // AdjustScrollBars |
// -------------------------------------------------------------------------------------------------------------- |
// MENU UTILITY ROUTINES |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
Boolean CommandToIDs(short commandID, short * menuID, short *itemID) |
{ |
short ** commandHandle; |
short whichMenu; |
short oldResFile = CurResFile(); |
Boolean returnValue = false; |
UseResFile(gApplicationResFile); |
for (whichMenu = mApple; whichMenu <= mLastMenu; whichMenu++) |
{ |
commandHandle = (short**) Get1Resource('MCMD', whichMenu); |
if (commandHandle) |
{ |
short * pCommands = *commandHandle; |
short commandIndex; |
short numCommands = pCommands[0]; |
for (commandIndex = 1; commandIndex <= numCommands; ++commandIndex) |
if (pCommands[commandIndex] == commandID) |
{ |
*menuID = whichMenu; |
*itemID = commandIndex; |
returnValue = (commandIndex == numCommands); |
} |
} |
} |
UseResFile(oldResFile); |
return returnValue; |
} // CommandToIDs |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
Boolean IsCommandEnabled(short commandID) |
/* |
returns true if a given command is currently enabled |
*/ |
{ |
short whichMenu, whichItem; |
MenuHandle menu; |
CommandToIDs(commandID, &whichMenu, &whichItem); |
menu = GetMenuHandle(whichMenu); |
if ((**menu).enableFlags & (1 << whichItem)) |
return(true); |
return(false); |
} // IsCommandEnabled |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
void EnableCommand(short commandID) |
/* |
Given a command ID, enables the first menu item with that command ID. |
If the command table for a given menu is less than the number of items in the menu, |
and the command being enabled is the last item in the command table, then all |
items from there on down are also enabled. This is useful for menus that get |
appended to, such as the desk accessory list, font list, or speaking voices list. |
*/ |
{ |
short whichMenu; |
short whichItem; |
if (CommandToIDs(commandID, &whichMenu, &whichItem)) |
{ |
short i; |
MenuHandle menu = GetMenuHandle(whichMenu); |
if (menu) |
{ |
short numItems = CountMItems(menu); |
for (i = whichItem; i <= numItems; ++i) |
EnableItem(menu, i); |
} |
} |
else |
{ |
MenuHandle menu = GetMenuHandle(whichMenu); |
if (menu) |
EnableItem(menu, whichItem); |
} |
} // EnableCommand |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
void ChangeCommandName(short commandID, short resourceID, short resourceIndex) |
{ |
short whichMenu; |
short whichItem; |
MenuHandle menu; |
// figure out how this command maps into the menu bar |
CommandToIDs(commandID, &whichMenu, &whichItem); |
menu = GetMenuHandle(whichMenu); |
// then make this item into the requested new string |
{ |
Str255 theString; |
GetIndString(theString, resourceID, resourceIndex); |
SetMenuItemText(menu, whichItem, theString); |
} |
} // ChangeCommandName |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
void EnableCommandCheck(short commandID, Boolean check) |
{ |
short whichMenu; |
short whichItem; |
if (CommandToIDs(commandID, &whichMenu, &whichItem)) |
{ |
short i; |
MenuHandle menu = GetMenuHandle(whichMenu); |
short numItems = CountMItems(menu); |
for (i = whichItem; i <= numItems; ++i) |
{ |
EnableItem(menu, i); |
CheckItem(menu, i, check); |
} |
} |
else |
{ |
MenuHandle menu = GetMenuHandle(whichMenu); |
EnableItem(menu, whichItem); |
CheckItem(menu, whichItem, check); |
} |
} // EnableCommandCheck |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
void EnableCommandCheckStyle(short commandID, Boolean check, short style) |
{ |
short whichMenu; |
short whichItem; |
if (CommandToIDs(commandID, &whichMenu, &whichItem)) |
{ |
short i; |
MenuHandle menu = GetMenuHandle(whichMenu); |
short numItems = CountMItems(menu); |
for (i = whichItem; i <= numItems; ++i) |
{ |
EnableItem(menu, i); |
CheckItem(menu, i, check); |
SetItemStyle(menu, i, style); |
} |
} |
else |
{ |
MenuHandle menu = GetMenuHandle(whichMenu); |
EnableItem(menu, whichItem); |
CheckItem(menu, whichItem, check); |
SetItemStyle(menu, whichItem, style); |
} |
} // EnableCommandCheckStyle |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
void AdjustMenus(WindowRef pWindow, Boolean editDialogs, Boolean forceTitlesOn) |
{ |
Boolean wasEnabled[mNumberMenus]; // Old state of menus |
short whichMenu; // for stepping through menus |
MenuHandle menu; // for reading in menu IDs |
WindowDataPtr pData = GetWindowInfo(pWindow); |
// Step through all of the menus |
for (whichMenu = mApple; whichMenu <= mLastMenu; whichMenu++) |
{ |
// Save the old state of the menu title |
menu = GetMenuHandle(whichMenu); |
if (menu) // because contents menu may not be around |
{ |
if (forceTitlesOn) |
wasEnabled[mLastMenu - whichMenu] = false; |
else |
wasEnabled[mLastMenu - whichMenu] = (((**menu).enableFlags && 1) == 1); |
// Disable the entire menu |
(**menu).enableFlags = 0; |
} |
} |
// select all, unless someone else changes it |
ChangeCommandName(cSelectAll, kMiscStrings, iSelectAllCommand); |
// if we have NO windows, or the current window is one we understand |
if ((pWindow == nil) || (pData)) |
{ |
// enable the default commands |
EnableCommand(cAbout); |
EnableCommand(cDeskAccessory); |
EnableCommand(cNew); |
EnableCommand(cOpen); |
EnableCommand(cQuit); |
EnableCommand(cShowClipboard); |
} |
else |
{ |
// it's printing or a dialog, so enable cut/copy/paste |
if (editDialogs) |
{ |
EnableCommand(cCut); |
EnableCommand(cCopy); |
EnableCommand(cPaste); |
EnableCommand(cClear); |
} |
// and desk accs too! |
EnableCommand(cDeskAccessory); |
} |
if ( (pWindow) && (pData) ) |
{ |
// all windows can be closed |
if (FrontWindow()) |
EnableCommand(cClose); |
// changed documents can be saved, but only if the file is open for write |
if ( (pData->changed) && |
((pData->isWritable) || (pData->dataRefNum == -1)) ) |
EnableCommand(cSave); |
// objects with a print method can be printed and page setup-ed |
if (pData->pPrintPage) |
{ |
EnableCommand(cPrint); |
EnableCommand(cPageSetup); |
EnableCommand(cPrintOneCopy); |
} |
// let object enable anything else that needs to be enabled |
if (pData->pAdjustMenus) |
(*(pData->pAdjustMenus)) (pWindow, pData); |
} |
// Now determine if any of the menus have changed state |
{ |
Boolean gotToRedraw = false; |
for (whichMenu = mApple; whichMenu <= mLastMenu; ++whichMenu) |
{ |
menu = GetMenuHandle(whichMenu); |
if (menu) // because contents menu may not be around |
{ |
// If any of the menu is enabled |
if ((**menu).enableFlags != 0) |
{ |
// Make sure to turn on the menu title |
(**menu).enableFlags |= 1; |
} |
/* If this new state is different than the saved state, then the menu bar |
will need to be redrawn */ |
if (wasEnabled[mLastMenu - whichMenu] != ((**menu).enableFlags && 1)) |
{ |
gotToRedraw = true; |
} |
} |
} |
// And if any titles have changed state, redraw them |
if (gotToRedraw) |
DrawMenuBar(); |
} |
} // AdjustMenus |
// -------------------------------------------------------------------------------------------------------------- |
// FILE UTILITY ROUTINES |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static Boolean BringToFrontIfOpen(FSSpecPtr pSpec) |
{ |
WindowRef pWindow; |
pWindow = FrontWindow(); |
while (pWindow) |
{ |
WindowDataPtr pData = GetWindowInfo(pWindow); |
if ( |
(pData) && |
(pData->fileSpec.vRefNum == pSpec->vRefNum) && |
(pData->fileSpec.parID == pSpec->parID) && |
EqualString(pData->fileSpec.name, pSpec->name, false, false) |
) |
{ |
SelectWindow(pWindow); |
return true; |
} |
pWindow = GetNextWindow(pWindow); |
} |
return false; |
} // BringToFrontIfOpen |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static Boolean BringToFrontIfExists(ResType windowKind) |
{ |
WindowRef pWindow; |
pWindow = FrontWindow(); |
while (pWindow) |
{ |
WindowDataPtr pData = GetWindowInfo(pWindow); |
if ((pData) && (pData->windowKind == windowKind)) |
{ |
SelectWindow(pWindow); |
return true; |
} |
pWindow = GetNextWindow(pWindow); |
} |
return false; |
} // BringToFrontIfExists |
// -------------------------------------------------------------------------------------------------------------- |
// MAIN SIMPLETEXT ROUTINES |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr MakeNewWindow(ResType windowKind, FSSpecPtr fileSpec, OSType fileType, Boolean *pWasAlreadyOpen) |
{ |
OSErr anErr = fnfErr; |
PreflightRecord thePreflight; |
PreflightWindowProc pPreflight = nil; |
WindowRef pWindow; |
WindowDataPtr pData; |
// require a certain amount of RAM free before we allow the new window to be created |
if (FreeMem() < kRAMNeededForNew) |
anErr = memFullErr; |
// <50> if we already have a document open from this file, bring the window to the |
// front and return with no error |
if ( (fileSpec) && (fileType != 'sEXT') && (BringToFrontIfOpen(fileSpec)) ) |
{ |
if (pWasAlreadyOpen) |
*pWasAlreadyOpen = true; |
anErr = noErr; |
return(anErr); |
} |
if (pWasAlreadyOpen) |
*pWasAlreadyOpen = false; |
if (anErr != fnfErr) |
{ |
nrequire(anErr, SanityCheckFailed); |
} |
// initialize our behavior |
thePreflight.continueWithOpen = true; |
thePreflight.resourceID = kDefaultWindowID; |
thePreflight.wantHScroll = false; |
thePreflight.wantVScroll = false; |
thePreflight.storageSize = sizeof(WindowDataRecord); |
thePreflight.makeProcPtr = nil; |
thePreflight.openKind = fsRdPerm; |
thePreflight.needResFork = false; |
thePreflight.doZoom = false; |
thePreflight.fileType = fileType; |
switch (windowKind) |
{ |
case kAboutWindow: |
pPreflight = AboutPreflightWindow; |
break; |
case kPICTWindow: |
pPreflight = PICTPreflightWindow; |
break; |
case kMovieWindow: |
pPreflight = MoviePreflightWindow; |
break; |
case kClipboardWindow: |
pPreflight = ClipboardPreflightWindow; |
break; |
case kTextWindow: |
pPreflight = TextPreflightWindow; |
break; |
case kThreeDWindow: |
pPreflight = ThreeDPreflightWindow; |
break; |
} |
// preflight the window |
if (pPreflight) |
anErr = (*pPreflight) (&thePreflight); |
nrequire(anErr, PreflightFailed); |
if (thePreflight.continueWithOpen) |
{ |
// allocate a place for the window |
pData = (WindowDataPtr)NewPtrClear(thePreflight.storageSize); |
anErr = MemError(); |
nrequire(anErr, FailedToAllocateWindow); |
// then actually create the window |
if (gMachineInfo.theEnvirons.hasColorQD) |
pWindow = (WindowRef)GetNewCWindow(thePreflight.resourceID, pData, (WindowPtr)-1); |
else |
pWindow = (WindowRef)GetNewWindow(thePreflight.resourceID, pData, (WindowPtr)-1); |
if (!pWindow) anErr = memFullErr; |
nrequire(anErr, NewWindowFailed); |
SetWRefCon(pWindow, (long) pData); |
// zoom the rectangle to big size on this monitor |
// based upon which scroll bars they want |
{ |
Rect rect = GetWindowPort(pWindow)->portRect; |
Rect bigRect; |
if (gMachineInfo.theEnvirons.hasColorQD) |
bigRect = (**GetMainDevice()).gdRect; |
else |
bigRect = qd.screenBits.bounds; |
bigRect.top += GetMBarHeight() * 2; |
bigRect.left += 4; |
bigRect.bottom -= 4; |
bigRect.right -= 65; |
SetPort((GrafPtr) GetWindowPort(pWindow)); |
LocalToGlobal(&TopLeft(rect)); |
LocalToGlobal(&BotRight(rect)); |
if ( (thePreflight.wantHScroll) || (thePreflight.doZoom) ) |
{ |
rect.left = bigRect.left; |
rect.right = bigRect.right; |
} |
if ( (thePreflight.wantVScroll) || (thePreflight.doZoom) ) |
{ |
rect.top = bigRect.top; |
rect.bottom = bigRect.bottom; |
} |
MoveWindow(pWindow, rect.left, rect.top, false); |
SizeWindow(pWindow, rect.right - rect.left, rect.bottom - rect.top, false); |
} |
// fill in the default contents of the window |
pData->windowKind = windowKind; |
pData->originalFileType = fileType; |
pData->pMakeWindow = (MakeWindowProc)thePreflight.makeProcPtr; |
pData->resRefNum = -1; |
pData->dataRefNum = -1; |
pData->contentRect = GetWindowPort(pWindow)->portRect; |
// make the scroll bars |
{ |
Rect controlRect; |
if (thePreflight.wantHScroll) |
{ |
pData->contentRect.bottom -= kScrollBarSize; |
controlRect = GetWindowPort(pWindow)->portRect; |
controlRect.top = controlRect.bottom - 16; |
if (thePreflight.wantVScroll) |
controlRect.right -= kGrowScrollAdjust; |
OffsetRect(&controlRect, -1, 1); |
pData->hScroll = NewControl(pWindow, &controlRect, "\p", true, 0, 0, 0, scrollBarProc, 0); |
} |
if (thePreflight.wantVScroll) |
{ |
pData->contentRect.right -= kScrollBarSize; |
controlRect = GetWindowPort(pWindow)->portRect; |
controlRect.left = controlRect.right - 16; |
if (thePreflight.wantVScroll) |
controlRect.bottom -= kGrowScrollAdjust; |
OffsetRect(&controlRect, 1, -1); |
pData->vScroll = NewControl(pWindow, &controlRect, "\p", true, 0, 0, 0, scrollBarProc, 0); |
} |
} |
// got a name? Open the file |
if (fileSpec) |
{ |
anErr = FSpOpenDF(fileSpec, thePreflight.openKind, &pData->dataRefNum); |
if ( |
((anErr == afpAccessDenied) || (anErr == opWrErr) || (anErr == permErr) ) && |
(thePreflight.openKind != fsRdPerm) |
) |
{ |
thePreflight.openKind = fsRdPerm; |
pData->isWritable = false; |
anErr = FSpOpenDF(fileSpec, thePreflight.openKind, &pData->dataRefNum); |
} |
else |
pData->isWritable = true; |
nrequire(anErr, FailedToOpenFile); |
// okay not to find a resource fork, because some don't have them |
pData->resRefNum = FSpOpenResFile(fileSpec, thePreflight.openKind); |
// save the file spec in case someone is interested |
pData->fileSpec = *fileSpec; |
} |
if (pData->pMakeWindow) |
{ |
Rect oldContent = pData->contentRect; |
anErr = (*(pData->pMakeWindow)) (pWindow, pData); |
if (!EqualRect(&oldContent, &pData->contentRect)) |
{ |
SizeWindow(pWindow, |
pData->contentRect.right + (pData->vScroll != 0) * kScrollBarSize, |
pData->contentRect.bottom + (pData->hScroll != 0) * kScrollBarSize, |
false); |
} |
} |
nrequire(anErr, FailedMakeWindow); |
// got a name? Use it as the window title |
if ( (fileSpec) && (!pData->openAsNew) ) |
SetWTitle(pWindow, fileSpec->name); |
else |
{ |
if ((gMachineInfo.documentCount == 1) && (pData->windowKind == kTextWindow)) |
{ |
Str255 tempString; |
GetIndString(tempString, kMiscStrings, iFirstNewDocumentTitle); // get the "untitled" string (no number) |
SetWTitle(pWindow, tempString); |
} |
else |
{ |
Str255 tempString; |
Str32 numString; |
GetWTitle(pWindow, tempString); |
NumToString(gMachineInfo.documentCount, numString); |
(void) ZeroStringSub(tempString, numString); |
SetWTitle(pWindow, tempString); |
} |
if (pData->bumpUntitledCount) |
gMachineInfo.documentCount++; // bump count if appropriate for this kind of document |
} |
// Make sure the scroll bars are reasonable in size, and move if they must |
AdjustScrollBars(pWindow, true, true, nil); |
// finally, if all goes well, we can see the window itself! |
ShowWindow(pWindow); |
} |
return noErr; |
// EXCEPTION HANDLING |
FailedMakeWindow: |
if (pData->resRefNum != -1) |
CloseResFile(pData->resRefNum); |
if (pData->dataRefNum != -1) |
FSClose(pData->dataRefNum); |
FailedToOpenFile: |
CloseWindow(pWindow); |
NewWindowFailed: |
DisposePtr((Ptr)pData); |
FailedToAllocateWindow: |
PreflightFailed: |
SanityCheckFailed: |
return anErr; |
} // MakeNewWindow |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
#define dontSaveChanges 3 |
#define kVisualDelay 8 |
static pascal Boolean SaveChangesFilter(DialogRef theDialog, EventRecord *theEvent, short *itemHit) |
{ |
if (StdFilterProc(theDialog, theEvent, itemHit)) |
return true; |
if (theEvent->what == updateEvt) |
{ |
HandleEvent(theEvent); |
} |
if (theEvent->what == keyDown) |
{ |
StringPtr keyEquivs = *GetString(kSaveChangesWindowID); |
unsigned char theKey = theEvent->message & charCodeMask; |
if (keyEquivs && (theKey == keyEquivs[1] || theKey == keyEquivs[2])) |
{ |
short itemType; |
Rect theRect; |
ControlRef theControl; |
unsigned long finalTicks; |
GetDialogItem(theDialog, dontSaveChanges, &itemType, (Handle *) &theControl, &theRect); |
HiliteControl(theControl, kControlButtonPart); |
Delay(kVisualDelay, &finalTicks); |
HiliteControl(theControl, 0); |
*itemHit = dontSaveChanges; |
return true; |
} |
} |
return false; |
} |
static OSErr DoCloseWindow(WindowRef pWindow) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
if ( (pData) && (pData->changed) ) |
{ |
short hit; |
Str255 wTitle; |
DialogRef dPtr; |
GetWTitle(pWindow, wTitle); |
SetCursor(&qd.arrow); |
ParamText(wTitle, "\p", "\p", "\p"); |
hit = cancel; |
dPtr = GetNewDialog(kSaveChangesWindowID, nil, (WindowRef)-1); |
if (dPtr) |
{ |
SetDialogDefaultItem(dPtr, ok); |
SetDialogCancelItem (dPtr, cancel); |
BeginMovableModal(); |
do |
{ |
MovableModalDialog(SaveChangesFilter, &hit); |
} while ((hit != dontSaveChanges) && (hit != ok) && (hit != cancel)); |
DisposeDialog(dPtr); |
EndMovableModal(); |
} |
switch (hit) |
{ |
case ok: |
anErr = DoCommand(pWindow, cSave, 0); |
if (anErr == eUserCanceled) // redundant? |
gAllDone = false; |
break; |
case cancel: |
anErr = eUserCanceled; |
gAllDone = false; |
break; |
case dontSaveChanges: |
// don't save, so just close it |
break; |
} |
} |
if (anErr == noErr) |
{ |
if ( (pData) && (pData->pCloseWindow) ) |
{ |
// let the object close the window if it wishes to |
anErr = (*(pData->pCloseWindow)) (pWindow, pData); |
} |
// otherwise we close it the default way |
if (anErr == noErr) |
{ |
if (pData) |
{ |
CloseWindow(pWindow); |
if (pData->hPrint) |
{ |
DisposeHandle((Handle) pData->hPrint); |
} |
if (pData->resRefNum != -1) |
CloseResFile(pData->resRefNum); |
if (pData->dataRefNum != -1) |
FSClose(pData->dataRefNum); |
DisposePtr((Ptr) pData); |
} |
} |
} |
// If we closed the last window, clean up |
if (FrontWindow() == nil) |
{ |
AdjustMenus(nil, true, false); |
gMachineInfo.documentCount = 1; // back to "untitled" |
} |
return anErr; |
} // DoCloseWindow |
#undef dontSaveChanges |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr DetermineWindowTypeOrOpen( |
FSSpecPtr theSpec, OSType theType, // optional input params -- file to open |
OSType *returnedTypeList, short * pNumTypes, // optional input params -- returns list of files |
Boolean *pWasAlreadyOpen) // optional input params -- was file already open |
{ |
OSErr anErr = noErr; |
OSType typeList[20]; |
OSType docList[20]; |
short numTypes; |
// use local copies if the input params are nil |
if (returnedTypeList == nil) |
returnedTypeList = &typeList[0]; |
if (pNumTypes == nil) |
pNumTypes = &numTypes; |
*pNumTypes = 0; |
// Load up all of the file types we know how to handle |
AboutGetFileTypes(returnedTypeList, docList, pNumTypes); |
PICTGetFileTypes(returnedTypeList, docList, pNumTypes); |
MovieGetFileTypes(returnedTypeList, docList, pNumTypes); |
ClipboardGetFileTypes(returnedTypeList, docList, pNumTypes); |
TextGetFileTypes(returnedTypeList, docList, pNumTypes); |
ThreeDGetFileTypes(returnedTypeList, docList, pNumTypes); |
if (theSpec != nil) |
{ |
short index; |
OSType windowType = '????'; |
for (index = 0; index < (*pNumTypes); ++index) |
if (theType == returnedTypeList[index]) |
windowType = docList[index]; |
if (windowType != '????') |
{ |
if ( (theType == 'TEXT') || (theType == 'sEXT') ) |
{ |
FInfo theInfo; |
FSpGetFInfo(theSpec, &theInfo); |
if ((theInfo.fdFlags & kIsStationery) != 0) |
theType = 'sEXT'; |
else |
theType = 'TEXT'; |
} |
anErr = MakeNewWindow(windowType, theSpec, theType, pWasAlreadyOpen); |
} |
else |
anErr = eDocumentWrongKind; |
} |
return anErr; |
} // DetermineWindowTypeOrOpen |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
// Handle update/activate events behind Standard File |
static pascal Boolean OpenDialogFilter(DialogRef theDialog, EventRecord *theEvent, |
short *itemHit, void *myDataPtr) |
{ |
#pragma unused(myDataPtr) |
// Pass updates through (Activates are tricky...was mucking with Apple menu & thereby |
// drastically changing how the system handles the menu bar during our alert) |
if ( (theEvent->what == updateEvt) && (theEvent->message != (long)theDialog) ) |
HandleEvent(theEvent); |
if (StdFilterProc(theDialog, theEvent, itemHit)) |
return(true); |
return(false); |
} // OpenDialogFilter |
#if GENERATINGCFM |
static RoutineDescriptor gOpenDialogFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterYDProcInfo, OpenDialogFilter); |
static ModalFilterYDUPP gOpenDialogFilter = &gOpenDialogFilterRD; |
#else |
static ModalFilterYDUPP gOpenDialogFilter = NewModalFilterYDProc(OpenDialogFilter); |
#endif |
static OSErr DoOpenWindow(void) |
{ |
OSErr anErr = noErr; |
short numTypes; |
OSType typeList[20]; |
StandardFileReply sfReply; |
Point thePoint = { -1, -1 }; |
DetermineWindowTypeOrOpen(nil, '????', &typeList[0], &numTypes, nil); |
if (gMachineInfo.haveQuickTime) |
{ |
CustomGetFilePreview(nil, numTypes, typeList, &sfReply, 0, thePoint, nil, gOpenDialogFilter, nil, nil, nil); |
} |
else |
{ |
CustomGetFile(nil, numTypes, typeList, &sfReply, 0, thePoint, nil, gOpenDialogFilter, nil, nil, nil); |
} |
if (sfReply.sfGood) |
{ |
SetWatchCursor(); |
anErr = DetermineWindowTypeOrOpen(&sfReply.sfFile, sfReply.sfType, &typeList[0], &numTypes, nil); |
SetCursor(&qd.arrow); |
} |
return anErr; |
} // DoOpenWindow |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr DoUpdateWindow(WindowRef pWindow) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
GrafPtr curPort; |
// only handle updates for windows we know about |
if (pData) |
{ |
GetPort(&curPort); |
SetPort((GrafPtr)GetWindowPort(pWindow)); |
BeginUpdate(pWindow); |
if (pData->pUpdateWindow) |
anErr = (*(pData->pUpdateWindow)) (pWindow, pData); |
EndUpdate(pWindow); |
SetPort(curPort); |
} |
return anErr; |
} // DoUpdateWindow |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
OSErr DoScrollContent(WindowRef pWindow, WindowDataPtr pData, short deltaH, short deltaV) |
{ |
OSErr anErr = noErr; |
if ((deltaH) || (deltaV)) |
{ |
// if we have a balloon displayed, update before scrolling anything |
if (HMIsBalloon()) |
DoUpdateWindow(pWindow); |
if ((pData) && (pData->pScrollContent)) |
anErr = (*(pData->pScrollContent)) (pWindow, pData, deltaH, deltaV); |
if (anErr == noErr) |
{ |
RgnHandle invalidRgn = NewRgn(); |
ScrollRect(&pData->contentRect, deltaH, deltaV, invalidRgn); |
InvalRgn(invalidRgn); |
DisposeRgn(invalidRgn); |
DoUpdateWindow(pWindow); |
} |
} |
return anErr; |
} // DoScrollContent |
// -------------------------------------------------------------------------------------------------------------- |
// BEGIN SCROLL ACTION PROCS |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
void SetControlAndClipAmount(ControlRef control, short * amount) |
{ |
short value, max; |
value = GetControlValue(control); /* get current value */ |
max = GetControlMaximum(control); /* and maximum value */ |
*amount = value - *amount; |
if ( *amount < 0 ) |
*amount = 0; |
else |
{ |
if ( *amount > max ) |
*amount = max; |
} |
SetControlValue(control, *amount); |
*amount = value - *amount; /* calculate the real change */ |
} // SetControlAndClipAmount |
// -------------------------------------------------------------------------------------------------------------- |
static pascal void VActionProc(ControlRef control, short part) |
{ |
if (part != 0) |
{ |
WindowRef pWindow = (**control).contrlOwner; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
short amount = 0; |
switch (part) |
{ |
case kControlUpButtonPart: |
amount = pData->vScrollAmount; |
break; |
case kControlDownButtonPart: |
amount = -pData->vScrollAmount; |
break; |
// vertical page scrolling should be a multiple of the incremental scrolling -- so that |
// we avoid half-lines of text at the bottom of pages. |
// More generically, if there was a method for dealing with text scrolling by a non-constant |
// amount, this would be better -- but SimpleText currently doesn't have a framework to allow |
// the document object to override the scroll amount dynamically. Maybe something to add in |
// the future. |
case kControlPageUpPart: |
amount = (((pData->contentRect.bottom - pData->contentRect.top) / pData->vScrollAmount)-1) * pData->vScrollAmount; |
if (amount == 0) |
amount = pData->contentRect.bottom - pData->contentRect.top; |
break; |
case kControlPageDownPart: |
amount = (((pData->contentRect.top - pData->contentRect.bottom) / pData->vScrollAmount)+1) * pData->vScrollAmount; |
if (amount == 0) |
amount = pData->contentRect.top - pData->contentRect.bottom; |
break; |
} |
SetControlAndClipAmount(control, &amount); |
if (amount != 0) |
DoScrollContent(pWindow, pData, 0, amount); |
} |
} // VActionProc |
#if GENERATINGCFM |
static RoutineDescriptor gVActionProcRD = BUILD_ROUTINE_DESCRIPTOR(uppControlActionProcInfo, VActionProc); |
static ControlActionUPP gVActionProc = &gVActionProcRD; |
#else |
static ControlActionUPP gVActionProc = VActionProc; |
#endif |
// -------------------------------------------------------------------------------------------------------------- |
static pascal void HActionProc(ControlRef control, short part) |
{ |
if (part != 0) |
{ |
WindowRef pWindow = (**control).contrlOwner; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
short amount = 0; |
switch (part) |
{ |
case kControlUpButtonPart: |
amount = pData->hScrollAmount; |
break; |
case kControlDownButtonPart: |
amount = -pData->hScrollAmount; |
break; |
case kControlPageUpPart: |
amount = pData->contentRect.right - pData->contentRect.left; |
break; |
case kControlPageDownPart: |
amount = pData->contentRect.left - pData->contentRect.right; |
break; |
} |
SetControlAndClipAmount(control, &amount); |
if (amount != 0) |
DoScrollContent(pWindow, pData, amount, 0); |
} |
} // HActionProc |
#if GENERATINGCFM |
static RoutineDescriptor gHActionProcRD = BUILD_ROUTINE_DESCRIPTOR(uppControlActionProcInfo, HActionProc); |
static ControlActionUPP gHActionProc = &gHActionProcRD; |
#else |
static ControlActionUPP gHActionProc = HActionProc; |
#endif |
// -------------------------------------------------------------------------------------------------------------- |
// END SCROLL ACTION PROCS |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr DoContentClick(WindowRef pWindow) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
if ( pData ) |
{ |
SetPort((GrafPtr) GetWindowPort(pWindow)); |
if (pData->pContentClick) |
{ |
// let the object handle the click if it wishes to |
anErr = (*(pData->pContentClick)) (pWindow, pData, &gEvent); |
} |
if (anErr == noErr) |
{ |
ControlRef theControl; |
short part; |
GlobalToLocal(&gEvent.where); |
part = FindControl(gEvent.where, pWindow, &theControl); |
switch (part) |
{ |
// do nothing for viewRect case |
case 0: |
break; |
// track the thumb, and then update all at once |
case kControlIndicatorPart: |
{ |
short value = GetControlValue(theControl); |
part = TrackControl(theControl, gEvent.where, nil); |
if (part != 0) |
{ |
// turn the value into a delta |
value -= GetControlValue(theControl); |
// if we actually moved |
if (value != 0) |
{ |
if (theControl == pData->hScroll) |
DoScrollContent(pWindow, pData, value, 0); |
if (theControl == pData->vScroll) |
DoScrollContent(pWindow, pData, 0, value); |
} |
} |
} |
break; |
// track the control, and scroll as we go |
default: |
if (theControl) |
{ |
if (theControl == pData->hScroll) |
part = TrackControl(theControl, gEvent.where, gHActionProc); |
if (theControl == pData->vScroll) |
part = TrackControl(theControl, gEvent.where, gVActionProc); |
} |
break; |
} |
} |
} |
return anErr; |
} // DoContentClick |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr DoGrowWindow(WindowRef pWindow, EventRecord *pEvent) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
Rect tempRect; |
LongRect docRect; |
long growResult; |
if (pData) |
{ |
GrafPtr pPort = (GrafPtr)GetWindowPort(pWindow); |
SetPort(pPort); |
RectToLongRect(&pData->contentRect, &docRect); |
if (pData->pGetDocumentRect) |
(*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, true); |
if (pData->vScroll) |
docRect.right += 16; |
if (pData->hScroll) |
docRect.bottom += 16; |
if ( (pData->hasGrow) && (pData->hScroll == nil) && (pData->vScroll == nil) ) |
{ |
docRect.right += 16; |
docRect.bottom += 16; |
} |
// set up resize constraints |
tempRect.left = pData->minHSize; |
if (tempRect.left == 0) |
tempRect.left = kMinDocSize; |
tempRect.right = docRect.right - docRect.left; |
if (tempRect.right < tempRect.left) |
tempRect.right = tempRect.left; |
tempRect.top = pData->minVSize; |
if (tempRect.top == 0) |
tempRect.top = kMinDocSize; |
tempRect.bottom = docRect.bottom - docRect.top; |
if (tempRect.bottom < tempRect.top) |
tempRect.bottom = tempRect.top; |
growResult = GrowWindow(pWindow, pEvent->where, &tempRect); |
if ( growResult != 0 ) |
{ |
Rect oldRect; |
RgnHandle currentInval = NewRgn(); |
Boolean needInvalidate; |
// save old content area |
oldRect = pData->contentRect; |
// save old pending update |
GetWindowUpdateRgn(pWindow, currentInval); |
OffsetRgn(currentInval, pPort->portBits.bounds.left, pPort->portBits.bounds.top); |
// grow window and recalc what is needed |
SizeWindow(pWindow, growResult & 0xFFFF, growResult >> 16, true); |
AdjustScrollBars(pWindow, true, true, &needInvalidate); |
if (needInvalidate) |
{ |
InvalRect(&pData->contentRect); |
} |
else |
{ |
// don't bother to redraw things that haven't changed |
SectRect(&oldRect, &pData->contentRect, &oldRect); |
ValidRect(&oldRect); |
// but, if a pending update was there, be sure to deal with that! |
InvalRgn(currentInval); |
} |
// if we have offset scrollbars, then force a redraw of them |
if (pData->hScrollOffset) |
{ |
oldRect = GetWindowPort(pWindow)->portRect; |
oldRect.right = oldRect.left + pData->hScrollOffset; |
oldRect.top = oldRect.bottom - kScrollBarSize; |
InvalRect(&oldRect); |
} |
if (pData->vScrollOffset) |
{ |
oldRect = GetWindowPort(pWindow)->portRect; |
oldRect.bottom = oldRect.top + pData->vScrollOffset; |
oldRect.left = oldRect.right - kScrollBarSize; |
InvalRect(&oldRect); |
} |
DisposeRgn(currentInval); |
} |
} |
return anErr; |
} // DoGrowWindow |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr DoZoomWindow(WindowRef pWindow, short zoomDir) |
{ |
Rect *windRect, *zoomRect; |
Rect globalPortRect, theSect, dGDRect; |
GDHandle nthDevice, dominantGDevice; |
long sectArea, greatestArea; |
short hMax, vMax; |
// determine the max size of the window |
{ |
WindowDataPtr pData = GetWindowInfo(pWindow); |
LongRect docRect; |
RectToLongRect(&pData->contentRect, &docRect); |
if (pData->pGetDocumentRect) |
(*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, true); |
if (pData->vScroll) |
docRect.right += kScrollBarSize; |
if (pData->hScroll) |
docRect.bottom += kScrollBarSize; |
if ( (pData->hasGrow) && (pData->hScroll == nil) && (pData->vScroll == nil) ) |
{ |
docRect.right += kScrollBarSize; |
docRect.bottom += kScrollBarSize; |
} |
hMax = docRect.right - docRect.left; |
vMax = docRect.bottom - docRect.top; |
} |
SetPort((GrafPtr) GetWindowPort(pWindow)); |
EraseRect(&GetWindowPort(pWindow)->portRect); // recommended for cosmetic reasons |
if (zoomDir == inZoomOut) |
{ |
/* |
* ZoomWindow() is a good basic tool, but it doesn't do everything necessary to |
* implement a good human interface when zooming. In fact it's not even close for |
* more high-end hardware configurations. We must help it along by calculating an |
* appropriate window size and location any time a window zooms out. |
*/ |
{ |
RgnHandle structRgn = NewRgn(); |
GetWindowStructureRgn(pWindow, structRgn); |
windRect = &(**structRgn).rgnBBox; |
DisposeRgn(structRgn); |
} |
dominantGDevice = nil; |
if (gMachineInfo.theEnvirons.hasColorQD) |
{ |
/* |
* Color QuickDraw implies the possibility of multiple monitors. This is where |
* zooming becomes more interesting. One should zoom onto the monitor containing |
* the greatest portion of the window. This requires walking the gDevice list. |
*/ |
nthDevice = GetDeviceList(); |
greatestArea = 0; |
while (nthDevice != nil) |
{ |
if (TestDeviceAttribute(nthDevice, screenDevice)) |
{ |
if (TestDeviceAttribute(nthDevice, screenActive)) |
{ |
SectRect(windRect, &(**nthDevice).gdRect, &theSect); |
sectArea = (long) RectWidth(theSect) * (long) RectHeight(theSect); |
if (sectArea > greatestArea) |
{ |
greatestArea = sectArea; // save the greatest intersection |
dominantGDevice = nthDevice; // and which device it belongs to |
} |
} |
} |
nthDevice = GetNextDevice(nthDevice); |
} |
} |
/* |
* At this point, we know the dimensions of the window we're zooming, and we know |
* what screen we're going to put it on. To be more specific, however, we need a |
* rectangle which defines the maximum dimensions of the resized window's contents. |
* This rectangle accounts for the thickness of the window frame, the menu bar, and |
* one or two pixels around the edges for cosmetic compatibility with ZoomWindow(). |
*/ |
if (dominantGDevice != nil) |
{ |
dGDRect = (**dominantGDevice).gdRect; |
if (dominantGDevice == GetMainDevice()) // account for menu bar on main device |
dGDRect.top += GetMBarHeight(); |
} |
else |
{ |
dGDRect = qd.screenBits.bounds; // if no gDevice, use default monitor |
dGDRect.top += GetMBarHeight(); |
} |
globalPortRect = GetWindowPort(pWindow)->portRect; |
LocalToGlobal(&TopLeft(globalPortRect)); // calculate the window's portRect |
LocalToGlobal(&BotRight(globalPortRect)); // in global coordinates |
// account for the window frame and inset it a few pixels |
dGDRect.left += 2 + globalPortRect.left - windRect->left; |
dGDRect.top += 2 + globalPortRect.top - windRect->top; |
dGDRect.right -= 1 + windRect->right - globalPortRect.right; |
dGDRect.bottom -= 1 + windRect->bottom - globalPortRect.bottom; |
/* |
* Now we know exactly what our limits are, and since there are input parameters |
* specifying the dimensions we'd like to see, we can move and resize the zoom |
* state rectangle for the best possible results. We have three goals in this: |
* 1. Display the window entirely visible on a single device. |
* 2. Resize the window to best represent the dimensions of the document itself. |
* 3. Move the window as short a distance as possible to achieve #1 and #2. |
*/ |
zoomRect = &(**(WStateDataHandle) ((WindowPeek) pWindow)->dataHandle).stdState; |
/* |
* Initially set the zoom rectangle to the size requested by the input parameters, |
* although not smaller than a minimum size. We do this without moving the origin. |
*/ |
zoomRect->right = (zoomRect->left = globalPortRect.left) + |
Max(hMax, kMinDocSize); |
zoomRect->bottom = (zoomRect->top = globalPortRect.top) + |
Max(vMax, kMinDocSize); |
// Shift the entire rectangle if necessary to bring its origin inside dGDRect. |
OffsetRect(zoomRect, |
Max(dGDRect.left - zoomRect->left, 0), |
Max(dGDRect.top - zoomRect->top, 0)); |
/* |
* Shift the rectangle up and/or to the left if necessary to accomodate the view, |
* and if it is possible to do so. The rectangle may not be moved such that its |
* origin would fall outside of dGDRect. |
*/ |
OffsetRect(zoomRect, |
-Pin(zoomRect->right - dGDRect.right, 0, zoomRect->left - dGDRect.left), |
-Pin(zoomRect->bottom - dGDRect.bottom, 0, zoomRect->top - dGDRect.top)); |
// Clip expansion to dGDRect, in case view is larger than dGDRect. |
zoomRect->right = Min(zoomRect->right, dGDRect.right); |
zoomRect->bottom = Min(zoomRect->bottom, dGDRect.bottom); |
} |
ZoomWindow(pWindow, zoomDir, pWindow == FrontWindow()); |
AdjustScrollBars(pWindow, true, true, nil); |
InvalRect(&GetWindowPort(pWindow)->portRect); |
return noErr; |
} // DoZoomWindow |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
OSErr DoActivate(WindowRef pWindow, Boolean activating) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
SetPort((GrafPtr) GetWindowPort(pWindow)); |
if ( pData ) |
{ |
if (pData->pActivateEvent) |
anErr = (*(pData->pActivateEvent)) (pWindow, pData, activating); |
if (anErr == noErr) |
{ |
if (activating) |
{ |
// Reshow all controls on activation |
if (pData->hScroll) |
ShowControl(pData->hScroll); |
if (pData->vScroll) |
ShowControl(pData->vScroll); |
} |
else |
{ |
// Hide all controls on deactivation |
if (pData->hScroll) |
HideControl(pData->hScroll); |
if (pData->vScroll) |
HideControl(pData->vScroll); |
} |
if (pData->hasGrow) |
{ |
Rect growIconRect; |
CalculateGrowIcon(pData, &growIconRect); |
InvalRect(&growIconRect); |
} |
} |
} |
AdjustMenus(pWindow, true, false); |
return anErr; |
} // DoActivate |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
OSErr DoDefault(WindowDataPtr pData) |
{ |
OSErr anErr = noErr; |
PrOpen(); |
anErr = PrError(); |
if (anErr == noErr) |
{ |
if (pData->hPrint == nil) |
{ |
pData->hPrint = NewHandleClear(sizeof(TPrint)); |
anErr = MemError(); |
if (anErr == noErr) |
extendPrDefault(pData->hPrint); |
} |
} |
PrClose(); |
return anErr; |
} // DoDefault |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
OSErr DoPageSetup(WindowRef pWindow) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
anErr = DoDefault(pData); |
nrequire(anErr, DoDefault); |
PrOpen(); |
anErr = PrError(); |
if (anErr == noErr) |
{ |
SetCursor(&qd.arrow); |
PrStlDialog(pData->hPrint); |
} |
PrClose(); |
// FALL THROUGH EXCEPTION HANDLING |
DoDefault: |
return anErr; |
} // DoPageSetup |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr DoPrintSetup(WindowRef pWindow, StringPtr pPrinterName) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
anErr = DoDefault(pData); |
nrequire(anErr, DoDefault); |
PrOpen(); |
anErr = PrError(); |
if (anErr == noErr) |
{ |
SetCursor(&qd.arrow); |
if (PrJobDialog(pData->hPrint) == false) |
anErr = eUserCanceled; |
} |
PrClose(); |
// FALL THROUGH EXCEPTION HANDLING |
DoDefault: |
return anErr; |
} // DoPrintSetup |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
// This function is a duplicate of DoPrintSetup, but without the DoDefault call |
// that DoPrintSetup normally does. The reason for this is that with the addition |
// of the scriptable printing, I may be passing a print record into this function |
// which I want to feed into the print dialog. If that's the case, the DoDefault |
// would wipe out that print record, which is not what I would want to do. |
// |
// Also, rather than modifying the DoPrintSetup function, I duplicate the function |
// here to illustrate the change more clearly. This probably isn't how you would |
// handle this sort of conflict (a function needing to change) in the real world, |
// but I think this better shows what you need to change. |
static OSErr DoPrintSetupNoDefault(WindowRef pWindow, StringPtr pPrinterName) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
PrOpen(); |
anErr = PrError(); |
if (anErr == noErr) |
{ |
SetCursor(&qd.arrow); |
if (PrJobDialog(pData->hPrint) == false) |
anErr = eUserCanceled; |
} |
PrClose(); |
return anErr; |
} // DoPrintSetupNoDefault |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr DoPrint(WindowRef pWindow, void * hPrint, Boolean oneCopy) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
Boolean didAllocate = false; |
TPPrPort printingPort; |
// use a watch cursor while printing |
SetWatchCursor(); |
PrOpen(); |
anErr = PrError(); |
if (anErr == noErr) |
{ |
if (hPrint == nil) |
{ |
hPrint = NewHandleClear(sizeof(TPrint)); |
anErr = MemError(); |
if (anErr == noErr) |
{ |
extendPrDefault(hPrint); |
didAllocate = true; |
} |
} |
if (anErr == noErr) |
{ |
short firstPage, lastPage; |
// be sure to get the page range BEFORE calling PrValidate(), |
// which blows it away for many drivers. |
firstPage = (**(THPrint)hPrint).prJob.iFstPage; |
lastPage = (**(THPrint)hPrint).prJob.iLstPage; |
// make sure the print record is cool to use |
extendPrValidate(hPrint); |
// then clear out the job itself -- some drivers don't |
// do this from within PrValidate(). We want the job |
// clear in case the driver bases background behavior |
// from this range (and many do). |
(**(THPrint)hPrint).prJob.iFstPage = 1; |
(**(THPrint)hPrint).prJob.iLstPage = 9999; |
if (oneCopy) |
(** ((THPrint)hPrint)).prJob.iCopies = 1; |
// start printing, and then loop over the pages |
printingPort = PrOpenDoc(hPrint, nil, nil); |
anErr = PrError(); |
if (anErr == noErr) |
{ |
long pageIndex; |
Rect pageRect; |
SetPort((GrafPtr) printingPort); |
pageRect = (**(THPrint)hPrint).prInfo.rPage; |
if (firstPage < 1) |
firstPage = 1; |
if (lastPage < firstPage) |
lastPage = firstPage; |
for (pageIndex = firstPage; pageIndex <= lastPage; ++pageIndex) |
{ |
PrOpenPage(printingPort, nil); |
anErr = PrError(); |
if (anErr == noErr) |
anErr = (*(pData->pPrintPage)) (pWindow, pData, &pageRect, &pageIndex); |
PrClosePage(printingPort); |
if (anErr == noErr) |
anErr = PrError(); |
if ( (anErr != noErr) || (pageIndex == -1) ) |
break; |
} |
} |
// Finish up printing of the document |
PrCloseDoc(printingPort); |
if (anErr == noErr) |
anErr = PrError(); |
if ( (anErr == noErr) && ((**(THPrint)hPrint).prJob.bJDocLoop == bSpoolLoop) ) |
{ |
TPrStatus theStatus; |
PrPicFile(hPrint, nil, nil, nil, &theStatus); |
anErr = PrError(); |
} |
} |
if (didAllocate) |
DisposeHandle((Handle) hPrint); |
} |
PrClose(); |
// restore cursor |
SetCursor(&qd.arrow); |
return anErr; |
} // DoPrint |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
OSErr DoCommand(WindowRef pWindow, short commandID, long menuResult) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = nil; |
if (pWindow) |
{ |
pData = (WindowDataPtr) GetWindowInfo(pWindow); |
if ( (pData) && (pData->pCommand) ) |
anErr = (*(pData->pCommand)) (pWindow, pData, commandID, menuResult); |
} |
if (anErr == noErr) |
{ |
// default command handling |
switch (commandID) |
{ |
// About box command |
case cAbout: |
if (!BringToFrontIfExists(kAboutWindow)) |
anErr = MakeNewWindow(kAboutWindow, nil, '????', nil); |
break; |
case cDeskAccessory: |
{ |
Str255 tempString; |
GetMenuItemText(GetMenuHandle(menuResult>>16), menuResult & 0xFFFF, tempString); |
OpenDeskAcc(tempString); |
} |
break; |
// New window command |
case cNew: |
anErr = MakeNewWindow(kTextWindow, nil, 'TEXT', nil); |
break; |
// Open window command |
case cOpen: |
anErr = DoOpenWindow(); |
break; |
// Close window command |
case cClose: |
anErr = DoCloseWindow(pWindow); |
break; |
case cPageSetup: |
anErr = DoPageSetup(pWindow); |
break; |
case cPrint: |
anErr = DoPrintSetup(pWindow, nil); |
if (anErr == noErr) { |
anErr = DoPrint(pWindow, pData->hPrint, false); |
} |
break; |
case cPrintOneCopy: |
anErr = DoPrint(pWindow, pData->hPrint, true); |
break; |
// get out of here command! |
case cQuit: |
gAllDone = true; |
break; |
// show/hide clipboard |
case cShowClipboard: |
if (!BringToFrontIfExists(kClipboardWindow)) |
{ |
anErr = MakeNewWindow(kClipboardWindow, nil, '????', nil); |
} |
else |
{ |
pWindow = FrontWindow(); |
anErr = DoCloseWindow(pWindow); |
} |
break; |
case cNextPage: |
gEvent.what = keyDown; |
gEvent.message = kPageDown << 8; |
gEvent.modifiers = 0; |
DoKeyEvent(pWindow, &gEvent, false); |
break; |
case cPreviousPage: |
gEvent.what = keyDown; |
gEvent.message = kPageUp << 8; |
gEvent.modifiers = 0; |
DoKeyEvent(pWindow, &gEvent, false); |
break; |
// Do nothing command |
case cNull: |
break; |
default: |
break; |
} |
} |
// don't report cancels |
if (anErr == iPrAbort) |
anErr = noErr; |
if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) && (anErr != eUserCanceled) ) |
{ |
// some commands are so similar to other commands that we map their IDs |
// for the purposes of the error strings |
if (commandID == cSaveAs) |
commandID = cSave; |
if (commandID == cPrintOneCopy) |
commandID = cPrint; |
ConductErrorDialog(anErr, commandID, cancel); |
} |
// in any case, unhilite the menu selected after command processing is done |
HiliteMenu(0); |
return anErr; |
} // DoCommand |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr DoMenuCommand(WindowRef pWindow, long menuResult) |
{ |
OSErr anErr = noErr; |
short commandID = cNull; |
short ** commandHandle; |
short menuID = menuResult >> 16; |
if (menuID >= mFontSubMenusStart) |
{ |
commandID = cSelectFontStyle; |
} |
else |
{ |
// read in the resource that controls this menu |
{ |
short oldResFile = CurResFile(); |
UseResFile(gApplicationResFile); |
commandHandle = (short**) Get1Resource('MCMD', menuID); |
UseResFile(oldResFile); |
anErr = ResError(); |
nrequire(anErr, FailedToLoadCommandTable); |
} |
if (commandHandle) |
{ |
short item = menuResult & 0xFFFF; |
short * pCommands = *commandHandle; |
if (item <= pCommands[0]) |
commandID = pCommands[item]; |
else |
commandID = pCommands[pCommands[0]]; |
} |
} |
anErr = DoCommand(pWindow, commandID, menuResult); |
// FALL THROUGH EXCEPTION HANDLING |
FailedToLoadCommandTable: |
return anErr; |
} // DoMenuCommand |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static void DoKeyPageDown(WindowRef pWindow, WindowDataPtr pData, Boolean processPageControls) |
{ |
if (GetControlValue(pData->vScroll) < GetControlMaximum(pData->vScroll)) |
VActionProc(pData->vScroll, kControlPageDownPart); |
else |
{ |
if ( (processPageControls) && (IsCommandEnabled(cNextPage)) ) |
{ |
short amount; |
if (DoCommand(pWindow, cNextPage, 0) == eActionAlreadyHandled) |
{ |
amount = GetControlValue(pData->vScroll); |
SetControlAndClipAmount(pData->vScroll, &amount); |
if (amount != 0) |
DoScrollContent(pWindow, pData, 0, amount); |
} |
AdjustMenus(pWindow, true, false); |
} |
} |
} // DoKeyPageDown |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static void DoKeyPageUp(WindowRef pWindow, WindowDataPtr pData, Boolean processPageControls) |
{ |
if (GetControlValue(pData->vScroll) > GetControlMinimum(pData->vScroll)) |
VActionProc(pData->vScroll, kControlPageUpPart); |
else |
{ |
if ( (processPageControls) && (IsCommandEnabled(cPreviousPage)) ) |
{ |
short amount; |
if (DoCommand(pWindow, cPreviousPage, 0) == eActionAlreadyHandled) |
{ |
amount = -(GetControlMaximum(pData->vScroll)-GetControlValue(pData->vScroll)); |
SetControlAndClipAmount(pData->vScroll, &amount); |
if (amount != 0) |
DoScrollContent(pWindow, pData, 0, amount); |
} |
AdjustMenus(pWindow, true, false); |
} |
} |
} // DoKeyPageUp |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
OSErr DoKeyEvent(WindowRef pWindow, EventRecord * pEvent, Boolean processPageControls) |
{ |
OSErr anErr = noErr; |
WindowDataPtr pData = nil; |
Boolean passToObject = false; |
Boolean isMotionKey = false; |
long menuResult = 0; |
char keyCode = (pEvent->message >> 8) & charCodeMask; |
if ( pEvent->modifiers & cmdKey ) /* Command key down */ |
{ |
AdjustMenus(pWindow, true, false); |
menuResult = MenuKey(pEvent->message & charCodeMask); |
DoMenuCommand(pWindow, menuResult); |
pWindow = FrontWindow(); |
} |
if (menuResult == 0) |
{ |
if (pWindow) |
{ |
pData = (WindowDataPtr)GetWindowInfo(pWindow); |
if ( (pData) && (pData->pKeyEvent) ) |
passToObject = true; |
SetPort((GrafPtr) GetWindowPort(pWindow)); |
} |
if (pData) |
{ |
switch (keyCode) |
{ |
case kHome: // top of file |
isMotionKey = true; |
if (pData->vScroll) |
{ |
short amount; |
if ( (processPageControls) && (IsCommandEnabled(cGotoPage)) ) |
DoCommand(pWindow, cGotoPage, cGotoFirst); |
amount = GetControlValue(pData->vScroll); |
SetControlAndClipAmount(pData->vScroll, &amount); |
if (amount != 0) |
DoScrollContent(pWindow, pData, 0, amount); |
passToObject = false; |
} |
break; |
case kEnd: // end of file |
isMotionKey = true; |
if (pData->vScroll) |
{ |
short amount; |
if ( (processPageControls) && (IsCommandEnabled(cGotoPage)) ) |
DoCommand(pWindow, cGotoPage, cGotoLast); |
amount = -(GetControlMaximum(pData->vScroll)-GetControlValue(pData->vScroll)); |
SetControlAndClipAmount(pData->vScroll, &amount); |
if (amount != 0) |
DoScrollContent(pWindow, pData, 0, amount); |
passToObject = false; |
} |
break; |
case kPageUp: // scroll bar page up |
isMotionKey = true; |
if (pData->vScroll) |
{ |
DoKeyPageUp(pWindow, pData, processPageControls); |
passToObject = false; |
} |
break; |
case kPageDown: // scroll bar page down |
isMotionKey = true; |
if (pData->vScroll) |
{ |
DoKeyPageDown(pWindow, pData, processPageControls); |
passToObject = false; |
} |
break; |
case kUpArrow: // scroll bar up arrow |
isMotionKey = true; |
if ( (pData->vScroll) && (!pData->pKeyEvent) ) |
{ |
if ( pEvent->modifiers & cmdKey ) /* Command key down */ |
DoKeyPageUp(pWindow, pData, processPageControls); |
else |
VActionProc(pData->vScroll, kControlUpButtonPart); |
passToObject = false; |
} |
break; |
case kDownArrow: // scroll bar down arrow |
isMotionKey = true; |
if ( (pData->vScroll) && (!pData->pKeyEvent) ) |
{ |
if ( pEvent->modifiers & cmdKey ) /* Command key down */ |
DoKeyPageDown(pWindow, pData, processPageControls); |
else |
VActionProc(pData->vScroll, kControlDownButtonPart); |
passToObject = false; |
} |
break; |
case kLeftArrow: // scroll bar left arrow |
isMotionKey = true; |
if ( (pData->hScroll) && (!pData->pKeyEvent) ) |
{ |
if ( pEvent->modifiers & cmdKey ) /* Command key down */ |
HActionProc(pData->hScroll, kControlPageUpPart); |
else |
HActionProc(pData->hScroll, kControlUpButtonPart); |
passToObject = false; |
} |
break; |
case kRightArrow: // scroll bar right arrow |
isMotionKey = true; |
if ( (pData->hScroll) && (!pData->pKeyEvent) ) |
{ |
if ( pEvent->modifiers & cmdKey ) /* Command key down */ |
HActionProc(pData->hScroll, kControlPageDownPart); |
else |
HActionProc(pData->hScroll, kControlDownButtonPart); |
passToObject = false; |
} |
break; |
} |
if (passToObject) |
anErr = (*(pData->pKeyEvent)) (pWindow, pData, pEvent, isMotionKey); |
else |
{ |
if ( (pData->documentAcceptsText == false) && !( pEvent->modifiers & cmdKey ) && !(isMotionKey) ) |
anErr = eDocumentNotModifiable; |
} |
} |
if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) ) |
ConductErrorDialog(anErr, cTypingCommand, ok); |
} // (menuResult == 0) |
return anErr; |
} // DoKeyEvent |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr DoAdjustCursor(WindowRef pWindow) |
{ |
OSErr anErr = noErr; |
Point mouse; |
Boolean didAdjust = false; |
if (pWindow) |
{ |
// not one of our windows? don't do anything |
if (GetWindowKind(pWindow) != userKind) |
didAdjust = true; |
SetPort((GrafPtr) GetWindowPort(pWindow)); |
if ( (!didAdjust) && (gMachineInfo.haveTSM) ) |
{ |
GetMouse(&mouse); |
LocalToGlobal(&mouse); |
if (SetTSMCursor(mouse)) |
didAdjust = true; |
} |
if (!didAdjust) |
{ |
WindowDataPtr pData = GetWindowInfo(pWindow); |
RgnHandle content = NewRgn(); |
Point globalMouse; |
GetMouse(&mouse); |
globalMouse = mouse; |
LocalToGlobal(&globalMouse); |
GetWindowContentRgn(pWindow, content); |
if ((pData) && (PtInRgn(globalMouse, content)) && (PtInRect(mouse, &pData->contentRect))) |
{ |
Rect tempRect; |
tempRect = pData->contentRect; |
LocalToGlobal(&TopLeft(tempRect)); |
LocalToGlobal(&BotRight(tempRect)); |
if (pData->pAdjustCursor) |
anErr = (*(pData->pAdjustCursor)) (pWindow, pData, &mouse, &tempRect); |
RectRgn(gCursorRgn, &tempRect); |
} |
DisposeRgn(content); |
} |
else |
anErr = eActionAlreadyHandled; |
} |
// nobody set the cursor, we do it ourselves |
if (anErr != eActionAlreadyHandled) |
SetCursor(&qd.arrow); |
return anErr; |
} // DoAdjustCursor |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static long DetermineWaitTime(WindowRef pWindow) |
{ |
long waitTime = kMaxWaitTime; |
while (pWindow) |
{ |
long newWaitTime; |
WindowDataPtr pData = GetWindowInfo(pWindow); |
if ((pData) && (pData->pCalculateIdleTime)) |
newWaitTime = (*(pData->pCalculateIdleTime)) (pWindow, pData); |
else |
newWaitTime = kMaxWaitTime; |
if (newWaitTime < waitTime) |
waitTime = newWaitTime; |
pWindow = GetNextWindow(pWindow); |
} |
return(waitTime); |
} // DetermineWaitTime |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
void HandleEvent(EventRecord * pEvent) |
{ |
WindowRef pWindow = FrontWindow(); |
switch (pEvent->what) |
{ |
case kHighLevelEvent: |
AEProcessAppleEvent(pEvent); |
break; |
case osEvt: |
switch ((pEvent->message >> 24) & 0xFF) /* high byte of message */ |
{ |
case mouseMovedMessage: |
DoAdjustCursor(pWindow); |
break; |
case suspendResumeMessage: /* suspend/resume is also an activate/deactivate */ |
gMachineInfo.amInBackground = (pEvent->message & 1) == 0; |
if (pWindow) |
DoActivate(pWindow, !gMachineInfo.amInBackground); |
break; |
} |
break; |
case activateEvt: |
pWindow = (WindowRef) pEvent->message; |
DoActivate(pWindow, (pEvent->modifiers & activeFlag) != 0); |
break; |
// disk inserted events must be handled, or uninitialized floppies |
// won't be recognized. |
case diskEvt: |
if ( HiWord(pEvent->message) != noErr ) |
{ |
Point where; |
SetPt(&where, 70, 50); |
ShowCursor(); |
(void) DIBadMount(where, pEvent->message); |
} |
break; |
case mouseUp: |
break; |
case mouseDown: |
{ |
short part = FindWindow(pEvent->where, &pWindow); |
switch ( part ) |
{ |
case inContent: |
if (pWindow != FrontWindow()) |
SelectWindow(pWindow); |
else |
DoContentClick(pWindow); |
break; |
case inGoAway: |
if (TrackGoAway(pWindow, pEvent->where) ) |
DoCommand(pWindow, cClose, 0); |
break; |
case inGrow: |
DoGrowWindow(pWindow, pEvent); |
break; |
case inZoomIn: |
case inZoomOut: |
if ( TrackBox(pWindow, pEvent->where, part) ) |
DoZoomWindow(pWindow, part); |
break; |
case inDrag: |
{ |
WindowDataPtr pData = GetWindowInfo(pWindow); |
if ( (pData) && (pData->dragWindowAligned) ) |
DragAlignedWindow((WindowPtr) pWindow, pEvent->where, &qd.screenBits.bounds, nil, nil); |
else |
DragWindow(pWindow, pEvent->where, &qd.screenBits.bounds); |
} |
break; |
case inMenuBar: /* process a mouse menu command (if any) */ |
{ |
long menuResult; |
// force these threads to run to completion so the |
// contents of the menus are fully initialized |
if (gFontThread != kNoThreadID) |
{ |
gDontYield = true; |
SetThreadState(gFontThread, kReadyThreadState, gFontThread); |
YieldToThread(gFontThread); |
gDontYield = false; |
} |
if (gAGThread != kNoThreadID) |
{ |
gDontYield = true; |
SetThreadState(gAGThread, kReadyThreadState, gAGThread); |
YieldToThread(gAGThread); |
gDontYield = false; |
} |
pWindow = FrontWindow(); |
AdjustMenus(pWindow, true, false); |
menuResult = MenuSelect(pEvent->where); |
if ( (gMachineInfo.haveTSM) && (TSMMenuSelect(menuResult)) ) |
HiliteMenu(0); |
else |
DoMenuCommand(pWindow, menuResult); |
} |
break; |
case inSysWindow: /* let the system handle the mouseDown */ |
SystemClick(pEvent, pWindow); |
break; |
} // switch(part) |
} |
break; |
case keyDown: |
case autoKey: /* check for menukey equivalents */ |
DoKeyEvent(pWindow, pEvent, true); |
break; |
case updateEvt: |
pWindow = (WindowRef) pEvent->message; |
DoUpdateWindow(pWindow); |
break; |
} // switch (pEvent->what) |
} // HandleEvent |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr DoEventLoop(void) |
{ |
OSErr anErr = noErr; |
Boolean gotEvent; |
Boolean trueGotEvent; |
WindowRef pWindow; |
do { |
pWindow = LMGetFirstWindow(); // walk all of our windows, even invisible ones |
DoAdjustCursor(pWindow); |
gotEvent = WaitNextEvent(everyEvent, &gEvent, DetermineWaitTime(pWindow), gCursorRgn); |
trueGotEvent = gotEvent; |
// WNE may close the window if it's owned by some silly extension. |
pWindow = LMGetFirstWindow(); |
// let text services handle the event first if it wishes to do so |
if ( gMachineInfo.haveTSM ) |
{ |
ScriptCode keyboardScript; |
WindowRef theFront = FrontWindow(); |
if (theFront) |
{ |
SetPort((GrafPtr) GetWindowPort(theFront)); |
keyboardScript = GetScriptManagerVariable(smKeyScript); |
if (FontToScript(qd.thePort->txFont) != keyboardScript) |
TextFont(GetScriptVariable(keyboardScript, smScriptAppFond)); |
} |
if (TSMEvent(&gEvent)) |
gotEvent = false; |
} |
// let all windows filter this event, and get time if they wish to |
while (pWindow) |
{ |
WindowDataPtr pData = GetWindowInfo(pWindow); |
Boolean finishedEvent = false; |
// help manager for the front window |
if ( (pWindow == FrontWindow()) && (pData) && (!gMachineInfo.amInBackground) && (HMGetBalloons()) ) |
{ |
Point theMouse, tipLocation; |
short newBalloon = iNoBalloon; |
Rect tempRect; |
// find out where the mouse is |
SetPort((GrafPtr) GetWindowPort(pWindow)); |
GetMouse(&theMouse); |
// and only do something if we are within the window itself |
if (PtInRect(theMouse, &GetWindowPort(pWindow)->portRect)) |
{ |
// is it in the vertical scroll bar? |
if (pData->vScroll) |
{ |
tempRect = (**(pData->vScroll)).contrlRect; |
if (PtInRect(theMouse, &tempRect)) |
{ |
newBalloon = iHelpActiveScroll; |
if (GetControlMinimum(pData->vScroll) == GetControlMaximum(pData->vScroll)) |
newBalloon = iHelpDimVertScroll; |
tipLocation.h = tempRect.right - kFromBottomTipOffset; |
tipLocation.v = tempRect.bottom - kFromBottomTipOffset; |
} |
} |
// is it in the horizontal scroll bar? |
if (pData->hScroll) |
{ |
tempRect = (**(pData->hScroll)).contrlRect; |
if (PtInRect(theMouse, &tempRect)) |
{ |
newBalloon = iHelpActiveScroll; |
if (GetControlMinimum(pData->hScroll) == GetControlMaximum(pData->hScroll)) |
newBalloon = iHelpDimHorizScroll; |
tipLocation.h = tempRect.right - kFromBottomTipOffset; |
tipLocation.v = tempRect.bottom - kFromBottomTipOffset; |
} |
} |
// is it in the grow box? |
if (pData->hasGrow) |
{ |
CalculateGrowIcon(pData, &tempRect); |
if (PtInRect(theMouse, &tempRect)) |
{ |
newBalloon = iHelpGrowBox; |
tipLocation.h = tempRect.right - kFromBottomTipOffset; |
tipLocation.v = tempRect.bottom - kFromBottomTipOffset; |
} |
} |
// none of the above, must be the content |
if (newBalloon == iNoBalloon) |
{ |
newBalloon = iHelpGenericContent; |
tempRect = pData->contentRect; |
if (pData->pGetBalloon) |
(*(pData->pGetBalloon)) (pWindow, pData, &theMouse, &newBalloon, &tempRect); |
tipLocation.h = tempRect.left + kFromTopTipOffset; |
tipLocation.v = tempRect.top + kFromTopTipOffset; |
} |
// show our new balloon, or remove the old one |
if (newBalloon != iNoBalloon) |
{ |
if ( (gMachineInfo.lastBalloonIndex != newBalloon) || (!HMIsBalloon()) ) |
{ |
HMMessageRecord message; |
if (newBalloon != iDidTheBalloon) |
{ |
message.hmmHelpType = khmmString; |
GetIndString(message.u.hmmString, kWindowHelpID, newBalloon); |
LocalToGlobal(&tipLocation); |
(void) HMShowBalloon(&message, tipLocation, nil, nil, 0, kDefaultBalloonVariant, 0); |
} |
gMachineInfo.lastBalloonIndex = newBalloon; |
} |
} |
else |
HMRemoveBalloon(); |
} |
} |
// if we hit a window we know about, then do filtering |
if (pData) |
{ |
if (pData->pFilterEvent) |
finishedEvent = (*(pData->pFilterEvent)) (pWindow, pData, &gEvent); |
} |
// if filtering indicates complete handling of event, then stop, and |
// do no regular processing. |
if (finishedEvent) |
{ |
gotEvent = false; |
pWindow = nil; |
} |
else |
pWindow = GetNextWindow(pWindow); |
} |
if (gotEvent) |
HandleEvent(&gEvent); |
// close request? |
if (gAllDone) |
{ |
pWindow = FrontWindow(); |
while ((gAllDone) && (pWindow) ) |
{ |
WindowRef nextWindow = GetNextWindow(pWindow); |
OSErr closeError = DoCloseWindow(pWindow); |
// window didn't close? then don't quit |
if (pWindow == FrontWindow()) |
gAllDone = false; |
// something bad happened, then don't quit |
if ( (closeError != noErr) /* && (closeError != eUserCanceled) */ ) |
gAllDone = false; |
pWindow = nextWindow; |
} |
} |
// our threads are low-priority, so we only give time to them on idle |
if (gMachineInfo.haveThreads && !trueGotEvent && !gAllDone) |
YieldToAnyThread(); |
} while (!gAllDone); |
return anErr; |
} // DoEventLoop |
// -------------------------------------------------------------------------------------------------------------- |
// DRAG MANAGEMENT GLOBAL SUPPORT ROUTINES |
// -------------------------------------------------------------------------------------------------------------- |
// Globals for our drag handlers |
Boolean gCanAccept; // if we can receive the item(s) being dragged |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Drag |
static pascal OSErr GlobalTrackingHandler(short message, WindowRef pWindow, void *handlerRefCon, DragReference theDragRef) |
{ |
#pragma unused(handlerRefCon) |
WindowDataPtr pData = GetWindowInfo(pWindow); |
// Call the tracking handler associated with this type of window. Only allow messages referencing |
// a specific window to be passed to the handler. |
if (pData) |
{ |
if (pData->pDragTracking) |
return ((*(pData->pDragTracking)) (pWindow, pData, theDragRef, message)); |
} |
return noErr; |
} // GlobalTrackingHandler |
DragTrackingHandlerUPP gGlobalTrackingHandler; |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Drag |
static pascal OSErr GlobalReceiveHandler(WindowRef pWindow, void *handlerRefCon, DragReference theDragRef) |
{ |
#pragma unused(handlerRefCon) |
WindowDataPtr pData = GetWindowInfo(pWindow); |
if (pData) |
{ |
if (pData->pDragTracking) |
return ((*(pData->pDragReceive)) (pWindow, pData, theDragRef)); |
} |
return noErr; |
} // GlobalReceiveHandler |
DragReceiveHandlerUPP gGlobalReceiveHandler; |
// -------------------------------------------------------------------------------------------------------------- |
// |
// IsOnlyThisFlavor - Given a DragReference and a FlavorType, we iterate through the drag items to determine if |
// all are of flavor theType. If this is so, we return true. If any of the items are not |
// theType, we return false, indicating that we should not accept the drag. |
// |
#pragma segment Drag |
Boolean IsOnlyThisFlavor(DragReference theDragRef, FlavorType theType) |
{ |
unsigned short items, index; |
FlavorFlags theFlags; |
ItemReference itemID; |
OSErr anErr = noErr; |
CountDragItems(theDragRef, &items); |
for(index = 1; index <= items; index++) |
{ |
GetDragItemReferenceNumber(theDragRef, index, &itemID); |
anErr = GetFlavorFlags(theDragRef, itemID, theType, &theFlags); |
if(anErr == noErr) |
continue; // it's okay, this flavor is cool |
return false; // this item has at least one flavor we don't like |
} |
return true; // all flavors in this item were cool |
} // IsOnlyThisFlavor |
// -------------------------------------------------------------------------------------------------------------- |
// |
// IsDropInFinderTrash - Returns true if the given dropLocation AEDesc is a descriptor of the Finder's Trash. |
// |
#pragma segment Drag |
Boolean IsDropInFinderTrash(AEDesc *dropLocation) |
{ |
OSErr result; |
AEDesc dropSpec; |
FSSpec *theSpec; |
CInfoPBRec thePB; |
short trashVRefNum; |
long trashDirID; |
// Coerce the dropLocation descriptor into an FSSpec. If there's no dropLocation or |
// it can't be coerced into an FSSpec, then it couldn't have been the Trash. |
if ((dropLocation->descriptorType != typeNull) && |
(AECoerceDesc(dropLocation, typeFSS, &dropSpec) == noErr)) |
{ |
unsigned char flags = HGetState(dropSpec.dataHandle); |
HLock(dropSpec.dataHandle); |
theSpec = (FSSpec *) *dropSpec.dataHandle; |
// Get the directory ID of the given dropLocation object. |
thePB.dirInfo.ioCompletion = 0L; |
thePB.dirInfo.ioNamePtr = (StringPtr) &theSpec->name; |
thePB.dirInfo.ioVRefNum = theSpec->vRefNum; |
thePB.dirInfo.ioFDirIndex = 0; |
thePB.dirInfo.ioDrDirID = theSpec->parID; |
result = PBGetCatInfoSync(&thePB); |
HSetState(dropSpec.dataHandle, flags); |
AEDisposeDesc(&dropSpec); |
if (result != noErr) |
return false; |
// If the result is not a directory, it must not be the Trash. |
if (!(thePB.dirInfo.ioFlAttrib & (1 << 4))) |
return false; |
// Get information about the Trash folder. |
FindFolder(theSpec->vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID); |
// If the directory ID of the dropLocation object is the same as the directory ID |
// returned by FindFolder, then the drop must have occurred into the Trash. |
if (thePB.dirInfo.ioDrDirID == trashDirID) |
return true; |
} |
return false; |
} // IsDropInFinderTrash |
// -------------------------------------------------------------------------------------------------------------- |
// APPLE EVENT SUPPORT ROUTINES |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static OSErr MissingParameterCheck( |
AppleEvent *inputEvent) |
/* |
This routine checks an input AppleEvent for the missing keyword. |
If the missing keyword is found, that means that some required |
parameters were missing (ie, an error). |
However, if the missing keyword isn't found, that means that we aren't missing |
any required parameters (that is to say, all REQUIRED parameters were supplied |
by the person who created the event). |
SOME DAY, THE ABOVE COMMENT WILL MAKE SENSE TO YOU. IT STILL DOESN'T |
TO ME AND I WAS THE ONE WHO WROTE IT. |
*/ |
{ |
OSErr anErr; |
AEKeyword missingKeyword; |
DescType ignoredActualType; |
Size ignoredActualSize; |
anErr = AEGetAttributePtr( |
inputEvent, |
keyMissedKeywordAttr, |
typeWildCard, |
&ignoredActualType, |
(Ptr) &missingKeyword, |
sizeof(AEKeyword), |
&ignoredActualSize); |
if (anErr == noErr) |
anErr = errAEParamMissed; |
else |
if (anErr == errAEDescNotFound) |
anErr = noErr; |
return anErr; |
} // MissingParameterCheck |
// -------------------------------------------------------------------------------------------------------------- |
// Globals for our handlers |
Boolean gQuitAfterPrint = true; |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static pascal OSErr DoOpenApp( |
AppleEvent *inputEvent, |
AppleEvent *outputEvent, |
long handlerRefCon) |
{ |
#pragma unused (outputEvent, handlerRefCon) |
DoCommand(nil, cNew, 0); |
gQuitAfterPrint = false; |
// so that the initial document opens more quickly, we don't start |
// the threads until we get an OpenApp or OpenDocument AppleEvent |
if (gStarterThread != kNoThreadID) |
SetThreadState(gStarterThread, kReadyThreadState, gStarterThread); |
return(MissingParameterCheck(inputEvent)); |
} // DoAppOpen |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static pascal OSErr DoQuitApp( |
AppleEvent *inputEvent, |
AppleEvent *outputEvent, |
long handlerRefCon) |
{ |
#pragma unused (outputEvent, handlerRefCon) |
DoCommand(nil, cQuit, 0); |
return(MissingParameterCheck(inputEvent)); |
} // DoQuitApp |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static pascal OSErr DoOpenOrPrint( |
AppleEvent *inputEvent, |
StringPtr pPrinterName) // nil => do not print, zero length => print to default, other => printer name |
{ |
OSErr anErr, anErr2; |
AEDescList docList; // list of docs passed in |
long index, itemsInList; |
void* hPrint; |
Boolean wasAlreadyOpen; |
anErr = AEGetParamDesc( inputEvent, keyDirectObject, typeAEList, &docList); |
nrequire(anErr, GetFileList); |
anErr = AECountItems( &docList, &itemsInList); // how many files passed in |
nrequire(anErr, CountDocs); |
for (index = 1; index <= itemsInList; index++) // handle each file passed in |
{ |
AEKeyword keywd; |
DescType returnedType; |
Size actualSize; |
FSSpec theFSS; |
anErr = AEGetNthPtr( &docList, index, typeFSS, &keywd, &returnedType, // get file's info |
(Ptr)(&theFSS), sizeof(theFSS), &actualSize); |
nrequire(anErr, AEGetNthPtr); |
{ |
FInfo theFileInfo; |
anErr = FSpGetFInfo(&theFSS, &theFileInfo); |
if (anErr == noErr) |
anErr = DetermineWindowTypeOrOpen(&theFSS, theFileInfo.fdType, nil, nil, &wasAlreadyOpen); |
if (anErr == eDocumentWrongKind) |
{ |
if (pPrinterName) |
ConductErrorDialog(anErr, cPrint, cancel); |
else |
ConductErrorDialog(anErr, cOpen, cancel); |
anErr = noErr; |
break; |
} |
nrequire(anErr, DetermineWindowTypeOrOpen); |
} |
if (pPrinterName) |
{ |
WindowRef pWindow = FrontWindow(); |
WindowDataPtr pData = GetWindowInfo(pWindow); |
if (pData->pPrintPage) |
{ |
if (index == 1) |
{ |
THPrint aePrintRecord = NULL; |
Boolean showDialog = true; // default to true |
// Get the default print record into pData->hPrint |
anErr = DoDefault(pData); |
if (anErr == noErr) { |
// look for the [optional] print settings parameter |
anErr = getPrintRecordFromEvent(inputEvent, &aePrintRecord); |
if ((anErr == noErr) && (aePrintRecord != NULL)) |
{ |
THPrint jobPrintRecord = NULL; |
// There was a print settings param. It's been saved in |
// aePrintRecord. |
// Merge the record we retrieved with a default print record. |
// This is necessary so that some of the hints, specifically |
// first and last page, get merged into the print record. |
// Since SimpleText hasn't opened the driver at this point, |
// PrOpen and PrClose must wrap the call to PrJobMerge(). |
PrOpen(); |
anErr = getPrintJobPrintRec(pData->hPrint, aePrintRecord, &jobPrintRecord); |
if (anErr == noErr) { |
pData->hPrint = jobPrintRecord; |
} |
PrClose(); |
// pData->hPrint now has a valid print record which can either |
// be used directly or can be used to "seed" the print dialog |
} |
if (anErr == noErr) |
{ |
// look for the [optional] parameter saying whether we show the print dialog |
anErr = getPrintJobShowDialog(inputEvent, &showDialog); |
if (anErr == noErr) |
{ |
if (!showDialog) |
{ |
// no need to show the print dialog, since we were told not to. |
// We do need to copy the print record from the window into |
// hPrint so it can be passed into doPrint(). |
hPrint = pData->hPrint; |
} |
else |
{ |
// we were told to show the print dialog. pWindow contains |
// (in pData->hPrint) the print record that should set up |
// the dialog. I want to call my new version of DoPrintSetup |
// which does not default the print record that has been |
// passed in. |
// NOTE: First Page and Last Page will not be entered into |
// the dialog correctly and the dialog will show "All Pages". |
// This is a bug in the driver (LaserWriter 8, version 8.7) |
// and will be fixed in a future version of the driver. |
anErr = DoPrintSetupNoDefault(pWindow, pPrinterName); |
if (anErr == noErr) |
hPrint = pData->hPrint; |
} |
} |
} |
} |
} |
if (anErr == noErr) |
anErr = DoPrint(pWindow, hPrint, false); |
if (index != itemsInList) |
pData->hPrint = nil; |
} |
if (!wasAlreadyOpen) |
DoCloseWindow(pWindow); |
if (anErr != noErr) |
break; |
} |
} |
// finally, make sure we didn't miss any parameters |
anErr2 = MissingParameterCheck(inputEvent); |
if (anErr == noErr) |
anErr = anErr2; |
// FALL THROUGH EXCEPTION HANDLING |
DetermineWindowTypeOrOpen: |
AEGetNthPtr: |
CountDocs: |
// done with doc list |
(void) AEDisposeDesc( &docList); |
GetFileList: |
// don't report cancels from prints |
if (pPrinterName) |
{ |
if (anErr == iPrAbort) |
anErr = noErr; |
} |
if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) && (anErr != eUserCanceled) ) |
{ |
if (pPrinterName) |
ConductErrorDialog(anErr, cPrint, cancel); |
else |
ConductErrorDialog(anErr, cOpen, cancel); |
} |
return anErr; |
} // DoOpenOrPrint |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static pascal OSErr DoOpenDocument( |
AppleEvent *inputEvent, |
AppleEvent *outputEvent, |
long handlerRefCon) |
{ |
#pragma unused (outputEvent, handlerRefCon) |
OSErr anErr; |
if (IsCommandEnabled(cOpen)) |
{ |
gQuitAfterPrint = false; |
anErr = DoOpenOrPrint(inputEvent, nil); |
} |
else |
{ |
anErr = errAEEventNotHandled; |
ConductErrorDialog(anErr, cOpen, cancel); |
} |
// so that the initial document opens more quickly, we don't start |
// the threads until we get an OpenApp or OpenDocument AppleEvent |
if (gStarterThread != kNoThreadID) |
SetThreadState(gStarterThread, kReadyThreadState, gStarterThread); |
return anErr; |
} // DoOpenDocument |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static pascal OSErr DoPrintDocument( |
AppleEvent *inputEvent, |
AppleEvent *outputEvent, |
long handlerRefCon) |
{ |
#pragma unused (outputEvent, handlerRefCon) |
OSErr anErr; |
FSSpec printerFSS; |
AEDescList dtpList; // list of docs passed in |
if (IsCommandEnabled(cOpen)) |
{ |
// try to find out if this doc was dropped onto a printer |
anErr = AEGetAttributeDesc( inputEvent, keyOptionalKeywordAttr, typeAEList, &dtpList); |
if (anErr == noErr) // doc dragged to dtp? |
{ |
AEKeyword keywd; |
DescType returnedType; |
Size actualSize; |
anErr = AEGetNthPtr( &dtpList, 1, typeFSS, &keywd, &returnedType, // get dtp info |
(Ptr)(&printerFSS), sizeof(printerFSS), &actualSize); |
} |
// if it wasn't, that's not an error, just print normally |
if (anErr != noErr) |
{ |
printerFSS.name[0] = 0; |
anErr = noErr; |
} |
anErr = DoOpenOrPrint(inputEvent, &printerFSS.name[0]); |
// if we are opened just for printing -- quit afterwards |
if (gQuitAfterPrint) |
DoCommand(nil, cQuit, 0); |
} |
else |
{ |
anErr = errAEEventNotHandled; |
ConductErrorDialog(anErr, cPrint, cancel); |
} |
return anErr; |
} // DoPrintDocument |
#if GENERATINGCFM |
static RoutineDescriptor gDoOpenAppRD = BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, DoOpenApp); |
static AEEventHandlerUPP gDoOpenApp = &gDoOpenAppRD; |
static RoutineDescriptor gDoQuitAppRD = BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, DoQuitApp); |
static AEEventHandlerUPP gDoQuitApp = &gDoQuitAppRD; |
static RoutineDescriptor gDoOpenDocumentRD = BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, DoOpenDocument); |
static AEEventHandlerUPP gDoOpenDocument = &gDoOpenDocumentRD; |
static RoutineDescriptor gDoPrintDocumentRD = BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, DoPrintDocument); |
static AEEventHandlerUPP gDoPrintDocument = &gDoPrintDocumentRD; |
#else |
static AEEventHandlerUPP gDoOpenApp = (AEEventHandlerUPP) DoOpenApp; |
static AEEventHandlerUPP gDoQuitApp = (AEEventHandlerUPP) DoQuitApp; |
static AEEventHandlerUPP gDoOpenDocument = (AEEventHandlerUPP) DoOpenDocument; |
static AEEventHandlerUPP gDoPrintDocument = (AEEventHandlerUPP) DoPrintDocument; |
#endif |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static pascal OSErr SimpleTextCoachHandler(Rect *pRect, Ptr name, long refCon) |
{ |
#pragma unused (refCon) |
OSErr anErr = noErr; |
WindowRef pWindow = FrontWindow(); |
WindowDataPtr pData = GetWindowInfo(pWindow); |
if ((pData) && (pData->pGetCoachRectangle)) |
anErr = (*(pData->pGetCoachRectangle)) (pWindow, pData, pRect, name); |
return(anErr); |
} // SimpleTextCoachHandler |
// -------------------------------------------------------------------------------------------------------------- |
// MAIN INITIALIZE/SHUTDOWN/LOOP ROUTINES |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
static pascal void* StarterThread(void* threadParam) |
{ |
#pragma unused(threadParam) |
/* |
All threads, including the starter thread, are initially created |
in a suspended state. The starter thread is made ready to run when |
we get an open application or open document event. It runs until |
there are no activate or update events pending, and then starts the |
font menu and Apple Guide threads. This gives much better performance |
for the initial creation and update of a document, because the threads |
(especially the font thread) chew up a lot of time at first. |
The starter thread isn't really necessary - we could get the same |
effect by just checking in the event loop for activate/update events - |
but hey, it's a lot easier to do it this way, doesn't cost much, and |
isn't that what threads are for? |
*/ |
for (;;) |
{ |
EventRecord er; |
YieldToAnyThread(); |
if (!EventAvail(activMask | updateMask, &er)) |
{ |
if (gFontThread != kNoThreadID) |
SetThreadState(gFontThread, kReadyThreadState, gFontThread); |
if (gAGThread != kNoThreadID) |
SetThreadState(gAGThread, kReadyThreadState, gAGThread); |
break; |
} |
} |
gStarterThread = kNoThreadID; |
return NULL; |
} // StarterThread |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Initialize |
static OSErr CreateThread(ThreadEntryProcPtr pThread, void* threadParam, ThreadID* ptid) |
{ |
OSErr anErr; |
anErr = NewThread(kCooperativeThread, pThread, threadParam, 0, kNewSuspend, |
&gThreadResults, ptid); |
if (anErr == noErr && gStarterThread == kNoThreadID) |
{ |
anErr = NewThread(kCooperativeThread, StarterThread, NULL, 0, kNewSuspend, |
&gThreadResults, &gStarterThread); |
if (anErr != noErr) |
DisposeThread(*ptid, &gThreadResults, false); |
// anErr remains != noErr |
} |
return anErr; |
} |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Initialize |
static OSErr BuildFontMenu(MenuHandle menu) |
{ |
OSErr anErr = noErr; |
AppendResMenu(menu, 'FONT'); |
return(anErr); |
} // BuildFontMenu |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Initialize |
static OSErr DoInitialize(void) |
{ |
short count; // loop counter |
Handle menuBar; // for loading our menus in |
OSErr anErr = noErr; // any errors we get, none so far |
long version; // version for Gestalt calls |
InitGraf((Ptr) &qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(nil); |
InitCursor(); |
gAllDone = false; |
// check that the system is correct to handle things |
SysEnvirons(1, &gMachineInfo.theEnvirons); |
if (gMachineInfo.theEnvirons.systemVersion < 0x0700) |
{ |
// Wait for app to come to front |
for (count = 1; count <= 3; ++count) |
EventAvail(everyEvent, &gEvent); |
anErr = eMachineToOld; |
nrequire(anErr, SysEnvirons); |
} |
gMachineInfo.lastBalloonIndex = iNoBalloon; |
gMachineInfo.amInBackground = false; |
gMachineInfo.documentCount = 1; |
gMachineInfo.haveQuickTime = (Gestalt(gestaltQuickTime, &version) == noErr); |
gMachineInfo.haveRecording = (Gestalt(gestaltSoundAttr, &version) == noErr) && ((version & (1<<gestaltHasSoundInputDevice)) != 0); |
gMachineInfo.haveTTS = (Gestalt(gestaltSpeechAttr, &version) == noErr) && ((version & (1<<gestaltSpeechMgrPresent)) != 0); |
gMachineInfo.haveTSM = (Gestalt(gestaltTSMgrVersion, &version) == noErr) && (version >= 1); |
gMachineInfo.haveTSMTE = (Gestalt(gestaltTSMTEAttr, &version) == noErr) && ((version & (1<<gestaltTSMTE)) != 0); |
gMachineInfo.haveDragMgr = (Gestalt(gestaltDragMgrAttr, &version) == noErr) && ((version & (1<<gestaltDragMgrPresent)) != 0) && |
(Gestalt(gestaltTEAttr, &version) == noErr) && ((version & (1<<gestaltTEHasGetHiliteRgn)) != 0); |
gMachineInfo.haveThreeD = false; |
gMachineInfo.haveThreads = (Gestalt(gestaltThreadMgrAttr, &version) == noErr) && ((version & (1<<gestaltThreadMgrPresent)) != 0); |
#if GENERATINGPOWERPC |
{ |
CFragConnectionID connID; |
Ptr mainAddr; |
Str255 errName; |
if ( (gMachineInfo.haveQuickTime) && (GetSharedLibrary("\pQuickTimeLib", kPowerPCCFragArch, kFindCFrag, &connID, &mainAddr, errName) != noErr) ) |
gMachineInfo.haveQuickTime = false; |
if ( (gMachineInfo.haveTTS) && (GetSharedLibrary("\pSpeechLib", kPowerPCCFragArch, kFindCFrag, &connID, &mainAddr, errName) != noErr) ) |
gMachineInfo.haveTTS = false; |
if ( (gMachineInfo.haveDragMgr) && (GetSharedLibrary("\pDragLib", kPowerPCCFragArch, kFindCFrag, &connID, &mainAddr, errName) != noErr) ) |
gMachineInfo.haveDragMgr = false; |
if ( (gMachineInfo.haveThreads) && (GetSharedLibrary("\pThreadsLib", kPowerPCCFragArch, kFindCFrag, &connID, &mainAddr, errName) != noErr) ) |
gMachineInfo.haveThreads = false; |
} |
#endif |
// initialize text services if they exist |
if (gMachineInfo.haveTSMTE) |
{ |
if (InitTSMAwareApplication() != noErr) |
{ |
gMachineInfo.haveTSM = false; |
gMachineInfo.haveTSMTE = false; |
} |
} |
// save away info we need from the get-go |
gApplicationResFile = CurResFile(); |
gCursorRgn = NewRgn(); |
// load up the menus |
menuBar = (Handle) GetNewMBar(rMenuBar); /* read menus into menu bar */ |
anErr = ResError(); |
if ( (anErr == noErr) && (menuBar == nil) ) |
anErr = resNotFound; |
nrequire(anErr, GetNewMBar); |
// install menus |
SetMenuBar(menuBar); |
DisposeHandle(menuBar); |
// build the Apple menu |
AppendResMenu(GetMenuHandle(mApple), 'DRVR'); /* add DA names to Apple menu */ |
// Build the font menu |
anErr = BuildFontMenu(GetMenuHandle(mFont)); |
nrequire(anErr, BuildFontMenu); |
// insert our heirarchical menus |
{ |
MenuHandle menu = GetMenu( mVoices ); |
short menuID, itemID; |
InsertMenu( menu, hierMenu ); |
CommandToIDs(cSelectVoice, &menuID, &itemID); |
menu = GetMenuHandle(menuID); |
SetItemCmd( menu, itemID, hMenuCmd ); |
SetItemMark( menu, itemID, mVoices ); |
} |
AdjustMenus(nil, true, false); |
DrawMenuBar(); |
// start up QuickTime, but problems result in us pretending not to have it |
if (gMachineInfo.haveQuickTime) |
if (EnterMovies() != noErr) |
gMachineInfo.haveQuickTime = false; |
// Install AppleEvent handlers for the base classes |
#define INSTALL(event, handler) \ |
AEInstallEventHandler(kCoreEventClass, event, handler, 0, false) |
INSTALL (kAEOpenApplication, gDoOpenApp); |
INSTALL (kAEQuitApplication, gDoQuitApp); |
INSTALL (kAEOpenDocuments, gDoOpenDocument); |
INSTALL (kAEPrintDocuments, gDoPrintDocument); |
#undef INSTALL |
// Install our global dragging procs, but only if we have Drag and Drop. An error results |
// in us pretending that we don't have drag support. Notice that in the test above, we also |
// require TextEdit to have TEGetHiliteRgn avalilable, which is always the case with the |
// present Drag Manager. |
if (gMachineInfo.haveDragMgr) |
{ |
gGlobalTrackingHandler = NewDragTrackingHandlerProc(GlobalTrackingHandler); |
gGlobalReceiveHandler = NewDragReceiveHandlerProc(GlobalReceiveHandler); |
anErr = InstallTrackingHandler(gGlobalTrackingHandler, nil, nil); |
if (anErr == noErr) |
{ |
anErr = InstallReceiveHandler(gGlobalReceiveHandler, nil, nil); |
if (anErr != noErr) |
{ |
RemoveTrackingHandler(gGlobalTrackingHandler, nil); |
gMachineInfo.haveDragMgr = false; |
} |
} |
else |
gMachineInfo.haveDragMgr = false; |
} |
return noErr; |
// EXCEPTION HANDLING |
BuildFontMenu: |
GetNewMBar: |
SysEnvirons: |
ConductErrorDialog(anErr, cNull, cancel); |
return anErr; |
} // DoInitialize |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Terminate |
static OSErr DoTerminate(void) |
{ |
OSErr anErr = noErr; |
if (gFontThread != kNoThreadID) |
DisposeThread(gFontThread, &gThreadResults, false); |
if (gAGThread != kNoThreadID) |
DisposeThread(gAGThread, &gThreadResults, false); |
if (gStarterThread != kNoThreadID) |
DisposeThread(gStarterThread, &gThreadResults, false); |
if (gMachineInfo.haveQuickTime) |
ExitMovies(); |
if (gMachineInfo.haveTSMTE) |
CloseTSMAwareApplication(); |
if (gMachineInfo.haveDragMgr) |
{ |
RemoveReceiveHandler(gGlobalReceiveHandler, nil); |
RemoveTrackingHandler(gGlobalTrackingHandler, nil); |
} |
return anErr; |
} // DoTerminate |
// -------------------------------------------------------------------------------------------------------------- |
#pragma segment Main |
main(void) |
{ |
OSErr anErr; |
#ifndef __MWERKS__ |
UnloadSeg((Ptr) _DataInit); /* note that _DataInit must not be in Main! */ |
#endif |
MaxApplZone(); /* expand the heap so code segments load at the top */ |
MoreMasters(); MoreMasters(); MoreMasters(); /* we love handles */ |
anErr = DoInitialize(); |
UnloadSeg((Ptr) DoInitialize); |
if (anErr == noErr) |
{ |
DoEventLoop(); |
// REVIEW: don't want to unload the segment we're in!! |
// UnloadSeg((Ptr) DoEventLoop); |
DoTerminate(); |
} |
return 0; |
} // main |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-26