Demonstration Program
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// Windows2.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
//
// This program demonstrates Mac OS 8.5 Window Manager features and functions relating
// to:
//
// ¥ Creating floating windows and document windows using CreateNewWindow. (Note that
// floating windows will not be created unless the program is run under Mac OS 8.6 or
// later.)
//
// ¥ Saving document windows and their associated data to a 'wind' resource.
//
// ¥ Creating document windows from 'wind' resources using CreateWindowFromResource.
//
// ¥ Managing windows in a floating windows environment.
//
// ¥ Setting and getting a window's property.
//
// ¥ Re-sizing a window using ResizeWindow and zooming a window using ZoomWindowIdeal.
//
// ¥ Showing and hiding windows using TransitionWindow.
//
// ¥ Displaying window proxy icons.
//
// Those aspects of the Mac OS 8.5 Window Manager not demonstrated in this program
// (full implementation of window proxy icons and window path pop-up menus) are
// demonstrated at the demonstration program associated with Chapter 16B (Files2).
//
// The program utilises the following resources:
//
// ¥ An 'MBAR' resource, and 'MENU' resources for Apple, File, Edit, Document Windows
// and Floating Windows menus (preload, non-purgeable).
//
// ¥ 'TEXT' resources for the document windows (non-purgeable).
//
// ¥ 'PICT' resources for the floating windows (non-purgeable).
//
// ¥ An 'ALRT' resource (purgeable), plus associated 'DITL', 'alrx', and 'dftb'
// resources (all purgeable), for a modal alert box invoked when the user chooses the
// About Windows2... item from the Apple menu.
//
// ¥ A 'SIZE' resource with the acceptSuspendResumeEvents, doesActivateOnFGSwitch,
// and is32BitCompatible flags set.
//
// In addition, the program itself creates a 'wind' resource, and saves it to the
// resource fork of the application file, when the user chooses CreateNewWindow from the
// Document Windows menu.
//
// Note that floating windows will not be created unless the program is run under Mac OS
// 8.6 or later.
//
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// ............................................................................. includes
#include <Appearance.h>
#include <Devices.h>
#include <Folders.h>
#include <Gestalt.h>
#include <Resources.h>
#include <Sound.h>
#include <ToolUtils.h>
// .............................................................................. defines
define mApple 128
define iAbout 1
define mFile 129
define mEdit 130
define iQuit 11
define mDocumentWindows 131
define iCreateWindow 1
define iCreateFromResource 2
define mFloatingWindows 132
define iColours 1
define iTools 2
define rMenubar 128
define rAboutAlert 128
define rText 128
define rColoursPicture 128
define rToolsPicture 129
define rWind 128
define MIN(a,b) ((a) < (b) ? (a) : (b))
// ............................................................................. typedefs
typedef struct
{
TEHandle editStrucHdl;
} docStructure, **docStructureHandle;
// ..................................................................... global variables
Boolean gMacOS86Present = false;
SInt16 gAppResFileRefNum;
WindowPtr gColoursFloatingWindowPtr;
WindowPtr gToolsFloatingWindowPtr;
Boolean gDone;
Boolean gInBackground;
// .................................................................. function prototypes
void main (void);
void doInitManagers (void);
void doEvents (EventRecord *);
void doMouseDown (EventRecord *);
void doUpdate (EventRecord *);
void doUpdateDocumentWindow (WindowPtr);
void doActivate (EventRecord *);
void doActivateDocumentWindow (WindowPtr,Boolean);
void doOSEvent (EventRecord *);
void doAdjustMenus (void);
void doMenuChoice (SInt32);
void doDocumentWindowsMenu (SInt16);
void doFloatingWindowsMenu (SInt16);
OSErr doCreateNewWindow (void);
OSErr doSaveWindow (WindowPtr);
OSErr doCreateWindowFromResource (void);
OSErr doCreateFloatingWindows (void);
void doCloseWindow (WindowPtr);
void doErrorAlert (SInt16);
void doConcatPStrings (Str255,Str255);
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× main
void main(void)
{
OSErr osError;
SInt32 response;
Handle menubarHdl;
MenuHandle menuHdl;
EventRecord eventStructure;
SInt32 sleepTime;
WindowPtr windowPtr;
docStructureHandle docStrucHdl;
UInt32 actualSize;
// .............................. check whether Mac OS 8.5 and 8.6 or later are present
osError = Gestalt(gestaltSystemVersion,&response);
if(osError == noErr && response < 0x00000850)
ExitToShell();
if(osError == noErr && response >= 0x00000860)
gMacOS86Present = true;
// ................................................................ initialise managers
doInitManagers();
// .......................................................... set up menu bar and menus
menubarHdl = GetNewMBar(rMenubar);
if(menubarHdl == NULL)
ExitToShell();
SetMenuBar(menubarHdl);
DrawMenuBar();
menuHdl = GetMenuHandle(mApple);
if(menuHdl == NULL)
ExitToShell();
else
AppendResMenu(menuHdl,'DRVR');
// ............................. set current resource file to application resource fork
gAppResFileRefNum = CurResFile();
// ............................................................ create floating windows
if(gMacOS86Present)
{
if(osError = doCreateFloatingWindows())
doErrorAlert(osError);
}
else
{
menuHdl = GetMenuHandle(mFloatingWindows);
DisableItem(menuHdl,0);
menuHdl = GetMenuHandle(mApple);
DisableItem(menuHdl,iAbout);
DrawMenuBar();
}
// .................................................................... enter eventLoop
gDone = false;
sleepTime = LMGetCaretTime();
while(!gDone)
{
if(WaitNextEvent(everyEvent,&eventStructure,sleepTime,NULL))
doEvents(&eventStructure);
else
{
if(windowPtr = FrontNonFloatingWindow())
{
if(!(GetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&actualSize,
&docStrucHdl)))
TEIdle((*docStrucHdl)->editStrucHdl);
}
}
}
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doInitManagers
void doInitManagers(void)
{
MaxApplZone();
MoreMasters();
MoreMasters();
InitGraf(&qd.thePort);
InitFonts();
if(gMacOS86Present)
InitFloatingWindows();
else
InitWindows();
InitMenus();
TEInit();
InitDialogs(NULL);
InitCursor();
FlushEvents(everyEvent,0);
RegisterAppearanceClient();
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doEvents
void doEvents(EventRecord *eventStrucPtr)
{
SInt8 charCode;
switch(eventStrucPtr->what)
{
case mouseDown:
doMouseDown(eventStrucPtr);
break;
case keyDown:
case autoKey:
charCode = eventStrucPtr->message & charCodeMask;
if((eventStrucPtr->modifiers & cmdKey) != 0)
{
doAdjustMenus();
doMenuChoice(MenuEvent(eventStrucPtr));
}
break;
case updateEvt:
doUpdate(eventStrucPtr);
break;
case activateEvt:
doActivate(eventStrucPtr);
break;
case osEvt:
doOSEvent(eventStrucPtr);
HiliteMenu(0);
break;
}
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMouseDown
void doMouseDown(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
SInt16 partCode, zoomPart;
WindowClass windowClass;
Rect growRect, newContentRect;
SInt32 newSize;
Point idealSize;
partCode = FindWindow(eventStrucPtr->where,&windowPtr);
switch(partCode)
{
case inMenuBar:
doAdjustMenus();
doMenuChoice(MenuSelect(eventStrucPtr->where));
break;
case inContent:
GetWindowClass(windowPtr,&windowClass);
if(windowClass == kFloatingWindowClass)
{
if(windowPtr != FrontWindow())
SelectWindow(windowPtr);
else
{
if(windowPtr == gColoursFloatingWindowPtr)
; // Appropriate action for Colours floating window here.
else if(windowPtr == gToolsFloatingWindowPtr)
; // Appropriate action for Tools floating window here.
}
}
else
{
if(windowPtr != FrontNonFloatingWindow())
SelectWindow(windowPtr);
else
; // Appropriate action for active document window here.
}
break;
case inDrag:
DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);
break;
case inGoAway:
GetWindowClass(windowPtr,&windowClass);
if(windowClass == kFloatingWindowClass)
{
if(TrackGoAway(windowPtr,eventStrucPtr->where) == true)
TransitionWindow(windowPtr,kWindowZoomTransitionEffect,
kWindowHideTransitionAction,NULL);
}
else
if(TrackGoAway(windowPtr,eventStrucPtr->where) == true)
doCloseWindow(windowPtr);
break;
case inGrow:
growRect = qd.screenBits.bounds;
growRect.top = 80;
growRect.left = 160;
if(gMacOS86Present)
{
ResizeWindow(windowPtr,eventStrucPtr->where,&growRect,&newContentRect);
InvalWindowRect(windowPtr,&windowPtr->portRect);
}
else
{
newSize = GrowWindow(windowPtr,eventStrucPtr->where,&growRect);
if(newSize != 0)
{
SizeWindow(windowPtr,LoWord(newSize),HiWord(newSize),true);
InvalWindowRect(windowPtr,&windowPtr->portRect);
}
}
break;
case inZoomIn:
case inZoomOut:
idealSize.v = qd.screenBits.bounds.bottom - 100;
idealSize.h = qd.screenBits.bounds.right - 200;
if(IsWindowInStandardState(windowPtr,&idealSize,NULL))
zoomPart = inZoomIn;
else
zoomPart = inZoomOut;
if(TrackBox(windowPtr,eventStrucPtr->where,partCode))
ZoomWindowIdeal(windowPtr,zoomPart,&idealSize);
break;
}
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doUpdate
void doUpdate(EventRecord *eventStrucPtr)
{
GrafPtr oldPort;
WindowPtr windowPtr;
GetPort(&oldPort);
windowPtr = (WindowPtr) eventStrucPtr->message;
BeginUpdate(windowPtr);
SetPort(windowPtr);
doUpdateDocumentWindow(windowPtr);
EndUpdate(windowPtr);
SetPort(oldPort);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doUpdateDocumentWindow
void doUpdateDocumentWindow(WindowPtr windowPtr)
{
Rect contentRect;
OSStatus osError;
UInt32 actualSize;
docStructureHandle docStrucHdl;
TEHandle editStrucHdl;
EraseRgn(windowPtr->visRgn);
DrawGrowIcon(windowPtr);
if(!(osError = GetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&actualSize,
&docStrucHdl)))
{
contentRect = windowPtr->portRect;
contentRect.right -= 15;
contentRect.bottom -= 15;
editStrucHdl = (*docStrucHdl)->editStrucHdl;
(*editStrucHdl)->destRect = (*editStrucHdl)->viewRect = contentRect;
TECalText(editStrucHdl);
TEUpdate(&contentRect,(*docStrucHdl)->editStrucHdl);
}
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doActivate
void doActivate(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
Boolean becomingActive;
windowPtr = (WindowPtr) eventStrucPtr->message;
becomingActive = ((eventStrucPtr->modifiers & activeFlag) == activeFlag);
doActivateDocumentWindow(windowPtr,becomingActive);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doActivateDocumentWindow
void doActivateDocumentWindow(WindowPtr windowPtr,Boolean becomingActive)
{
docStructureHandle docStrucHdl;
UInt32 actualSize;
OSStatus osError;
if(!(osError = GetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&actualSize,
&docStrucHdl)))
{
if(becomingActive)
TEActivate((*docStrucHdl)->editStrucHdl);
else
TEDeactivate((*docStrucHdl)->editStrucHdl);
}
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOSEvent
void doOSEvent(EventRecord *eventStrucPtr)
{
WindowPtr windowPtr;
switch((eventStrucPtr->message >> 24) & 0x000000FF)
{
case suspendResumeMessage:
gInBackground = (eventStrucPtr->message & resumeFlag) == 0;
windowPtr = FrontNonFloatingWindow();
if(windowPtr != NULL)
doActivateDocumentWindow(windowPtr,!gInBackground);
if(gInBackground)
HideFloatingWindows();
else
ShowFloatingWindows();
break;
}
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doAdjustMenus
void doAdjustMenus(void)
{
MenuHandle floatMenuHdl;
Boolean isVisible;
floatMenuHdl = GetMenuHandle(mFloatingWindows);
isVisible = ((WindowPeek) gColoursFloatingWindowPtr)->visible;
CheckItem(floatMenuHdl,iColours,isVisible);
isVisible = ((WindowPeek) gToolsFloatingWindowPtr)->visible;
CheckItem(floatMenuHdl,iTools,isVisible);
DrawMenuBar();
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMenuChoice
void doMenuChoice(SInt32 menuChoice)
{
SInt16 menuID, menuItem;
Str255 itemName;
SInt16 daDriverRefNum;
menuID = HiWord(menuChoice);
menuItem = LoWord(menuChoice);
if(menuID == 0)
return;
switch(menuID)
{
case mApple:
if(menuItem == iAbout)
{
Alert(rAboutAlert,NULL);
HiliteWindow(gColoursFloatingWindowPtr,true);
HiliteWindow(gToolsFloatingWindowPtr,true);
}
else
{
GetMenuItemText(GetMenuHandle(mApple),menuItem,itemName);
daDriverRefNum = OpenDeskAcc(itemName);
}
break;
case mFile:
if(menuItem == iQuit)
gDone = true;
break;
case mDocumentWindows:
doDocumentWindowsMenu(menuItem);
break;
case mFloatingWindows:
doFloatingWindowsMenu(menuItem);
break;
}
HiliteMenu(0);
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doDocumentWindowsMenu
void doDocumentWindowsMenu(SInt16 menuItem)
{
OSErr osError;
switch(menuItem)
{
case iCreateWindow:
if(osError = doCreateNewWindow())
doErrorAlert(osError);
break;
case iCreateFromResource:
if(osError = doCreateWindowFromResource())
doErrorAlert(osError);
break;
}
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFloatingWindowsMenu
void doFloatingWindowsMenu(SInt16 menuItem)
{
Boolean isVisible;
if(menuItem == iColours)
{
isVisible = ((WindowPeek) gColoursFloatingWindowPtr)->visible;
if(isVisible)
TransitionWindow(gColoursFloatingWindowPtr,kWindowZoomTransitionEffect,
kWindowHideTransitionAction,NULL);
else
TransitionWindow(gColoursFloatingWindowPtr,kWindowZoomTransitionEffect,
kWindowShowTransitionAction,NULL);
}
else if(menuItem == iTools)
{
isVisible = ((WindowPeek) gToolsFloatingWindowPtr)->visible;
if(isVisible)
TransitionWindow(gToolsFloatingWindowPtr,kWindowZoomTransitionEffect,
kWindowHideTransitionAction,NULL);
else
TransitionWindow(gToolsFloatingWindowPtr,kWindowZoomTransitionEffect,
kWindowShowTransitionAction,NULL);
}
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCreateFloatingWindows
OSErr doCreateFloatingWindows(void)
{
Rect contentRect;
OSStatus osError;
PicHandle pictureHdl;
SetRect(&contentRect,102,59,391,132);
if(!(osError = CreateNewWindow(kFloatingWindowClass,
kWindowStandardFloatingAttributes +
kWindowSideTitlebarAttribute,
&contentRect,&gColoursFloatingWindowPtr)))
{
if(pictureHdl = GetPicture(rColoursPicture))
SetWindowPic(gColoursFloatingWindowPtr,pictureHdl);
osError = TransitionWindow(gColoursFloatingWindowPtr,kWindowZoomTransitionEffect,
kWindowShowTransitionAction,NULL);
}
if(osError != noErr)
return osError;
SetRect(&contentRect,149,88,213,280);
if(!(osError = CreateNewWindow(kFloatingWindowClass,
kWindowStandardFloatingAttributes,
&contentRect,&gToolsFloatingWindowPtr)))
{
if(pictureHdl = GetPicture(rToolsPicture))
SetWindowPic(gToolsFloatingWindowPtr,pictureHdl);
osError = TransitionWindow(gToolsFloatingWindowPtr,kWindowZoomTransitionEffect,
kWindowShowTransitionAction,NULL);
}
return osError;
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCreateNewWindow
OSErr doCreateNewWindow(void)
{
Rect contentRect;
OSStatus osError;
WindowPtr windowPtr;
docStructureHandle docStrucHdl;
Handle textHdl;
SetRect(&contentRect,10,40,470,340);
do
{
if(osError = CreateNewWindow(kDocumentWindowClass,kWindowStandardDocumentAttributes,
&contentRect,&windowPtr))
break;
if(!(docStrucHdl = (docStructureHandle) NewHandle(sizeof(docStructure))))
{
osError = MemError();
break;
}
if(osError = SetWindowProperty(windowPtr,0,'docs',sizeof(docStructure),
&docStrucHdl))
break;
SetPort(windowPtr);
TextSize(10);
textHdl = GetResource('TEXT',rText);
osError = ResError();
if(osError != noErr)
break;
OffsetRect(&contentRect,-contentRect.left,-contentRect.top);
contentRect.right -= 15;
contentRect.bottom -= 15;
(*docStrucHdl)->editStrucHdl = TENew(&contentRect,&contentRect);
TEInsert(*textHdl,GetHandleSize(textHdl),(*docStrucHdl)->editStrucHdl);
SetWTitle(windowPtr,"\pCreateNewWindow");
if(osError = SetWindowProxyCreatorAndType(windowPtr,0,'TEXT',kOnSystemDisk))
break;
if(osError = SetWindowModified(windowPtr,false))
break;
if(osError = RepositionWindow(windowPtr,NULL,kWindowCascadeOnMainScreen))
break;
if(osError = TransitionWindow(windowPtr,kWindowZoomTransitionEffect,
kWindowShowTransitionAction,NULL))
break;
if(osError = doSaveWindow(windowPtr))
break;
} while(false);
if(osError)
{
if(windowPtr)
DisposeWindow(windowPtr);
if(docStrucHdl)
DisposeHandle((Handle) docStrucHdl);
}
return osError;
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSaveWindow
OSErr doSaveWindow(WindowPtr windowPtr)
{
Collection collection = NULL;
OSStatus osError;
docStructureHandle docStrucHdl;
UInt32 actualSize;
Handle flatCollectHdl, flatCollectResHdl, existingResHdl;
do
{
if(!(collection = NewCollection()))
{
osError = MemError();
break;
}
if(osError = StoreWindowIntoCollection(windowPtr,collection))
break;
if(osError = GetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&actualSize,
&docStrucHdl))
break;
if(osError = AddCollectionItemHdl(collection,'TEXT',1,
(*(*docStrucHdl)->editStrucHdl)->hText))
break;
if(!(flatCollectHdl = NewHandle(0)))
{
osError = MemError();
break;
}
if(osError = FlattenCollectionToHdl(collection,flatCollectHdl))
break;
existingResHdl = Get1Resource('wind',rWind);
osError = ResError();
if(osError != noErr && osError != resNotFound)
break;
if(existingResHdl != NULL)
RemoveResource(existingResHdl);
osError = ResError();
if(osError != noErr)
break;
AddResource(flatCollectHdl,'wind',rWind,"\p");
osError = ResError();
if(osError != noErr)
break;
flatCollectResHdl = flatCollectHdl;
flatCollectHdl = NULL;
WriteResource(flatCollectResHdl);
osError = ResError();
if(osError != noErr)
break;
UpdateResFile(gAppResFileRefNum);
osError = ResError();
if(osError != noErr)
break;
} while(false);
if(collection)
DisposeCollection(collection);
if(flatCollectHdl)
DisposeHandle(flatCollectHdl);
if(flatCollectResHdl)
ReleaseResource(flatCollectResHdl);
return osError;
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCreateWindowFromResource
OSErr doCreateWindowFromResource(void)
{
OSStatus osError;
WindowPtr windowPtr;
Collection unflattenedCollection = NULL;
Handle windResHdl;
docStructureHandle docStrucHdl;
SInt32 dataSize = 0;
Handle textHdl;
Rect contentRect;
do
{
if(osError = CreateWindowFromResource(rWind,&windowPtr))
break;
if(!(unflattenedCollection = NewCollection()))
{
osError = MemError();
break;
}
windResHdl = GetResource('wind',rWind);
osError = ResError();
if(osError != noErr)
break;
if(osError = UnflattenCollectionFromHdl(unflattenedCollection,windResHdl))
break;
if(!(docStrucHdl = (docStructureHandle) NewHandle(sizeof(docStructure))))
{
osError = MemError();
break;
}
if(osError = GetCollectionItem(unflattenedCollection,'TEXT',1,&dataSize,
kCollectionDontWantData))
break;
if(!(textHdl = NewHandle(dataSize)))
{
osError = MemError();
break;
}
if(osError =
GetCollectionItem(unflattenedCollection,'TEXT',1,kCollectionDontWantSize,
*textHdl))
break;
contentRect = windowPtr->portRect;
contentRect.right -= 15;
contentRect.bottom -= 15;
SetPort(windowPtr);
TextSize(10);
(*docStrucHdl)->editStrucHdl = TENew(&contentRect,&contentRect);
TEInsert(*textHdl,dataSize,(*docStrucHdl)->editStrucHdl);
if(osError = SetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&docStrucHdl))
break;
SetWTitle(windowPtr,"\pCreateWindowFromResource");
if(osError = SetWindowProxyCreatorAndType(windowPtr,0,'TEXT',kOnSystemDisk))
break;
if(osError = SetWindowModified(windowPtr,false))
break;
if(osError = RepositionWindow(windowPtr,NULL,kWindowCascadeOnMainScreen))
break;
if(osError = TransitionWindow(windowPtr,kWindowZoomTransitionEffect,
kWindowShowTransitionAction,NULL))
break;
} while(false);
if(unflattenedCollection)
DisposeCollection(unflattenedCollection);
if(windResHdl)
ReleaseResource(windResHdl);
return osError;
}
// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCloseWindow
void doCloseWindow(WindowPtr windowPtr)
{
OSStatus osError;
docStructureHandle docStrucHdl;
UInt32 actualSize;
do
{
if(osError = TransitionWindow(windowPtr,kWindowZoomTransitionEffect,
kWindowHideTransitionAction,NULL))
break;
if(osError = GetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&actualSize,
&docStrucHdl))
break;
} while(false);
if(osError)
doErrorAlert(osError);
if((*docStrucHdl)->editStrucHdl)
TEDispose((*docStrucHdl)->editStrucHdl);
if(docStrucHdl)
DisposeHandle((Handle) docStrucHdl);
DisposeWindow(windowPtr);
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doErrorAlert
void doErrorAlert(SInt16 errorCode)
{
AlertStdAlertParamRec paramRec;
Str255 errorCodeString;
Str255 theString = "\pAn error occurred. The error code is ";
SInt16 itemHit;
paramRec.movable = false;
paramRec.helpButton = false;
paramRec.filterProc = NULL;
paramRec.defaultText = (StringPtr) kAlertDefaultOKText;
paramRec.cancelText = NULL;
paramRec.otherText = NULL;
paramRec.defaultButton = kAlertStdAlertOKButton;
paramRec.cancelButton = 0;
paramRec.position = kWindowAlertPositionMainScreen;
NumToString((SInt32) errorCode,errorCodeString);
doConcatPStrings(theString,errorCodeString);
StandardAlert(kAlertStopAlert,theString,NULL,¶mRec,&itemHit);
ExitToShell();
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doConcatPStrings
void doConcatPStrings(Str255 targetString,Str255 appendString)
{
SInt16 appendLength;
appendLength = MIN(appendString[0],255 - targetString[0]);
if(appendLength > 0)
{
BlockMoveData(appendString+1,targetString+targetString[0]+1,(SInt32) appendLength);
targetString[0] += appendLength;
}
}
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
Demonstration Program Comments
This program will run only under Mac OS 8.5 or later. The program's floating windows
will be created only if the program is run under Mac OS 8.6 or later.
Two Mac OS 8.5 Window Manager features (full window proxy icon implementation and window
path pop-up menus) are not demonstrated in this program. However, they are demonstrated
at the demonstration program associated with Chapter 16B (Files2).
When the program is run, the user should:
¥ Choose CreateNewWindow from the Document Windows menu, noting that, when the new
window is displayed, the floating windows and the new (document) window are all
active.
(Note: As well as creating the window, the program loads and displays a 'TEXT'
resource (simulating a document associated with the window) and then saves the
window and the text to a 'wind' resource.)
¥ Choose CreateWindowFromResource from the Document Windows menu, noting that the
window is created from the 'wind' resource saved when CreateNewWindow was chosen.
¥ Choose About Windows2... from the Apple menu, noting that the floating windows
appear in the deactivated state when the alert box opens.
¥ Hide the floating windows by clicking their close boxes, and toggle the floating
windows between hidden and showing by choosing their items in the Floating Windows
menu, noting the transitional animations and sounds.
¥ Click in the Finder to send the application to the background, noting that the
floating windows are hidden by this action. Then click in one of the application's
windows, noting that the floating windows re-appear.
¥ Drag a document window to various locations on the screen, zoom the window in and
out at those locations, and note that the zoom out to the standard state conforms
with human interface guidelines.
¥ Resize the document windows.
¥ Note the transitional animations and sounds when the document windows are opened and
closed.
×define
The first twelve ×defines establish constants representing menu IDs and resources,
menu item numbers, and the menu bar resource ID. The next five represent the resource
IDs for an 'ALRT' resource (and associated 'DITL', 'alrx', and 'dfnt' resources), a
'TEXT' resource, two 'PICT' resources, and the 'wind' resource created by the program.
The (fairly common) macro which follows is required by the application-defined string
concatenation doConcatPStrings.
×typedef
A document structure of type docStructure will be "attached" to each document
window. The single field in the document structure (editStrucHdl) will be assigned a
handle to a TextEdit edit structure, which will contain the text displayed in the
window.
Global Variables
gMacOS86Present will be assigned true if Mac OS 8.6 or later is present.
gAppResFileRefNum will be assigned the file reference number for the application file's
resource fork. gColoursFloatingWindowPtr and gToolsFloatingWindowPtr will be assigned
pointers to the colour graphics port structures for the floating windows. gDone, when
set to true, will cause the main event loop to exit and the program to terminate.
gInBackground relates to foreground/background switching.
main
Gestalt is called to determine which version of the Mac OS is present. If Mac OS
8.5 or later is not present, the program terminates. If Mac OS 8.6 or later is present,
the global variable gMacOS86Present is set to true.
The next block sets up the menus. Note that error handling in this block is very
rudimentary: the program simply terminates.
At the next block CurResFile is called to set the application's resource fork as the
current resource file. This is necessary because the program will be saving a 'wind'
resource to the application file's resource fork.
If Mac OS 8.6 is present, an application-defined function is called to create and show
the floating windows, otherwise the Floating Windows menu and the About Windows2... item
in the Apple menu are disabled.
In the next block (the main event loop), WaitNextEvent's sleep parameter is assigned the
value returned by LMGetCaretTime. (LMGetCaretTime returns the value stored in the low
memory global CaretTime, which determines the blinking rate for the insertion point caret
as set by the user using the General Controls Control Panel.) This ensures that TEIdle,
which causes the caret to blink, will be called at the correct interval.
When WaitNextEvent returns a NULL event, the Mac OS 8.5 function FrontNonFloatingWindow
is called to obtain a pointer to the front document window. If such a window exists, the
Mac OS 8.5 function GetWindowProperty is called to retrieve a handle to the window's
document structure. The handle to the TextEdit edit structure, which is stored in the
window's document structure, is then passed in the call to TEIdle, which causes the caret
to blink.
doInitManagers
Note that, if Mac OS 8.6 is present, the Mac OS 8.5 function InitFloatingWindows is
called, otherwise InitWindows is called.
doMouseDown
doMouseDown continues the processing of mouse-down events, switching according to
the part code.
The inContent case is handled differently depending on whether the event is in a floating
window or a document window. The Mac OS 8.5 function GetWindowClass returns the window's
class. If the window is a floating window, and if that window is not the front floating
window, SelectWindow is called to bring that floating window to the front. If the window
is the front floating window, the identity of the window is determined and the
appropriate further action is taken. (In this demonstration, no further action is
taken.)
If the window is not a floating window, and if the window is not the front non-floating
window, SelectWindow is called to:
¥ Unhighlight the currently active non-floating window, bring the specified window to
the front of the non-floating windows, and highlight it.
¥ Generate activate events for the two windows.
¥ Move the previously active non-floating window to a position immediately behind the
specified window.
If the window is the front non-floating window, the appropriate further action is taken.
(In this demonstration, no further action is taken.)
The inGoAway case is also handled differently depending on whether the event is in a
floating window or a document window. TrackGoAway is called in both cases to track user
action while the mouse-button remains down. If the pointer is still within the go away
box when the mouse-button is released, and if the window is a floating window, the Mac OS
8.5 function TransitionWindow is called to hide the window. If the window is a
non-floating window, the application-defined function doCloseWindow is called to close
the window.
The inGrow case first sets up the Rect passed in the third parameter of the ResizeWindow
and GrowWindow calls which, in turn, will limit the minimum and maximum sizes to which
the window can be resized. The top, left, bottom and right fields must contain,
respectively, the minimum vertical, the minimum horizontal, the maximum vertical, and the
maximum horizontal measurements. At the first line, this Rect is set to the boundaries
of the screen, which is a reasonable way to get reasonable values into the bottom and
right fields. The top and left fields, however, need to be manually set to some
reasonable values (the two next lines).
If Mac OS 8.6 or later is present, the Mac OS 8.6 function ResizeWindow is called to
retain control while the mouse-button remains down, and to draw the window frame in its
new size when the mouse button is released. (When ResizeWindow returns, its
newContentRect parameter contains the new dimension of the window's content region in
global coordinates, although this information is not used in this demonstration.) The
call to the Mac OS 8.5 function InvalWindowRect will cause the entire content region to
be erased and redrawn (see doUpdateDocumentWindow).
If Mac OS 8.5 or earlier is present, GrowWindow is called and retains control until the
user releases the mouse button, at which time the Rect variable newSize will contain the
new window size coordinates. (Note that GrowWindow does not redraw the window in this
size.) The SizeWindow call then redraws the window frame. The call to the Mac OS 8.5
function InvalWindowRect will cause the entire content region to be erased and redrawn
(see doUpdateDocumentWindow).
At the inZoomIn and InZoomOut cases, the first two lines set the fields of a Point
variable to equal the height and width of the main screen less 100 and 200 pixels
respectively. This represents what this application considers to be the ideal size for
the window. The call to the Mac OS 8.5 function IsWindowInStandardState compares the
window's current size with this ideal size and, if they are equal, inZoomIn is assigned
to the local variable zoomPart, meaning that the window is to be zoomed in to the user
state. If they are not equal, inZoomOut is assigned to zoomPart, meaning that the window
is to be zoomed out to the standard state. TrackBox retains control until the user
releases the mouse button. If the pointer is still within the zoom box when the mouse
button is released, the Mac OS 8.5 function ZoomWindowIdeal is called to zoom the window
in accordance with human interface guidelines, and in the direction specified by
zoomPart.
doUpdate
doUpdate further processes update events. When an update event is received,
doUpdate calls doUpdateDocumentWindow. (As will be seen, in this particular
demonstration, the Window Manager will not generate updates for the floating
windows.)
doUpdateDocumentWindow
doUpdateDocumentWindow is concerned with the redrawing of the content region of the
non-floating windows.
Firstly, the window's visible region, which at this point equates to the update region,
is erased and DrawGrowIcon is called to draw the scroll bar delimiting lines. (This
latter call is for cosmetic purposes only and would not be made if the window contained
scroll bars.)
The Mac OS 8.5 function GetWindowProperty is then called to retrieve the handle to the
window's document structure, which, as previously stated, contains a handle to a TextEdit
edit text structure containing the text displayed in the window. If the call is
successful, measures are taken to redraw the text in the window, taking account of the
current height and width of the content region less the area that would ordinarily be
occupied by scroll bars. (The TextEdit is calls in this section are incidental to the
demonstration. TextEdit is addressed at Chapter 19 Ñ Text and TextEdit.)
doActivate
doActivate attends to those aspects of window activation not handled by the Window
Manager. The modifiers field of the event structure is tested to determine whether the
window in question is being activated or deactivated. The result of this test is passed
as a parameter in a call to the application-defined function for activating non-floating
windows.
doActivateDocumentWindow
doActivateDocumentWindow performs, for the non-floating windows, those window
activation actions for which the application is responsible. In this demonstration, that
action is limited to calling TEActivate or TEDeactivate to show or remove the insertion
point caret.
The Mac OS 8.5 function GetWindowProperty is called to retrieve the handle to the
window's document structure, which contains a handle to the TextEdit edit text structure
containing the text displayed in the window. If this call is successful, and if the
window is being activated, TEActivate is called to display the insertion point caret. If
the window is being deactivated, TEDeactivate is called to remove the insertion point
caret.
doOSEvent
doOSEvent handles operating system events. In this demonstration, action is taken
only in the case of suspend and resume messages.
If the event is a suspend event, the global variable gInBackground is assigned true,
otherwise it is assigned false. The call to the Mac OS 8.5 function
FrontNonFloatingWindow and the following line determines whether there are any
non-floating windows present. If so, a pointer to the front non-floating window is
passed in the call to the application-defined function for activating and deactivating
no-floating windows. In the next block, if the event was a suspend event, the Mac OS 8.5
function HideFloatingWindows is called to hide the floating windows, otherwise the Mac OS
8.5 function ShowFloatingWindows is called to show the floating windows.
doAdjustMenus
doAdjustMenus is called in the event of a mouse-down event in the menu bar when a
key is pressed together with the Command key. The function checks or unchecks the items
in the Floating Windows menu depending on whether the associated floating window is
currently showing or hidden.
doMenuChoice
doMenuChoice switches according to the menu choices of the user.
If the user chooses the About Windows2... item from the Apple menu, Alert is called to
display the About Windows2... alert box.
The calls to HiliteWindow explicitly activate the two floating windows when the alert box
is dismissed. This is a workaround to compensate for what appears to be a Window Manager
window activation anomaly. This anomaly is evidenced as follows:
¥ When the application is launched and a document window is opened before the alert box
is invoked, the floating windows appear in the deactivated state while the alert box
is present and in the activated state when the alert box is dismissed. This is the
expected correct behaviour.
¥ However, if a document window is not opened before the alert box is invoked, the
floating windows remain in the deactivated state when the alert box is dismissed.
The calls to HiliteWindow have been included to cater for the second of the above
situations.
If the user chooses the Quit item in the File menu, the global variable gDone is set to
true, causing the program to terminate.
doDocumentWindowsMenu
doDocumentWindowsMenu further processes choices from the Document Windows menu. If
the user chose the first item, the application-defined function doCreateNewWindow is
called. If the user chose the second item, the application-defined function
doCreateWindowFromResource is called. If either of these functions return an error, an
application-defined error-handling function is called.
doFloatingWindowsMenu
doFloatingWindowsMenu further processes choices from the Floating Windows menu.
When an item is chosen, the visible field of the window's colour window structure is
examined to determine whether the window is currently showing or hidden. The Mac OS 8.5
function TransitionWindow is then called, with the appropriate constant passed in the
action parameter, to hide or show the window, depending on the previously determined
current visibility state.
doCreateFloatingWindows
doCreateFloatingWindows is called from main to create the floating windows.
The Colours floating window is created first. SetRect is called to define a rectangle
which will be used to establish the size of the window and its opening location in global
coordinates. The Mac OS 8.5 function CreateNewWindow is then called to create a floating
window (first parameter) with a close box, a collapse box, and a side title bar (second
parameter), and with the previously defined content region size and location (third
parameter).
If this call is successful, GetPicture is called to load the specified 'PICT' resource.
If the resource is loaded successfully, SetWindowPic is called to store the handle to the
picture structure in the windowPic field of the window's colour window structure. This
latter means that the Window Manager will draw the picture in the window instead of
generating update events for it. Finally, the Mac OS 8.5 function TransitionWindow is
called to make the window visible (with animation and sound).
The same general procedure is then followed to create the Tools floating window.
doCreateNewWindow
doCreateNewWindow is called when the user chooses Create New Window from the
Document Windows menu. In addition to creating a window, and for the purposes of this
demonstration, doCreateNewWindow also saves the window and its associated data (text) in
a 'wind' resource.
Firstly, SetRect is called to define a rectangle that will be used to establish the size
of the window and its opening location in global coordinates. The call to the Mac OS 8.5
function CreateNewWindow creates a document window (first parameter) with a close box, a
full zoom box, a collapse box, and a size box (second parameter), and with the previously
defined content region size and location (third parameter).
NewHandle is then called to create a relocatable block for the document structure to be
associated with the window. The Mac OS 8.5 function SetWindowProperty associates the
document structure with the window. 0 is passed in the propertyCreator parameter because
this demonstration has no application signature. The value passed in the propertyTag
parameter ('docs') is just a convenient value with which to identify the data.
The call to SetPort sets the window's colour graphics port as the current port and the
call to TextSize ensures that the size of the text to be drawn in the window will be 10
points.
The next three blocks load a 'TEXT' resource, insert the text into a TextEdit edit text
structure, and assign a handle to that structure to the editStrucHdl field of the
window's document structure. This is all for the purpose of simulating some text that
the user has typed into the window.
SetWTitle sets the window's title.
The window lacks an associated file, so the Mac OS 8.5 function
SetWindowProxyCreatorAndType is called to cause a proxy icon to be displayed in the
window's drag bar. 0 passed in the fileCreator parameter and 'TEXT' passed in the
fileType parameter cause the system's default icon for a document file to be displayed.
The Mac OS 8.5 function SetWindowModified is then called with false passed in the
modified parameter to cause the proxy icon to appear in the enabled state (indicating no
unsaved changes).
The call to the Mac OS 8.5 function RepositionWindow positions the window relative to
other windows according to the constant passed in the method parameter.
As the final step in creating the window, the Mac OS 8.5 function TransitionWindow is
called to make the window visible (with animation and sound).
To facilitate the demonstration of creating a window from a 'wind' resource (see the
function doCreateWindowFromResource), an application-defined function is called to save
the window and its data (the text) to a 'wind' resource in the application's resource
fork.
If an error occurred within the do/while loop, if a window was created, it is disposed
of. Also, if a nonrelocatable block for the document structure was created, it is
disposed of.
doSaveWindow
doSaveWindow is called by doCreateNewWindow to save the window and its data (the
text) to a 'wind' resource.
The call to the Collection Manager function NewCollection allocates memory for as new
collection object and initializes it. The call to the Mac OS 8.5 function
StoreWindowIntoCollection stores data describing the window into the collection.
The Mac OS 8.5 function GetWindowProperty retrieves the handle to the window's document
structure.
The handle to the window's text is is stored in the hText field of the TextEdit edit text
structure. The handle to the edit text structure is, in turn, stored in the window's
document structure. The Collection Manager function AddCollectionItemHdl adds a new item
to the collection, specifically, a copy of the text.
The call to NewHandle allocates a zero-length handle which will be used to hold a
flattened collection. The Collection Manager function FlattenCollectionToHdl flattens
the collection into a Memory Manager handle.
The next six blocks use Resource Manager functions to save the flattened collection as a
'wind' resource in the resource fork of the application file.
Get1Resource attempts to load a 'wind' resource with ID 128. If ResError reports an
error, and if the error is not the "resource not found" error, the whole save process is
aborted. (Accepting the "resource not found" error as an acceptable error caters for the
possibility that this may be the first time the window and its data have been saved.)
If Get1Resource successfully loaded a 'wind' resource with ID 128, RemoveResource is
called to remove that resource from the resource map, AddResource is called to make the
flattened collection in memory into a 'wind' resource, assigning a resource type, ID and
name to that resource, and inserting an entry in the resource map for the current
resource file. WriteResource is called to write the resource to the application's
resource fork. Since the resource map has been changed, UpdateResFile is called to
update the resource map on disk.
Below the do/while loop, the collection and the flattened collection block are disposed
of and the resource in memory is released.
doCreateWindowFromResource
doCreateWindowFromResource creates a window from the 'wind' resource created by
doSaveWindow.
The Mac OS 8.5 function CreateWindowFromResource creates a window, invisibly, from the
'wind' resource with ID 128.
The call to the Collection Manager function NewCollection creates a new collection.
GetResource loads the 'wind' resource with ID 128. The Collection Manager function
UnflattenCollectionFromHdl unflattens the 'wind' resource and stores the unflattened
collection in the collection object unflattenedCollection.
NewHandle allocates a relocatable block the size of a window document structure.
The Collection Manager function GetCollectionItem is called twice, the first time to get
the size of the text data, not the data itself. (The item in the collection is specified
by the second and third parameters (tag and ID)). This allows the call to NewHandle to
create a relocatable block of the same size. GetCollection is then called again, this
time to obtain a copy of the text itself.
The next block creates a new TextEdit edit text structure (TENew), assigning its handle
to the editStrucHdl field of the document structure which will shortly be associated with
the window. TEInsert inserts the copy of the text obtained by the second call to
GetCollectionItem into the edit text structure.
The call to the Mac OS 8.5 function SetWindowProperty associates the document structure
with the window, thus associating the edit text structure and its text with the window.
SetWTitle sets the window's title.
The window lacks an associated file, so the Mac OS 8.5 function
SetWindowProxyCreatorAndType is called to cause a proxy icon to be displayed in the
window's drag bar. 0 passed in the fileCreator parameter and 'TEXT' passed in the
fileType parameter cause the system's default icon for a document file to be displayed.
The Mac OS 8.5 function SetWindowModified is then called with false passed in the
modified parameter to cause the proxy icon to appear in the enabled state (indicating no
unsaved changes).
The call to the Mac OS 8.5 function RepositionWindow positions the window relative to
other windows according to the constant passed in the method parameter.
As the final step in creating the window, the Mac OS 8.5 function TransitionWindow is
called to make the window visible (with animation and sound).
Below the do/while loop, the unflattened collection is disposed of and the 'wind'
resource is released.
doCloseWindow
doCloseWindow is called when the user clicks the close box of a document window.
TransitionWindow is called to hide the window (with animation and sound). The Mac OS 8.5
function GetWindowProperty is then called to retrieve a handle to the window's document
structure, allowing the memory occupied by the edit text structure and document structure
associated with the window to be disposed of. DisposeWindow is then called to remove the
window from the window list and discard all its data storage.
doErrorAlert and doConcatPStrings
doErrorAlert is called when errors are detected. In this demonstration, the action
taken is somewhat rudimentary. A stop alert box displaying the error number is invoked.
When the user dismisses the alert box, the program terminates.
doConcatPStrings is called from doErrorAlert to concatenate two strings into the single
string displayed in the alert box.
|