BigEasy/BigEasy2.c

/*
    File:       BigEasy2.c
 
    Copyright:  © 1990-1992, 1994 by Apple Computer, Inc., all rights reserved.
 
    This file is used in these builds: Warhol
 
    Change History (most recent first):
 
        <41+>    22-9-94    dvb universal headers   
        <41>     22-9-94    dvb     
        <40+>    17-8-94    dvb     allocate gx job when pagesetup, no sooner, coz its slow.
        <40>     17-8-94    dvb     GX Printing
        <39>      9-8-94    dvb     
        <38>     27-7-94    dvb     installquititem
        <37+>    5/27/94    dvb     InstallQuitItem
        <37>     5/27/94    dvb     .
        <35>      1/7/93    dvb     Compile under mpw.
        <34>      1/6/93    dvb     Built in window-copy command.
        <33>     4/23/92    dvb     Test checkout from new project
        <32>     4/13/92    dvb     Pass activate/deactivates to back windows.
        <31>     3/22/92    dvb     QuitApp message.
        <30>     1/20/92    dvb     Cool new features. Much easier appleevents.
        <29>    12/19/91    JB      removing think 4.0 code
        <28>    10/14/91    JB      added #ifdef to create old window ports for debugging
        <27>     9/18/91    PH      support silly disk inserted events
        <26>     8/12/91    MD      support for timing profiler nastiness
        <25>      7/3/91    PH      qd. is bad under old think
        <24>     6/28/91    dvb     Make it work with/without MacHeaders in LSC5.
        <23>      6/4/91    PH      compilin'
        <22>      6/3/91    dvb     Just hackin.
        <21>     5/28/91    JB      Added prototypes for BigEasy Proc Ptrs
        <20>     5/27/91    PH      to compile again...
        <19>     5/25/91    JB      OLD_THINK_C && TOOLBOX_LINKED
        <18>     5/23/91    PH      changes for THINK 5
        <17>     5/22/91    PH      new style prototypes
        <16>      5/6/91    PH      nifty line after about...
        <15>      5/5/91    dvb     Latest features, and App-Events for document open.
       
        <14>     4/25/91    JB      Changing to new THINK C interface files
        <13>     4/19/91    PH      i like content clicks
        <12>     4/19/91    dvb     Add WindowEventProc
        <11>     3/29/91    PH      minor activate fix
        <10>     3/29/91    dvb     Repair deactivate vs closewindow conflict, roll in latest cool
                                    features.
         <9>      3/9/91    dvb     Adjust to work with or without (LSC) mac headers
         <8>      3/7/91    JB      Adjusting for using MacHeaders
         <7>      3/1/91    dvb     Trivial new functions
         <6>     2/24/91    dvb     Various cool new calls
         <5>     2/18/91    dvb     Miscellaneous Updates
         <4>      1/9/91    JB      Increasing ItemsPerMenu & #Menus
         <3>    11/21/90    JB      Changes for INIT & mpw compatability
         <2>    11/17/90    dvb     Pass on unused command-keys to document windows
        <1> 11/17/90    dvb     New again after 1st CD pressing! Yay!
 
    To Do:
*/
 
/* file: BigEasy2.c
  *
  * Started 30 June 1988, more or less.
  *
  * A set of routines to allow the quick development
  * of simple Macintosh applications.
  * :)
  */
 
 
#define BigEasy2
 
#include <QuickDraw.h>
#include <Gestalt.h>
#include <Events.h>
#include <AppleEvents.h>
#include <Resources.h>
#include <Menus.h>
#include <ToolUtils.h>
#include <Menus.h>
#include <Windows.h>
#include <Dialogs.h>
#include <Memory.h>
#include <devices.h>
#include <Fonts.h>
#include <Scrap.h>
#include <SegLoad.h>
 
//#undef BigEasyGXPrinting
 
#ifdef BigEasyGXPrinting
    #include <PrintingManager.h>
    #include <Graphics Toolbox.h>
    #include <Graphics Routines.h>
#endif
 
 
 
/* #define THINK_C_PROFILE /* */
#if defined(TIMING_PROFILE) || defined(STACK_KILLER)
    #include "stack killer.h"
#endif
 
#include "BigEasy2.h"
 
 
 
#ifdef BigEasyGXPrinting
    #define WantsGX 1
#else
    #define WantsGX 0
#endif
 
/*----------------
    Limits
----------------*/
#define kMMax 10            /* Number of menus in menubar */
#define kMIMax 50           /* Number of items per menu */
#define kMenuNameMax 32     /* Length of a menu title */
 
#define kStagLimX 97
#define kStagLimY 37
 
/*----------------
    Constants
----------------*/
#define kOSEvent                        app4Evt /* event used by MultiFinder */
#define kSuspendResumeMessage           1       /* high byte of suspend/resume event message */
#define kResumeMask                 1       /* bit of message field for resume vs. suspend */
 
#define kWinPosType 'bewP'
#define trapExitToShell 0xA9F4
 
 
 
/*----------------
    Major BigEasy2 Structures
----------------*/
 
typedef struct TEasyWindow
    {
    Boolean wUsed;
    long iNum;
    long flags;
    Boolean wGrowable;
    beUpdateProcPtr wUpdateProc;
    beClickProcPtr wClickProc;
    beKeyProcPtr wKeyProc;
    beGoAwayProcPtr wGoAwayProc;
    beWNumCallProcPtr wZoomProc;
    beActivateProcPtr wActivateProc;
    beDeactivateProcPtr wDeactivateProc;
    beIdleProcPtr wIdleProc;
    beResizeProcPtr wResizeProc;
    beGrowWindowProcPtr wGrowWindowProc;
    beMoveWindowProcPtr wMoveWindowProc;
    beEventProcPtr wEventProc;
    WindowPtr wWindow;
#ifdef BigEasyGXPrinting
    gxJob job;
#endif
    } TEasyWindow;
 
typedef struct
    {
    short ref;
    char mark;
    char enable;
    char cmdEquiv;
    beMenuProcPtr proc;
    } TEasyMenuItem;
 
/*----------------
    Globals
----------------*/
static short gIdleSeed;
static Rect gResizeLim = {50,50,1000,1000};
static TEasyWindow **gEasyWindowListH;          /* Handle to array of window objects    */
static TEasyWindow *gEasyWindowList;            /* Pointer to array of window objects   */
static short gEasyWindowListSize;               /* Number of window objects allocated   */
 
/*** Menus ***/
static MenuHandle gMenuHandleList[kMMax];       /* MenuHandles indexed by MenuID's      */
static short gMenuLength[kMMax];
static char gMenuName[kMMax][kMenuNameMax];
static TEasyMenuItem gMenu[kMMax][kMIMax];
static short gMenuCount;                        /* How many menus defined */
static short gCurrentMenu;                      /* the one to add to */
static MenuHandle gMenuEdit;                    /* Which one is the edit menu? */
 
/*** Phantom Menu ***/
static MenuHandle phantomMenuH = 0;
 
/*** About ***/
static beAboutProcPtr gAboutProc;
static char gAboutS0[256];
 
/*** Application Edit Commands ***/
static beWNumCallProcPtr gAppUndoProc,gAppCutProc,gAppCopyProc,gAppPasteProc,gAppClearProc;
 
static beMenuProcPtr gAppPageSetupProc=0,gAppPrintProc=0;
 
/*** Global Status ***/
static beOpenAppProcPtr gMasterOpenAppProc;
static beOpenDocProcPtr gMasterOpenDocProc;
static beQuitAppProcPtr gMasterQuitAppProc;
 
static beAboutProcPtr gMasterIdleProc;
static short gStagX,gStagY;
static WindowPtr gLastFrontIdle;
static short gLastFrontWindowNumber;
static short gSleep;
static short gCoolDragState;
static Point gCoolDragPoint;
static short gCoolDragWindowNumber;
static TEasyWindow *gCoolDragEW;
static Boolean gInvalidMenuBar;
 
static void *gOldExitToShell;
 
PicHandle GetWindowPICT(TEasyWindow *thisEasyWindow);
 
