HLE.c

/* A simple (real simple) High Level Event sample */
#include <Types.h>
#include <memory.h>
#include <Packages.h>
#include <Errors.h>
#include <quickdraw.h>
#include <fonts.h>
#include <dialogs.h>
#include <windows.h>
#include <menus.h>
#include <events.h>
#include <OSEvents.h>
#include <Desk.h>
#include <diskinit.h>
#include <OSUtils.h>
#include <resources.h>
#include <toolutils.h>
#include <AppleEvents.h>
#include <EPPC.h>
#include <GestaltEqu.h>
#include <PPCToolbox.h> 
#include <Processes.h>
 
/* prototypes */
void DoDiskEvents(long dinfo);                              /* hi word is error code, lo word is drive number */
void DrawMain(WindowPtr drawIt);
Boolean DoSelected(long val);
pascal Boolean MyGenericFilter(Ptr myData,HighLevelEventMsgPtr theBuffer,const TargetID *sender);
void SendHLE(void);
void InitAEStuff(void);
void DoHighLevel(EventRecord *AERecord);
void DoDaCall(MenuHandle themenu, long theit);
pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
Boolean BrowseForMe(void);
pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
 
ProcessSerialNumber gOurSN;
 
#define kMBarID 128
#define kAppleMenu 128
#define kFileMenu 129
#define kEditMenu 130
#define kToolsMenu 131
#define kSendButton 128
#define kResumeMask             1       /* bit of message field for resume vs. suspend */
#define kBadCombo 129
#define kNoFind 130
#define kSearch 200
#define kFirstEvent 'MYEV'
#define kSecondEvent '2YEV'
MenuHandle gAppleMenuHandle, gFileMenuHandle, gEditMenuHandle, gToolMenuHandle;
Handle gMymenu;                                             /* my menu bar handle */
ControlHandle sendButton;
 
typedef struct MyHLEGetter{
short whichData;
Ptr specificData;
}MyHLEGetter;
 
enum{kMessageField =1,kRawData,kRefCon};
 
AEAddressDesc targetAddress;                                /* address of the person to get the data from */
 
TargetID theID,theID2;
Boolean gQuit, gInBackground;
EventRecord gERecord;
AEDesc gTheAddress;
WindowPtr myWindow;
LocationNameRec theLoc;
PortInfoRec theRec;
PPCPortRec myPortName;
LocationNameRec myLoc;
PPCPortRefNum gPortRef = 0;
PPCParamBlockRec myParamBlock;
 
GetSpecificFilterUPP gGetSpecificFilterUPP; /* filter for GetSpecificHighLevelEvent */
 
 
Str255 displayString;
 
#ifdef powerc
   QDGlobals    qd;
#endif
 
