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.
CoreSample.c
/* |
File: CoreSample.c |
Contains: An application that is Apple Event-aware, Scripting Compatible, |
and recordable. It supports the Required and Core Suite of |
Apple Events, the Object Model, and the Open Scripting |
Architecture. |
The main purpose of this sample code is to demonstrate how to develop an |
application that is Apple event-aware, scripting compatible, uses the Object |
Support Library, and supports Apple's Open Scripting Architecture. In |
addition, it has its own 'aete' (Apple Event Terminology Extension) resource |
(CoreSampleAETE.r). By incorporating these technologies into your application, |
your application will support Apple's Open Scripting Architecture. |
The functionality of CoreSample is basic window manipulation. The user may |
create, drag, size, zoom, and close windows. All these actions may be |
performed through Apple events. |
This application is also "factored", which means that user interactions (such |
as dragging or sizing a window, selecting a menuitem) are converted into Apple |
events which the application sends off to itself, and then is handled by the |
corresponding event handler. Factoring makes it possible to access the appli- |
cation's functionality through Apple events. It also makes it easier to record |
the user's actions in the form of Apple events. |
CoreSample supports the Required and Core suites of events, and the application |
and window object classes. One additional property has been added to the window |
class, and that is its position, the top left-hand coordinates of the window. |
Some events only apply to the window class, such as Create, Move, Clone, and |
Set Data (application properties are not modifiable, except for pClipboard, |
which I do not support). Currently, CoreSample supports the Simple Grammar, |
as defined in the "Object Support Library Developer Note". |
The properties you may access with the Get Data Apple event are as follows: |
Application - Best Type, Default Type, Class, Name, IsFrontProcess, Version |
Window - Best Type, Default Type, Bounds, Class, Index, Name, Position, |
Closeable, Titled, Resizable, Zoomable, Floating, Modal, Zoomed, |
and Visible. |
The properties you may set with the Set Data Apple event are as follows: |
Window - Bounds, Index, Zoomed, Name, Position, and Visible. |
When you create a new element, you may pass it initial data values. This |
application will create the new element accordingly if either or both of the |
initial data parameters exist. In addition, with CoreSample, you may create or |
move a window without passing it an insertion location record. By default, a |
window will be created/moved to the frontmost position. |
(NOTE: Some portions of this code are derived from TESample, a |
sample application provided by Apple Developer Technical Support.) |
Written by: Sue Dumont |
Copyright: Copyright © 1992-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source 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 source |
code, but that you've made changes. |
Change History (most recent first): |
7/21/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
12/1/93 <dan> added PowerPC support - will run native on PowerPC if |
compiled on PowerPC system. These changes are denoted |
by [pwpc]. |
6/22/93 <doo> converted files to run in the Think C 6.0 environment |
Fixed incorrect comparison of rects and windowlist problems |
associated with the Think compiler. |
4/02.93 <smd> added GetWindowBounds routine to calculate the correct |
bounds when the bounds accessed from the content region is |
invalid (such as when the application is hidden). |
- cleaned up the aete. |
10/01/92 <smd> Added pVersion to application and now set the port before |
setting the pPosition property. |
07/19/92 <smd> Fixed bug where the Move event was not recording the |
correct window being moved when the data was being passed |
by index rather than by name. |
04/30/92 <smd> Check if replacing the same window in HandleMove |
(i.e., "move window 2 to window 2"). If so, do nothing. |
06/25/92 <smd> Changed FindRelativeWindow to return the windowPtr of the |
window being replaced rather than closing it. This caused |
an error when trying to replace the same window, in which |
case nothing should happen. (Ex. move window 2 to window 2). |
04/27/92 <smd> Fixed bug in DoSetData where data was set to a pointer, and |
then the pointer was diposed of. |
04/20/92 <smd> Fixed a bug with setting the visibility property of a window. |
02/28/92 <smd> Added coercion routines (thanks Kevin) to clean up code. |
These convert from descs to boolean, long, and pstrings. |
02/25/92 <smd> Modified GetWindowWithTitle, GetWidnowWithIndex, and |
GetWindowIndexNum routines to use WindowList so ALL windows |
will be accessed (even invisible ones). |
- Changed InitializeDescs to MyInitDescs and DisposeDescs to |
MyDisposeDescs. |
- Removed the FailIfErr calls from the AE Handlers so that |
they will return the error code rather than dying. |
02/24/92 <smd> Now sends a Move event when just making a window active. |
This is done in the DoEvent routine, drag region. |
02/21/92 <smd> Fixed bug where the same AEDesc was being passed as source |
and dest to AECoerceDesc(). |
Send myself a Move event when user clicks in content of a |
window. |
02/17/92 <smd> Added InitializeDescs() and DisposeDescs() routines. |
02/05/92 <smd> Handling optional parameters in Create Element event. |
01/30/92 <smd> Adding complete support for core suite and properties. |
01/21/92 <smd> Positive and negative offset when referencing by index. |
01/10/92 <smd> Made insertion location parameter optional in the Create |
and Move events, and provided my own default behavior. |
01/09/92 <kc> Quick clean up for Scripting QuickStart. |
01/06/92 <kc> Added code for Count Elements, Do Objects Exist, Move, |
and Get Data Size |
11/91 <smd> Initial code implementation. |
*/ |
#include <Types.h> |
#include <Quickdraw.h> |
#include <Events.h> |
#include <AppleEvents.h> |
#include <AEObjects.h> |
#include <AEPackObject.h> |
#include <Resources.h> // for version resource |
#include <Windows.h> |
#include <Menus.h> |
#include <Dialogs.h> |
#include <Desk.h> |
#include <Scrap.h> |
#include <limits.h> |
#include <ToolUtils.h> |
#include <Memory.h> |
#include <SegLoad.h> |
#include <OSUtils.h> |
#include <OSEvents.h> |
#include <DiskInit.h> |
#include <Packages.h> |
#include <Traps.h> |
#include <string.h> |
#include <Strings.h> |
#include <stdarg.h> |
#include "AERegistry.h" // Constants defined in the Registry. |
#include "CoreSample.h" |
#include <LowMem.h> |
#define HiWrd(aLong) (((aLong) >> 16) & 0xFFFF) |
#define LoWrd(aLong) ((aLong) & 0xFFFF) |
typedef long* LongPtr; |
typedef WindowPeek* PeekPtr; |
// Globals. |
SysEnvRec gMac; // Contains the system environment |
Boolean gHasWaitNextEvent; // True if WaitNextEvent trap is available |
Boolean gInBackground; // Determines if currently in the background |
long gNumWindowsOpen; // The number of windows open |
short gNewWindows; // The number of new windows created |
Boolean gQuitApp; // True to quit the application |
AEDesc gNullDesc; // A null descriptor record |
AEAddressDesc gSelfAddress; // A self-addressed address descriptor record |
ProcessSerialNumber gSelfPSN; // This application's psn |
short gRefNum; // reference number of rescource file |
//----------------------------------------------------------------------------------// |
// PROTOTYPES // |
//----------------------------------------------------------------------------------// |
void AdjustMenuStates(void); |
void AlertUser(short error); |
void CloseTheWindow(WindowPtr window); |
WindowPtr DoCreateNewWindow(WindowPtr behind); |
OSErr CreateWindowObjectSpec(WindowPtr window,short formType,AEDesc *objectSpec); |
void DoEvent(EventRecord *event); |
void DoGrowWindow(WindowPtr window, EventRecord *event); |
void DoMenuCommand(long menuResult); |
OSErr DoSetData(AEDesc *token, AEDesc *data); |
void DoUpdate(WindowPtr window); |
void EventLoop(void); |
void FailIfErr(OSErr error); |
OSErr FindRelativeWindow(WindowPtr *window,AEDesc *object,DescType pos,WindowPtr *replaceWindow); |
OSErr GetAppData(DescType theProperty, AEDesc *result); |
OSErr GetMissingParams(AppleEvent *theAppleEvent); |
OSErr GetWindowData(DescType property, WindowPtr window, AEDesc *result); |
long GetWindowIndexNum(WindowPtr window); |
WindowPtr GetWindowAtIndex(long index); |
WindowPtr GetWindowWithTitle(ConstStr255Param title); |
void InitAEHandlers(void); |
void Initialize(void); |
Boolean IsAppWindow(WindowPtr window); |
Boolean IsDAWindow(WindowPtr window); |
Boolean IsTrapAvailable(short tNumber, TrapType tType); |
void ReportError(AppleEvent *reply, long err); |
WindowPtr ResolveToWindow(AEDesc *objectSpecifier); |
void SendClose(WindowPtr window); |
void SendCreateElement(void); |
void SendMoveEvent(WindowPtr windowToMove, long index); |
void SendQuitApp(void); |
void SendSetData(AEDesc *pDesc, AEDesc *pData, AEDesc *object); |
void SetUpPropertyData(WindowPtr window,DescType propType,DescType dataType,Size dataSize); |
void SignalError(short error); |
void Terminate(void); |
void ZoomIt(WindowPtr window, short part); |
Rect DoGetWindowBounds(WindowPtr window); |
void MakeNewWindowTitle( short num, // Window number. |
Str255 title); |
void MyInitDescs(AEDesc* desc1, ... ); |
void MyDisposeDescs(AEDesc* desc1, ... ); |
OSErr DescToBoolean(const AEDesc* desc, Boolean* boolvalue); |
OSErr DescToLong(const AEDesc* desc, long* longvalue); |
OSErr DescToPString(const AEDesc* desc, Str255 str, short maxLength); |
pascal OSErr HandleOpenApp(AppleEvent *theAppleEvent, AppleEvent* reply, long refCon); |
pascal OSErr HandleQuitApp(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon); |
WindowPtr DoCloneWindow(WindowPtr windowToClone, WindowPtr behindWindow); |
pascal OSErr HandleClone(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon); |
pascal OSErr HandleClose(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon); |
pascal OSErr HandleCountElements(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon); |
pascal OSErr HandleCreateElement(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon); |
pascal OSErr HandleDoObjectsExist(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon); |
pascal OSErr HandleSetData(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon); |
pascal OSErr HandleGetData( AppleEvent* theAppleEvent, |
AppleEvent* reply, |
long refCon ); |
pascal OSErr HandleMove(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon); |
pascal OSErr DummyHandler( AppleEvent *theAppleEvent, |
AppleEvent *reply, |
long refCon ); |
pascal OSErr WindowAccessor( DescType classWanted, // window class |
AEDesc* container, // the application (null container) |
DescType containerClass, |
DescType keyform, |
AEDesc* selectionData, |
AEDesc* resultToken, // specified window is returned in result |
long theRefCon ); |
pascal OSErr WindowPropertyAccessor( DescType classWanted, // Property class |
AEDesc* container, // Window object |
DescType containerClass, |
DescType form, |
AEDesc* selectionData, |
AEDesc* resultToken, |
long theRefCon ); |
pascal OSErr AppPropertyAccessor( DescType classWanted, // Property class. |
AEDesc* container, // Application. |
DescType containerClass, |
DescType form, |
AEDesc* selectionData, |
AEDesc* resultToken, |
long theRefCon ); |
extern pascal OSErr CreateObjSpecifier(DescType theClass, AEDesc *theContainer, |
DescType keyForm, AEDesc *keyData, Boolean disposeInputs, |
AEDesc *objSpecifier); |
extern void _DataInit(); |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void main() |
{ |
#ifndef THINK_C |
UnloadSeg((Ptr) _DataInit); // Note that _DataInit must not be in Main! |
#endif |
MaxApplZone(); // Expand the heap so code segments load at the top. |
Initialize(); // Initialize the program |
#ifndef THINK_C // Initialize the program |
UnloadSeg((Ptr)Initialize); // Note that Initialize must not be in Main! |
#endif |
EventLoop(); // Call the main event loop |
} |
//----------------------------------------------------------------------------------// |
// Continue retrieving events until the application terminates. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void EventLoop() |
{ |
RgnHandle cursorRgn; |
Boolean gotEvent; |
EventRecord event; |
cursorRgn = NewRgn(); |
gQuitApp = false; // This is set to true in Terminate(). |
while (!gQuitApp) // Loop until user quits or error. |
{ |
if (gHasWaitNextEvent) |
gotEvent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursorRgn); |
else |
{ |
SystemTask(); |
gotEvent = GetNextEvent(everyEvent, &event); |
} |
if (gotEvent) |
DoEvent(&event); |
} |
} |
//----------------------------------------------------------------------------------// |
// Find out which event this is and send it off to its appropriate handler. // |
// When the user clicks in the drag region, either one of two events may be // |
// triggered. The set position property (set data event) would occur if the widnow // |
// is dragged to another location, or the move event would be sent if the window // |
// is just made active. In the latter case, the window's index before being // |
// moved to the front is passed to SendMoveEvent for recording purposes. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void DoEvent( EventRecord* event ) |
{ |
long index=0; |
short part, err; |
WindowPtr window; |
char key; |
Rect bounds1, bounds2; |
Point aPoint; |
switch (event->what) |
{ |
case mouseDown: |
part = FindWindow(event->where, &window); |
switch (part) |
{ |
case inMenuBar: |
AdjustMenuStates(); |
DoMenuCommand(MenuSelect(event->where)); |
break; |
case inSysWindow: |
SystemClick(event, window); |
break; |
case inContent: |
if (window != FrontWindow()) |
SendMoveEvent(window, index); |
break; |
case inDrag: |
index = GetWindowIndexNum(window); |
bounds1 = (*((WindowPeek)window)->contRgn)->rgnBBox; |
DragWindow(window, event->where, &qd.screenBits.bounds); |
bounds2 = (*((WindowPeek)window)->contRgn)->rgnBBox; |
if ((bounds1.left == bounds2.left) && |
(bounds1.top == bounds2.top)) |
SendMoveEvent(GetWindowAtIndex(index), index); |
else |
SetUpPropertyData(window,pPosition,typeQDPoint,sizeof(Point)); |
break; |
case inGoAway: |
if (TrackGoAway(window, event->where)) |
SendClose(window); |
break; |
case inGrow: |
DoGrowWindow(window, event); |
break; |
case inZoomIn: // For recording purposes, we send an Apple |
case inZoomOut: // event to ourselves to set the bounds property. |
if (TrackBox(window, event->where, part)) |
{ |
ZoomIt(window, part); |
SetUpPropertyData(window, pIsZoomed, typeBoolean, sizeof(Boolean)); |
} |
break; |
} |
break; |
case keyDown: |
case autoKey: // Only handle menu key equivalents |
key = event->message & charCodeMask; |
if (event->modifiers & cmdKey) // Command key down |
{ |
if (event->what == keyDown) |
{ |
AdjustMenuStates(); // Enable/disable/check menu items properly |
DoMenuCommand(MenuKey(key)); |
} |
} |
break; |
case activateEvt: |
DrawGrowIcon((WindowPtr)event->message); |
break; |
case updateEvt: |
DoUpdate((WindowPtr) event->message); |
break; |
case diskEvt: |
if (HiWord(event->message) != noErr) |
{ |
SetPt(&aPoint, kDILeft, kDITop); |
err = DIBadMount(aPoint, event->message); |
} |
break; |
case kOSEvent: |
{ |
switch ((event->message >> 24) & 0x0FF) // High byte of message. |
{ |
case kMouseMovedMessage: |
break; // Do nothing if mouse moved. |
case kSuspendResumeMessage: // suspend/resume is also an activate/deactivate |
SetCursor(&qd.arrow); |
if (IsAppWindow(window = FrontWindow())) |
DrawGrowIcon(window); |
break; |
} |
} |
break; |
case kHighLevelEvent: // Let the Apple Event Manager handle high level event. |
AEProcessAppleEvent(event); |
break; |
default: |
break; |
} |
} |
//----------------------------------------------------------------------------------// |
// Handle the mouseDown event in the grow box region of the window. If the // |
// window has been resized, an Apple Event is sent to set the bounds property. // |
// This is done for recording purposes. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void DoGrowWindow( WindowPtr window, |
EventRecord* event ) |
{ |
long result; |
Rect tempRect; |
tempRect = qd.screenBits.bounds; // Set up the limiting values. |
tempRect.top = kMinWinDim; |
tempRect.left = kMinWinDim; |
result = GrowWindow(window, event->where, &tempRect); |
if (result) // Did window actually change size? |
{ |
SetPort(window); |
InvalRect(&window->portRect); |
SizeWindow(window, LoWrd(result), HiWrd(result), true); |
InvalRect(&window->portRect); // Send event for recording purposes. |
SetUpPropertyData(window, pBounds, typeQDRectangle, sizeof(Rect)); |
} |
} |
//----------------------------------------------------------------------------------// |
// Zoom the window and set the refcon field to reflect its zoomed state. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void ZoomIt( WindowPtr window, |
short part ) |
{ |
SetPort(window); |
EraseRect(&window->portRect); // We just have a blank window. |
ZoomWindow(window, part, window == FrontWindow()); |
SetWRefCon(window, (long)part == inZoomOut); // Set to true if zoomed. |
InvalRect(&window->portRect); |
} |
//----------------------------------------------------------------------------------// |
// This is called when an update event is received for a window. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void DoUpdate( WindowPtr window ) |
{ |
if (IsAppWindow(window)) |
{ |
BeginUpdate(window); |
SetPort(window); |
EraseRect(&window->portRect); // We just have an empty window. |
DrawGrowIcon(window); |
EndUpdate(window); |
} |
} |
//----------------------------------------------------------------------------------// |
// Set up the menus according to the current state. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void AdjustMenuStates() |
{ |
WindowPtr window; |
MenuHandle menu; |
window = FrontWindow(); |
menu = GetMenuHandle(mFile); |
if (gNumWindowsOpen < kMaxOpenWindows) |
EnableItem(menu, iNew); // Enable New if we can open more windows. |
else |
DisableItem(menu, iNew); |
if (window) |
EnableItem(menu, iClose); // Enable Close if there is a window to close. |
else |
DisableItem(menu, iClose); |
} |
//----------------------------------------------------------------------------------// |
// This is called when an item is chosen from the menu bar. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void DoMenuCommand(long menuResult) |
{ |
short menuID, menuItem; |
short itemHit, daRefNum; |
Str255 daName; |
WindowPtr window; |
window = FrontWindow(); |
menuID = HiWord(menuResult); |
menuItem = LoWord(menuResult); |
switch (menuID) |
{ |
case mApple: |
switch (menuItem) |
{ |
case iAbout: |
itemHit = Alert(rAboutAlert, nil); |
break; |
default: // all other items in this menu are DA's. |
GetMenuItemText(GetMenuHandle(mApple), menuItem, daName); |
daRefNum = OpenDeskAcc(daName); |
break; |
} |
break; |
case mFile: |
switch (menuItem) // All these items send Apple events to |
{ // handle the selection. |
case iNew: |
SendCreateElement(); |
break; |
case iClose: |
SendClose(FrontWindow()); |
break; |
case iQuit: |
SendQuitApp(); |
break; |
} |
break; |
case mEdit: // Call SystemEdit for DA editing & MultiFinder. |
SystemEdit(menuItem-1); |
break; |
} |
HiliteMenu(0); // Unhighlight what MenuSelect (or MenuKey) hilited. |
} |
//----------------------------------------------------------------------------------// |
// This routine appends the ascii representation of num to the title string. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void MakeNewWindowTitle( short num, // Window number. |
Str255 title) // Window title. |
{ |
short i, count, index; |
char numStr[5]; |
i = 0; |
do { |
numStr[i++] = num % 10 + '0'; |
} while (num /= 10); |
index = title[0] + 1; // Get length of title string. |
for (count = i-1; count >= 0; count--) |
title[index++] = numStr[count]; |
title[0] += i; |
} |
//----------------------------------------------------------------------------------// |
// Create a new window behind the given window. Use the window's refCon // |
// field to indicate whether the window is zoomed or not. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
WindowPtr DoCreateNewWindow(WindowPtr behindWindow) |
{ |
Ptr storage; |
WindowPtr newWindow, firstWindow; |
Rect bounds; |
Str255 title; |
if (gNumWindowsOpen < kMaxOpenWindows) |
{ |
storage = NewPtr(sizeof(WindowRecord)); |
if (storage != nil) |
{ |
newWindow = GetNewWindow(rDocWindow, storage, behindWindow); |
if (newWindow != nil) |
{ |
gNumWindowsOpen++; // Increment the number of windows currently open. |
gNewWindows++; // Increment the number of new windows created. |
GetWTitle(newWindow, title); |
MakeNewWindowTitle(gNewWindows, title); |
SetWTitle(newWindow, title); |
if (firstWindow = FrontWindow()) |
{ |
//¥¥¥ bounds = (*((WindowPeek)firstWindow)->contRgn)->rgnBBox; |
bounds = DoGetWindowBounds(firstWindow); |
MoveWindow(newWindow, bounds.left+30, bounds.top+30, false); |
} |
SetWRefCon(newWindow, 0L); // set zoom state to false. |
SetPort(newWindow); |
return(newWindow); |
} |
else |
DisposePtr(storage); // Dispose of the storage if it is not used. |
} |
} |
return(nil); |
} |
//----------------------------------------------------------------------------------// |
// Close the given window or desk accessory. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void CloseTheWindow(WindowPtr window) |
{ |
if (IsDAWindow(window)) |
CloseDeskAcc(((WindowPeek)window)->windowKind); |
else |
if (IsAppWindow(window)) |
{ |
CloseWindow(window); |
DisposePtr((Ptr)window); |
gNumWindowsOpen--; |
} |
} |
//----------------------------------------------------------------------------------// |
// Returns true if the window belongs to this application, else false. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
Boolean IsAppWindow(WindowPtr window) |
{ |
if (!window) |
return(false); |
else |
return(((WindowPeek)window)->windowKind == userKind); |
} |
//----------------------------------------------------------------------------------// |
// Returns true if the given window belongs to a DA, else false is returned. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
Boolean IsDAWindow(WindowPtr window) |
{ |
if (window == nil) |
return(false); |
else // DA windows have negative windowKinds. |
return(((WindowPeek)window)->windowKind < 0); |
} |
//----------------------------------------------------------------------------------// |
// If an error has occurred, I check the user interaction level. If I can // |
// interact with the user, I put up a dialog and exit the application; otherwise, // |
// I just exit the application. // |
// // |
// ***NOTE: Real applications would not handle errors in this fashion! If they // |
// cannot interact with the user, they should abort the Apple event handler and // |
// return the error in the reply parameter. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void FailIfErr(OSErr error) |
{ |
if (error) |
{ |
if (!(AEInteractWithUser(kNoTimeOut, nil, nil))) // Can we interact? |
AlertUser(eAEError); // Yes, so put up the dialog. |
ExitToShell(); |
} |
} |
//----------------------------------------------------------------------------------// |
// Display an alert for the user to indicate that an error has occurred. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void AlertUser(short error) |
{ |
short itemHit; |
Str255 message; |
GetIndString(message, kErrStrings, error); |
ParamText(message, (ConstStr255Param)"\p", (ConstStr255Param)"\p", (ConstStr255Param)"\p"); // [pwpc] |
itemHit = Alert(rUserAlert, nil); |
} |
//----------------------------------------------------------------------------------// |
// Quit the application by closing all windows and setting the quit flag to true. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void Terminate() |
{ |
WindowPtr aWindow; |
while(aWindow = FrontWindow()) |
CloseTheWindow(aWindow); |
AEDisposeDesc(&gSelfAddress); // Dispose of my self-addressed descriptor. |
gQuitApp = true; |
} |
//----------------------------------------------------------------------------------// |
// Perform the initialization necessary at start-up time. Note that we use // |
// kCurrentProcess in our psn rather than calling GetCurrentProcess. Using // |
// kCurrentProcess will allow us to record those events we send to ourselves, // |
// otherwise, the recorder won't recognize the psn and won't record our event! // |
//----------------------------------------------------------------------------------// |
#pragma segment Initialize |
void Initialize() |
{ |
Handle menuBar; |
long total, contig; |
EventRecord event; |
short count; |
gInBackground = false; |
InitGraf((Ptr)&qd.thePort); |
InitWindows(); |
InitMenus(); |
InitDialogs(nil); |
InitCursor(); |
InitAEHandlers(); |
for (count = 1; count <= 3; count++) |
EventAvail(everyEvent, &event); |
SysEnvirons(kSysEnvironsVersion, &gMac); |
if (gMac.machineType < 0) |
SignalError(eWrongMachine); // Less than 128K ROM's. |
gHasWaitNextEvent = IsTrapAvailable(_WaitNextEvent, ToolTrap); |
if ((long)GetApplLimit() - (long)ApplicationZone() < kMinHeap) |
SignalError(eSmallSize); |
PurgeSpace(&total, &contig); |
if (total < kMinSpace) |
if (UnloadScrap() != noErr) |
SignalError(eNoMemory); |
else |
{ |
PurgeSpace(&total, &contig); |
if (total < kMinSpace) |
SignalError(eNoMemory); |
} |
if (!(menuBar = GetNewMBar(rMenuBar))) // Set up menu bar. |
SignalError(eNoMemory); |
SetMenuBar(menuBar); |
DisposeHandle(menuBar); |
AppendResMenu(GetMenuHandle(mApple), 'DRVR'); // Add DA's to menu. |
DrawMenuBar(); |
// Set up the self-addressed descriptor record. |
gSelfPSN.highLongOfPSN = 0; |
gSelfPSN.lowLongOfPSN = kCurrentProcess; //* Use this instead of GetCurrentProcess *// |
FailIfErr(AECreateDesc(typeProcessSerialNumber,(Ptr)&gSelfPSN,sizeof(ProcessSerialNumber),&gSelfAddress)); |
gNullDesc.descriptorType = typeNull; // Initialize the global null descriptor record. |
gNullDesc.dataHandle = nil; |
gRefNum = CurResFile(); |
gNumWindowsOpen = 0; |
gNewWindows = 0; |
} |
//----------------------------------------------------------------------------------// |
// Returns true if the given trap number is implemented, else returns false. // |
//----------------------------------------------------------------------------------// |
#pragma segment Initialize |
Boolean IsTrapAvailable(short trapNum, TrapType tType) |
{ |
if ((tType == (unsigned char)ToolTrap) && (gMac.machineType > envMachUnknown) && |
(gMac.machineType < envMacII)) |
{ // it's a 512K, Plus, or SE |
trapNum = trapNum & 0x03FF; |
if (trapNum > 0x01FF) // which means the tool traps |
trapNum = _Unimplemented; // only go to 0x01FF |
} |
return(NGetTrapAddress(trapNum, tType) != GetToolTrapAddress(_Unimplemented)); // [pwpc] |
} |
//----------------------------------------------------------------------------------// |
#pragma segment Initialize |
void SignalError(short error) |
{ |
AlertUser(error); |
ExitToShell(); |
} |
//**********************************************************************************// |
// * Apple Events and Object Model Support * // |
//**********************************************************************************// |
//----------------------------------------------------------------------------------// |
// Initializes all descriptor records passed in to this routine. The variable // |
// argument list is null terminated. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void MyInitDescs(AEDesc* desc1, ... ) // Variable, null terminated argument list. |
{ |
va_list argptr; // pointer to each argument in list. |
AEDesc* nextDesc; // next descriptor argument in list. |
va_start(argptr, desc1); |
desc1->descriptorType = typeNull; |
desc1->dataHandle = nil; |
while(nextDesc = va_arg(argptr, AEDesc *)) |
{ |
nextDesc->descriptorType = typeNull; |
nextDesc->dataHandle = nil; |
} |
va_end(argptr); |
} |
//----------------------------------------------------------------------------------// |
// Dispose all descriptor records passed into this routine. (Variable arg. list). // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void MyDisposeDescs(AEDesc* desc1, ... ) // Null terminated argument list. |
{ |
va_list argptr; // pointer to each argument in list. |
AEDesc* nextDesc; // descriptor argument in list. |
va_start(argptr, desc1); |
if (desc1->dataHandle) |
AEDisposeDesc(desc1); |
while(nextDesc = va_arg(argptr, AEDesc *)) |
{ |
if (nextDesc->dataHandle) |
AEDisposeDesc(nextDesc); |
} |
va_end(argptr); |
} |
//----------------------------------------------------------------------------------// |
// Converts a descriptor to a boolean. // |
//----------------------------------------------------------------------------------// |
#pragma segment AppleEvents |
OSErr DescToBoolean(const AEDesc* desc, Boolean* boolvalue) |
{ |
AEDesc tempDesc; |
Handle dataHandle; |
tempDesc.dataHandle = nil; |
if (desc->descriptorType == typeBoolean) |
dataHandle = desc->dataHandle; |
else |
if (AECoerceDesc(desc, typeBoolean, &tempDesc) == noErr) |
dataHandle = tempDesc.dataHandle; |
else |
return(errAECoercionFail); |
*boolvalue = **dataHandle; |
MyDisposeDescs(&tempDesc, kEndOfList); |
return(noErr); |
} |
//----------------------------------------------------------------------------------// |
// Converts a descriptor to a long. // |
//----------------------------------------------------------------------------------// |
#pragma segment AppleEvents |
OSErr DescToLong(const AEDesc* desc, long* longvalue) |
{ |
AEDesc tempDesc; |
Handle dataHandle; |
tempDesc.dataHandle = nil; |
if (desc->descriptorType == typeLongInteger) |
dataHandle = desc->dataHandle; |
else |
if (AECoerceDesc(desc, typeLongInteger, &tempDesc) == noErr) |
dataHandle = tempDesc.dataHandle; |
else |
return(errAECoercionFail); |
*longvalue = *(LongPtr)*dataHandle; |
MyDisposeDescs(&tempDesc, kEndOfList); |
return(noErr); |
} |
//----------------------------------------------------------------------------------// |
// Converts a descriptor to a pascal string. // |
//----------------------------------------------------------------------------------// |
#pragma segment AppleEvents |
OSErr DescToPString(const AEDesc* desc, Str255 str, short maxLength) |
{ |
AEDesc tempDesc; |
Handle dataHandle; |
long charCount; |
tempDesc.dataHandle = nil; |
if (desc->descriptorType == typeChar) |
dataHandle = desc->dataHandle; |
else |
if (AECoerceDesc(desc, typeChar, &tempDesc) == noErr) |
dataHandle = tempDesc.dataHandle; |
else |
return(errAECoercionFail); |
charCount = GetHandleSize(dataHandle); |
if (charCount > maxLength) |
{ |
MyDisposeDescs(&tempDesc, kEndOfList); |
return(errAECoercionFail); |
} |
str[0] = charCount; |
HLock(dataHandle); |
BlockMove(*dataHandle, &str[1], charCount); |
HUnlock(dataHandle); // This may be from desc, so must unlock. |
MyDisposeDescs(&tempDesc, kEndOfList); |
return(noErr); |
} |
//----------------------------------------------------------------------------------// |
// Create the first window in response to the Open Application Apple Event. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr HandleOpenApp(AppleEvent *theAppleEvent, AppleEvent* reply, long refCon) |
{ |
#pragma unused (reply,refCon) |
WindowPtr window; |
OSErr err; |
if (!(err = GetMissingParams(theAppleEvent))) // Error if any parameters. |
{ |
if (window = DoCreateNewWindow((WindowPtr)-1)) // Create initial window |
ShowWindow(window); |
else |
err = errAEEventNotHandled; |
} |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// Send a Quit Application Apple Event to myself to terminate this app. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void SendQuitApp() |
{ |
AppleEvent myAppleEvent, reply; |
// Create the Apple Event. |
FailIfErr(AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &gSelfAddress, |
kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent)); |
// Send the Apple Event. |
FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAENeverInteract, kAENormalPriority, |
kAEDefaultTimeout, nil, nil)); |
AEDisposeDesc(&myAppleEvent); // Dispose of the Apple Event. |
} |
//----------------------------------------------------------------------------------// |
// Quit the application. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr HandleQuitApp(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon) |
{ |
#pragma unused (reply,refCon) |
OSErr err; |
if (!(err = GetMissingParams(theAppleEvent))) // Error if there are any parameters. |
Terminate(); |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// This routine makes a clone of the given window by copying its bounds, zoom // |
// state, and title (with the addition of "copy") properties. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
WindowPtr DoCloneWindow(WindowPtr windowToClone, WindowPtr behindWindow) |
{ |
WindowPtr clonedWindow; |
Rect bounds; |
Str255 title; |
if (clonedWindow = DoCreateNewWindow(behindWindow)) |
{ |
GetWTitle(windowToClone, title); |
p2cstr(title); |
strcat((char *)title, " copy\0"); |
c2pstr((char *)title); |
bounds = DoGetWindowBounds(windowToClone); |
SetWTitle(clonedWindow, title); |
MoveWindow(clonedWindow, bounds.left, bounds.top, false); |
SizeWindow(clonedWindow, bounds.right-bounds.left, bounds.bottom-bounds.top, true); |
SetWRefCon(clonedWindow, GetWRefCon(windowToClone)); |
return(clonedWindow); |
} |
return(nil); |
} |
//----------------------------------------------------------------------------------// |
// Handle the Clone Apple Event and create a clone of the given object. To clone // |
// a window, I clone its bounds, zoom state, and visible properties. In addition, // |
// I clone the window's title and append " copy" to it for the cloned window's // |
// title. If the insertion location parameter is not in the event record, I // |
// perform the default behavior, which is to position the clone behind the // |
// window being cloned. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr HandleClone(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon) |
{ |
#pragma unused (refCon) |
AEDesc cloneObject, windowObject, replyObject, insertionLoc; |
AERecord insertionRec; |
DescType theType, position; |
WindowPtr windowToClone, window, rplcWindow, behindWindow = nil; |
Size paramSize; |
OSErr err = noErr; |
MyInitDescs(&cloneObject,&windowObject,&replyObject,&insertionLoc,&insertionRec,kEndOfList); |
// Let's get the direct object, the object to clone. |
if (err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &cloneObject)) |
goto myExit; |
if (!(windowToClone = ResolveToWindow(&cloneObject))) |
{ |
err = errAENoSuchObject; |
goto myExit; |
} |
else // we have a window to clone. |
{ |
if (!(err = AEGetParamDesc(theAppleEvent,keyAEInsertHere,typeInsertionLoc,&insertionLoc))) |
if (!(err = AECoerceDesc(&insertionLoc, typeAERecord, &insertionRec))) |
// Get object as typeWildCard because it may be null or an object specifier. |
if (!(err = AEGetKeyDesc(&insertionRec, keyAEObject, typeWildCard, &windowObject))) |
if (!(err = AEGetKeyPtr(&insertionRec,keyAEPosition,typeEnumeration,&theType, |
(Ptr)&position,sizeof(DescType),¶mSize))) |
err = FindRelativeWindow(&behindWindow, &windowObject, position, &rplcWindow); |
if (err) |
if (err == errAEDescNotFound) |
behindWindow = windowToClone; // Registry's default behavior. |
else |
goto myExit; |
} |
if (window = DoCloneWindow(windowToClone, behindWindow)) |
{ |
if (((WindowPeek)windowToClone)->visible) |
ShowWindow(window); |
if (position == kAEReplace) |
CloseTheWindow(rplcWindow); |
if (reply->dataHandle != nil) |
{ |
CreateWindowObjectSpec(window, kIndexKeyForm, &replyObject); |
err = AEPutParamDesc(reply, keyAEResult, &replyObject); |
} |
} |
else |
err = errAEEventNotHandled; |
myExit: |
MyDisposeDescs(&cloneObject,&windowObject,&replyObject,&insertionLoc,&insertionRec,kEndOfList); |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// Send a Close Apple Event to myself to close the specified window. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void SendClose(WindowPtr window) |
{ |
AppleEvent myAppleEvent, reply; |
AEDesc windowObject; // The window object specifier. |
// Create the Close Apple Event. |
FailIfErr(AECreateAppleEvent(kAECoreSuite, kAEClose, &gSelfAddress, kAutoGenerateReturnID, |
kAnyTransactionID, &myAppleEvent)); |
// Create the window object specifier and add this to myAppleEvent. |
CreateWindowObjectSpec(window, kIndexKeyForm, &windowObject); |
FailIfErr(AEPutParamDesc(&myAppleEvent, keyDirectObject, &windowObject)); |
// Send the Apple Event. |
FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract, kAENormalPriority, |
kAEDefaultTimeout, nil, nil)); |
// Now dispose of the AppleEvent and object specifier. |
AEDisposeDesc(&myAppleEvent); |
AEDisposeDesc(&windowObject); |
} |
//----------------------------------------------------------------------------------// |
// Respond to the Close Apple Event by closing the specified window object. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr HandleClose(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon) |
{ |
#pragma unused (reply,refCon) |
AEDesc windowObject; |
WindowPtr windowToClose; |
OSErr myErr; |
MyInitDescs(&windowObject,kEndOfList); |
// First, get the direct object which is the object to close. |
myErr = AEGetParamDesc(theAppleEvent,keyDirectObject,typeObjectSpecifier,&windowObject); |
if (!myErr && !(myErr = GetMissingParams(theAppleEvent))) |
{ |
if (windowToClose = ResolveToWindow(&windowObject)) |
CloseTheWindow(windowToClose); |
else |
myErr = errAENoSuchObject; |
} |
MyDisposeDescs(&windowObject,kEndOfList); |
return(myErr); |
} |
//----------------------------------------------------------------------------------// |
// Respond to the Count Elements Apple Event. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr HandleCountElements(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon) |
{ |
#pragma unused (refCon) |
AEDesc directObject; |
DescType theType, theClass; |
Size paramSize; |
OSErr err; |
MyInitDescs(&directObject, kEndOfList); |
// Get the direct object, should be null. |
if (!(err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, &directObject))) |
if (!(err = AEGetParamPtr(theAppleEvent,keyAEObjectClass,typeType,&theType,(Ptr)&theClass, |
sizeof(DescType),¶mSize))) // Get class of elements to count. |
err = GetMissingParams(theAppleEvent); // Error if more parameters. |
if (err) |
goto myExit; |
// If we had a deeper object hierarchy, we'd probably call AEResolve here, but... |
// we only handle the window class contained within the null object. |
if (theClass == cWindow && directObject.descriptorType == typeNull) |
err = AEPutParamPtr(reply, keyAEResult, typeLongInteger, (Ptr)&gNumWindowsOpen, sizeof(long)); |
myExit: |
MyDisposeDescs(&directObject, kEndOfList); |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// Send a Create Element Apple Event to myself to create a new window. By default, // |
// I am setting the position to the beginning of the null container (frontmost). // |
// In this case, as well as at the end of the container, the object parameter is // |
// the null container. If the position is before, after, or replace, the object // |
// parameter must be an object specifier to indicate the relative window. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void SendCreateElement() |
{ |
AppleEvent myAppleEvent, reply; |
AERecord insertionRec; // Insertion Loc record. |
AEDesc insertionLoc; // The coerced insertionRec. |
DescType theType; |
// Create the Apple Event. |
FailIfErr(AECreateAppleEvent(kAECoreSuite, kAECreateElement, &gSelfAddress, kAutoGenerateReturnID, |
kAnyTransactionID, &myAppleEvent)); |
// Attach the class of the new element, which in this case is cWindow. |
theType = cWindow; |
FailIfErr(AEPutParamPtr(&myAppleEvent, keyAEObjectClass, typeType, (Ptr)&theType, sizeof(DescType))); |
// Create insertion loc, object is null container and position is beginning. |
FailIfErr(AECreateList(nil, 0, true, &insertionRec)); // Create an AE Record. |
theType = kAEBeginning; |
FailIfErr(AEPutKeyDesc(&insertionRec, keyAEObject, &gNullDesc)); |
FailIfErr(AEPutKeyPtr(&insertionRec, keyAEPosition, typeEnumeration, (Ptr)&theType, sizeof(DescType))); |
FailIfErr(AECoerceDesc(&insertionRec, typeInsertionLoc, &insertionLoc)); |
// Now add the insertion location descriptor record to the Apple Event. |
FailIfErr(AEPutParamDesc(&myAppleEvent, keyAEInsertHere, &insertionLoc)); |
// Send the Apple Event. |
FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract, kAENormalPriority, |
kAEDefaultTimeout, nil, nil)); |
// Now dispose of the AppleEvent and other records. |
MyDisposeDescs(&myAppleEvent, &insertionRec, &insertionLoc, kEndOfList); |
} |
//----------------------------------------------------------------------------------// |
// Respond to the Create Element Apple event and create a new window. For this // |
// application, the keyAEInsertHere parameter is optional. If this parameter is // |
// not present, a new window is created in the frontmost position. // |
// This routine also handles the optional initial data parameters (keyAEData and // |
// keyAEPropData) if they are present. A window object specifier must be in the // |
// keyAEData parameter, which is essentially used to make a clone. If the // |
// property data exists, these properties will override those previously set. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr HandleCreateElement(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon) |
{ |
#pragma unused (refCon) |
AEDesc windowObject, dataObject, propData, propObject, replyObject; |
AEDesc insLocParam; |
AERecord insLocRec; |
AERecord dataPropParam; // Initial data parameters. |
AEKeyword keyWord; // Property id code for PropData. |
DescType theType, theClass, position; |
WindowPtr window, relativeWindow, dataWindow, rplcWindow; |
Rect bounds; |
Size theSize; |
Str255 buffer; |
long numItems; |
short i; |
Boolean isVisible; |
OSErr err; |
if (err = AEGetParamPtr(theAppleEvent, keyAEObjectClass, typeType, &theType, (Ptr)&theClass, |
sizeof(DescType), &theSize)) |
return(err); |
if (theClass != cWindow) // We only handle elements of the class cWindow. |
return(errAEEventNotHandled); |
position = typeNull; |
MyInitDescs(&windowObject,&dataObject,&propData,&propObject,&insLocParam,&dataPropParam,&replyObject,&insLocRec,kEndOfList); |
// Now get the insertion location record as an AERecord, if it exists. |
if (!(err = AEGetParamDesc(theAppleEvent, keyAEInsertHere, typeInsertionLoc, &insLocParam))) |
{ // coerce the insertion loc record to an AE record. |
err = AECoerceDesc(&insLocParam, typeAERecord, &insLocRec); |
// Get the object as typeWildCard because it may be a null descriptor or an object. |
if (!(err = AEGetKeyDesc(&insLocRec, keyAEObject, typeWildCard, &windowObject))) |
if (!(err = AEGetKeyPtr(&insLocRec, keyAEPosition, typeEnumeration, &theType, (Ptr)&position, |
sizeof(DescType), &theSize))) |
{ |
relativeWindow = nil; |
err = FindRelativeWindow(&relativeWindow, &windowObject, position, &rplcWindow); |
} |
} |
else |
if (err == errAEDescNotFound) // No insertion loc, make it frontmost by default. |
{ |
relativeWindow = (WindowPtr)-1; |
position = kAEBeginning; |
err = noErr; // Not an error for me because I make this param optional. |
} |
if (err) |
goto myExit; |
// Check if optional data parameter is present. |
if (!(err = AEGetParamDesc(theAppleEvent,keyAEData,typeObjectSpecifier,&dataObject))) |
{ |
if (dataWindow = ResolveToWindow(&dataObject)) |
{ |
window = DoCloneWindow(dataWindow, relativeWindow); |
isVisible = ((WindowPeek)dataWindow)->visible; |
} |
else |
{ |
err = errAENoSuchObject; |
goto myExit; |
} |
} |
else |
if (err == errAEDescNotFound) // The optional data parameter is not present. |
{ |
if (window = DoCreateNewWindow(relativeWindow)) |
{ |
err = noErr; |
isVisible = true; |
if (position == kAEReplace) // Replace the window in the right position. |
{ |
bounds = DoGetWindowBounds(rplcWindow); |
MoveWindow(window, bounds.left, bounds.top, false); |
} |
} |
else |
{ |
err = errAEEventNotHandled; // couldn't create a new window. |
goto myExit; |
} |
} |
else |
goto myExit; |
if (isVisible) // We set the visibility here because it may be changed |
ShowWindow(window); // by the following property data. |
// Handle PropData parameter if it exists. |
if (!(err = AEGetParamDesc(theAppleEvent,keyAEPropData,typeAERecord,&dataPropParam))) |
{ |
AECountItems(&dataPropParam, &numItems); |
for (i = 1; i <= numItems; i++) |
{ |
if (!(err = AEGetNthPtr(&dataPropParam,i,typeWildCard,&keyWord,&theType,&buffer,sizeof(Str255),&theSize))) |
{ |
AECreateDesc(keyWord, (Ptr)&window, sizeof(Ptr), &propObject); |
AECreateDesc(theType, (Ptr)&buffer, theSize, &propData); |
err = DoSetData(&propObject, &propData); |
AEDisposeDesc(&propObject); |
AEDisposeDesc(&propData); |
if (err) |
break; |
} |
} |
} |
if (!err || err == errAEDescNotFound) |
{ |
if (position == kAEReplace) |
CloseTheWindow(rplcWindow); |
err = noErr; |
if (reply->dataHandle != nil) |
{ |
CreateWindowObjectSpec(window, kIndexKeyForm, &replyObject); |
err = AEPutParamDesc(reply, keyAEResult, &replyObject); |
} |
} |
myExit: |
MyDisposeDescs(&windowObject,&dataObject,&propData,&propObject,&insLocParam,&dataPropParam,&replyObject,&insLocRec,kEndOfList); |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// Respond to the Do Objects Exist AE by attempting to resolve the object specifier// |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr HandleDoObjectsExist(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon) |
{ |
#pragma unused (reply,refCon) |
AEDesc target, token; |
Boolean exists; |
OSErr err; |
MyInitDescs(&target, &token, kEndOfList); |
if (!(err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, &target))) |
if (!(err = GetMissingParams(theAppleEvent))) // Check for missing params. |
{ |
exists = true; |
token.descriptorType = typeNull; |
if (target.descriptorType != typeNull) |
exists = (AEResolve(&target, kAEIDoMinimum, &token) == noErr); |
// Add data to the reply Apple event record. |
err = AEPutParamPtr(reply, keyDirectObject,typeBoolean,(Ptr)&exists,sizeof(Boolean)); |
} |
myExit: |
MyDisposeDescs(&target, &token, kEndOfList); |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// Send the Set Data Apple Event with the object, property, and property data. // |
// *NOTE*: I am sending myself the Set Data event in response to user interaction. // |
// These actions have already occurred by this time, so I am sending the event // |
// with the "don't execute" flag set for "smart" recorders. A "smart" recorder // |
// would check this flag when it intercepts the Apple event, and if it was set, // |
// it wouldn't pass the event to the application. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void SendSetData( AEDesc* propDesc, // the property to set |
AEDesc* propData, // the property data |
AEDesc* target ) // object to set property of |
{ |
AppleEvent myAppleEvent, reply; |
AEDesc objectToSet; |
FailIfErr(AECreateAppleEvent(kAECoreSuite, kAESetData, &gSelfAddress, kAutoGenerateReturnID, |
kAnyTransactionID, &myAppleEvent)); |
// Create the object specifier for the property of the object. |
FailIfErr(CreateObjSpecifier(cProperty, target, formPropertyID, propDesc, |
false, &objectToSet)); |
// Attach the property object specifier. |
FailIfErr(AEPutParamDesc(&myAppleEvent, keyDirectObject, &objectToSet)); |
// Add the property data. |
FailIfErr(AEPutParamDesc(&myAppleEvent, keyAEData, propData)); |
FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract+kAEDontExecute, kAENormalPriority, |
kAEDefaultTimeout, nil, nil)); |
AEDisposeDesc(&objectToSet); // Clean up. |
AEDisposeDesc(&myAppleEvent); |
} |
//----------------------------------------------------------------------------------// |
// To set the data of an object, the expected data is passed in its raw form with // |
// the property type in the descriptorType field and the data in the dataHandle. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr HandleSetData(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon) |
{ |
#pragma unused (reply,refCon) |
AEDesc target, data, token; |
OSErr err; |
MyInitDescs(&target, &data,&token, kEndOfList); |
// First, get the direct object. This is the object whose data is to be set. |
if (!(err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &target))) |
if (!(err = AEResolve(&target, kAEIDoMinimum, &token))) // Resolve it. |
if (!(err = AEGetParamDesc(theAppleEvent, keyAEData, typeWildCard, &data))) |
err = DoSetData(&token, &data); |
MyDisposeDescs(&target, &data, &token, kEndOfList); |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// Return a reply to the Get Data or Get Data Size Apple Event for the requested // |
// data. The refcon parameter is used to distinguish the two events. If typeBest // |
// is the requested return type, the data's descriptor type is the result type. // |
// **NOTE: Do not use the same descriptor as source and dest in AECoerceDesc(). // |
// This routine creates a copy of the source, and then it is impossible to dispose // |
// of the memory originally contained in the source's dataHandle. // |
// 2/25/92 - Removed FailIfErr calls. Now the error is returned as a result. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr HandleGetData( AppleEvent* theAppleEvent, |
AppleEvent* reply, |
long refCon ) // kAEGetData or kAEGetDataSize. |
{ |
AEDesc theObject, token; // direct object and resolved token. |
AEDesc objectData, tempDesc; // object data, and coerced data. |
DescType reqType; |
WindowPtr window; |
Size theSize; |
OSErr err; |
MyInitDescs(&theObject, &objectData, &token, kEndOfList); |
// First, get the direct objet. |
if (err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &theObject)) |
goto myExit; |
// Next, get the requested return type, if it exists. |
if (err = AEGetParamPtr(theAppleEvent, keyAERequestedType, typeType, &reqType, |
(Ptr)&reqType, sizeof(DescType), &theSize)) |
{ |
if (err == errAEDescNotFound) // not an error if return type is not found |
{ |
err = noErr; |
reqType = typeWildCard; |
} |
else |
goto myExit; |
} |
if (err = GetMissingParams(theAppleEvent)) // check for missing params |
goto myExit; |
// Resolve the object specifier and get the token containing the property and container. |
if (!(err = AEResolve(&theObject, kAEIDoMinimum, &token))) |
if (window = (WindowPtr)*(LongPtr)*token.dataHandle) // Nil for application; WindowPtr for window |
err = GetWindowData(token.descriptorType, window, &objectData); |
else |
err = GetAppData(token.descriptorType, &objectData); |
if (err == noErr && reply->dataHandle != nil) |
{ // Add data to the reply Apple event record. |
if (reqType != typeWildCard && reqType != typeBest && |
reqType != objectData.descriptorType) |
{ |
err = AECoerceDesc(&objectData, reqType, &tempDesc); |
MyDisposeDescs(&objectData, kEndOfList); |
objectData.descriptorType = tempDesc.descriptorType; |
objectData.dataHandle = tempDesc.dataHandle; |
} |
if (!err) |
{ |
if (refCon == kAEGetData) // return data |
err = AEPutParamDesc(reply, keyAEResult, &objectData); |
else if (refCon == kAEGetDataSize) // return data size |
{ |
theSize = GetHandleSize(objectData.dataHandle); |
err = AEPutParamPtr(reply, keyAEResult, typeLongInteger, (Ptr)&theSize, sizeof(long)); |
} |
} |
} |
myExit: |
MyDisposeDescs(&theObject, &objectData, &token, kEndOfList); |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// Send a Move Apple event to myself in response to a user selecting a window // |
// and making it frontmost. This event is sent with the insertion location record // |
// specifying the beginning of the null container. If the index is non-zero, this // |
// indicates that the move event has already been performed by DragWindow(). Thus, // |
// this event is passed with the don't execute flag set. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void SendMoveEvent(WindowPtr windowToMove, long index) |
{ |
AppleEvent myAppleEvent, reply, windowObject; |
AERecord insertionRec; // Insertion Loc record. |
AEDesc insertionLoc; // The coerced insertionRec. |
DescType theType; |
// Create the Apple Event. |
FailIfErr(AECreateAppleEvent(kAECoreSuite, kAEMove, &gSelfAddress, kAutoGenerateReturnID, |
kAnyTransactionID, &myAppleEvent)); |
// Create the object spec for the window to move. |
FailIfErr(CreateWindowObjectSpec(windowToMove, kIndexKeyForm, &windowObject)); |
FailIfErr(AEPutParamDesc(&myAppleEvent, keyDirectObject, &windowObject)); |
// Create insertion loc record for beginning of null container. |
FailIfErr(AECreateList(nil, 0, true, &insertionRec)); // Create an AE Record. |
theType = kAEBeginning; |
FailIfErr(AEPutKeyDesc(&insertionRec, keyAEObject, &gNullDesc)); |
FailIfErr(AEPutKeyPtr(&insertionRec,keyAEPosition,typeEnumeration,(Ptr)&theType,sizeof(DescType))); |
FailIfErr(AECoerceDesc(&insertionRec, typeInsertionLoc, &insertionLoc)); |
// Now add the insertion location descriptor record to the Apple Event. |
FailIfErr(AEPutParamDesc(&myAppleEvent, keyAEInsertHere, &insertionLoc)); |
// Send the Apple Event. |
if (index) |
FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract+kAEDontExecute, |
kAENormalPriority, kAEDefaultTimeout, nil, nil)); |
else |
FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract, |
kAENormalPriority, kAEDefaultTimeout, nil, nil)); |
// Now dispose of the AppleEvent and other records. |
MyDisposeDescs(&myAppleEvent,&windowObject,&insertionRec,&insertionLoc,kEndOfList); |
} |
//----------------------------------------------------------------------------------// |
// Respond to the Move Apple Event by reordering the window list. For CoreSample, // |
// the keyAEInsertHere parameter is optional. If this parameter does not exist, // |
// the specified window will move the to the front. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr HandleMove(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon) |
{ |
#pragma unused (refCon) |
AEDesc object, windowObj, replyObj, insertionLoc; |
AERecord insertionRec; |
DescType theType, position; |
WindowPtr windowToMove, relativeWindow, rplcWindow; |
Rect bounds; |
Size paramSize; |
OSErr err; |
MyInitDescs(&object,&windowObj,&insertionLoc,&insertionRec,&replyObj,kEndOfList); |
// First, get the direct parameter, the object to move. |
if (err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &object)) |
goto myExit; |
if (!(windowToMove = ResolveToWindow(&object))) // Check if valid window object. |
{ |
err = errAENoSuchObject; |
goto myExit; |
} |
// Retrieve the insertion location record, if it exists. |
if ((err = AEGetParamDesc(theAppleEvent,keyAEInsertHere,typeInsertionLoc,&insertionLoc)) == errAEDescNotFound) |
{ // Execute *MY* default behavior since insertion loc param not present. |
SelectWindow(windowToMove); |
err = noErr; |
goto myExit; |
} |
else |
if (err) |
goto myExit; |
else // get data from insertion loc and coerce it to typeAERecord. |
{ |
if ((err = GetMissingParams(theAppleEvent)) || |
(err = AECoerceDesc(&insertionLoc, typeAERecord, &insertionRec)) || |
(err = AEGetKeyDesc(&insertionRec,keyAEObject,typeWildCard,&windowObj)) || |
(err = AEGetKeyPtr(&insertionRec,keyAEPosition,typeEnumeration,&theType, |
(Ptr)&position,sizeof(DescType),¶mSize))) |
goto myExit; |
} |
if (!(err = FindRelativeWindow(&relativeWindow,&windowObj,position,&rplcWindow))) |
{ |
if (position == kAEReplace) |
if (windowToMove == rplcWindow) |
goto myExit; // do nothing. |
else |
{ |
bounds = DoGetWindowBounds(rplcWindow); |
CloseTheWindow(rplcWindow); |
MoveWindow(windowToMove, bounds.left, bounds.top, false); |
} |
if (relativeWindow == (WindowPtr)-1) // [pwpc] |
SelectWindow(windowToMove); |
else |
if (windowToMove != relativeWindow) |
SendBehind(windowToMove, relativeWindow); // NOTE: may have to call PaintOne and |
// CalcVis if after; see IM I-286 |
if (position == kAEReplace && windowToMove != rplcWindow) |
{ |
bounds = DoGetWindowBounds(rplcWindow); |
CloseTheWindow(rplcWindow); |
MoveWindow(windowToMove, bounds.left, bounds.top, false); |
} |
} |
myExit: |
if (!err) |
if (reply->dataHandle != nil) |
{ |
CreateWindowObjectSpec(windowToMove, kIndexKeyForm, &replyObj); |
err = AEPutParamDesc(reply, keyAEResult, &replyObj); |
} |
MyDisposeDescs(&object,&windowObj,&insertionLoc,&insertionRec,&replyObj,kEndOfList); |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// Set up the descriptor records needed to set the data for the bounds, position, // |
// and zoomed properties. The bounds is set in response to sizing a window; the // |
// position is set after dragging a window; and the isZoomed property is set when // |
// zooming a window in or out. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void SetUpPropertyData( WindowPtr window, // Window object. |
DescType propType, // Property descriptor type. |
DescType dataType, // Descriptor type for data. |
Size dataSize ) // Size of data. |
{ |
AEDesc windowObject, theData, theProperty; |
Rect bounds; |
Boolean isZoomed; |
MyInitDescs(&windowObject, &theData, &theProperty, kEndOfList); |
if (propType == pIsZoomed) |
{ |
isZoomed = (Boolean)GetWRefCon(window); |
FailIfErr(AECreateDesc(dataType,(Ptr)&isZoomed,dataSize,&theData)); |
} |
else // it's either pBounds or pPosition. |
{ |
bounds = DoGetWindowBounds(window); |
FailIfErr(AECreateDesc(dataType, (Ptr)&bounds, dataSize, &theData)); |
} |
CreateWindowObjectSpec(window, kIndexKeyForm, &windowObject); |
FailIfErr(AECreateDesc(typeType, (Ptr)&propType, sizeof(DescType), &theProperty)); |
SendSetData(&theProperty, &theData, &windowObject); |
MyDisposeDescs(&windowObject, &theData, &theProperty, kEndOfList); |
} |
//----------------------------------------------------------------------------------// |
// Set the property data for the specified object. For now, we only handle window // |
// objects, and you may only set the modifiable properties (defined in Registry). // |
// *NOTE*: We do not allow the application's properties to be modified. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
OSErr DoSetData( AEDesc* token, // Contains the property and object. |
AEDesc* data ) // Contains the data to set. |
{ |
AEDesc propData; // Property data. |
Rect bounds; |
GrafPtr oldPort; |
WindowPtr window, behindWindow; |
Str255 name; |
long newIndex; |
short part; |
Boolean value; |
Point pt; |
OSErr err; |
err = noErr; |
if (window = (WindowPtr)*(LongPtr)*(token->dataHandle)) |
{ |
GetPort(&oldPort); |
switch (token->descriptorType) |
{ |
case pBounds: |
if (data->descriptorType != typeQDRectangle) |
{ |
propData.dataHandle = nil; |
err = AECoerceDesc(data, typeQDRectangle, &propData); |
bounds = *(Rect *)*propData.dataHandle; // Get content region. |
MyDisposeDescs(&propData, kEndOfList); |
} |
else |
bounds = *(Rect *)*data->dataHandle; // Get content region. |
if (!err) |
{ |
SetPort(window); |
InvalRect(&window->portRect); |
// Real applications may want to make a sanity check on the new bounds. |
MoveWindow(window, bounds.left, bounds.top, false); |
SizeWindow(window, bounds.right-bounds.left, bounds.bottom-bounds.top, true); |
InvalRect(&window->portRect); |
} |
break; |
case pIndex: |
if (DescToLong(data,&newIndex) != noErr) |
return(errAECoercionFail); // Data cannot be coerced. |
if (newIndex > gNumWindowsOpen) |
err = errAEIndexTooLarge; |
else |
{ |
if (newIndex == 1) |
SelectWindow(window); |
else |
if (behindWindow = GetWindowAtIndex(newIndex)) |
SendBehind(window, behindWindow); |
else |
err = errAEEventFailed; |
} |
break; |
case pIsZoomed: |
if (DescToBoolean(data,&value) != noErr) |
return(errAECoercionFail); // Data cannot be coerced. |
part = value ? inZoomOut : inZoomIn; |
ZoomIt(window, part); |
break; |
case pName: |
if (DescToPString(data,name,kMaxStrSize) != noErr) |
return(errAECoercionFail); |
SetWTitle(window, name); |
break; |
case pPosition: |
if (data->descriptorType != typeQDPoint) |
{ |
propData.dataHandle = nil; |
err = AECoerceDesc(data, typeQDPoint, &propData); |
pt = *(Point *)*propData.dataHandle; |
MyDisposeDescs(&propData, kEndOfList); |
} |
else |
pt = *(Point *)*data->dataHandle; |
if (!err) |
{ |
// Real applications may want to make a sanity check on the new loc. |
SetPort(window); |
MoveWindow(window, pt.h, pt.v, false); |
InvalRect(&window->portRect); |
} |
break; |
case pVisible: |
if (DescToBoolean(data,&value) != noErr) |
return(errAECoercionFail); // Data cannot be coerced. |
if (value) |
ShowWindow(window); |
else |
HideWindow(window); |
break; |
default: // No other properties are modifiable. |
return(errAENotModifiable); |
} |
SetPort(oldPort); |
} |
else |
return(errAEEventFailed); |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// This is a dummy handler that receives Apple events which I don't handle. It // |
// is mainly provided as a stub in order to support all the events in the // |
// required suite, as well as the entire core suite. This is the handler for the // |
// Open Document and Print Document events (required suite); and the Save, Get // |
// Class Info, and Get Event Info events (core suite). The Get Class Info and Get // |
// Event Info events "MAY" be supported internally in the future, so applications // |
// will not need to handle these events themselves. This support may be provided // |
// since it would be consistent across all applications, and the information may // |
// be retrieved from the 'aeut'/'aete' resources. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr DummyHandler( AppleEvent *theAppleEvent, |
AppleEvent *reply, |
long refCon ) |
{ |
#pragma unused (theAppleEvent,reply,refCon) |
return(errAEEventNotHandled); |
} |
//----------------------------------------------------------------------------------// |
// Locate the window that is relative to the specified window object at the // |
// insertion position. If the location is replace, the window to replace is // |
// closed, and its bounds are returned to the calling routine. // |
// **Note**: if windowObj is used within this routine, the object param will // |
// contain the same dataHandle. This will be disposed of by the calling routine. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
OSErr FindRelativeWindow( WindowPtr* relativeWindow, // window before insertion loc. |
AEDesc* object, // object to be relative to. |
DescType position, // insertion position. |
WindowPtr* replaceWindow ) // window to replace. |
{ |
AEDesc windowObj; // Coerced descriptor. |
WindowPtr windowToReplace; |
long index; |
OSErr err; |
err = noErr; |
*replaceWindow = nil; |
switch(position) |
{ |
case kAEBeginning: // The object should be the container. |
if (object->descriptorType == typeNull) |
*relativeWindow = (WindowPtr)-1; |
else |
err = errAENoSuchObject; |
break; |
case kAEEnd: // The object should be the container. |
if (object->descriptorType == typeNull) |
*relativeWindow = nil; |
else |
err = errAENoSuchObject; |
break; |
case kAEBefore: // The object should be an object specifier. |
case kAEReplace: |
if (object->descriptorType != typeObjectSpecifier) |
{ |
err = AECoerceDesc(object, typeObjectSpecifier, &windowObj); |
MyDisposeDescs(object, kEndOfList); |
object->descriptorType = windowObj.descriptorType; |
object->dataHandle = windowObj.dataHandle; |
} |
if (!err) |
if (windowToReplace = ResolveToWindow(object)) |
{ |
index = GetWindowIndexNum(windowToReplace); |
*relativeWindow = (index==1) ? (WindowPtr)-1 : GetWindowAtIndex(index-1); |
if (position == kAEReplace) |
*replaceWindow = windowToReplace; |
} |
else // We weren't able to resolve the object specifier to a window. |
err = errAENoSuchObject; |
break; |
case kAEAfter: // The object should be an object specifier. |
if (object->descriptorType != typeObjectSpecifier) |
{ |
err = AECoerceDesc(object,typeObjectSpecifier,&windowObj); |
MyDisposeDescs(object, kEndOfList); |
object->descriptorType = windowObj.descriptorType; |
object->dataHandle = windowObj.dataHandle; |
} |
if (!err) |
if (!(*relativeWindow = ResolveToWindow(object))) |
err = errAENoSuchObject; |
break; |
default: |
return(errAEEventNotHandled); |
} |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// Retrieves the data for the specified property of the window. The result token // |
// contains the type of the data in the descriptorType field, and the data itself // |
// in the dataHandle field. I know my application's window properties // |
// (i.e., has title bar, has close box, is zoomable, etc.), so I set up the // |
// result token accordingly. If your application handles various window types, // |
// you may need to look at the window defproc to determine which type of window it // |
// is. If the property is pBestType or pDefaultType, I return an object specifier// |
// for the window which may be used to easily reference it. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
OSErr GetWindowData( DescType theProperty, // Window property. |
WindowPtr window, |
AEDesc *result ) // Contains the result upon return. |
{ |
DescType theType; |
Str255 title; |
Rect bounds; |
long index; |
Boolean myAnswer; |
switch (theProperty) |
{ |
case pBestType: |
case pDefaultType: |
return(CreateWindowObjectSpec(window, kIndexKeyForm, result)); |
case pBounds: |
bounds = DoGetWindowBounds(window); |
return(AECreateDesc(typeQDRectangle, (Ptr)&bounds, sizeof(Rect), result)); |
case pClass: |
theType = cWindow; |
return(AECreateDesc(typeType, (Ptr)&theType, sizeof(DescType), result)); |
case pIndex: |
index = GetWindowIndexNum(window); |
return(AECreateDesc(typeLongInteger, (Ptr)&index, sizeof(long), result)); |
case pName: |
GetWTitle(window, title); |
return(AECreateDesc(typeChar, (Ptr)&title[1], title[0], result)); |
case pPosition: |
bounds = DoGetWindowBounds(window); |
return(AECreateDesc(typeQDPoint, (Ptr)&bounds, sizeof(Point), result)); |
case pHasCloseBox: |
case pHasTitleBar: |
case pIsResizable: |
case pIsZoomable: |
myAnswer = true; |
return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result)); |
case pIsFloating: |
case pIsModal: |
myAnswer = false; |
return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result)); |
case pIsZoomed: |
myAnswer = GetWRefCon(window); |
return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result)); |
case pVisible: // Must check this because it is modifiable. |
myAnswer = ((WindowPeek)window)->visible; |
return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result)); |
case pSelection: // No selection in CoreSample. |
return(errAENoSuchObject); |
default: // We don't handle requested property. |
return(errAEEventNotHandled); |
} |
} |
//----------------------------------------------------------------------------------// |
// Get the property data for the application and return it in the result parameter.// |
// The result token contains the property type in the descriptorType field, and // |
// a nil value in the dataHandle field to represent the null application. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
OSErr GetAppData( DescType theProperty, |
AEDesc* result ) // Descriptor record to hold the property data. |
{ |
ProcessInfoRec myProcessInfo; // [pwpc] |
DescType theType; |
short refNum; |
Str255 name; |
Handle myHandle; |
ProcessSerialNumber thePSN, currentProcess; |
Boolean isFront; |
OSErr err; |
switch (theProperty) |
{ |
case pBestType: // Return the null descriptor representing |
case pDefaultType: // the application. |
return(AEDuplicateDesc(&gNullDesc, result)); |
case pClass: |
theType = cApplication; |
return(AECreateDesc(typeType,(Ptr)&theType,sizeof(DescType),result)); |
case pName: |
// [pwpc] Clear out the name, and then call the process manager to get |
// the string for the name of our application. |
name[0] = 0; |
myProcessInfo.processInfoLength = sizeof(myProcessInfo); |
myProcessInfo.processName = name; |
myProcessInfo.processAppSpec = NULL; |
GetCurrentProcess(¤tProcess); |
GetProcessInformation(¤tProcess, &myProcessInfo); |
// Create an AEDesc returning the application name string |
// returned by the process manager. |
return(AECreateDesc(typeChar, (Ptr)&name[1], name[0], result)); |
case pIsFrontProcess: |
GetFrontProcess(&thePSN); |
SameProcess(&gSelfPSN, &thePSN, &isFront); |
return(AECreateDesc(typeBoolean,(Ptr)&isFront,sizeof(Boolean),result)); |
case pVersion: |
refNum = CurResFile(); // save current resource |
UseResFile(gRefNum); // set this resource to be current |
myHandle = (Handle)Get1Resource((ResType)'vers', 1); |
HLock(myHandle); |
err = AECreateDesc(typeVersion, *myHandle, GetHandleSize(myHandle), result); |
HUnlock(myHandle); |
UseResFile(refNum); // reset back to resource previously set |
return(err); |
default: // We don't handle the requested property. |
return(errAEEventNotHandled); |
} |
} |
//----------------------------------------------------------------------------------// |
// Create an object specifier for the window with the indicated key form. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
OSErr CreateWindowObjectSpec( WindowPtr window, |
short keyForm, // index or name key form. |
AEDesc* objectSpec ) // Resulting object specifier. |
{ |
AEDesc data; |
Str255 title; |
long index; |
OSErr err; |
MyInitDescs(&data, kEndOfList); |
switch(keyForm) |
{ |
case kNameKeyForm: // Object specifier with name. |
GetWTitle(window, title); |
if (!(err = AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data))) |
err = CreateObjSpecifier(cWindow, &gNullDesc, formName, &data, |
false, objectSpec); |
break; |
case kIndexKeyForm: // Object specifier with index. |
index = GetWindowIndexNum(window); |
if (!(err = CreateOffsetDescriptor(index, &data))) |
err = CreateObjSpecifier(cWindow, &gNullDesc, formAbsolutePosition, &data, |
false, objectSpec); |
break; |
} |
MyDisposeDescs(&data, kEndOfList); |
return(err); |
} |
//----------------------------------------------------------------------------------// |
// Check to see if there exists any additional parameters in the Apple Event. // |
// If so, return an error to the calling routine. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
OSErr GetMissingParams(AppleEvent* theAppleEvent) |
{ |
DescType theType; |
Size actualSize; |
OSErr err; |
err = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard, |
&theType, nil, 0, &actualSize); |
if (err == errAEDescNotFound) |
return(noErr); |
else |
return(errAEEventNotHandled); |
} |
//----------------------------------------------------------------------------------// |
// If a reply is expected, the error number is returned in the reply parameter. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
void ReportError( AppleEvent* reply, |
long err ) |
{ |
if (reply->dataHandle != nil && err != noErr) |
FailIfErr(AEPutParamPtr(reply,keyErrorNumber,typeLongInteger,(Ptr)&err,sizeof(long))); |
} |
//----------------------------------------------------------------------------------// |
// This routine returns the window object contained in the given object specifier. // |
// If the resolution does not return a descriptor record of type cWindow, nil is // |
// returned as a result. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
WindowPtr ResolveToWindow(AEDesc* objectSpecifier) |
{ |
AEDesc token; |
WindowPtr window; |
MyInitDescs(&token, kEndOfList); |
window = nil; |
if (objectSpecifier->descriptorType == typeObjectSpecifier) |
if (!(AEResolve(objectSpecifier, kAEIDoMinimum, &token))) |
if (token.descriptorType == cWindow) |
window = (WindowPtr)*((LongPtr)*(token.dataHandle)); |
MyDisposeDescs(&token, kEndOfList); |
return(window); |
} |
//----------------------------------------------------------------------------------// |
// Retrieve the window from the null container by the key form and return its // |
// pointer in the dataHandle field of resultToken. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr WindowAccessor( DescType classWanted, // window class |
AEDesc* container, // the application (null container) |
DescType containerClass, |
DescType keyform, |
AEDesc* selectionData, |
AEDesc* resultToken, // specified window is returned in result |
long theRefCon ) |
{ |
#pragma unused (classWanted,container,containerClass,theRefCon) |
WindowPtr window; |
DescType seldataType; |
Str255 title; |
long index; |
OSErr err; |
window = nil; |
err = noErr; |
if (!gNumWindowsOpen) |
return(errAENoSuchObject); |
else |
{ |
seldataType = selectionData->descriptorType; |
switch(keyform) |
{ |
case formName: // Window title. |
if (DescToPString(selectionData,title,kMaxStrSize) != noErr) |
return(errAECoercionFail); |
if (!(window = GetWindowWithTitle(title))) |
return(errAENoSuchObject); // Window was not found. |
break; |
case formAbsolutePosition: |
if (DescToLong(selectionData,&index) != noErr) |
return(errAECoercionFail); // Data cannot be coerced. |
if (!(window = GetWindowAtIndex(index))) |
return(errAENoSuchObject); // Window was not found. |
break; |
default: // I don't handle any other key forms. |
return(errAEEventNotHandled); |
} |
} |
return(AECreateDesc(cWindow, (Ptr)&window, sizeof(Ptr), resultToken)); |
} |
//----------------------------------------------------------------------------------// |
// Return a token representing the property for the containing window. The token // |
// is returned with the property and window pointer. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr WindowPropertyAccessor( DescType classWanted, // Property class |
AEDesc* container, // Window object |
DescType containerClass, |
DescType form, |
AEDesc* selectionData, |
AEDesc* resultToken, |
long theRefCon ) |
{ |
#pragma unused (containerClass, theRefCon) |
Ptr window; |
DescType propType; |
// Let's make sure we're accessing a valid descriptor type. |
if ((classWanted != cProperty) || (form != formPropertyID)) |
return(errAEWrongDataType); |
window = (Ptr)*(LongPtr)*(container->dataHandle); // Get the window pointer. |
propType = *(LongPtr)*selectionData->dataHandle; // Get the property type. |
return(AECreateDesc(propType, (Ptr)&window, sizeof(Ptr), resultToken)); |
} |
//----------------------------------------------------------------------------------// |
// Return a token that contains the property type and nil to represent the null // |
// container (the application). // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
pascal |
OSErr AppPropertyAccessor( DescType classWanted, // Property class. |
AEDesc* container, // Application. |
DescType containerClass, |
DescType form, |
AEDesc* selectionData, |
AEDesc* resultToken, |
long theRefCon ) |
{ |
#pragma unused (container,containerClass,theRefCon) |
DescType propType; |
long nilValue; |
// Let's make sure we're accessing a valid descriptor type. |
if ((classWanted != cProperty) || (form != formPropertyID)) |
return(errAEWrongDataType); |
nilValue = nil; |
propType = *(LongPtr)*selectionData->dataHandle; // Get the property type. |
return(AECreateDesc(propType, (Ptr)&nilValue, sizeof(long), resultToken)); |
} |
//----------------------------------------------------------------------------------// |
// Returns the window with the given title if found. Otherwise, nil is returned. // |
// Use WindowList in order to find windows that may be invisible. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
WindowPtr GetWindowWithTitle( ConstStr255Param titleToFind ) |
{ |
WindowPeek window; |
Str255 thisTitle; |
#ifdef THINK_C |
window = (WindowPeek)LMGetWindowList(); // WindowList finds invisible windows as well. |
#else |
window = *(PeekPtr)LMGetWindowList(); // WindowList finds invisible windows as well. |
#endif |
while (window) |
{ |
GetWTitle((WindowPtr)window, thisTitle); |
if (EqualString(thisTitle, titleToFind, false, false)) |
return((WindowPtr)window); |
window = window->nextWindow; |
} |
return(nil); |
} |
//----------------------------------------------------------------------------------// |
// Search all windows (including invisible), and return the window at the given // |
// index if found. Otherwise, nil is returned. This routine also handles negative // |
// indices which indicates that the offset is from the end of the container. // // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
WindowPtr GetWindowAtIndex(long index) |
{ |
WindowPeek window; |
short count; |
index = index < 0 ? gNumWindowsOpen+index+1 : index; |
count = 1; |
#ifdef THINK_C |
window = (WindowPeek)LMGetWindowList(); // WindowList finds invisible windows as well. |
#else |
window = *(PeekPtr)LMGetWindowList(); // WindowList finds invisible windows as well. |
#endif |
while (window) |
{ |
if (count == index) |
return((WindowPtr)window); |
window = window->nextWindow; |
count++; |
} |
return(nil); |
} |
//----------------------------------------------------------------------------------// |
// Returns the index number of the given window, where 1 is the frontmost. // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
long GetWindowIndexNum(WindowPtr myWindow) |
{ |
WindowPeek thisWindow; |
long index; |
#ifdef THINK_C |
thisWindow = (WindowPeek)LMGetWindowList(); // Compilers are so much fun!!. |
#else |
thisWindow = *(PeekPtr)LMGetWindowList(); // WindowList finds invisible windows as well. |
#endif |
index = 1; |
while (thisWindow) |
{ |
if (thisWindow == (WindowPeek)myWindow) // [pwpc] |
return(index); |
thisWindow = thisWindow->nextWindow; |
index++; |
} |
return(nil); |
} |
//----------------------------------------------------------------------------------// |
// This routine returns the bounds of a given window. Special calculations are // |
// performed when the bounds is invalid (i.e., the window is hidden). // |
//----------------------------------------------------------------------------------// |
#pragma segment Main |
Rect DoGetWindowBounds(WindowPtr window) |
{ |
Rect portRect, bitMapRect, bounds; |
bounds = (*((WindowPeek)window)->contRgn)->rgnBBox; // check the content region. |
if (bounds.top == 0 && bounds.left == 0 && |
bounds.bottom == 0 && bounds.right == 0) |
{ |
portRect = window->portRect; |
bitMapRect = window->portBits.bounds; |
bounds.top = portRect.top - bitMapRect.top; |
bounds.left = portRect.left - bitMapRect.left; |
bounds.bottom = portRect.bottom - bitMapRect.top; |
bounds.right = portRect.right - bitMapRect.left; |
} |
return(bounds); |
} |
//----------------------------------------------------------------------------------// |
#pragma segment Initialize |
void InitAEHandlers() |
{ |
AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,NewAEEventHandlerProc(HandleOpenApp), nil,false); |
AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,NewAEEventHandlerProc(DummyHandler), nil,false); |
AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,NewAEEventHandlerProc(DummyHandler), nil,false); |
AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc(HandleQuitApp), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAEClone, NewAEEventHandlerProc(HandleClone), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAEClose, NewAEEventHandlerProc(HandleClose), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAECountElements, NewAEEventHandlerProc(HandleCountElements), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAECreateElement, NewAEEventHandlerProc(HandleCreateElement), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAEDelete, NewAEEventHandlerProc(HandleClose), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist, NewAEEventHandlerProc(HandleDoObjectsExist), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAEGetData, NewAEEventHandlerProc(HandleGetData), kAEGetData, false); |
AEInstallEventHandler(kAECoreSuite, kAEGetDataSize, NewAEEventHandlerProc(HandleGetData), kAEGetDataSize, false); |
AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo, NewAEEventHandlerProc(DummyHandler), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo, NewAEEventHandlerProc(DummyHandler), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAEMove, NewAEEventHandlerProc(HandleMove), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAESave, NewAEEventHandlerProc(DummyHandler), nil, false); |
AEInstallEventHandler(kAECoreSuite, kAESetData, NewAEEventHandlerProc(HandleSetData), nil, false); |
AEObjectInit(); |
AEInstallObjectAccessor(cWindow, typeNull, NewOSLAccessorProc(WindowAccessor), nil, false); |
AEInstallObjectAccessor(cProperty, typeNull, NewOSLAccessorProc(AppPropertyAccessor), nil, false); |
AEInstallObjectAccessor(cProperty, cWindow, NewOSLAccessorProc(WindowPropertyAccessor), nil, false); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14