/*----------------
    Prototypes
----------------*/
static void InitToolbox(void);
static void CheckMenubar(void);
static void EventLoop(void);
static void InitBigEasy(void);
static void ExitBigEasy(void);
static void InstallMyExitToShell(void);
static pascal void MyExitToShell(void);
static void GetGrowRect(WindowPtr,Rect*);
static void EnoughEasyWindows(short);
static void FrontDAEdits(void);
static TEasyWindow *GoodWNum(short);
static Boolean CoolBigEasyCmdKeys(short key);
 
static void DoMyAbout(void);
static void BEUndo(short);
static void BECopy(short);
static void BECut(short);
static void BEPaste(short);
static void BEClear(short);
static void BENull(void);
void BEPageSetup(short n, short menuItem, short menuRef);
void BEPrint(short n, short menuItem, short menuRef);
 
static void MenuClick(Point p);
static void DeleteIndexedMenuItem(short menu,short item);
static Boolean DoKeyPress(long k);
static void MenuPoint(long theclick);
static void StartMenus(void);
static short ScanWindowList(WindowPtr w);
static void DoMouseClick(EventRecord *event);
static void MyDrawGrowIcon(WindowPtr w);
 
static pascal OSErr BigEasyOpenAppThang(AppleEvent *theEvent, AppleEvent *reply,long refCon);
static pascal OSErr BigEasyOpenDocThang(AppleEvent *theEvent, AppleEvent *reply,long refCon);
static pascal OSErr BigEasyQuitAppThang(AppleEvent *theEvent, AppleEvent *reply,long refCon);
static OSErr MissedAEParameters (AppleEvent *message);
 
Boolean ActivateWindow(WindowPtr w, Boolean activate);
 
#ifdef BigEasyGXPrinting
void MakeSureWeHaveJob(TEasyWindow *thisWindow);
#endif
 
void main(void);
 
/*----------------
    Some useful routines
----------------*/
 
void InitToolbox(void)
    {
    InitGraf(&qd.thePort);
    InitFonts();
    FlushEvents(0xffff,0);
    InitWindows();
    InitMenus();
    InitDialogs(0);
    TEInit();
    InitCursor();
    }
 
 
void GetGrowRect(WindowPtr w,Rect *r)
    {
    register Rect *gr;
 
    gr = r;
    *gr = w->portRect;
    gr->left = gr->right - 15;
    gr->top = gr->bottom - 15;
    }
 
void GoWatch(void)
    {
    SetCursor(*(Cursor**)GetCursor(4));
    }
 
void GoArrow(void)
    {
    SetCursor(&qd.arrow);
    }
 
void GoCursor(short c)
/*
  * Attempt to set to cursor ID c,
  * but skip it if not there.
  */
    {
    register Cursor **cur;
 
    cur = (Cursor **)GetCursor(c);
    if(cur)
        SetCursor(*cur);
    }
 
static void EnoughEasyWindows(short n)
/*
  * If there are less than n window objects in the list,
  * grow the handle appropriately.
  */
    {
    short i;
 
    n++;
    if(gEasyWindowListSize < n)
        {
        HUnlock((Handle)gEasyWindowListH);
        SetHandleSize((Handle)gEasyWindowListH,sizeof(TEasyWindow) * (long)n);
        HLock((Handle)gEasyWindowListH);
        gEasyWindowList = *gEasyWindowListH;
 
        for(i = gEasyWindowListSize; i < n; i++)
            gEasyWindowList[i].wUsed = 0;
 
        gEasyWindowListSize = n;
        }
    }
 
static TEasyWindow *GoodWNum(short n)
/*
  * return true if n is the number of an
  * existing, used window.
  */
    {
    register TEasyWindow *thisWindow;
    if(n<0 || n>=gEasyWindowListSize)
        return 0;
    thisWindow = &gEasyWindowList[n];
    if(thisWindow->wUsed)
        return thisWindow;
    else
        return 0;
    }
 
 
static void FrontDAEdits(void)
/*
 * Check the front window. If it's a DA,
 * enable all edit menu options.
 */
    {
    WindowRecord *w;
 
    w = (WindowRecord*)FrontWindow();
    if(w->windowKind < 0)                                   /* Any click in a DA window: */
        EnDisEdits(1,1,1,1,1);                              /* enable edit menu. */
    }
 
 
void DoMyAbout(void)
    {
    DialogPtr d;
    Handle h;
    short hit;
 
    if(gAboutProc)
        (*gAboutProc)();
    else
        {
        h = GetResource('DLOG',1962);                           /* does it exist? */
        if( (ResError()==0) && (h!=nil) )
            {
            ParamText((StringPtr)gAboutS0,0,0,0);
            d = GetNewDialog(1962,0,(WindowPtr)-1);
            ModalDialog(nil,&hit);
            DisposDialog(d);
            }
        }
    }
 
void SetMasterIdle(r)
    beAboutProcPtr r;
    {
    gMasterIdleProc = r;
    }
 
void SetWindowResizeProc(short n,beResizeProcPtr resizeProc)
/*
  * Sets the procedure which gets called when the window is resized
  */
    {
    TEasyWindow *thisWindow;
 
    thisWindow = GoodWNum(n);
    if(thisWindow)
        thisWindow->wResizeProc = resizeProc;
    }
 
void SetWindowGrowWindowProc(short n,beGrowWindowProcPtr growWindowProc)
/*
  * Sets the procedure which gets called when the window grows.
  *   Allows alternate to GrowWindow.
  */
    {
    TEasyWindow *thisWindow;
 
    thisWindow = GoodWNum(n);
    if(thisWindow)
        thisWindow->wGrowWindowProc = growWindowProc;
    }
 
void SetWindowMoveProc(short n,beMoveWindowProcPtr moveWindowProc)
    {
    TEasyWindow *thisWindow;
 
    thisWindow = GoodWNum(n);
    if(thisWindow)
        thisWindow->wMoveWindowProc = moveWindowProc;
    }
 
 
void SetWindowZoomProc(short n,beWNumCallProcPtr zoomProc)
    {
    register TEasyWindow *thisWindow;
 
    thisWindow = GoodWNum(n);
    if(thisWindow)
        thisWindow->wZoomProc = zoomProc;
    }
 
void SetWindowEventProc(short n,beEventProcPtr eventProc)
    {
    register TEasyWindow *thisWindow;
 
    thisWindow = GoodWNum(n);
    if(thisWindow)
        thisWindow->wEventProc = eventProc;
    }
 
long GetWindowFlags(short n)
    {
    TEasyWindow *thisWindow;
 
    if(!(thisWindow = GoodWNum(n)))
        return 0;
 
    return thisWindow->flags;
    }
 
void SetWindowFlags(short n,long flags)
    {
    TEasyWindow *thisWindow;
 
    if(!(thisWindow = GoodWNum(n)))
        return;
 
    thisWindow->flags = flags;
    }
 
void SetAbout(StringPtr progName,StringPtr s0,beAboutProcPtr aboutProc)
/*
 * Sets the program's name in the about box, and
 * sets the second string as ParamText 0 (^0)
 * for the about dialog, 1962.
 */
    {
    short i;
    
    SetItem(gMenuHandleList[1],1,(StringPtr)progName);
 
    for(i=0; i<256; i++)
        gAboutS0[i] = *s0++;
 
    gAboutProc = aboutProc;
    } 
 
/*----------------
    Error Handling
----------------*/
 
void InstallMyExitToShell(void)
/*
  * Add my HatStrap call to
  * the classic routine, "ExitToShell"
  */
    {
    gOldExitToShell =  (void *) NGetTrapAddress(trapExitToShell, ToolTrap);
    NSetTrapAddress((UniversalProcPtr) MyExitToShell, trapExitToShell, ToolTrap);
    }
 
pascal void MyExitToShell(void)
/*
  * My exit routine, which does
  * all the good cleanup.
  */
    {
    Hatstrap();
    NSetTrapAddress((UniversalProcPtr) gOldExitToShell, trapExitToShell, ToolTrap);
    ExitToShell();
    }   
 
void FailNil(long x)
/*
  * If x is zero, post an error
  * alert and quit the program.
  */
    {
    if(!x)
        {
        Alert(200,nil);
        Debugger();
        ExitToShell();
        }
    }
 
void FailOSErr(long x)
/*
  * If x isn't zero, post an error
  * alert and quit the program.
  */
    {
    if(x)
        {
        Debugger();
        Alert(200,nil);
        ExitToShell();
        }
    }
 
/*----------------
    Some inherent methods
----------------*/
 