main()
{
    WindowPtr twindow;
    ControlHandle returnedControl;
    MaxApplZone();
    InitGraf((Ptr)&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();
    
    InitAEStuff();
    
    /* create the UPP for the filter to GetSpecificHighLevelEvent */
    gGetSpecificFilterUPP = NewGetSpecificFilterProc(MyGenericFilter);
    
    /* set up my menu junk */
    gMymenu = GetNewMBar(kMBarID);
    SetMenuBar(gMymenu);
    gAppleMenuHandle = GetMenuHandle(kAppleMenu);
    gFileMenuHandle = GetMenuHandle(kFileMenu);
    gEditMenuHandle = GetMenuHandle(kEditMenu);
    gToolMenuHandle = GetMenuHandle(kToolsMenu);
    AppendResMenu(gAppleMenuHandle, 'DRVR');
 
    
   
    DrawMenuBar();
    myWindow = GetNewWindow(128, nil, (WindowPtr)-1);
 
    do {
        WaitNextEvent(everyEvent, &gERecord, 30, nil);
        switch (gERecord.what) {
            
            case nullEvent:
                /* no nul processing in this sample */
                break;
            case updateEvt:
                DrawMain((WindowPtr)gERecord.message);      /* draw whatever window needs an update */
                break;
            case mouseDown:
                /* first see where the hit was */
                switch (FindWindow(gERecord.where, &twindow)) {
                    
                    case inDesk:                            /* if they hit in desk, then the process manager */
                        break;                              /* will switch us out, we don't need to do anything */
                    case inMenuBar:
                        DoSelected(MenuSelect(gERecord.where));
                        break;
                        
                    case inSysWindow:
                        /* pass to the system */
                        SystemClick(&gERecord, twindow);
                        break;
                    case inContent:
                        GlobalToLocal(&gERecord.where);
                        /* track my button as needed */
                        if (FindControl(gERecord.where, twindow, &returnedControl)) {
                            if (TrackControl(returnedControl, gERecord.where, nil)) {
                               
                            }
                        }
                        break;
                    case inDrag:
                        if (twindow == FrontWindow())
                            DragWindow(twindow, gERecord.where, &qd.screenBits.bounds);
                        break;
                    case inGrow:
                    case inGoAway:
                        /* don't care */
                        break;
                        
                }
            case mouseUp:
                /* don't care */
                break;
                /* same action for key or auto key */
            case keyDown:
            case autoKey:
                if (gERecord.modifiers & cmdKey)
                    DoSelected(MenuKey(gERecord.message & charCodeMask));
                break;
            case keyUp:
                /* don't care */
                break;
            case diskEvt:
                /* I don't do anything special for disk events, this just passes them */
                /* to a function that checks for an error on the mount */
                DoDiskEvents(gERecord.message);
                break;
            case activateEvt:
                if (gERecord.modifiers & activeFlag)
                    DrawMain((WindowPtr)gERecord.message);
                break;
            case networkEvt:
                /* don't care */
                break;
            case driverEvt:
                /* don't care */
                break;
            case app4Evt:
                switch ((gERecord.message >> 24) & 0x0FF) {     /* high byte of message */
                    case suspendResumeMessage:              /* suspend/resume is also an activate/deactivate */
                        gInBackground = (gERecord.message & kResumeMask) == 0;
                        break;
                }
                break;
                case kHighLevelEvent:
                /* This dispatches high level events (AppleEvents, for example) */
                /* to our dispatch routine.  This is NEW in the event loop for */
                /* System 7 */
 
                DoHighLevel(&gERecord);
                break;
            default:
                break;
    
                
        }
    } while (gQuit != true);
    
    
}
 
/* DoDaCall opens the requested DA.  It's here as a seperate routine if you'd */
/* like to perform some action or just know when a DA is opened in your */
/* layer.  Can be handy to track memory problems when a DA is opened */
/* with an Option-open */
void DoDaCall(MenuHandle themenu, long theit)
{
    long qq;
    char DAname[255];
    GetMenuItemText(themenu, theit, &DAname);
    qq = OpenDeskAcc(DAname);
}
 
/* end DoDaCall */
 
/* DoDiskEvents just checks the error code from the disk mount, */
/* and puts up the 'Format' dialog (through DIBadMount) if need be */
/* You can do much more here if you care about what disks are */
/* in the drive */
void DoDiskEvents(long dinfo)                               /* hi word is error code, lo word is drive number */
{
    short hival, loval, tommy;
    Point fredpoint =  {
        40, 40
    };
    hival = HiWord(dinfo);
    loval = LoWord(dinfo);
    if (hival != noErr)                                     /* something happened */ {
        tommy = DIBadMount(fredpoint, dinfo);
    }
}
 
/* draws my window.  Pretty simple */
void DrawMain(WindowPtr drawIt)
{
    BeginUpdate(drawIt);
    SetPort(drawIt);
    EraseRect(&drawIt->portRect);
    MoveTo(20,20);
    DrawString("\pData passed:");
    if(displayString[0]){
    DrawString(displayString);
    } else {
    DrawString("\p no data sent yet ");
    }
    EndUpdate(drawIt);
}
 
/* my menu action taker.  It returns a Boolean which I usually ignore, but it */
/* mught be handy someday */
Boolean DoSelected(long val)
{
    short loval, hival;
    Boolean temp = false;
    loval = LoWord(val);
    hival = HiWord(val);
    
    switch (hival) {                                        /* switch off the menu number selected */
        case kAppleMenu:                                    /* Apple menu */
            if (loval != 1) {                               /* if this was not About, it's a DA */
                DoDaCall(gAppleMenuHandle, loval);
            } else {
                Alert(128, nil);                            /* do about box */
            }
            break;
        case kFileMenu:                                     /* File menu */
            gQuit = true;                                   /* only  item */
            break;
        case kEditMenu:
            /* edit menu junk */
            /* don't care */
            break;
        case kToolsMenu:
        /* add all your test stuff here */
        
        SendHLE();
        
        break;
       
    }
    HiliteMenu(0);
}
 
/* InitAEStuff installs my appleevent handlers */
void InitAEStuff(void)
{    
    OSErr aevtErr = noErr;
    long aLong = 0;
    Boolean gHasAppleEvents = false;
    /* Check this machine for AppleEvents.  If they are not here (ie not 7.0)
    *   then we exit */
    gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &aLong) == noErr);
    /* The following series of calls installs all our AppleEvent Handlers.
    *   These handlers are added to the application event handler list that 
    *   the AppleEvent manager maintains.  So, whenever an AppleEvent happens
    *   and we call AEProcessEvent, the AppleEvent manager will check our
    *   list of handlers and dispatch to it if there is one.
    */
    if (gHasAppleEvents) {
         aevtErr = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, 
             NewAEEventHandlerProc(AEOpenHandler),0, false);
             if (aevtErr)  ExitToShell();
 
         aevtErr = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, 
             NewAEEventHandlerProc(AEOpenDocHandler),0, false);
             if (aevtErr)  ExitToShell();
 
         aevtErr = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, 
             NewAEEventHandlerProc(AEQuitHandler), 0, false);
             if (aevtErr)  ExitToShell();
 
         aevtErr = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, 
             NewAEEventHandlerProc(AEPrintHandler),0, false);
             if (aevtErr)  ExitToShell();
         
       } 
    else ExitToShell();
    
}
 