void BEUndo(short n)
    {
    if(!SystemEdit(0) && gAppUndoProc)
        (*gAppUndoProc)(n);
    }
 
void BECut(short n)
    {
    if(!SystemEdit(2) && gAppCutProc)
        (*gAppCutProc)(n);
    }
 
PicHandle GetWindowPICT(TEasyWindow *tew)
    {
    Rect visBounds;
    beUpdateProcPtr fp;
    PicHandle picH;
 
    SetPort(tew->wWindow);  /* Set port to window   */
 
    visBounds = qd.thePort->portRect;
    InsetRect(&visBounds,-1,-1);
    ForeColor(blackColor);
    BackColor(whiteColor);
    PenSize(1,1);
 
    picH = OpenPicture(&visBounds);
    ClipRect(&visBounds);
    FrameRect(&visBounds);
 
    fp = tew->wUpdateProc;
    if(fp)
        (*fp)(tew->iNum);                           /* Call drawing proc    */
 
    SetOrigin(0,0);
 
    ClosePicture();
    ClipRect(&gBigRect);
 
    return picH;
    }
 
 
void BECopy(short n)
    {
    TEasyWindow *thisEasyWindow;
 
    if(!SystemEdit(3))
        {
        thisEasyWindow = GoodWNum(n);
        if(thisEasyWindow->flags & wCopyDraw)
            /*
             * 
             */
            {
            PicHandle picH;
 
            picH = GetWindowPICT(thisEasyWindow);
 
            HLock((Handle)picH);
            ZeroScrap();
            PutScrap(GetHandleSize((Handle)picH),'PICT',(Ptr)*picH);
 
            KillPicture(picH);
            }
        else if(gAppCopyProc)
            (*gAppCopyProc)(n);
        }
    }
 
void BEPaste(short n)
    {
    if(!SystemEdit(4) && gAppPasteProc)
        (*gAppPasteProc)(n);
    }
 
void BEClear(short n)
    {
    if(!SystemEdit(5) && gAppClearProc)
        (*gAppClearProc)(n);
    }
 
void BENull(void){}
 
 
void BEPageSetup(short n, short menuItem, short menuRef)
    {
    OSErr err;
    long oldMenus;
 
#ifdef BigEasyGXPrinting
    TEasyWindow *tew;
    gxDialogResult result;
    gxEditMenuRecord editMenuRec;
 
    tew = GoodWNum(n);
    if(tew->flags & wPrintDraw)
        {
        oldMenus = DisableAllMenus();
    
        editMenuRec.editMenuID = 0;
        editMenuRec.cutItem = 0; 
        editMenuRec.copyItem = 0;
        editMenuRec.pasteItem = 0;
        editMenuRec.clearItem = 0;
        editMenuRec.undoItem = 0;
        
        MakeSureWeHaveJob(tew);
        result = GXJobDefaultFormatDialog(tew->job,&editMenuRec);
        err = GXGetJobError(tew->job);
    
        EnableAllMenus(oldMenus);
        }
    else
#endif
        {
        if(gAppPageSetupProc)
            (*gAppPageSetupProc)(n,menuItem,menuRef);
        }
    }
 
void BEPrint(short n, short menuItem, short menuRef)
    {
    OSErr err;
    PicHandle picH;
    Rect pictR,centeredR,pageR;
    Point p;
    Str255 s;
    long oldMenus;
 
#ifdef BigEasyGXPrinting
    TEasyWindow *tew;
    gxFormat format;
    gxTranslationStatistic stats;
    gxRectangle pageSize,paperSize;
    gxDialogResult result;
    gxEditMenuRecord editMenuRec;
    gxShape sh;
 
    tew = GoodWNum(n);
    if(tew->flags & wPrintDraw)
        {
        oldMenus = DisableAllMenus();
    
        editMenuRec.editMenuID = 0;
        editMenuRec.cutItem = 0; 
        editMenuRec.copyItem = 0;
        editMenuRec.pasteItem = 0;
        editMenuRec.clearItem = 0;
        editMenuRec.undoItem = 0;
        
        MakeSureWeHaveJob(tew);
        result = GXJobPrintDialog(tew->job,&editMenuRec);
        err = GXGetJobError(tew->job);
    
        picH = GetWindowPICT(tew);
    
        pictR = (**picH).picFrame;
        p.h = p.v = 0;
 
        /*
          * Center the image in the page rectangle
          */
        format = GXGetJobFormat(tew->job,1);
        GXGetFormatDimensions(format,&pageSize,&paperSize);
        pageR.top = pageSize.top >> 16;
        pageR.bottom = pageSize.bottom >> 16;
        pageR.left = pageSize.left >> 16;
        pageR.right = pageSize.right >> 16;
        centeredR = pictR;
        OffsetRect(&centeredR,
                (pageR.left + pageR.right - pictR.left - pictR.right + 1) >> 1,
                (pageR.top + pageR.bottom - pictR.top - pictR.bottom + 1) >> 1);
    
        sh = GXConvertPICTToShape(picH, gxDefaultOptionsTranslation, &pictR, &centeredR, p, nil, &stats);
    
        GetWTitle(tew->wWindow,s);
    
        GXStartJob(tew->job,s,0);
        err = GXGetJobError(tew->job);
        GXPrintPage(tew->job,1,nil,sh);
        err = GXGetJobError(tew->job);
        GXFinishJob(tew->job);
        err = GXGetJobError(tew->job);
        GXDisposeShape(sh);
    
        EnableAllMenus(oldMenus);
        }
#endif
        {
        if(gAppPageSetupProc)
            (*gAppPageSetupProc)(n,menuItem,menuRef);
        }
    }
 
 
/*----------------
    Menu Action Routines
----------------*/
 
Boolean DoKeyPress(long k)
    {
    register long thePoint;
    register Boolean didIt;
 
    thePoint = MenuKey((char)k);
    didIt = (thePoint>>16) != 0;
    if(didIt)
        MenuPoint(thePoint);
 
    return didIt;
    }
    
void MenuClick(Point p)
    {
    KeyMap  theKeys;
    Boolean putBack = false;
    short   oldID;
    
    if (phantomMenuH) {
    GetKeys(theKeys);
        
        if ((theKeys[1]&4) == 0) {
            putBack = true;
            oldID = (**phantomMenuH).menuID;
            DeleteMenu( oldID );
            }
        }
    MenuPoint(MenuSelect(p));
    if (putBack)
        {
        InsertMenu(phantomMenuH,oldID);
        }
    }
 
void MenuPoint(long theclick)
    {
    register short mID,mItem;
    char DAname[30];
    short wNum;
    TEasyWindow *thisWindow;
    register beMenuProcPtr aProc;
    register TEasyMenuItem *emi;
 
    mID = theclick>>16;
    mItem = theclick & 0xffff;
 
    if(mID == 0) return;
 
    if(mID == 1)                            /* Apple menu */
        {
        if(mItem == 1)                      /* Its either the about box */
            DoMyAbout();
        else    
            {                                   /* Or a DA */
            GetItem(gMenuHandleList[1],mItem,(StringPtr)DAname);
            OpenDeskAcc((StringPtr)DAname);
            }
        }
    else
        {
        wNum = gLastFrontWindowNumber;
        thisWindow = GoodWNum(wNum);
        if(thisWindow)                                  /* if one of our window in front, setport   */
            SetPort(thisWindow->wWindow);
 
        emi = &gMenu[mID][0];
        aProc = emi->proc;
        if(aProc)                                       /* call the menu's routine, if any      */
            (*aProc)(wNum,mItem,gMenu[mID][mItem].ref);
 
        emi = &gMenu[mID][mItem];
        aProc = emi->proc;
        if(aProc)                                       /* call the item's routine, if any      */
            (*aProc)(wNum,mItem,emi->ref);
        }
 
    HiliteMenu(0);
    }
 
char dAbout[] = "\pAbout ";
 
void StartMenus(void)
/*
 * Start with just an About box, and some DA's.
 */
    {
    char aboutS[255];
    MenuHandle applemenu;
 
    BlockMove(&dAbout[0],aboutS,dAbout[0]+1);           /* "About" */
    BlockMove((StringPtr )0x910 + 1,aboutS + aboutS[0] + 1, *(StringPtr )0x910); /* ProgName */
    aboutS[0] += *((StringPtr )0x910);
    aboutS[aboutS[0] + 1] = 'É';
    aboutS[0]++;
 
    applemenu = NewMenu(1,(StringPtr)"\p");                /* Apple menu: ID 1                 */
    AppendMenu(applemenu,(StringPtr)aboutS);
    AppendMenu(applemenu,(StringPtr)"\p(-");
    AddResMenu(applemenu,'DRVR');
    InsertMenu(applemenu,0);
    DrawMenuBar();
    gMenuHandleList[1] = applemenu;
    gMenu[1][0].enable = true;
 
    gMenuCount = 1;                     /* Next menu added will be ID 2     */
    gCurrentMenu = 1;
    gMenuLength[1] = 0;                 /* No items, really, in Apple menu      */
    }
 
MenuHandle InstallMenu(StringPtr s,beMenuProcPtr action,short ref)
/*
 * Start a new menu with name s
 */
    {
    register TEasyMenuItem *emi;
    register MenuHandle mh;
 
    gMenuCount++;                               /* new menu                     */
    gCurrentMenu = gMenuCount;
 
    if(*s > kMenuNameMax-1)
        *s = kMenuNameMax-1;
 
    gMenuLength[gCurrentMenu] = 0;
    mh = NewMenu(gCurrentMenu,(StringPtr)s);
    gMenuHandleList[gCurrentMenu] = mh;
    InsertMenu(mh,0);
 
    emi = &gMenu[gCurrentMenu][0];
    emi->enable = ref >= 0;
    if(!emi->enable)
        {
        DisableItem(mh,0);
        ref =- ref;
        }
    emi->proc = action;
    emi->ref = ref;
 
    gInvalidMenuBar = true;                 /* redraw soon */
    BlockMove(s,gMenuName[gCurrentMenu],*s+1);
    return mh;
    }
 
static Str255 dQuitString = "\pQuit ";
#define kQuitLength 5
static Str15 dQuitCmdKey = "\p/Q";
 
void InstallQuitItem(beMenuProcPtr action,short ref)
    {
    short i,j;
    StringPtr w;
 
    i = kQuitLength;
 
    w = (StringPtr)0x910;
    j = *w++;
    while(j--)
        dQuitString[++i] = *w++;
 
    w = dQuitCmdKey;
    j = *w++;
    while(j--)
        dQuitString[++i] = *w++;
 
    dQuitString[0] = i;
 
    InstallMenuItem(dQuitString,action,ref);
    }
 
 
 
void InstallMenuItem(StringPtr s,beMenuProcPtr action,short ref)
/*
 * Add an item to the last menu, and associate a routine with it.
 */
    {
    register MenuHandle mh;
    register TEasyMenuItem *emi;
    register short item;
 
 
    mh = gMenuHandleList[gCurrentMenu];
    gMenuLength[gCurrentMenu]++;
    item = gMenuLength[gCurrentMenu];
    emi = &gMenu[gCurrentMenu][item];
 
    if (ref < 0)
        {
        DisableItem(mh,item);
        ref =- ref;
        emi->enable = 0;
        }
    else
        emi->enable = 1;
 
    AppendMenu(mh,(StringPtr)s);
    emi->proc = action;
    emi->ref = ref;
    emi->mark = 0;
    if(*(s+*s-1) == '/')
        emi->cmdEquiv = *(s+*s);
    else
        emi->cmdEquiv = 0;
    }
 
void RemoveMenuItem(short ref)
/*
 * Remove all menu items with
 * refcon ref.
 */
    {
    short menu;
    short item;
 
    for(menu = 1; menu <= gMenuCount; menu++)
        for(item = gMenuLength[menu]; item > 0; item--)
            {
            if(gMenu[menu][item].ref == ref)
                DeleteIndexedMenuItem(menu,item);
            }
    }
 
void DeleteIndexedMenuItem(short menu,short item)
    {
    StringPtr oldStrings;
    MenuHandle mh;
    short i;
    short itemCount;
    register TEasyMenuItem *emi;
    register StringPtr w;
 
    itemCount = gMenuLength[menu];
    mh = gMenuHandleList[menu];
    oldStrings = (StringPtr)NewPtrClear(256 * (itemCount));
    FailNil((long)oldStrings);
 
    for(i = 1; i<=itemCount; i++)
        GetItem(mh,i,(StringPtr)&oldStrings[(i-1)*256]);
 
    DeleteMenu(menu);
    DisposeMenu(mh);
 
    mh = NewMenu(menu,(StringPtr)gMenuName[menu]);
    emi = &gMenu[menu][1];
    w = oldStrings;
    for(i = 1; i<=itemCount; i++)
        {
        if(i != item)
            {
            if(emi->cmdEquiv)
                {
                *(w+*w+1) = '/';
                *(w+*w+2) = emi->cmdEquiv;
                *w = *w + 2;
                }
            AppendMenu(mh,(StringPtr)w);
            }
        emi++;
        w += 256;
        }
 
    emi = &gMenu[menu][item];
    for(i = item; i<itemCount; i++)
        {
        *emi = *(emi+1);
        emi++;
        }
 
    gMenuLength[menu]--;
    itemCount--;
 
    emi = &gMenu[menu][1];
    for(i = 1; i<=itemCount; i++)
        {
        if(!emi->enable)
            DisableItem(mh,i);
        if(emi->mark)
            SetItemMark(mh,i,emi->mark);
        emi++;
        }
 
    InsertMenu(mh,menu+1);
    DisposPtr((Ptr)oldStrings);
    }
 
void InstallEditMenu(beWNumCallProcPtr Xundo,
        beWNumCallProcPtr Xcut,
        beWNumCallProcPtr Xcopy,
        beWNumCallProcPtr Xpaste,
        beWNumCallProcPtr Xclear)
    /*
     * Start an edit menu, and put the first six things in.
     */
    {
    gAppUndoProc = Xundo;
    gAppCutProc = Xcut;
    gAppCopyProc = Xcopy;
    gAppPasteProc = Xpaste;
    gAppClearProc = Xclear;
 
    InstallMenu("\pEdit",nil,0);
    InstallMenuItem("\px/Z",(beMenuProcPtr)BEUndo,-mUndo);          /* barfs because it is static */
    InstallMenuItem("\p(-",(beMenuProcPtr)BENull,0);
    InstallMenuItem("\px/X",(beMenuProcPtr)BECut,-mCut);
    InstallMenuItem("\px/C",(beMenuProcPtr)BECopy,-mCopy);
    InstallMenuItem("\px/V",(beMenuProcPtr)BEPaste,-mPaste);
    InstallMenuItem("\px/B",(beMenuProcPtr)BEClear,-mClear);
 
    gMenuEdit = gMenuHandleList[gCurrentMenu];
 
    EnDisEdits(-1,-1,-1,-1,-1);
    }
 
void InstallPrintItems(beMenuProcPtr pageSetup,beMenuProcPtr print)
    {
    gAppPageSetupProc = pageSetup;
    gAppPrintProc = print;
 
    InstallMenuItem("\pPage SetupÉ/¹",(beMenuProcPtr)BEPageSetup,-mPageSetup);
    InstallMenuItem("\pPrintÉ/P",(beMenuProcPtr)BEPrint,-mPrint);
    }
 
void SetMenuItem(short ref,char enable,char isMarked,char mark,StringPtr s)
/*
  * Set all items with the reference number to the
  * enable/disable state, with mark, and name s.
  * pass enable + to enable, - to disable, and
  * zero to leave alone.
  */
    {
    short m,i;
    MenuHandle mh;
    register TEasyMenuItem *emi;
 
    for(m=1; m<=gMenuCount; m++)
        {
        mh = gMenuHandleList[m];
        for(i=gMenuLength[m]; i>=0; i--)
            {
            emi = &gMenu[m][i];
            if(emi->ref == ref)
                {
                if(enable)
                    {
                    if(!i)
                        gInvalidMenuBar = true;
                    if(enable > 0)
                        {
                        emi->enable = 1;
                        EnableItem(mh,i);
                        }
                    else
                        {
                        emi->enable = 0;
                        DisableItem(mh,i);
                        }
                    }
                if(i > 0)                   /* these only apply to items */
                    {
                    if(isMarked)
                        if(isMarked > 0)
                            {
                            emi->mark = mark;
                            SetItemMark(mh,i,mark);
                            //CheckItem(mh,i,true);
                            }
                        else
                            {
                            emi->mark = 0;
                            SetItemMark(mh,i,0);
                            }
                    if(s)
                        SetItem(mh,i,(StringPtr)s);
                    }
                }
            }
        }
    }
 
 
 