/* end InitAEStuff */
/* I'm not doing error handling in this sample for clarities sake, you should. Hah, */
/* easy for me to say, huh? */
void DoHighLevel(EventRecord *AERecord)
{
 
    if(noErr != AEProcessAppleEvent(AERecord)){
    /* if it was not an AppleEvent, it must be my HLE.  Since in this sample I send two at once,
    we'll filter for the second one */
    OSErr myErr;
    MyHLEGetter myData;
    OSType theMessageNow ;
    theMessageNow = kSecondEvent;
    /* set up the myData structure for the type of event I sent second */
    myData.whichData = kMessageField;
    myData.specificData = (Ptr)&theMessageNow;
    GetSpecificHighLevelEvent(gGetSpecificFilterUPP,&myData,&myErr);
    }
    
}
 
/* end DoHighLevel */
 
/* This is the standard Open Application event.  */
pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
{
#pragma unused (messagein,reply,refIn)
    /* we of course don't do anything here in this simple app */
    return(noErr);
}
 
/* end AEOpenHandler */
 
/* Open Doc, opens our documents.  Remember, this can happen at application start AND */
/* anytime else.  If your app is up and running and the user goes to the desktop, hilites one */
/* of your files, and double-clicks or selects Open from the finder File menu this event */
/* handler will get called. Which means you don't do any initialization of globals here, or */
/* anything else except open then doc.  */
/* SO-- Do NOT assume that you are at app start time in this */
/* routine, or bad things will surely happen to you. */
 
pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
{
#pragma unused (reply, refIn)
    /* we of course don't do anything here */
    return(errAEEventNotHandled);                           /* we have no docs, so no odoc events should come to us */
}
 
pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
{                                                           /* no printing handler in yet, so we'll ignore this */
    /* the operation is functionally identical to the ODOC event, with the additon */
    /* of calling your print routine.  */
#pragma unused (reply,refIn)
    /* we of course don't do anything here */
    return(errAEEventNotHandled);                           /* we have no docs, so no pdoc events should come to us */
}
 
/* Standard Quit event handler, to handle a Quit event from the Finder, for example.  */
/* ¥¥¥¥¥ DO NOT CALL EXITTOSHELL HERE ¥¥¥¥¥ or you will never have a happy life.  */
pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
{
#pragma unused (messagein,refIn)
    
    /* prepQuit sets the Stop flag for us.  It does _NOT_ quit, you */
    /* should NEVER quit from an AppleEvent handler.  Calling */
    /* ExitToShell here would blow things up */
    gQuit = true;
    return(noErr);
}
 
 
 
Boolean BrowseForMe(void)
{Str255 tWext = "\p Find Target Application";
Str255 txWext = "\p apps";
 
return(noErr == PPCBrowser(tWext,
                        &txWext,
                        false,
                        &theLoc,
                        &theRec,
                       nil,
                        nil));
 
 
}
 