void EnDisEdits(short Eundo,short Ecut,short Ecopy,short Epaste,short Eclear)
/*
 * For each edit menu entry,
 * -1=disable, 1=enable, 0=leave alone.
 */
    {
    SetMenuItem(mUndo,Eundo,false,0,"\pUndo");
    SetMenuItem(mCut,Ecut,false,0,"\pCut");
    SetMenuItem(mCopy,Ecopy,false,0,"\pCopy");
    SetMenuItem(mPaste,Epaste,false,0,"\pPaste");
    SetMenuItem(mClear,Eclear,false,0,"\pClear");
    }
 
MenuHandle SetCurrentMenu(short ref)
/*
 * Set which menu will take
 * future "InstallMenuItem"s.
 */
    {
    register short i;
 
    for(i = 0; i<gMenuCount; i++)
        {
        if(gMenu[i][0].ref == ref)
            {
            gCurrentMenu = i;
            return gMenuHandleList[i];
            }
        }
    return 0;
    }
 
long DisableAllMenus(void)
/*
 * Disable all menus, as for a modal dialog,
 * and return a long with the masks of which should get reenabled.
 */
    {
    long result;
    long mask;
    TEasyMenuItem *emi;
    short i;
 
    result = 0;
    mask = 1;
    for(i = 0; i<kMMax; i++)
        {
        emi = &gMenu[i][0];
        if(emi->enable)
            {
            DisableItem(gMenuHandleList[i],0);
            result |= mask;
            }
        mask <<= 1;
        }
    DrawMenuBar();
    return result;
    }
 
void EnableAllMenus(long saveMenus)
/*
 * Enable menus according to the mask returned by DisableAllMenus().
 */
    {
    long mask;
    short i;
 
    mask = 1;
    for(i = 0; i<kMMax; i++)
        {
        if(saveMenus & mask)
            EnableItem(gMenuHandleList[i],0);
        mask <<= 1;
        }
    DrawMenuBar();
    }
 
 
short ScanWindowList(WindowPtr w)
/*
  * return a window number from a WindowPeek,
  * or -1 if no known window.
  */
    {
    short i;
    TEasyWindow *wo;
 
    wo= &gEasyWindowList[0];
 
    for(i=0; i<gEasyWindowListSize; i++)
        {
        if (wo->wUsed && (wo->wWindow==w))
            return i;
        wo++;
        }
    return -1;
    }
 
 
/*----------------
    Mouse Action Routines
----------------*/
void DoMouseClick(EventRecord *event)
    {
    WindowPtr w;
    short part;
    register short wNum;
    register TEasyWindow *thisEasyWindow;
    Point p;
    Rect r;
    Boolean tookEvent;
 
    p = event->where;
    part = FindWindow (p, &w);
    wNum = ScanWindowList(w);
    thisEasyWindow = GoodWNum(wNum);
 
    switch (part)
        {
        case inDesk:
            break;
 
        case inMenuBar:
            MenuClick(p);
            break;
        
        case inSysWindow:
            SystemClick(event,w);
            break;
        
        case inContent:
        contentClick:
            if (w != FrontWindow())             /* If clicked on a non-front window, */
                SelectWindow(w);                            /* bring it to the front. */
            else if(thisEasyWindow)                         /* Click on front window: give click */
                {                                       /* to window's click routine. */
                SetPort(w);
                GlobalToLocal(&p);
 
                ClipRect(&gBigRect);
                SetOrigin(0,0);
 
                if(thisEasyWindow && thisEasyWindow->wEventProc)
                    (*thisEasyWindow->wEventProc)(wNum,event,&tookEvent);
                else
                    tookEvent = false;
 
                if(!tookEvent)
                    {
                    register beClickProcPtr fp;
 
                    fp = thisEasyWindow->wClickProc;
                    if(fp)
                        (*fp)(wNum,p,
                                event->modifiers);
                    }
                }
            break;
 
        case inDrag:
            if(((thisEasyWindow->flags & wCoolDrag)!=0)
                    ^ ((event->modifiers & optionKey)!=0))
                {
                gCoolDragPoint = event->where;
                gCoolDragState = 1;
                gCoolDragEW = thisEasyWindow;
                gCoolDragWindowNumber = wNum;
                if(!(event->modifiers & 256))
                    SelectWindow(w);
                }
            else
                if(Button())                                /* for quick title-bar clicks */
                    {
                    beMoveWindowProcPtr fp;
 
                    DragWindow(w,event->where,&gBigRect);
                    fp = thisEasyWindow->wMoveWindowProc;
                    if(fp)
                        (fp)(wNum);                 
                    }
                else
                    SelectWindow(w);
            break;
 
        case inGrow:
            if(thisEasyWindow && (thisEasyWindow->flags & wGrowable))
                {
                long oldSize,newSize;
                beGrowWindowProcPtr fp;
                beResizeProcPtr rsfp;
                
                SetPort(w);
                GetGrowRect(w,&r);
                InvalRect(&r);
 
                fp = thisEasyWindow->wGrowWindowProc;
                if(fp)
                    (*fp)(&newSize,wNum,w,event->where,&gResizeLim);
                else
                    newSize = GrowWindow(w,event->where,&gResizeLim);
 
                if(newSize)
                    {
                    rsfp = thisEasyWindow->wResizeProc;
                    if(rsfp)
                        {
                        oldSize = ((long)(w->portRect.bottom-w->portRect.top)<<16) |
                                (w->portRect.right-w->portRect.left);
                        (*rsfp)(wNum,(Point *)&oldSize,(Point *)&newSize,event->modifiers);
                        }
                    else
                        SizeWindow(w,newSize&0xffff,newSize>>16,1);
                    GetGrowRect(w,&r);
                    InvalRect(&r);
                    }
                }
            else
                goto contentClick;
            break;
 
        case inGoAway:
            if(thisEasyWindow)
                if (TrackGoAway(w,event->where))
                    {
                    beGoAwayProcPtr fp;
                    
                    fp = thisEasyWindow->wGoAwayProc;
                    if(fp)
                        (*fp)(wNum);
                    }
            break;
 
        /*
         * The following way to handle zoom only
         * applies to zooming to 1 state.  This does
         * not handle zooming in and out between 2
         * states.  Check IM IV.
         */
 
        case inZoomIn:  /* zoomBox */
        case inZoomOut:
            if(thisEasyWindow)
                {
                if (TrackBox(w,event->where,part))
                    {
                    beWNumCallProcPtr fp;
                    
                    fp = thisEasyWindow->wZoomProc;
                    if(fp)
                        (*fp)(wNum);
                    }
                }
            break;
        }
    }
 
/*----------------
    Window Action Routines
----------------*/
 
WindowPtr InstallWindow(short iNum,StringPtr iTitle,Rect *iRect,short iType,short iFlags,
        beUpdateProcPtr iUpdate,beClickProcPtr iClick,beKeyProcPtr iKey,beGoAwayProcPtr iGoAway,
        beActivateProcPtr iActivate,beDeactivateProcPtr iDeactivate,beIdleProcPtr iIdle)
/*
 * Add a window to BigEasy's list. If the window is
 * already up somewhere, bring it to the front and
 * visualize it.
 */
    {
    TEasyWindow *thisWindow;
    Rect stagRect,**oldPos;
    Boolean isVisible;
    RgnHandle rh;
    KeyMap km;
    Boolean opt;
 
    GetKeys(km);
 
    opt =km[58/8] &  (1<< (58%8) );
 
    isVisible = iNum>0;
    if(!isVisible)
        iNum = -iNum;
 
    EnoughEasyWindows(iNum);            /* Make sure there's space for new one      */
    thisWindow = &gEasyWindowList[iNum];
 
    if (thisWindow->wUsed)              /* something already assigned to this window? */
        {
        Show(iNum);
        goto goHome;
        }
 
    oldPos = (Rect **)Get1Resource(kWinPosType,iNum);   /* attempt to find saved window position        */
    stagRect = *iRect;
 
    if(oldPos && !opt)                                  /* (option key "forgets" old window */
        OffsetRect(&stagRect,
                (**oldPos).left - stagRect.left,(**oldPos).top - stagRect.top);
 
        {
        Rect lilRect;
 
        lilRect.top = stagRect.top - 10;
        lilRect.left = stagRect.left + 4;
        lilRect.bottom = lilRect.top + 1;
        lilRect.right = lilRect.left + 1;
 
        rh = NewRgn();
        RectRgn(rh,&lilRect);
        SectRgn(rh,*(RgnHandle *)0x9EE,rh);
        if(EmptyRgn(rh) && gWindowsInView)
            OffsetRect(&stagRect,50 - iRect->left,80 - iRect->top);
 
        if(gStaggerWindows)
            {
            gStagX = (gStagX + gStagStepX)%kStagLimX;
            gStagY = (gStagY + gStagStepY)%kStagLimY;
            OffsetRect(&stagRect,gStagX,gStagY);
            }
        DisposeRgn(rh);
        }
 
    thisWindow->wUsed = 1;
 
    if(gHasColor)
        thisWindow->wWindow = NewCWindow(0,&stagRect,(StringPtr)iTitle,isVisible,
                ((iFlags & wZoomable) != 0) ? zoomDocProc : iType,
                (WindowPtr)-1,iGoAway!=0,0);
    else
        thisWindow->wWindow = NewWindow(0,&stagRect,(StringPtr)iTitle,isVisible,
                ((iFlags & wZoomable) != 0) ? zoomDocProc : iType,
                (WindowPtr)-1,iGoAway!=0,0);
 
    SetPort(thisWindow->wWindow);
 
    thisWindow->flags = iFlags;
    thisWindow->iNum = iNum < 0 ? -iNum : iNum;
    thisWindow->wUpdateProc = iUpdate;
    thisWindow->wClickProc = iClick;
    thisWindow->wKeyProc = iKey;
    thisWindow->wGoAwayProc = iGoAway;
    thisWindow->wZoomProc = nil;
    thisWindow->wActivateProc = iActivate;
    thisWindow->wDeactivateProc = iDeactivate;
    thisWindow->wIdleProc = iIdle;
    thisWindow->wResizeProc = nil;
    thisWindow->wGrowWindowProc = nil;
    thisWindow->wMoveWindowProc = nil;
    thisWindow->wEventProc = nil;
 
#ifdef BigEasyGXPrinting
    thisWindow->job = nil;
#endif
 
goHome:
    return thisWindow->wWindow;
    }
 
 
#ifdef BigEasyGXPrinting
void MakeSureWeHaveJob(TEasyWindow *thisWindow)
    {
    if(!thisWindow->job)
        if((thisWindow->flags & wPrintDraw) && gHasGX)
            {
            GoWatch();
            GXNewJob(&thisWindow->job);
            GoArrow();
            }
    }
#endif
 
 
 
 
void UninstallWindow(short iNum)
    {
    register TEasyWindow *thisWindow;
    register beDeactivateProcPtr fp;
 
    gCoolDragState = 0;                 /* just in case we were dragging the dissappeared window */
 
    if(!(thisWindow = GoodWNum(iNum)))
        return;
 
    SetPort(thisWindow->wWindow);
 
    fp = thisWindow->wDeactivateProc;
    if(fp)
        (*fp)(iNum);
    CloseWindow(thisWindow->wWindow);
    EnDisEdits(-1,-1,-1,-1,-1);
 
#ifdef BigEasyGXPrinting
    if((thisWindow->flags & wPrintDraw) && gHasGX)
        GXDisposeJob(thisWindow->job);
#endif
 
    thisWindow->wUsed = 0;
    }
 
void Show(short iNum)
    {
    register TEasyWindow *thisWindow;
 
    thisWindow = GoodWNum(iNum);
    if(thisWindow)
        {
        if(!((WindowPeek)(thisWindow->wWindow))->visible)   /* If so, just show it, and bring it to the front. */
            ShowWindow(thisWindow->wWindow);
        SelectWindow(thisWindow->wWindow);
        }
    }
 
void Hide(short iNum)
/*
  * Just do HideWindow to the
  * specified window number.
  */
    {
    register TEasyWindow *thisWindow;
 
    gCoolDragState = 0;                                 /* It might have been this window */
 
    thisWindow = GoodWNum(iNum);
    if(thisWindow)
        HideWindow(thisWindow->wWindow);
    }
 
    
 
void GetWindowRect(short n,Rect *r)
/*
  * return the window's current rectangle
  * in global cošrdinate space.
  */
    {
    TEasyWindow *thisWindow;
    WindowPtr g;
 
    if(!(thisWindow = GoodWNum(n)))
        return;
 
    if(thisWindow->wUsed)
        {
        g = thisWindow->wWindow;
        SetPort(g);
        *r = g->portRect;
        LocalToGlobal((Point *)r);
        LocalToGlobal((Point *)( (char*)r + 4));
        }
    }
        
WindowPtr GetWindowPtr(short n)
/*
  * return the windowptr for
  * the specified window number
  */
    {
    TEasyWindow *thisWindow;
    WindowPtr g;
 
    if(!(thisWindow = GoodWNum(n)))
        g = 0;
    else
        g = thisWindow->wWindow;
 
    return g;
    }
 
Boolean GetWindowVisible(short n)
/*
  * return true if the window exists,
  * and is visible, or false if its invisible
  * or doesn't exist.
  */
    {
    register WindowPtr g;
 
    g = GetWindowPtr(n);
    if(g)
        return ((WindowPeek)g)->visible;
    else
        return false;
    }
 
void SaveWindowPosition(short n)
/*
  * Save the position of window number n,
  * or all windows if n = -1;
  */
    {
    Rect **rH;
    register Rect *r;
    register short i;
    register short n1,n2;
    TEasyWindow *thisWindow;
 
    rH = (Rect **)NewHandleClear(sizeof(Rect));
    FailNil((long)rH);
    HLock((Handle)rH);
    r = *rH;
 
    if(n < 0)
        {
        n1 = 0;
        n2 = gEasyWindowListSize-1;
        }
    else
        n1 = n2 = n;
 
    for(i = n1; i<=n2; i++)
        {
        thisWindow = GoodWNum(i);
        if(thisWindow && thisWindow->wUsed)
            {
            GetWindowRect(i,r);
            if( !((WindowPeek)(thisWindow->wWindow))->visible )
                SwapShort(r->left,r->right);
            Replace1Resource((Handle)rH,kWinPosType,i);
            }
        }
 
    DisposHandle( (Handle)rH );
    }
 
void ForgetWindowPosition(short n)
/*
  * Forget the saved window position n,
  * or all windows if n<0.
  */
    {
    register short i;
    register short n1,n2;
    register TEasyWindow *thisWindow;
 
    if(n < 0)
        {
        n1 = 0;
        n2 = gEasyWindowListSize-1;
        }
    else
        n1 = n2 = n;
 
    for(i = n1; i<=n2; i++)
        {
        thisWindow = GoodWNum(i);
        if(thisWindow && thisWindow->wUsed)
            Replace1Resource(0,kWinPosType,i);
        }
    }
 
 
void Replace1Resource(Handle h,long type,short id)
/*
  * This is AddResource with a
  * RmveResource if necessary.
  * Pass h==nil to delete the resource.
  */
    {
    Handle old;
 
    /*
     * A lame hack to prevent writing resources
     * to a lightspeed project file.
     */
    if( *(StringPtr)(0x910 + (*(StringPtr)0x910)) == '¹')
        {
        /* do nothing */
        }
    else
        {
 
        old = Get1Resource(type,id);
        if(old)
            RemoveResource(old);
        if(h)
            {
            AddResource(h,type,id,(StringPtr)"\p");
            WriteResource(h);
            DetachResource(h);
            }
 
        }
    }
 
void CheckMenubar(void)
    {
    if(gInvalidMenuBar)
        {
        DrawMenuBar();
        gInvalidMenuBar = false;
        }
    }
 
/*----------------
    Event Routines
----------------*/
 