/*  Send two high level events */
void SendHLE(void)
{OSErr myErr;
EventRecord eventToSend;
EventRecord eventToSend2;
 
Str255 dataToSend = "\p sample data";
Str255 dataToSend2 = "\p sample data2";
/* search for a target address. */
if(BrowseForMe()){
 
    theID.name = theRec.name;
    theID2.name = theRec.name;
eventToSend.what = kHighLevelEvent;
eventToSend.message = kFirstEvent;
eventToSend.where.h = 'IN';
eventToSend.where.v = 'IT';
 
myErr =PostHighLevelEvent(&eventToSend,(unsigned long)&theID,nil,(Ptr)&dataToSend,(dataToSend[0])+1,receiverIDisTargetID);
eventToSend2.what = kHighLevelEvent;
eventToSend2.message = kSecondEvent;
eventToSend2.where.h = '2M';
eventToSend2.where.v = 'VT';
myErr |= PostHighLevelEvent(&eventToSend2,(unsigned long)&theID2,nil,(Ptr)&dataToSend2,(dataToSend2[0])+1,receiverIDisTargetID);
 
if(myErr)DebugStr("\perr on Post");
}
 
 
}
 
/*
Your filter is specified like as below, with these clarifications to the IM VI words
The data pointer you pass (myData) is COMPLETELY up to you.  It's purpose is to give your
filter the ability to be very generic, you pass it whatever information you need to 
decide if this is the event you want.  My structure for the data in this is, as a sample,
typedef struct MyHLEGetter{
short whichData;
Ptr specificData;
}MyHLEGetter;
The data passed in the HighLevelEventMsgPtr is as follows;
struct HighLevelEventMsg {
 unsigned short HighLevelEventMsgHeaderLength;
 unsigned short version;
 unsigned long reserved1;
 EventRecord theMsgEvent;
 unsigned long userRefcon;
 unsigned long postingOptions;
 unsigned long msgLength;
}; 
so you can examine any of these fields to make a determination about whether to accept the event
or not.  By changing the selector in whichData and the data in specificData, you can tell yourself
to examine any of the fields in the HLE record passed.  
*/
 
 
pascal Boolean MyGenericFilter(Ptr myData,HighLevelEventMsgPtr theBuffer,const TargetID *sender)
{
OSType myCheckOSType;
Boolean acceptIt = false;
MyHLEGetter *theSelectionData = (MyHLEGetter *)myData; /* cast for easier reading */
/* so since I may use this many different times, I'd add a switch... */
 
switch(theSelectionData->whichData){
    case kMessageField:
    /* this is the only one I have implemented, tells me that this pass through the */
    /* filter we are looking for an event record that has the message field set to */
    /* the same value as I have in the pointer part of the struct I created and passed */
    /* as myData */
    /* so it's a simple check */
    myCheckOSType = *((OSType *)theSelectionData->specificData);
    if(myCheckOSType == theBuffer->theMsgEvent.message)acceptIt = true;
    break;
    case kRawData:
    break;
    case kRefCon:
    break;
    /* and so on, switching on whatever you need to recognized the event you want. */
}
/* if it is the event I want, then I'll call AcceptHighLevel inside the filter.  */
/* you don't need to do this, you can just return a TRUE and expect the caller of  */
/* GetSpecificHighLevelEvent to do the actual event retreival */
if(acceptIt){
    TargetID sender;
    unsigned long theRefCon;
    Ptr theBuffer = nil;
    unsigned long theLength = 0;
    OSErr myErr;
    
    do{
    myErr = AcceptHighLevelEvent(&sender,
                                  &theRefCon,
                                  theBuffer,
                                  &theLength);
    if(myErr == bufferIsSmall){
    /* small buffer, get the size and do it again */
    theBuffer = NewPtr(theLength);
    } else {
    WindowPtr temp;
    /* move the data into my string display area */
    BlockMove(theBuffer,(Ptr)displayString,theLength);
    GetPort(&temp);
    SetPort(myWindow);
    InvalRect(&myWindow->portRect);
    SetPort(temp);
    break;  /* on any other error, or noErr, exit the thing */
    }
        }while(true);                         
                                  
                                  }
return(acceptIt);
}