Boolean HandleUpdateEvent(EventRecord *er)
/*
 * Update the appropriate window, if we know who it is.
 */
    {
    Boolean result;
    short wNum;
    TEasyWindow *thisEasyWindow;
    WindowPtr w;
    GrafPtr oldPort;
 
    GetPort(&oldPort);
    result = false;
 
    if(er->what != updateEvt)
        {
        result = false;
        goto goHome;
        }
 
    w = (WindowPtr)er->message;
    wNum = ScanWindowList(w);                   /* other than null or click, scan list      */
    thisEasyWindow = GoodWNum(wNum);            /* and get record                   */
 
    if(thisEasyWindow)
        {
        Rect visBounds;
        beUpdateProcPtr fp;
 
        SetPort(w);
        BeginUpdate(w);
    
        result = true;
        visBounds = (**w->visRgn).rgnBBox;
        fp = thisEasyWindow->wUpdateProc;
        if(fp)
            {
            SetPort(thisEasyWindow->wWindow);                   /* Set port to window   */
            (*fp)(wNum);            /* Call drawing proc        */
            }
 
        SetOrigin(0,0);
 
        if (thisEasyWindow->flags & wGrowable)          /* Draw growbox, if...  */
            MyDrawGrowIcon(w);
 
        ClipRect(&gBigRect);
 
 
        DrawControls(w);
        EndUpdate(w);
        }
    else
        result = false;
 
goHome:
 
    SetPort(oldPort);
    return result;
    }
 
 
Boolean ActivateWindow(WindowPtr w, Boolean activate)
    {
    Boolean result;
    short wNum;
    TEasyWindow *thisEasyWindow;
    GrafPtr oldPort;
 
    GetPort(&oldPort);
 
    wNum = ScanWindowList(w);                   /* other than null or click, scan list      */
    thisEasyWindow = GoodWNum(wNum);            /* and get record                   */
 
    if(!thisEasyWindow)
        {
        result = false;
        goto goHome;
        }
 
    result = true;
 
    FrontDAEdits();
 
    if(thisEasyWindow)
        {
        SetPort(thisEasyWindow->wWindow);
        if(activate)
            {
            beActivateProcPtr fp;
            short copyItem,printItems;
 
            if(thisEasyWindow->flags & wCopyDraw)
                copyItem = 1;
            else
                copyItem = -1;
 
            EnDisEdits(-1,-1,copyItem,-1,-1);
 
            if(((thisEasyWindow->flags & wPrintDraw) && gHasGX)
                    || (gAppPageSetupProc && gAppPrintProc) )
                printItems = 1;
            else
                printItems = -1;
            SetMenuItem(mPageSetup,printItems,0,0,nil);
            SetMenuItem(mPrint,printItems,0,0,nil);
 
            fp = thisEasyWindow->wActivateProc;
            if(fp)
                (*fp)(wNum);
            }
        else
            {
            beDeactivateProcPtr fp;
                        
            EnDisEdits(-1,-1,-1,-1,-1);
            SetMenuItem(mPageSetup,-1,0,0,nil);
            SetMenuItem(mPrint,-1,0,0,nil);
            fp = thisEasyWindow->wDeactivateProc;
            if(fp)
                (*fp)(wNum);
            }
 
        InitCursor();
        if (thisEasyWindow->flags & wGrowable)          /* Draw growbox, if...  */
            MyDrawGrowIcon(w);
        }
 
goHome:
    SetPort(oldPort);
    return result;
    }
 
Boolean HandleActivateEvent(EventRecord *er)
/*
 * Handle it, if we can find out who it is.
 */
    {
    Boolean result;
 
    result = true;
 
    switch(er->what)
        {
        case activateEvt:
            ActivateWindow((WindowPtr)er->message,er->modifiers & 1);
            break;      
 
        case kOSEvent:
            switch ((unsigned long) er->message >> 24)  /*  high byte of message  */
                {
                case kSuspendResumeMessage:
                    ActivateWindow(FrontWindow(),er->modifiers & 1);
                    break;
                default:
                    result = false;
                    break;
                }
            break;
 
        default:
            result = false;
            break;
        }
goHome:
    return result;
    }
 
 
 
 
 
void EventLoop(void)
    {
    EventRecord er;
    short i;
    register short wNum;
    WindowPtr w;
    register TEasyWindow *thisEasyWindow;
    Boolean tookKey,tookEvent;
 
    CheckMenubar();
 
    WaitNextEvent(0xffff,&er,gSleep,nil);
        {
        gLastModifiers = er.modifiers;
        gLastEventTime = er.when;
 
        if(er.what > 5 && er.what < 12)                 /* update event or higher: in message   */
            w = (WindowPtr)er.message;
        else
            w = FrontWindow();                          /* else, use FrontW                 */
 
        if(er.what > 1)
            {
            wNum = ScanWindowList(w);                   /* other than null or click, scan list      */
            thisEasyWindow = GoodWNum(wNum);            /* and get record                   */
            }
        else
            thisEasyWindow = 0;
 
        SetPort(w);
 
        if(thisEasyWindow && thisEasyWindow->wEventProc)
            (*thisEasyWindow->wEventProc)(wNum,&er,&tookEvent);
        else
            tookEvent = 0;
 
        if(!tookEvent)
            switch (er.what)
                {
                case 0: /* null event */
                    break;
    
                case mouseDown:
                    FrontDAEdits();
                    DoMouseClick(&er);
                    break;
    
                case keyDown:
                case autoKey:
                    FrontDAEdits();
    
                    tookKey = false;
                    if( (!gMenuNeedsCmdKey) || (er.modifiers & 256) )
                        tookKey = DoKeyPress(er.message);
    
                    if(!tookKey && ((!gMenuNeedsCmdKey) || (er.modifiers & 256)) )
                        tookKey = CoolBigEasyCmdKeys(er.message & 0xFF);
    
                    if(!tookKey)
                        if(thisEasyWindow)
                            {
                            beKeyProcPtr fp;
                            
                            fp = thisEasyWindow->wKeyProc;
                            if(fp)
                                {
                                SetPort(thisEasyWindow->wWindow);               /* Set port to window   */
                                (*fp)(wNum,         /* Call key proc        */
                                        (short)(er.message&0xff),           /* with the key */
                                        (short)((er.message>>8)&0xff),      /* the key code */
                                        er.modifiers);                      /* and the modifiers */
                                }
                            }
                    break;
    
                case updateEvt:
                    HandleUpdateEvent(&er);
                    break;
    
                case activateEvt:
                    HandleActivateEvent(&er);
                    break;
    
                case kOSEvent:
                    switch ((unsigned long) er.message >> 24)   /*  high byte of message  */
                        {
                        case kSuspendResumeMessage:
                            if(thisEasyWindow)                  /* just like activate event... */
                                {
                                ActivateWindow(FrontWindow(),
                                        er.message & kResumeMask);
                                }
                        break;
                        }
                    break;
    
                case kHighLevelEvent:
                    AEProcessAppleEvent(&er);
                    break;
                case diskEvt:
                    if (er.message & 0xffff0000) {
                        Point where = {100,100};
                    //  DIBadMount(where, er.message);
                    }
                    break;  
                default:
                    /*Debugger();/**/
                    ;
                }
        }
 
    /*
      * See if we're doing a fake cool drag-window
      */
    if(gCoolDragState)
        {
        Point p,q;
 
        SetPort(gCoolDragEW->wWindow);
        GetMouse(&p);
        LocalToGlobal(&p);
        if( (p.v!=gCoolDragPoint.v) || (p.h!=gCoolDragPoint.h) )
            {
            q.h = gCoolDragEW->wWindow->portRect.left;
            q.v = gCoolDragEW->wWindow->portRect.top;
            LocalToGlobal(&q);
            MoveWindow(gCoolDragEW->wWindow,
                    q.h+p.h-gCoolDragPoint.h,
                    q.v+p.v-gCoolDragPoint.v,0);
            gCoolDragPoint = p;
 
                {
                beMoveWindowProcPtr fp;
 
                fp = gCoolDragEW->wMoveWindowProc;
                if(fp)
                    (fp)(gCoolDragWindowNumber);                    
                }
 
            }
        if(!Button())
            gCoolDragState = 0;
        }
 
    SystemTask();
    w = FrontWindow();
    if ( w == gLastFrontIdle)                   /* Minor optimization, wins if the same     */
        wNum = gLastFrontWindowNumber;      /* window is frontmost for a while.         */
    else
        {
        wNum = ScanWindowList(w);
        gLastFrontIdle = w;
        gLastFrontWindowNumber = wNum;
        }
 
    if(er.what != mouseDown && er.what != activateEvt && !gQuitApp) /* anything but a mousedown or [de]activate */
        {
        gIdleSeed ++;
        if(gIdleSeed & 1)   /* every other chance... */
            for(i = 1; i<gEasyWindowListSize; i++)
                {
                if(gEasyWindowList[i].wUsed && gEasyWindowList[i].wIdleProc)
                    {
                    SetPort(gEasyWindowList[i].wWindow);
                    (*gEasyWindowList[i].wIdleProc)
                            ((short)i,(Boolean)(w == gEasyWindowList[i].wWindow));
                    }
                }
        }
 
    if (gMasterIdleProc && !gQuitApp)
        (*gMasterIdleProc)();
    }
 
 
Boolean CoolBigEasyCmdKeys(short key)
    {
    WindowRecord *w;
 
    switch(key)
        {
        /*
         * Rotate active window
         */
        case 9:     /* <tab> */
            w = *(WindowRecord **)0x9D6;        /* windowlist */
            if(w)
                {
                while (w->nextWindow)
                    w = w->nextWindow;
                SelectWindow((WindowPtr)w);
                }
            break;
 
        default:
            return false;
        }
    return true;
    }
 
 
void IdleWindow(short n)
/*
 * Idle window number n, or
 * -1 to idle all windows.
 */ 
    {
    register short i;
    short lo,hi;
    WindowPtr w;
    register TEasyWindow *ew;
    GrafPtr oldPort;
 
    GetPort(&oldPort);
 
    if(n<0)
        {
        lo = 1;
        hi = gEasyWindowListSize;
        }
    else
        {
        lo = n;
        hi = n + 1;
        }
 
    w = FrontWindow();
    ew = &gEasyWindowList[lo];
 
    for(i = lo; i < hi; i++)
        {
        if(ew->wUsed && ew->wIdleProc)
            {
            SetPort(ew->wWindow);
            (*ew->wIdleProc)((short)i,ew->wWindow == w);
            }
        ew++;
        }
 
    SetPort(oldPort);
    SystemTask();
    }   
 
void MyDrawGrowIcon(WindowPtr w)
    {
    Rect r;
 
    SetPort(w);
    GetGrowRect(w,&r);
    ClipRect(&r);
    DrawGrowIcon(w);
    ClipRect(&gBigRect);
    }
 
 
void SetMasterOpenAppProc(beOpenAppProcPtr openAppProc)
    {
    gMasterOpenAppProc = openAppProc;
    if(gHasAppleEvents)
        AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
                (AEEventHandlerUPP)BigEasyOpenAppThang, 0, false);
    }
 
 
void SetMasterOpenDocProc(beOpenDocProcPtr openDocProc)
    {
    gMasterOpenDocProc = openDocProc;
    if(gHasAppleEvents)
        AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
                (AEEventHandlerUPP)BigEasyOpenDocThang, 0, false);
    }
 
void SetMasterQuitAppProc(beQuitAppProcPtr quitAppProc)
    {
    gMasterQuitAppProc = quitAppProc;
    }
 
pascal OSErr BigEasyOpenAppThang(AppleEvent *theEvent, AppleEvent *reply,long refCon)
    {
    #pragma unused (reply,refCon,theEvent)
    return noErr;
    }
 
pascal OSErr BigEasyOpenDocThang(AppleEvent *message, AppleEvent *reply,long refCon)
    {
    FSSpec fSpec;
    AEDescList docList;
    long index, itemsInList;
    Size actualSize;
    AEKeyword keywd;
    DescType typeCode;
    OSErr thisError;
    #pragma unused (reply,refCon)
 
    thisError = AEGetParamDesc(message, keyDirectObject, typeAEList, &docList);
    if(thisError)
        goto goHome;
 
    thisError = MissedAEParameters(message);
    if(thisError)
        goto goHome;
 
    thisError = AECountItems(&docList, &itemsInList);
    if(thisError)
        goto goHome;
 
    for (index = 1; index <= itemsInList; index++)
        {
        thisError = AEGetNthPtr(&docList, index, typeFSS, &keywd, &typeCode,
                    (Ptr)&fSpec, sizeof(FSSpec), &actualSize);
        if(thisError)
            goto goHome;
 
        if(gMasterOpenDocProc)
            (*gMasterOpenDocProc)(&fSpec);
        }
 
    thisError = AEDisposeDesc(&docList);
 
goHome:
    return thisError;
    }
 
pascal OSErr BigEasyQuitAppThang(AppleEvent *theEvent, AppleEvent *reply,long refCon)
    {
    OSErr thisError;
    #pragma unused (reply,refCon)
 
    thisError = MissedAEParameters(theEvent);
    if (!thisError)
        {
        ++ gQuitApp;
    
        if(gMasterQuitAppProc)
            (*gMasterQuitAppProc)();
        }
 
    return thisError;
    }
 
OSErr MissedAEParameters (AppleEvent *message)
    {
    DescType typeCode;
    Size actualSize;
    OSErr err;
 
    err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeWildCard,
            &typeCode, nil, 0L, &actualSize);
    if (err == errAEDescNotFound)
        return(noErr);
    return(err = noErr ? errAEEventNotHandled : err);
    }
 
 
 
 
void InitBigEasy(void)
    {
    long result;
 
    InstallMyExitToShell();
    gMasterOpenAppProc = nil;
    gMasterOpenDocProc = nil;
    gMasterIdleProc = nil;
    gAboutProc = nil;
    gQuitApp = false;
    gMenuNeedsCmdKey = true;
    gStaggerWindows = true;
    gWindowsInView = true;
    gSleep = 0;
    gInvalidMenuBar = false;
 
    gStagStepX = 7;
    gStagStepY = 7;
 
    SetRect(&gBigRect,-16000,-16000,16000,16000);
 
    gEasyWindowListH = (TEasyWindow**)NewHandleClear(sizeof(TEasyWindow));
    HLock((Handle)gEasyWindowListH);
    gEasyWindowList = *gEasyWindowListH;
    gEasyWindowList[0].wUsed = 0;
    gEasyWindowListSize = 1;
 
    gLastFrontIdle = (WindowPtr) 0;
    gLastFrontWindowNumber = -1;
 
    gCoolDragState = 0;
 
 
/*
 * 7.0 Feature stuff
 */
    gSystemVersion = (Gestalt('sysv', &result)) ? 0 : result;
    gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &result) ? false : result != 0);
    gHasColor = (Gestalt('qdrw',&result)) ?
            false : (result & (1<<gestaltHasDeepGWorlds)) != 0;
 
    /*
     * The quit-app message, if available.
     */
    gMasterQuitAppProc = nil;
    if(gHasAppleEvents)
        AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
                (AEEventHandlerUPP)BigEasyQuitAppThang, 0, false);
 
/*
 * GX Feature stuff
 */
 
#ifdef BigEasyGXPrinting
    gHasGX = WantsGX
            && ( (Gestalt(gestaltGXVersion,&result)) ? false : true );
 
    if(gHasGX)
        {
        GXEnterGraphics();
        GXInitPrinting();
        }
#else
    gHasGX = false;
#endif
 
 
    }
 
static void ExitBigEasy(void)
    {
#ifdef BigEasyGXPrinting
    if(gHasGX)
        {
        GXExitGraphics();
        GXExitPrinting();
        }
#endif
    }
 
void main(void)
    {
#if 0
#ifdef THINK_C_PROFILE
    freopen("profile output","w+",stdout);
 
    InitProfile(1000,50);
#endif THINK_C_PROFILE  
#endif
 
    MaxApplZone();
    MoreMasters();
    MoreMasters();
 
    InitToolbox();
    StartMenus();
 
    InitBigEasy();
    Bootstrap();
    
    #if THINK_C >= 5
        #if defined(STACK_KILLER) || defined(TIMING_PROFILE)
            prepStackKiller();      /** slime from HELL **/
            #ifdef TIMING_PROFILE
                InitTimingProfile(150); /* call depth */
            #endif TIMING_PROFILE
        #endif
    #endif
 
    while (!gQuitApp)
        EventLoop();
 
    FlushEvents(0xffff,0);
 
    #ifdef TIMING_PROFILE
        DumpProfile(0, 0, "\ptiming stats");
    #endif
 
    ExitBigEasy();
 
    ExitToShell();
    }