TweetFollow Us on Twitter

4D External Area Shell
Volume Number:7
Issue Number:2
Column Tag:C Workshop

4D External Area Shell

By Alexander Colwell, Redondo Beach, CA

Introduction

4th Dimension™ (4D) is an amazing database developed for the Macintosh. It allows rapid development of an application’s database for specified requirements. One of the nice features in 4D is the ability to execute external procedures and areas. External procedure (EP) is similar to HyperCard™ external commands and functions. This gives the database developers additional controls required in their input and output layout designs.

The external area (EA) is a section of the layout to display some graphical object the 4D does not handle. 4D does handle almost every thing the database developer would normally require. However, there may be some cases where the standard data entry field types: text, radio button, check-box button, pop-up menus, etc would not handle the desire operation in user mac-friendly style. For example, Figure 1 shows an EA of a calendar. (Alex uses an alternate and configurable WDEF; he also uses an alternate CDEF for scrollbars.-ed)

Figure 1

The calendar EA would be more intuitive to the user determining how to input the specified days rather than text-base form or some other radio/check-box button combinations. For example: If using text-base form then the user should enter the data as: April 1990 18-20,26-27; Apr 1990 18,19,20,26,27; 18-20,26-27 APRIL 90; or other zillion combinations. Clearly, I believe, an EA would be ideal under these conditions.

This article will attempt to explain how to develop an EA. But wait! With simple EA as the calendar, it can be difficult to debug the EA with the 4D environment. So, this article will also cover a 4D debugger emulator similar to Think C’s ‘cdev’ and DA debugging tools for developing an EA, specifically the Calendar EA. Hence, the database developer can perform the majority of the debugging phase using Think C’s symbolic debugger.

Writing EAs are not really difficult, but documentation is rather skimpy on more advanced EAs other than their simple examples. There is a section describing how to write an EA in 4D 1.X manuals, and it is completely missing in v2.X manuals!! I suppose, the people at ACIUS want to keep writing EA a mystery to most database developers.

The only other documentation available can be found in ACIUS Technical Note #35 and MacTutor September 1988 issue. Armed with these information, I was able to write rather interesting EAs.

I used Think C’s Object classes to emulate EA and EPs, which has given me the ability to use the symbolic debugger. The object classes hierarchy are similar to MacApp™ other than the different names for the object classes. This helped me to use the Think C’s objects quickly, but there is still a substantial learning curve associated with Think C’s objects as well as MacApp’s objects. So you have to put in your time to learn how to use the object libraries.

External Area Events

The EA can receive two classes of events: standard Mac Events and 4D Events. The standard Mac events are nullEvent, updateEvt, mouseDown, and keyDown. These events are generated as one expects. The nullEvent is sent to EA whenever there is nothing to do and perform standard idling operations. The updateEvt event is sent to EA to update the rectangular area within the layout. The mouseDown event is sent to EA whenever the mouse is clicked inside the EAs rectangular area. And, the keyDown event is sent to the EA whenever there are keyboard inputs. More about keyDown event in selectReq event.

The initEvt 4D event informs the EA to be initialized. Normally, the EA will save its data handle in the eaData variable. I will discuss about this later in the External Area Protocol with External Procedures topic. This is the first event the EA will receive other than the drawReq event when opening a layout containing the EA.

The deInitEvt event informs the EA to release its memory allocation via the eaData handle. This is the last event the EA will receive before the layout is closed.

The selectReq event asks the EA if it wants to receive keyDown, activeNote, and deActivNote events. If the EA wants these events then it must reset the eaEvent->message to 101 value. This event always occurs after the initEvt event. Otherwise, the EA will not receive these events.

The cursorEvt event informs the EA that the cursor is inside the rectangular area of the EA. The EA may want to change the cursor into something else other than arrow cursor.

The activNote event informs the EA that it has been selected and the previous standard 4D field or another EA has been deselected.

The deActivNote event informs the EA that it has been deselected and selected another field or EA. This is opposite of the activNote event.

The scrollEvt event informs the EA that the current rectangular area has been scrolled to new position. The eaRect will contain a new location of the EA. Note: The EA should not update the contents of the rectangular area, but wait for update event to occur.

The drawReq event is a special event to inform the EA to draw inside the specified rectangular area in “Design” mode while editing the layouts. If the EA wants to perform its own drawing rather allowing the 4D to fill the EA with “0101010101” then it should reset the eaEvent->message to 102 value and do its own drawing. Note: The C4th class in the 4th Class.c source file will call the initEvt, updateEvt, and deInitEvt events to emulate the normal EA updating protocol.

The Edit’s menu events are sent to EA to perform its equivalent Undo, Cut, Copy, Paste, Clear, and Select All events.

There are several other events generated by 4D which I do not use, since it appears to be redundant. I call these events afterActivEvt, afterDeactivEvt, and afterIdleEvt. The afterActivEvt always occurs after the activNote event and the afterDeactivEvt always occurs after the deActivNote event. The afterIdleEvt always occurs during the activNote phase with the nullEvent. Hence, every nullEvent will have its associated afterIdleEvt during EA selection. Of course, these events are generated only if the selectReq event return value 101 in the eaEvent->message variable.

I suspect there are other 4D events though I did not detect any.

External Area Protocol with External Procedures

The EA has four arguments used to communicate with the 4D procedures and its EPs. Think C calling convention defined as follows

/* 1 */

pascal void
 main(eaEvent,eaRect,eaName,eaData)
      EventRecord *eaEvent;
      Rect        *eaRect;
      char        *eaName;
      Handle      *eaData;

The eaEvent variable contains the standard Mac and 4D event information as discussed earlier. The message variable may be modified for selectReq and drawReq events to 101 and 102 value respectively. Otherwise, the EA should examine the values within the event record like a normal application.

The eaRect variable contain the rectangular area of the EA within the layout to be displayed. The EA should make very few assumptions how to use the rectangular area coordinates. Since during different events, the origin of the rectangle area can move around! I will discuss more about this in Things You Can’t Do with External Areas topic when using the rectangular area for drawing, mouse-clicks, etc.

The eaName variable is the name of the EA defined in the layout which is used to be passed around to EP in the layout’s procedure code.

The eaData variable is a pointer containing the data handle which typically contains a data structure required by the EA for its operations. The important point here is that the eaData variable does not have to be a handle. It could be used as simple long word, a Ptr, or in my case an object pointer called C4th.

The EPs are used by the layout’s procedures to communicate with the EA. The layout’s procedures use the equivalent eaName variable name to be passed as the actual value of the eaData’s pointer. Then the EP will examine the contents of the eaData’s data structure and modify the other arguments in the EP.

Refer to the layout’s procedure Calendar for additional details. The SetCalendar and GetCalendar EPs use the theCalendar variable which is the same name as the EAs eaName variable and contains the value of the eaData variable. The theCalendar variable is the name of the EA defined in the layout editor as shown in Figure 2. This way the association is made between the layout’s procedure and the actual EA.

The EPs would need to receive the eaData value used by the EA to perform the necessary operations required by the layout’s procedures. Note: There is a limit of 10 number arguments you can pass to the EP. Refer to ACIUS Technical Note #30.

Figure 2

Things You Can’t Do with External Areas

There are few considerations you should take into account when developing EA. They are window pointers retrieved by “GetPort” ROM call, using “SetOrigin”, “ClipRgn” ROM calls, and ‘CDEF’ controls.

GetPort: You need to be careful how the EA accesses the window pointer’s internal data structures retrieved by “GetPort” ROM call. During the updateEvt event, the window data structure is inconsistent because the portBits is pointing to off-screen bit map and other parts of the data structure seem to be in funny state, too.

SetOrigin: In my first attempt, I wanted to use the “SetOrigin” ROM call to normalize the external rectangle area’s left and top position to be (0,0). This would simplify drawing without resorting to keeping track of your (left,top) and (right,bottom) positions. Otherwise, the EA would be required to keep track of the width and height of the rectangle area. However, between updateEvt and mouseDown events tends to messes-up whenever the EA wants to draw into the rectangular area during mouseDown events. Also, it works OK in input layout but screws up in output layout. Nothing is perfect!

ClipRgn: This call will not work for drawReq event while it will work under all other events. In the “Design” mode, the layout’s EA will be strangely missing while the layouts work OK in “User” mode. Again, I wanted to use the “ClipRgn” ROM call to suppress any slopping drawing outside of the EA, but I could not use this feature either.

‘CDEF’ controls: It sort-of works in input layouts. If the layout window want to scroll, it won’t always re-position the controls properly during scrolling operations. I tried several convoluted schemes and none of them work consistently, but you can use the controls if the input layout does not have any scroll bars.

It won’t work in the output layout at all! 4D somehow gets into an infinite procedure loop and causes the layout’s procedure to terminate.

Installing External Area and Procedures

Creating an EA using Think C is quite easy. The configuration in Figure 3 shows the necessary settings. The important point that is not so obvious is that the File Type field must be APPL even though it is not a standard Mac application. This is required by 4D External Mover application to select file containing the EAs and EPs.

The resource Type must be ‘CODE’. And again, this is required by 4D External Mover application.

The Multi-Segment check-box must be checked even though it is a single-segment resource. For some reason, Think C wants this checked using objects extensions.

Figure 3

To install the EAs and EPs then use the 4D External Mover application. The application is similar to Font/DA Mover application. However, it is not very clear how to install your EAs and EPs for the first time.

I usually create a file called Proc.Ext used by the Calendar database. After creating a new file, select the “Transfer...” button and it will display a dialog as shown in Figure 4. Since I used ID = 2, I must enter same value 2 into the Segment Number field. Also, change the Procedure Offset to 0, since Think C code resources start at location 0. The dialog always default to 4 bytes offset from the beginning of the code resource containing the EA or EP.

After entering the necessary values in their respective fields, select the <<Left or Right>> buttons containing the direction of the file opened to be installed with the new EAs and EPs.

Figure 4

When installing the EAs, do not add any parameters as shown in Figure 5. However, the EPs needs the parameters entered as shown in Figure 6. In this case, the SetCalendar EP contains four arguments where the first argument is theCalendar variable that is mapped into the eaData variable as discussed earlier.

Figure 5

Figure 6

Source File Description

The Calendar layout’s procedure is rather simple. It calls the SetCalendar EP during its Before phase, and the After phase will call the GetCalendar EP to extract the current calendar settings in the EA defined by the theCalendar variable. This is all there is to it in the layout’s procedure. It can’t get any simpler!

The 4D debugger emulation comprises of three files: 4thDefs.h, 4thDebugger.h, and 4thDebugger.c. The source file uses the Think C’s Objects to build simple application to simulate the 4D EA and controls the EPs communications to the EA.

The C4th class is defined in the 4th Class.h and 4th Class.c source files. New EAs can override this class to build new EAs namely the CCalendar class.

The CCalendar class overrides the C4th class to perform the necessary operations for the calendar’s EA. The Calendar.h, Calendar.c, SetCalendar.c, GetCalendar.c are sources files to the EA and EPs respectively.

Wrap Up

Using the 4thDebugger application to simulate the EA can substantially reduce debugging time developing EAs. I had been using this debugging technique since last year and it has made a major difference meeting tight dead-line schedules. I want to extend my thanks to the people at Hughes Aircraft Company insisting developing EAs and EPs to extend the 4D databases.

  ‘ Procedure   : Calendar
  ‘ Author      : Alexander S. Colwell
  ‘               Copyright © 1990
  ‘ Description : This procedure will display the
  ‘               “CalendarArea” external area and use
  ‘               “SetCalendar” and “GetCalendar”
  ‘               external procedure to commnicate the
  ‘               month, year, and days fields to the
  ‘               external area.

Case of 
  : (Before)
    If ([Calendar]month=0)
      [Calendar]month:=Month of(Current date)
    End if 
    If ([Calendar]year=0)
      [Calendar]year:=Year of(Current date)
    End if 
    theMonth:=[Calendar]month
    theYear:=[Calendar]year
    theDays:=[Calendar]days
    SetCalendar(theCalendar;theMonth;theYear;theDays)
  : (During)
  : (After)
    GetCalendar(theCalendar;theMonth;theYear;theDays)
    [Calendar]month:=theMonth
    [Calendar]year:=theYear
    [Calendar]days:=theDays
End case 

/*
 * Include     - 4thDefs.h
 * Author      - Alexander S. Colwell
 *               Copyright © 1990
 * Description - This 4th Dimension’s external area
 *               event constants.
 */

#ifndef _4thDefs_
#define _4thDefs_

                             /* 4th DB ext area events*/
#define initEvt        16    /* Init event            */
#define deInitEvt      17    /* Close event           */
#define cursorEvt      18    /* Cursor event          */
#define selectReq      20    /* Selection request evt */
#define activNote      21    /* Activate note event   */
#define deActivNote    22    /* Deactivate note event */
#define scrollEvt      25    /* Scroll event          */
#define drawReq        26    /* Draw request event    */
#define undoEvt        30    /* Edit’s “Undo” event   */
#define cutEvt         31    /* Edit’s “Cut” event    */
#define copyEvt        32    /* Edit’s “Copy” event   */
#define pasteEvt       33    /* Edit’s “Paste” event  */
#define clearEvt       34    /* Edit’s “Clear” event  */
#define selectAllEvt   35    /* Edit’s “Select All”   */
#define afterActivEvt  40    /* After “ActivNote” evt */
#define afterDeactivEvt 41   /* After “DeactivNote”   */
#define activeIdleEvt  43    /* Selection idle event  */

#endif

/*
 * Source       - 4th Debugger.h
 * Author       - Alexander S. Colwell
 *                Copyright © 1990
 * Description  - This 4th Dimension’s external area
 *                debugger include file.
 */

#ifndef _4thDebugger_        /* Has been include yet? */
#define _4thDebugger_        /* Mark it been included */

#include <Global.h>          /* Global variable defs  */
#include <CApplication.h>    /* Appl object defs      */
#include <Commands.h>        /* Command object defs   */
#include <CBartender.h>      /* Menu object defs      */
#include <CDecorator.h>      /* Wind display obj defs */
#include <CDesktop.h>        /* Desktop layer obj defs*/
#include <CDocument.h>       /* Document object defs  */
#include <CEditText.h>       /* Text edit object defs */
#include <CScrollPane.h>     /* Scroll pane obj defs  */
#include “4th Class.h”       /* 4th Ext Area obj defs */

                             /* Min/Max defs          */
#define maxDbgChars 8000     /* Max # in debug window */

                             /* Window/Dialog ID defs */
#define eaWIND   500         /* “External Area” WIND  */
#define dbgWIND  501         /* Debugger WIND template*/
#define atDLOG   500         /* “About This...” DLOG  */

                             /* External area commands*/
#define eaOpen   1024        /* Open “Ext Area” cmd   */
#define eaClose  1025        /* Close “Ext Area” cmd  */
#define ep1      1026        /* Run “Ext Proc #1” cmd */
#define ep2      1027        /* Run “Ext Proc #2” cmd */
#define ep3      1028        /* Run “Ext Proc #3” cmd */
#define ep4      1029        /* Run “Ext Proc #4” cmd */
#define ep5      1030        /* Run “Ext Proc #5” cmd */
#define ep6      1031        /* Run “Ext Proc #6” cmd */
#define ep7      1032        /* Run “Ext Proc #7” cmd */
#define ep8      1033        /* Run “Ext Proc #8” cmd */
#define ep9      1034        /* Run “Ext Proc #9” cmd */
#define eaSelectAll 1035     /* Edit “Select All” cmd */
#define eaDebugger 1036      /* Edit “Hide/Show” cmd  */

struct CEAPane : CPanorama { /* Ext area pane object  */

                             /* Variable instances    */
 Rect eaRect;                /* External rect area    */
 Rect eaSRect;               /* Scrolled ext rect area*/
 C4th *eaObject;             /* External 4th obj hdl  */
 Point lastWhere;            /* Last mouse position   */
 
                             /* Method instances      */
 void Dispose(void);         /* Dispose ext area      */
 void UpdateMenus(void);     /* Update menu items     */
 void AdjustToEnclosure(Rect *);/* Adjust to enclosure*/
 void AdjustCursor(Point, RgnHandle);/* Adjust cursor */
 void Dawdle(long *);        /* Dawdle (Idle)         */
 void Draw(Rect *);          /* Draw                  */
 void Scroll(short,short,Boolean);/* Scroll           */
 void DoClick(Point,short,long);/* Mouse down         */
 void DoKeyDown(char,Byte,EventRecord *);/* Key-down  */
 void DoAutoKey(char,Byte,EventRecord *);/* Key-down  */
 void Activate(void);        /* Activate pane         */
 void Deactivate(void);      /* Deactivate pane       */
 void DoCommand(long);       /* Command               */
 void DoSendEvent(short);    /* Send event            */
 void DoExtEvent(EventRecord *);/* Execute ext event  */
 void DoExtProc(short);      /* Execute ext procedure */
 short DoGetModifiers(void); /* Get current modifiers */
 };
 
struct CDbgDoc : CDocument { /* Debugger (bogus) obj  */
 
                             /* Method instances      */
 Boolean Close(Boolean);     /* Close                 */
 };
 
struct CDbgPane : CEditText {/* Text edit pane object */
 
                             /* Variable instances    */
 short maxChars;             /* Max # of characters   */
 
                             /* Method instances      */
 void DoPrint(char *, ...);  /* Do print output stream*/
 };

                             /* 4th Debugger classes  */
struct C4thDbgApp : CApplication {/* Application obj  */

                             /* Variable instances    */
 CDocument *eaDoc;           /* Ext Area window doc   */
 CDbgDoc *dbgDoc;            /* Debugger window doc   */
 Str255 eaName;              /* Ext area name         */
 Rect eaIRect;               /* Ext initial rect area */
 ProcPtr eaProc[10];         /* Ext procedure table   */
 
                             /* Methods               */
 void IApplication(short,Size,Size);/* Initialization */
 void InitExtArea(void);     /* Init external area    */
 void InstallExtProc(short,ProcPtr);/* Install proc   */
 void SetExtArea(short,short,short,short);
 void SetExtName(char *);    /* Set external name     */
 void CreateDocument(void);  /* Create debugger window*/
 void CreateExtArea(void);   /* Create ext area window*/
 void DoCommand(long);       /* Command               */
 void UpdateMenus(void);     /* Update menu items     */
 void AboutThis(void);       /* About this dialog     */
 };

                             /* Define external refs  */
extern C4thDbgApp  *gApplication;/* Application object*/
extern CDecorator  *gDecorator;/* Window display obj  */
extern CDesktop    *gDesktop;/* Desktop view layer obj*/
extern CBartender  *gBartender;/* Menu handler object */

#endif

/*
 * Source       - 4th Debugger.c
 * Author       - Alexander S. Colwell
 *                Copyright © 1990
 * Description  - This application will assist debugging
 *                4th Dimension’s external area and
 *                related external procedures.
 */

#define  DbgExtArea          /*Mark debugging ext area*/
#include “4th Debugger.h”    /* 4th Dim Debugger defs */
#include “4th Class.h”       /* 4th Ext Area obj defs */
#include <StdIO.h>           /* Std I/O defs          */
#include “stdarg.h”          /* Std Variable Args defs*/
#include <string.h>          /* String defs           */

pascal void C4thMain();      /* Define ext procedures */

void main()
 {
  gApplication = new(C4thDbgApp);/* Create appl object*/
  gApplication->IApplication(4,4096L,2048L);/* Init it*/
  gApplication->Run();       /* Startup appl execution*/
  gApplication->Exit();      /* Return to da “Finder” */
 }
 
void C4thDbgApp::IApplication(short extraMasters,
                              Size aRainyDayFund,
                              Size aCreditLimit)
 {
  register short i;          /* Working index         */
  
  eaDoc = NULL;              /* Mark no ext area wind */
  eaIRect.left = eaIRect.top =
  eaIRect.right = eaIRect.bottom = 0;
  
  for(i = 0; i < 10; i++)    /* Init ext procedures   */
   eaProc[i] = NULL;         /* Invalid ext proc ptr  */
   
  eaName[0] = 0;             /* Null ext name string  */
  
                             /* Continue init          */
  inherited::IApplication(extraMasters,
                          aRainyDayFund,aCreditLimit);

  InitExtArea();             /* Init external area    */
 }

void C4thDbgApp::InstallExtProc(short epIdx,
                                ProcPtr epPtr)
 {
  short idx = epIdx - ep1;   /* Working ext proc index*/
  
  if (idx >= 0 && idx < 10)  /* Check if index valid  */
   eaProc[idx] = epPtr;      /* Install new proc ptr  */
 }
 
void C4thDbgApp::SetExtArea(short l, short t,
                            short r, short b)
 {
  eaIRect.left = l;          /* Set external rect area*/
  eaIRect.top = t;
  eaIRect.right = r;
  eaIRect.bottom = b;
 }
 
void C4thDbgApp::SetExtName(char *name)
 {
  register long len;         /* Working string length */
  
  BlockMove(name,eaName,     /* Copy da string        */
      len = min((unsigned char)(*name) + 1, sizeof(eaName)));
  
  eaName[0] = len;           /* Reset to max str len  */
 }
 
void C4thDbgApp::CreateDocument(void)
 {
  register CScrollPane *theScrollPane;
  register CDbgPane    *theMainPane;
  Rect                 margin;/* Working margin area  */
 
  
  dbgDoc = new(CDbgDoc);     /* Create new doc object */

  dbgDoc->IDocument(this,TRUE);/* Do normal init      */
  
  dbgDoc->itsWindow = new(CWindow);/* Create wind obj */
  dbgDoc->itsWindow->IWindow(dbgWIND,FALSE,
                             gDesktop,dbgDoc);
  
  theScrollPane = new(CScrollPane);/* Make scroll obj */
  theScrollPane->IScrollPane(dbgDoc->itsWindow,dbgDoc,
        10,10,0,0,sizELASTIC,sizELASTIC,TRUE,TRUE,TRUE);
  theScrollPane->FitToEnclFrame(TRUE,TRUE);
  theMainPane = new(CDbgPane);
  dbgDoc->itsMainPane = theMainPane;
  dbgDoc->itsGopher = theMainPane;
  theMainPane->IEditText(theScrollPane,dbgDoc,
          1,1,0,0,sizELASTIC,sizELASTIC,432);
  theMainPane->FitToEnclosure(TRUE,TRUE);
  SetRect(&margin,2,2,-2,-2);
  theMainPane->ChangeSize(&margin,FALSE);
  theMainPane->SetFontNumber(monaco);
  theMainPane->SetFontSize(9);
  (*theMainPane->macTE)->crOnly = -1;
  theMainPane->maxChars = maxDbgChars;
  
  theScrollPane->InstallPanorama(theMainPane);
 
  dbgDoc->itsWindow->Select();/* Select our window    */
 }

void C4thDbgApp::CreateExtArea(void)
 {
  register CScrollPane *theScrollPane;
  register CEAPane     *theMainPane;
  Rect                 wRect;/* Working rect area     */
  EventRecord          eaEvent;/* Working event hdlr  */

  eaDoc = new(CDocument);    /* Make 4th ext area doc */
  
  eaDoc->IDocument(this,TRUE);/* Do normal init       */
  
  eaDoc->itsWindow = new(CWindow);/* Create wind obj  */
  eaDoc->itsWindow->IWindow(eaWIND,FALSE, gDesktop,eaDoc);
  
                 /* Try and fit ext area within window*/
  wRect = eaDoc->itsWindow->macPort->portRect;
  wRect.right = min(max(wRect.right,
                        wRect.left+max(0,eaIRect.left)+
                    eaIRect.right - eaIRect.left + 32),
                    screenBits.bounds.right -
                    screenBits.bounds.left - 16 + 
       eaDoc->itsWindow->macPort->portBits.bounds.left);
  wRect.bottom = min(max(wRect.bottom,
                         wRect.top + max(0,eaIRect.top)+ 
                         eaIRect.bottom-eaIRect.top+32),
                     screenBits.bounds.bottom -
                     screenBits.bounds.top - 16 +
        eaDoc->itsWindow->macPort->portBits.bounds.top);
  eaDoc->itsWindow->ChangeSize(wRect.right - wRect.left,
                               wRect.bottom-wRect.top);
  
  theScrollPane = new(CScrollPane);/* Make scroll obj */
  theScrollPane->IScrollPane(eaDoc->itsWindow,eaDoc,
        10,10,0,0,sizELASTIC,sizELASTIC,TRUE,TRUE,TRUE);
  theScrollPane->FitToEnclFrame(TRUE,TRUE);
  theScrollPane->SetSteps(16,16);
  
  theMainPane = new(CEAPane); /* Create pane object   */
  eaDoc->itsMainPane = theMainPane;
  eaDoc->itsGopher = theMainPane;

  wRect = eaIRect;           /* Set ext rect area     */
  
                             /* Init ext area’s pane  */
  theMainPane->IPanorama(theScrollPane,eaDoc,
      wRect.right - wRect.left + abs(wRect.left) + 16,
      wRect.bottom - wRect.top + abs(wRect.top) + 16,
    wRect.left,wRect.top,sizFIXEDSTICKY,sizFIXEDSTICKY);
  theMainPane->FitToEnclosure(TRUE,TRUE);
  theMainPane->SetWantsClicks(TRUE);
  theScrollPane->InstallPanorama(theMainPane);
 
  eaDoc->itsWindow->Select();/* Select our window     */

  theMainPane->eaRect = eaIRect;/* Set rect area      */
  theMainPane->eaSRect = eaIRect;
  theMainPane->eaObject = NULL;/* Set no ext area obj */

  eaEvent.what = initEvt;    /* Initialize event rec  */
  eaEvent.message = (long)(theMainPane->macPort);
  eaEvent.when = TickCount();
  eaEvent.where.h = eaEvent.where.v = 0;
  eaEvent.modifiers = 0;
  
  theMainPane->DoExtEvent(&eaEvent);/* Do ext area evt*/
 }
 
void C4thDbgApp::DoCommand(long theCommand)
 {
  switch(theCommand) {       /* Process command       */
   case cmdAbout:            /* About This dialog     */
    AboutThis(); break;
    
   case eaOpen:              /* Open external area    */
    CreateExtArea(); break;
    
   case eaDebugger:          /* Hide/Show Debugger    */
    dbgDoc->itsWindow->ShowOrHide
        (!dbgDoc->itsWindow->IsVisible());
    break;
    
   default:                  /* Don’t know this msg   */
    inherited::DoCommand(theCommand);/* Cont handler  */
  }
 }
 
void C4thDbgApp::UpdateMenus(void)
 {
  Str255 wStr;               /* Working string        */
  
  inherited::UpdateMenus();  /* Update other items    */
  
  if (!eaDoc)                /* Check if ext not open */
   gBartender->EnableCmd(eaOpen);/* Enable open ext   */
  gBartender->EnableCmd(eaDebugger);/*Enable Hide/Show*/
  
                             /* Setup Hide/Show item  */
  GetIndString(wStr,eaDebugger,
               (dbgDoc->itsWindow->IsVisible()?1:2));
  gBartender->SetCmdText(eaDebugger,wStr);
 }

void C4thDbgApp::AboutThis(void)
 {
  DialogPtr dPtr;            /* Working dialog pointer*/
  Point     wPt;             /* Working mouse point   */
  
                             /* DisplayAbout This...  */
  if (dPtr = GetNewDialog(atDLOG,(Ptr)(NULL),-1L)) {
   SetPort(dPtr);            /* Set to this dlg port  */
   DrawDialog(dPtr);         /* Draw the items        */
   while(TRUE)               /* Do until time to quit */
    if (Button()) {          /* Check if mouse is down*/
     GetMouse(&wPt);         /* Get cur mse position  */
     if (PtInRect(wPt,&dPtr->portRect))/*Inside wind? */
      break;                 /* Let’s break-out now!! */
    }
   DisposDialog(dPtr);       /* Kill the dialog!!!!   */
   FlushEvents(mDownMask|mUpMask,0);/* Flush da events*/
  }
 }
 
void CEAPane::Dispose(void)
 {
  DoSendEvent(deInitEvt);    /* Do external area event*/
  
  gApplication->eaDoc = NULL;/* Mark no ext area wind */
  
  inherited::Dispose();      /* Let’s dispose it now  */
 }
 
void CEAPane::UpdateMenus(void)
 {
  inherited::UpdateMenus();  /* Update other items    */
  
  gBartender->EnableCmd(eaClose);/* Enable the items  */
  gBartender->EnableCmd(ep1);
  gBartender->EnableCmd(ep2);
  gBartender->EnableCmd(ep3);
  gBartender->EnableCmd(ep4);
  gBartender->EnableCmd(ep5);
  gBartender->EnableCmd(ep6);
  gBartender->EnableCmd(ep7);
  gBartender->EnableCmd(ep8);
  gBartender->EnableCmd(ep9);
  gBartender->EnableCmd(cmdUndo);
  gBartender->EnableCmd(cmdCut);
  gBartender->EnableCmd(cmdCopy);
  gBartender->EnableCmd(cmdPaste);
  gBartender->EnableCmd(cmdClear);
  gBartender->EnableCmd(eaSelectAll);
 }
 
void CEAPane::AdjustToEnclosure(Rect *deltaEncl)
 {
  inherited::AdjustToEnclosure(deltaEncl);/* Adjust it*/
  FitToEnclosure(TRUE,TRUE); /* Re-adjust to window   */
 }
 
void CEAPane::AdjustCursor(Point where,
                           RgnHandle mouseRgn)
 {
  EventRecord eaEvent;       /* Working event handler */
  
  if (!PtInRect(where,&eaSRect))/* Inside ext area?   */
   inherited::AdjustCursor(where,mouseRgn);/*Adjust it*/
  
 else {                      /* Nope, it’s in ext area*/
   
   eaEvent.what = cursorEvt; /* Initialize evt record */
   eaEvent.message = (long)(macPort);
   eaEvent.when = TickCount();
   eaEvent.where = where;
   eaEvent.modifiers = DoGetModifiers();
   
   DoExtEvent(&eaEvent);     /* Do external area event*/
  }
 }

void CEAPane::Dawdle(long *maxSleep)
 {
  inherited::Dawdle(maxSleep);/* Do any other stuff   */
  
  DoSendEvent(nullEvent);    /* Do external area event*/
  
  *maxSleep = 0L;            /* Do it fast as possible*/
 }
 
void CEAPane::Draw(Rect *area)
 {
  Rect  wRect;               /* Working rect area     */
  
  wRect = *area;             /* Set clipping area     */
  FillRect(&wRect,ltGray);   /* Draw into unused area */
  
  DoSendEvent(updateEvt);    /* Do external area event*/
 }

void CEAPane::Scroll(short hDelta, short vDelta,
                     Boolean reDraw)
 {
  OffsetRect(&eaSRect,-hDelta,-vDelta);/* Offset it   */

  DoSendEvent(scrollEvt);    /* Do external area event*/
  
  inherited::Scroll(hDelta,vDelta,reDraw);/* Do it    */
 }
 
void CEAPane::DoClick(Point hitPt, short modifierKeys,
                      long when)
 {
  EventRecord eaEvent;       /* Working event handler */
  
  eaEvent.what = mouseDown;  /* Initialize evt record */
  eaEvent.message = (long)(macPort);
  eaEvent.when = when;
  eaEvent.where = hitPt;
  eaEvent.modifiers = modifierKeys;
  
  DoExtEvent(&eaEvent);      /* Do external area event*/
 }

void CEAPane::DoKeyDown(char theChar, Byte keyCode,
                        EventRecord *macEvent)
 {
  EventRecord eaEvent;       /* Working event handler */
  
  if (eaObject) {            /* Check if has C4th obj */
   if (eaObject->keyBoardEvents) {/* Wants key events?*/
    eaEvent.what = keyDown;  /* Initialize evt record */
    eaEvent.message = theChar | (keyCode << 8);
    eaEvent.when = macEvent->when;
    eaEvent.where = lastWhere;
    eaEvent.modifiers = macEvent->modifiers;
    
    DoExtEvent(&eaEvent);    /* Do ext area event     */
   }
  }
 }
 
void CEAPane::DoAutoKey(char theChar, Byte keyCode,
                        EventRecord *macEvent)
 {
  DoKeyDown(theChar,keyCode,macEvent);/* Pass it on!  */
 }

void CEAPane::Activate(void)
 {
  inherited::Activate();     /* Do other stuff first  */

  if (eaObject)              /* Check if has C4th obj */
   if (eaObject->keyBoardEvents)/* Want activate evts?*/
    DoSendEvent(activNote);  /* Send message          */
 }

void CEAPane::Deactivate(void)
 {
  if (gApplication->eaDoc)   /* Check if not quitting */
   if (eaObject)             /* Check if has C4th obj */
    if (eaObject->keyBoardEvents)/* Want deactive evts*/
     DoSendEvent(deActivNote);/* Send message         */

  inherited::Deactivate();   /* Do other stuff first  */
 }

void CEAPane::DoCommand(long theCommand)
 {
  switch(theCommand) {       /* Process command       */
   case cmdUndo:             /* Edit “Undo” event     */
    DoSendEvent(undoEvt); break;
    
   case cmdCut:              /* Edit “Cut” event      */
    DoSendEvent(cutEvt); break;
    
   case cmdCopy:             /* Edit “Copy” event     */
    DoSendEvent(copyEvt); break;
    
   case cmdPaste:            /* Edit “Paste” event    */
    DoSendEvent(pasteEvt); break;
    
   case cmdClear:            /* Edit “Clear” event    */
    DoSendEvent(clearEvt); break;
    
   case eaSelectAll:         /* Edit “Select All” evt */
    DoSendEvent(selectAllEvt); break;
    
   case eaClose:             /* Close External Area   */
    inherited::DoCommand(cmdClose); break;
    
   case ep1:                 /* Execute Ext Proc # 1  */
   case ep2:                 /* Execute Ext Proc # 2  */
   case ep3:                 /* Execute Ext Proc # 3  */
   case ep4:                 /* Execute Ext Proc # 4  */
   case ep5:                 /* Execute Ext Proc # 5  */
   case ep6:                 /* Execute Ext Proc # 6  */
   case ep7:                 /* Execute Ext Proc # 7  */
   case ep8:                 /* Execute Ext Proc # 8  */
   case ep9:                 /* Execute Ext Proc # 9  */
    DoExtProc(theCommand - ep1); break;
    
   default:                  /* None of these, inherit*/
    inherited::DoCommand(theCommand);/*Cont processing*/
  }
 }
 
void CEAPane::DoSendEvent(short theCommand)
 {
  EventRecord eaEvent;       /* Working event handler */
  WindowPtr wPtr = eaObject->wPtr;/* Working wind ptr */
  
  if (printing)              /* Check if printing     */
   GetPort(&wPtr);           /* Get current print port*/
   
  eaEvent.what = theCommand; /* Initialize evt record */
  eaEvent.message = (long)(wPtr);
  eaEvent.when = TickCount();
  eaEvent.where = lastWhere;
  eaEvent.modifiers = DoGetModifiers();
  
  DoExtEvent(&eaEvent);      /* Do external area event*/
 }
 
void CEAPane::DoExtEvent(EventRecord *theEvent)
 {
  C4th   *wObject;           /* Working ext area obj  */
  Str255 wName;              /* Working ext area name */
  Rect   wRect;              /* Working ext rect area */
  
  Prepare();                 /* Prepare for drawing   */
  
  lastWhere = theEvent->where;/* Save last “where” pt */
  
  wRect = eaRect;            /* Set external rect area*/
  wObject = eaObject;        /* Set ext area obj hdl  */
  BlockMove(gApplication->eaName,wName,/* Copy name   */
            (long)(gApplication->eaName[0]));
      
  C4thMain(theEvent,&wRect,wName,&wObject);/* Do it   */
  
  eaObject = wObject;        /* Reset ext area obj hdl*/
 }

void CEAPane::DoExtProc(short epIdx)
 {
  C4th *wObject;             /* Working 4th object    */
  
  if (gApplication->eaProc[epIdx]) {/* Check if valid */
   wObject = eaObject;       /* Copy ext area object  */
   (*gApplication->eaProc[epIdx])(&wObject);/* Pass it*/
   eaObject = wObject;       /* Resave ext area object*/
  }
 }
 
short CEAPane::DoGetModifiers(void)
 {
  KeyMap         keyMap;       /* Working key map     */
  register short modifiers = 0;/* Working modifiers   */
  
  GetKeys(&keyMap);          /* Get the key map status*/
  
  if (keyMap.Key[1] & 0x00000001L)/* Check if “shift” */
   modifiers |= shiftKey;    /* Set “shift” modifier  */
   
  if (keyMap.Key[1] & 0x00000004L)/* Check if “option”*/
   modifiers |= optionKey;   /* Set “option” modifier */
   
  if (keyMap.Key[1] & 0x00008000L)/* Check if “cmd”   */
   modifiers |= cmdKey;      /* Set “cmd” modifier    */
   
  if (keyMap.Key[1] & 0x00000002L)/* Check if “caps”  */
   modifiers |= alphaLock;   /* Set “caps” modifier   */
   
  if (!Button())             /* Check if mouse is up  */
   modifiers |= btnState;    /* Set button state      */
   
  return(modifiers);         /* Return key’s modifiers*/
 }
 
Boolean CDbgDoc::Close(Boolean quitting)
 {
  register Boolean status = FALSE;/* Closing status   */

  if (quitting) {            /* Check if quitting     */
   itsWindow->ShowOrHide(TRUE);/* Show it before close*/
   status = inherited::Close(quitting);/* Cont closing*/
  }
  else                       /* Nope, hiding da window*/
   itsWindow->ShowOrHide(FALSE);/* Let’s hide it only */
   
  return(status);            /* Return status flag    */
 }
 
void CDbgPane::DoPrint(fmt,args)
 char    *fmt;
 va_list args;
 {
  register short i;          /* Working index         */
  char           buffer[512];/* Working output buffer */
  register long  bufferLen;  /* Working output length */
  
  vsprintf(buffer,fmt,&args);/* Copy into output buf  */
  
  bufferLen = strlen(buffer);/* Get output buffer len */
  
  for(i = 0; i < bufferLen; i++)/* Cnvt special chars */
   switch(buffer[i]) {       /* Process this character*/
    case ‘\t’: buffer[i] = ‘ ‘; break;
    case ‘\n’: buffer[i] = ‘\r’; break;
   }
   
  Prepare();                 /* Prepare for drawing   */
  
                             /* Buffer too big?       */
  if ((*macTE)->teLength + bufferLen > maxChars)
   for(i = 0; (*macTE)->nLines; i++)
    if ((*macTE)->lineStarts[i] > bufferLen) {
     TESetSelect(0L,(long)((*macTE)->lineStarts[i] - 1),
                 macTE);
     TEDelete(macTE);
    }
  
                             /* Reset to end-of-buffer*/
  TESetSelect((long)((*macTE)->teLength),
              (long)((*macTE)->teLength),macTE);
     
  TEInsert(buffer,bufferLen,macTE);/* Insert buffer   */
  
  AdjustBounds();            /* Re-adjust boundaries  */
  ScrollToSelection();       /* Scroll to cursor      */
 }
 
/*
 * Include  - 4th Class.h
 * Author   - Alexander S. Colwell
 *            Copyright © 1990
 */

#ifndef _4thClass_           /* Has been include yet? */
#define _4thClass_           /* Mark it been included */

                             /* Compilation parameters*/
#define ExtArea              /* Mark debug ext area   */

#ifndef _4thDefs_            /* Has been include yet? */
#include “4thDefs.h”         /* Include 4th Dim defs  */
#endif

#include <oops.h>            /* OOPS defs             */
#include <Color.h>           /* Color defs            */

#ifndef DbgExtArea           /* Debugging ext area?   */
#ifdef  ExtArea              /* Is real external area?*/
#include <SetupA4.h>         /* Setup Register A4 defs*/
#define DbgPrint  DummyProc  /* Dummy procedure       */

#else                        /* Nope, we’ve debugging */
#define main C4thMain        /* Re-define “main” entry*/
#define RememberA4() DummyProc()
#define RememberA0() DummyProc()
#define SetUpA4()  DummyProc()
#define RestoreA4()  DummyProc()
#define DbgPrint  ((CDbgPane *) \
        (gApplication->dbgDoc->itsMainPane))->DoPrint
#endif
#endif

                             /* Trap definitions      */
#define SysEnvironsTrap  0xa090/* System Env trap     */
#define GetDeviceListTrap 0xaa29/* Graphics Dev trap  */
#define UnknownTrap   0xa89f /* Unknown trap instr    */

                             /* Mac ROM ID’s          */
#define macIIROM   0x0078    /* Mac II ROM ID         */
#define macSEROM   0x0076    /* Mac SE ROM ID         */
#define macPlusROM 0x0075    /* Mac Plus ROM ID       */
#define macROM     0x0069    /* Original Mac ROM ID   */

extern RGBColor HiliteRGB : 0xda0;/* Hilite RGB color */

#ifndef NULL                 /* “NULL” is not defined?*/
#define NULL (0L)            /* Define “NULL” constant*/
#endif

                             /* Macro functions       */
#define abs(a)   (a<0?-a:a)  /* Absolute value        */
#define min(a,b) (a<b?a:b)   /* Minimum value         */
#define max(a,b) (a<b?b:a)   /* Maximum value         */

struct C4th : indirect {     /* 4th obj data structure*/

                             /* Variable instances    */
 WindowPtr wPtr;             /* Ext Area window ptr   */
 short     layout;           /* Layout flag indicator */
 short     dirty;            /* Dirty flag indicator  */
 short     active;           /* Active flag indicator */
 short     keyBoardEvents;   /* Using keyboard events */
 char      *name;            /* Ext area name str ptr */
 EventRecord *event;         /* Ext area event pointer*/
 Rect      drawArea;         /* Ext drawing area      */
 Rect      prevArea;         /* Prevs ext drawing area*/
 short     width;            /* Ext area width        */
 short     height;           /* Ext area height       */

                             /* System variable defs  */
 SysEnvRec sysEnv;           /* System configuration  */
 short     originalMac;      /* Using 128K/512K Macs  */
 short     hasGraphicDevices;/* Using graphic devices */
 
                             /* Working variable defs */
 PenState  savePenState;     /* Save cur pen states   */
 short     saveFont;         /* Save cur font’s ID    */
 short     saveSize;         /* Save cur font’s size  */
 Style     saveStyle;        /* Save cur font’s style */
 short     saveMode;         /* Save cur font’s mode  */
 RgnHandle tmpRgn;           /* Temporary region      */
 
                             /* Method instances      */
 void   Message(void);       /* Dispatch message      */
 void   IExtArea(short);     /* Initialization message*/
 void   Close(void);         /* Close message         */
 void   Idle(void);          /* Idle message          */
 void   Cursor(Point);       /* Cursor message        */
 void   Select(void);        /* Activate message      */
 void   Deselect(void);      /* Deactivate message    */
 void   Scroll(void);        /* Scroll message        */
 void   Draw(void);          /* Draw message          */
 void   DoClick(Point,short,long);/* Mouse message    */
 void   DoKeyDown(char,Byte);/* Key message           */
 void   DoUndo(void);        /* Edit “Undo” message   */
 void   DoCut(void);         /* Edit “Cut” message    */
 void   DoCopy(void);        /* Edit “Copy” message   */
 void   DoPaste(void);       /* Edit “Paste” message  */
 void   DoClear(void);       /* Edit “Clear” message  */
 void   DoSelectAll(void);   /* Edit “Select All” msg */
 void   SaveStates(void);    /* Save state for drawing*/
 void   RestoreStates(void); /* Restore drawing       */
 short  TrackMouse(Point,RgnHandle);/* Track da mouse */
 short  UsingColor(void);    /* Check if using color  */
 };
 
#endif

/*
 * Source       - 4th Class.c
 * Author       - Alexander S. Colwell
 *                Copyright © 1990
 * Description  - This 4th Dimension’s External Area
 *                class.
 */

#include “4th Class.h”       /* 4th Ext Area defs     */

C4th *New(void);             /* “New” func proto-type */

pascal void main(eaEvent, eaRect, eaName, eaObject)
 EventRecord  *eaEvent;      /* Ext Area event ptr    */
 Rect         *eaRect;       /* Ext Rect area pointer */
 char         *eaName;       /* Ext Area name pointer */
 C4th         **eaObject;    /* Ext Area object       */
 {
  WindowPtr curWPtr;         /* Working cur window ptr*/
  C4th      *fake;           /* Working fake ext area */
  
     RememberA0();           /* Save reg A0 for A4    */
     SetUpA4();              /* Setup register A4     */

  if (eaEvent->what == drawReq) {/* “Layout” draw?    */
   eaEvent->message = 102;   /* Let’s draw ext area   */
 
   fake = New();             /* Create fake objec     */

   GetPort(&curWPtr);        /* Get cur window pointer*/
   fake->layout = TRUE;      /* Set layou stat        */
   fake->wPtr = curWPtr;     /* Save window pointe    */
   fake->name = eaName;      /* Save ext area name    */
   fake->event = eaEvent;    /* Save event record ptr */
   fake->drawArea = *eaRect; /* Setup drawing area    */
   fake->prevArea = *eaRect; /* Setup previous area   */
   fake->width = eaRect->right - eaRect->left;
   fake->height = eaRect->bottom - eaRect->top;
   fake->tmpRgn = NULL;      /* Invalidate region     */

   eaEvent->what = initEvt;  /* Fake init event       */
   fake->Message();          /* Handle message        */

   eaEvent->what = updateEvt;/* Fake update event     */
   fake->Message();          /* Handle message        */

   eaEvent->what = deInitEvt;/* Fake deinit event     */
   fake->Message();          /* Handle message        */

   SetPort(curWPtr);         /* Restore prev wind port*/
  }
  else {                     /* Do real-thing         */
  
                             /* Check if initialized  */
      if (eaEvent->what == initEvt) {
       *eaObject = New();    /* Create new object     */
       (*eaObject)->layout = FALSE;/* Not layout area */
       (*eaObject)->tmpRgn = NULL;/* Invalidate region*/
       (*eaObject)->wPtr = NULL;/* Invalid window ptr */
       (*eaObject)->prevArea = *eaRect;/* Set prev rec*/
      }
       
      if (*eaObject) {       /* Check if got object   */
       GetPort(&curWPtr);    /* Get current window ptr*/
       (*eaObject)->wPtr = curWPtr;/* Save window ptr */
       (*eaObject)->name = eaName;/* Save ext name    */
       (*eaObject)->event = eaEvent;/* Save event ptr */
       (*eaObject)->drawArea = *eaRect;/*Set draw area*/
       (*eaObject)->width = eaRect->right-eaRect->left;
       (*eaObject)->height = eaRect->bottom-eaRect->top;
       (*eaObject)->Message();/* Handle message       */
       SetPort(curWPtr); /* Restore prevs window port */
      }
     }
     
     RestoreA4();            /* Restore register A4   */
 }
 
void C4th::Message(void)
 {
  register short what;       /* Working event type    */
  Rect           wRect;      /* Working rect area     */
  
  SaveStates();              /* Save state for drawing*/
        
  switch(what = event->what) {/* Process event message*/
   case nullEvent:           /* Null event handler    */
    Idle(); break;
    
   case initEvt:             /* Init event            */
    IExtArea(FALSE); break;
    
   case deInitEvt:           /* Close event           */
    Close(); break;
    
   case cursorEvt:           /* Cursor event          */
    Cursor(event->where); break;
    
   case selectReq:           /* Selection request evt */
    if (keyBoardEvents)      /*Wnt keyboard selection?*/
     event->message = 101;   /* Set keyboard request  */
    break;
    
   case activNote:           /* Activate select evt   */
    Select(); break;
    
   case deActivNote:         /* Deactivate select evt */
    Deselect(); break;
    
   case scrollEvt:           /* Scroll event          */
    Scroll(); break;
    
   case undoEvt:             /* Edit’s “Undo” event   */
    DoUndo(); break;
    
   case cutEvt:              /* Edit’s “Cut” event    */
    DoCut(); break;
    
   case copyEvt:             /* Edit’s “Copy” event   */
    DoCopy(); break;
    
   case pasteEvt:            /* Edit’s “Paste” event  */
    DoPaste(); break;
    
   case clearEvt:            /* Edit’s “Clear” event  */
    DoClear(); break;
    
   case selectAllEvt:        /*Edit’s “Select All” evt*/
    DoSelectAll(); break;
    
   case afterActivEvt:       /* After “ActivNote” evt */
    break;
    
   case afterDeactivEvt:     /*After “DeactivNote” evt*/
    break;
    
   case activeIdleEvt:       /* Selection idle event  */
    break;
    
   case updateEvt:           /* Update external area  */
    wRect = drawArea;        /* Set area to erase     */
    EraseRect(&wRect);       /* Clear it now          */
    Draw();                  /* Do “Draw” method      */
    break;
           
   case mouseDown:           /* Mouse down in ext area*/
    DoClick(event->where,event->modifiers,event->when);
    break;
           
   case keyDown:             /* Key down event        */
   case autoKey:             /* Auto-key down event   */
    DoKeyDown(event->message & charCodeMask,
              (event->message & keyCodeMask) >> 8);
    break;
           
   default:                  /* Don’t know this event */
    break;
  }
  
  if (what != deInitEvt)     /* Check if not closing  */
    RestoreStates();         /* Restore drawing stuff */
 }
 
void C4th::IExtArea(short getKeyBoard)
 {
  short          rom;        /* Working ROM id        */
  short          machine;    /* Working Mac id        */
  register short canDoIt;    /* Working can do it flag*/
  SysEnvRec      wSysEnv;    /* Working system config */

  dirty = FALSE;             /* Mark ext not dirty    */
  active = FALSE;            /* Mark ext not active   */
  keyBoardEvents = getKeyBoard;/* Get keyboard events */
  tmpRgn = NewRgn();         /* Temporary region      */

  originalMac = FALSE;       /* Not using 128K/512K   */
  hasGraphicDevices = FALSE; /* Has no graphic devices*/
  sysEnv.environsVersion = 0;/* Bogus system config n */
  sysEnv.machineType = 0;
  sysEnv.systemVersion = 0;
  sysEnv.processor = 0;
  sysEnv.hasFPU = FALSE;
  sysEnv.hasColorQD = FALSE;
  sysEnv.keyBoardType = 0;
  sysEnv.atDrvrVersNum = 0;
  sysEnv.sysVRefNum = 0;

  Environs(&rom,&machine);   /* Get Mac’s evniroment  */
  if (machine == macXLMachine)/* Check if Lisa clone  */
   canDoIt = FALSE;          /* It’s a Lisa computer! */
  else if (rom >= macIIROM)  /* It’s Mac II           */
   canDoIt = TRUE;           /* It’s Mac II computer  */
  else if (rom >= macSEROM)  /* It’s Mac SE           */
   canDoIt = TRUE;           /* It’s Mac SE computer  */
  else if (rom >= macPlusROM) {/* it’s 128K rom       */
                             /* Check if Mac 512KE    */
   if (MemTop > (char *)(1024L * 512L))
    canDoIt = TRUE;          /* It’s Mac 512K Enhanced*/
   else
    canDoIt = TRUE;          /* Its Mac Plus computer */
  }
  else  if (rom >= macROM) { /* It’s 64K rom          */
   canDoIt = FALSE;          /* It’s original Mac!    */
   originalMac = TRUE; 
  }
  if (canDoIt)  {            /* OK, we can do it!     */
            
                             /* SysEnvirons valid?    */
   if ((long)NGetTrapAddress(SysEnvironsTrap,OSTrap) != 
       (long)NGetTrapAddress(UnknownTrap,ToolTrap)) {
    SysEnvirons(1,&wSysEnv); /* Get system enviroment */
    sysEnv = wSysEnv;        /* Save configuration    */
   }
  
                             /* “Graphics Dev” valid? */
   if ((long)NGetTrapAddress(GetDeviceListTrap,ToolTrap)
       != (long)NGetTrapAddress(UnknownTrap,ToolTrap))
    hasGraphicDevices = TRUE;/* Mark it available     */
  }
 }
 
void C4th::Close(void)
 {
  RestoreStates();           /* Restore drawing       */
  if (tmpRgn)                /* Have clipping region ?*/
   DisposeRgn(tmpRgn);       /* Release region        */
  tmpRgn = NULL;             /* Invalidate it         */
  delete(this);              /* Release this object   */
 }
 
void C4th::Idle(void)
 {
  if (dirty) {               /* Check if it’s dirty   */
   Draw();                   /* Re-draw everything!!! */
   dirty = FALSE;            /* Reset dirty indicator */
  }
 }
 
void C4th::Cursor(Point pt)
 {
  CursHandle crossHdl;       /* Working cursor handle */
  
                             /* Check if got cursor   */
  if (crossHdl = GetCursor(crossCursor))
   SetCursor(*crossHdl);     /* Set to cross cursor   */
 }
 
void C4th::Select(void)
 { active = TRUE; }          /* Mark ext area active  */
 
void C4th::Deselect(void)
 { active = FALSE; }         /* Mark ext area not act */
 
void C4th::Scroll(void) {}
 
void C4th::Draw(void)
 {
  Rect wRect;                /* Working rect area     */
  
  wRect = drawArea;          /* Set drawing rect area */
  
  PaintRect(&wRect);         /* Show something        */
 }
 
void C4th::DoClick(Point pt, short modifiers,long ticks)
 {}
 
void C4th::DoKeyDown(char theChar, Byte keyCode) {}

void C4th::DoUndo(void) {}

void C4th::DoCut(void) {}

void C4th::DoCopy(void) {}

void C4th::DoPaste(void) {}

void C4th::DoClear(void) {}

void C4th::DoSelectAll(void) {}

void C4th::SaveStates(void)
 {
  GetPenState(&savePenState);/* Get current pen states*/
  PenNormal();               /* Normalize pen states  */
  saveFont = wPtr->txFont;   /* Save cur font’s states*/
  saveSize = wPtr->txSize;
  saveStyle = wPtr->txFace;
  saveMode = wPtr->txMode;
 }

void C4th::RestoreStates(void)
 {
  SetPenState(&savePenState);/* Restore pen states    */
  TextFont(saveFont);        /* Restore font’s states */
  TextSize(saveSize);
  TextFace(saveStyle);
  TextMode(saveMode);
  prevArea = drawArea;       /* Save previous area    */
  if (tmpRgn)                /* Check if has temp rgn */
   EmptyRgn(tmpRgn);         /* Free-up some memory   */
 }
 
short C4th::TrackMouse(Point pt,RgnHandle rgn)
 {
  register RgnHandle wRgn;   /* Working region handle */
  register short  hilite = FALSE;/* Hilite state      */
  register short  status = FALSE;/* Working status    */
  
  if (PtInRgn(pt,rgn)) {     /* Initially inside rgn? */
   if (wRgn = NewRgn()) {    /* Check if got region   */
    CopyRgn(rgn,wRgn);       /* Copy mouse’s region   */
    InsetRgn(wRgn,1,1);      /* Shrink it a bit       */
    while(Button()) {        /* Do while mouse is down*/
     GetMouse(&pt);          /* Get next mse position */
     if (PtInRgn(pt,rgn))    /* Check if mouse inside?*/
      status = TRUE;         /* Set inside the region */
     else                    /* Nope, outside region  */
      status = FALSE;        /* Set outside of region */
     if (hilite != status) { /* Check if change hilite*/
      hilite = status;       /* Reset hilite state    */
      HiliteMode &= 0x7f;    /* Set highliting bit    */
      InvertRgn(wRgn);       /* Invert it             */
     }
    }
    if (hilite) {            /* Restore hilite state? */
     HiliteMode &= 0x7f;     /* Set highliting bit    */
     InvertRgn(wRgn);        /* Invert it             */
    }
    DisposeRgn(wRgn);        /* Release region handle */
   }
  }
  return(status);            /* Return status flag    */
 }
 
short C4th::UsingColor(void)
 {
  register short    hasColor = TRUE;/* Color flag     */
  register GDHandle theDevice;/* Working screen device*/
  Rect              globalRect;/* Working ext area    */
  Rect              wRect;   /* Working window area   */

  if (sysEnv.hasColorQD) {   /* Check if using color  */
   if (hasGraphicDevices) {  /* Has graphic devices?  */
    hasColor = TRUE;         /* Assume using color    */
    globalRect = drawArea;   /* Setup global rect area*/
    LocalToGlobal(&globalRect.top);/* Cnvt to global  */
    LocalToGlobal(&globalRect.bottom);
    theDevice = GetDeviceList();/* Get main device    */
    while(hasColor && theDevice) {/* Search B&W device*/
                             /* Area within view?     */
     if (SectRect(&globalRect,
                  &(*(*theDevice)->gdPMap)->bounds, &wRect))
      if ((*(*theDevice)->gdPMap)->pixelSize <= 2)
       hasColor = FALSE;
     theDevice = GetNextDevice(theDevice);/* Get next */
    }
   }
  }
  return(hasColor);          /* Return color indicator*/
 }
 
int DummyProc() {}           /* Dummy procedure       */

/*
 * Source       - CalendarDebugger.c
 * Author       - Alexander S. Colwell
 *                Copyright © 1990
 * Description  - This is Calendar simulator.
 */

#include “Calendar.h”        /* Calendar defs         */
#include “4th Debugger.h”    /* 4th Debugger          */

                             /* Define ext references */
pascal void SetCalendar(),GetCalendar();
void  DoSetCalendar(),DoGetCalendar();

void C4thDbgApp::InitExtArea(void)
 {
  Str255 item;               /* Working item string   */
  
  SetExtArea(65,25,265,127); /* Set external rect area*/
  SetExtName(“\pCalendarArea”);/* Set ext area name   */
  
                             /* Install ext procedures*/
  InstallExtProc(ep1,(ProcPtr)(DoSetCalendar));
  InstallExtProc(ep2,(ProcPtr)(DoGetCalendar));
  
                             /* Setup ext proc items  */
  BlockMove(“\pSet Calender Data”,item,18L);
  gBartender->SetCmdText(ep1,item);
  BlockMove(“\pGet Calendar Data”,item,18L);
  gBartender->SetCmdText(ep2,item);
  
  gBartender->RemoveMenuCmd(ep3);/* Remove other items*/
  gBartender->RemoveMenuCmd(ep4);
  gBartender->RemoveMenuCmd(ep5);
  gBartender->RemoveMenuCmd(ep6);
  gBartender->RemoveMenuCmd(ep7);
  gBartender->RemoveMenuCmd(ep8);
  gBartender->RemoveMenuCmd(ep9);
 }

void DoSetCalendar(CCalendar **eaObject)
 {
  short itsMonth = 1;        /* Working month         */
  short itsYear = 1990;      /* Working year          */
  long  itsSelect = 0L;      /* Working day selection */
  
                             /* Set new date/selection*/
  SetCalendar(eaObject,&itsMonth,&itsYear,&itsSelect);
 }

void DoGetCalendar(CCalendar **eaObject)
 {
  short itsMonth;            /* Working month         */
  short itsYear;             /* Working year          */
  long  itsSelect;           /* Working day selection */
  
                             /* Set new date/selection*/
  GetCalendar(eaObject,&itsMonth,&itsYear,&itsSelect);
  
                             /* Output debugging info */
  DbgPrint(“month - %d, year - %d, select - %lx\n”,
           itsMonth,itsYear,itsSelect);
 }

/*
 * Source      - Calendar.h
 * Author      - Alexander S. Colwell
 *               Copyright © 1990
 * Description - This is Calendar’s include file
 */

#ifndef _Calendar_           /* Has been include yet? */
#define _Calendar_           /* Mark it been included */

#include “4th Class.h”       /* 4th Ext Area defs     */
 
#define headerHeight 16      /* Height for month/year */

struct CCalendar : C4th {    /* Calendar object       */

                             /* Variable instances    */
 short month;                /* Current month         */
 short year;                 /* Current year          */
 short dayIndex;             /* Day idx 1st row cell  */
 unsigned long daySelect;    /* Current day selection */
 RgnHandle nextMonth;        /* Next month cntl handle*/
 RgnHandle prevMonth;        /* Prevs month cntl hdl  */
 
                             /* Working variable defs */
 short dayWidth;             /* Day width             */
 short dayHeight;            /* Day height            */
 
                             /* Method instances      */
 void IExtArea(short);       /* External area init    */
 void Close(void);           /* Close external area   */
 void Cursor(Point);         /* Cursor                */
 void SetupValues(void);     /* Setup working values  */
 void Draw(void);            /* Draw method           */
 void DrawDay(char *,short,short);/* Draw cell        */
 void HiliteDay(short,short);/* Hilite day            */
 void DayRect(Rect *,short,short);/* Get day rect area*/
 short MakeDayOutline(void); /* Make day outline rgn  */
 void Select(void);          /* Do ext area selection */
 void Deselect(void);        /* Do ext area deselect  */
 void Scroll(void);          /* Scroll ext area       */
 void DoClick(Point,short,long);/* Do click method    */
 short GetDays(void);        /* Get # days this month */
 short GetDayIndex(void);    /* Get day idx offset    */
 short GetRowIndex(short);   /* Get row idx offset    */
 short GetColumnIndex(short);/* Get column idx offset */
 short LeapYear(void);       /* Check if it leap year */
 };
 
#endif

/*
 * Source      - Calendar.c
 * Author      - Alexander S. Colwell
 *               Copyright © 1990
 * Description - This is external area to display an
 *               calendar.
 */

#include “Calendar.h”        /* Calendar defs         */
 
C4th *New(void) { return(new(CCalendar)); }

void CCalendar::IExtArea(short getKeyBoard)
 {
  Rect wRect;                /* Working rect area     */
  
  inherited::IExtArea(TRUE); /* Do other inits        */
  
  month = 1;                 /* Set “January” default */
  year = 1990;               /* Set 1990 year default */
  daySelect = 0L;            /* Set no selected days  */
  dayIndex = GetDayIndex();  /* Set “day” offset      */

  nextMonth = NewRgn();      /* Get next button rgn   */
  prevMonth = NewRgn();      /* Get prevs button rgn  */
 }
 
void CCalendar::Close(void)
 {
  if (nextMonth)             /* Region hdl is valid?  */
   DisposeRgn(nextMonth);    /* Release this rgn hdl  */
  nextMonth = NULL;          /* Invalidate region hdl */
  
  if (prevMonth)             /* Region hdl is valid?  */
   DisposeRgn(prevMonth);    /* Release this rgn hdl  */
  prevMonth = NULL;          /* Invalidate region hdl */
  
  inherited::Close();        /* Continue closing      */
 }
 
void CCalendar::Cursor(Point pt)
 {
  register short i;          /* Working index         */
  register short days;       /* Working # of days     */
  register short doIt = FALSE;/* Working status flag  */
  Rect           wRect;      /* Working day area      */
  
  if (nextMonth)             /* Next button rgn valid?*/
   if (PtInRgn(pt,nextMonth))/* Inside this region?   */
    doIt = TRUE;             /* Let’s do it           */
   
  if (!doIt)                 /* Check if should cont  */ 
   if (prevMonth)            /* Prev button rgn valid?*/
    if (PtInRgn(pt,prevMonth))/* Inside this region?  */
     doIt = TRUE;            /* Let’s do it           */
    
  if (!doIt) {               /* Check if should cont  */
   days = GetDays();         /* Get # of days         */
   for(i = 1; i <= days; i++) {/* Search selected days*/
    DayRect(&wRect,GetRowIndex(i),GetColumnIndex(i));
    if (PtInRect(pt,&wRect)) {/* Point inside day?    */
     doIt = TRUE; /* Let’s do it      */
     break;                  /* Break-out of da loop! */
    }
   }
  }

  if (doIt)                  /* Check if want to do it*/
   inherited::Cursor(pt);    /* OK, do standard cursor*/
  else                       /* Nope, let’s not do it */
   InitCursor();             /* Reset to arrow cursor */
 }
 
void CCalendar::SetupValues(void)
 {
  dayWidth = width / 7;      /* Compute aveages       */
  dayHeight = (height - headerHeight) / 7;
 }
 
void CCalendar::Draw(void)
 {
  register short i;          /* Working index         */
  register short days;       /* Working # of days     */
  register short usingColor; /* Working using color   */
  Str255         label;      /* Working label string  */
  Rect           wRect;      /* Working rect area     */
  RGBColor       saveColor;  /* Working save fore colr*/
  register RgnHandle wRgn;   /* Working region handle */
   
  TextFont(geneva);          /* Set to “Geneva” font  */
  TextSize(9);               /* Set to 9-point font   */
  TextFace(0);               /* Set to “plain” text   */
  
  wRect = drawArea;          /* Setup drawing area    */
  
  EraseRect(&wRect);         /* Clear-out old stuff   */
  FrameRect(&wRect);         /* Frame da calendar     */
  
  SetupValues();             /* Setup working values  */
  
  switch(month) {            /* Copy month to label   */
   case 1:  BlockMove(“\pJanuary “,label,9L); break;
   case 2:  BlockMove(“\pFeburary “,label,10L); break;
   case 3:  BlockMove(“\pMarch “,label,7L); break;
   case 4:  BlockMove(“\pApril “,label,7L); break;
   case 5:  BlockMove(“\pMay “,label,5L); break;
   case 6:  BlockMove(“\pJune “,label,6L); break;
   case 7:  BlockMove(“\pJuly “,label,6L); break;
   case 8:  BlockMove(“\pAugust “,label,8L); break;
   case 9:  BlockMove(“\pSeptember “,label,11L); break;
   case 10: BlockMove(“\pOctober “,label,9L); break;
   case 11: BlockMove(“\pNovember “,label,10L); break;
   case 12: BlockMove(“\pDecember “,label,10L); break;
  }
  
                             /* Concat year           */
  NumToString((long)(year),&label[128]);
  BlockMove(&label[129],&label[label[0]+1],
            (long)(label[128]));
  label[0] += label[128];
  
  DrawDay((char *)(label),0,4);/*Draw Month/Year label*/
  
  DrawDay(“\pS”,1,1);        /* Draw “Week Day” labels*/
  DrawDay(“\pM”,1,2);
  DrawDay(“\pT”,1,3);
  DrawDay(“\pW”,1,4);
  DrawDay(“\pT”,1,5);
  DrawDay(“\pF”,1,6);
  DrawDay(“\pS”,1,7);
  
  days = GetDays();          /* Get # of days         */
  for(i = 1; i <= days; i++) {/* Draw “Day” labels    */
   NumToString((long)(i),label);
   DrawDay((char *)(label),GetRowIndex(i), GetColumnIndex(i));
  }
   
  if (active) || !tmpRgn) {  /* Check if it’s active  */
   for(i = 1; i <= days; i++)/* Hilite the days       */
    if (daySelect & (1L << (long)(i - 0)))
     HiliteDay(GetRowIndex(i),GetColumnIndex(i));
  }
  else {                     /* Nope, let’s frame it  */
   MakeDayOutline();         /* Make day’s outline    */
   if (wRgn = NewRgn()) {    /* Check if got rgn hdl  */
    CopyRgn(tmpRgn,wRgn);    /* Copy outline rgn hdl  */
    InsetRgn(wRgn,1,1);      /* Shrink it a bit       */
    DiffRgn(tmpRgn,wRgn,tmpRgn);/* OK, get difference */
    DisposeRgn(wRgn);        /* Release working region*/
    HiliteMode &= 0x7f;      /* Set highliting bit    */
    InvertRgn(tmpRgn);       /* Outline days          */
   }
   else {                    /* Nope, do sub-optimal  */
    if (usingColor = UsingColor()) {/* Using color?   */
     GetForeColor(&saveColor);/* Save fore color      */
     RGBForeColor(&HiliteRGB);/* Set hilite fore color*/
    }
    FrameRgn(tmpRgn);        /* Outline the days      */
    if (usingColor)          /* Check if using color  */
     RGBForeColor(&saveColor);/* Restore fore color   */
   }
  }
  
                             /* Draw separators       */
  MoveTo(drawArea.left,drawArea.top + headerHeight);
  LineTo(drawArea.left + width, drawArea.top + headerHeight);
  MoveTo(drawArea.left,
         drawArea.top + dayHeight + headerHeight);
  LineTo(drawArea.left + width,
         drawArea.top + dayHeight + headerHeight);
  
  if (prevMonth) {           /* Region hdl is valid?  */
   if (EmptyRgn(prevMonth)) {/* Empty to be drawn?    */
    OpenRgn();               /* Start button drawing  */
    MoveTo(drawArea.left+3, drawArea.top+headerHeight/2+1);
    LineTo(drawArea.left+headerHeight/2+2, drawArea.top+1);
    LineTo(drawArea.left+headerHeight/2+2,
           drawArea.top+headerHeight/4+1);
    LineTo(drawArea.left+headerHeight-headerHeight/6,
           drawArea.top+headerHeight/4+1);
    LineTo(drawArea.left+headerHeight-headerHeight/6,
           drawArea.top+headerHeight-headerHeight/4);
    LineTo(drawArea.left+headerHeight/2+2,
           drawArea.top+headerHeight-headerHeight/4);
    LineTo(drawArea.left+headerHeight/2+2,
           drawArea.top+headerHeight-1);
    LineTo(drawArea.left+3,
           drawArea.top+headerHeight/2+1);
    CloseRgn(prevMonth);     /* Close button drawing  */
   }
   if (layout || active)     /*Check if should draw it*/
    FrameRgn(prevMonth);     /* Draw “prev” button    */
  }
  
  if (nextMonth) {           /* Region hdl is valid?  */
   if (EmptyRgn(nextMonth)) {/* Empty to be drawn?    */
    OpenRgn();               /* Start button drawing  */
    MoveTo(drawArea.right-3, drawArea.top+headerHeight/2+1);
    LineTo(drawArea.right-headerHeight/2-2, drawArea.top+2);
    LineTo(drawArea.right-headerHeight/2-2,
           drawArea.top+headerHeight/4+1);
    LineTo(drawArea.right-headerHeight+headerHeight/6,
           drawArea.top+headerHeight/4+1);
    LineTo(drawArea.right-headerHeight+headerHeight/6,
           drawArea.top+headerHeight-headerHeight/4);
    LineTo(drawArea.right-headerHeight/2-2,
           drawArea.top+headerHeight-headerHeight/4);
    LineTo(drawArea.right-headerHeight/2-2,
           drawArea.top+headerHeight-1);
    LineTo(drawArea.right-3, drawArea.top+headerHeight/2+1);
    CloseRgn(nextMonth);     /* Close button drawing  */
   }
   if (layout || active)     /*Check if should draw it*/
    FrameRgn(nextMonth);     /* Draw “previous” button*/
  }
 }
 
void CCalendar::DrawDay(char *label,
                        short row, short column)
 {
  FontInfo fontInfo;         /* Working font infor    */
  Rect     wRect;            /* Working rect area     */
  
  DayRect(&wRect,row,column);/* Get day rect area     */
  
  GetFontInfo(&fontInfo);    /* Get current font info */
  
                             /* Position da string    */
  MoveTo(wRect.left + dayWidth/2-StringWidth(label)/2,
         wRect.top + ((row ? dayHeight : headerHeight) - 
         fontInfo.ascent - fontInfo.descent) / 2 + 
         fontInfo.ascent); 
           
  DrawString(label);         /* Draw the string label */
 }
 
void CCalendar::HiliteDay(short row, short column)
 {
  Rect wRect;                 /* Working rect area    */
  
  DayRect(&wRect,row,column); /* Get day rect area    */
  HiliteMode &= 0x7f;         /* Set highliting bit   */
  InvertRect(&wRect);         /* Invert it            */
 }
 
void CCalendar::DayRect(Rect *rect, short row, short column)
 {
  rect->left = rect->top = 0;/* Set relative rect area*/
  rect->right = dayWidth;
  rect->bottom = dayHeight;
  
                             /* Offset day for drawing*/
  OffsetRect(rect,dayWidth * (column - 1)+drawArea.left,
       dayHeight * row + (row ? max(0,headerHeight - day
 Height) : 0) + drawArea.top);
 }
 
short CCalendar::MakeDayOutline(void)
 {
  register short i;          /* Working index         */
  register short days;       /* Working # of days     */
  Rect           wRect;      /* Working rect area     */
  register short status = FALSE;/* Working status flag*/
  
  if (tmpRgn) {              /* Check if it’s valid   */
   days = GetDays();         /* Get # of days         */
   EmptyRgn(tmpRgn);         /* Set region empty      */
   OpenRgn();                /* Start region drawing  */
   for(i = 1; i <= days; i++)/* Outline the days      */
    if (daySelect & (1L << (long)(i - 0))){/*This day?*/
     status = TRUE;          /*Mark has some outlining*/
     DayRect(&wRect,GetRowIndex(i),GetColumnIndex(i));
     FrameRect(&wRect);

    }
   CloseRgn(tmpRgn);         /* Copy da region        */
  }
  
  return(status);            /* Return any outlining  */
 }

void CCalendar::Select(void)
 {
  inherited::Select();       /* Do other stuff first  */
  if (MakeDayOutline()) {    /* Make day’s outline    */
   InsetRgn(tmpRgn,1,1);     /* Shrink it a bit       */
   HiliteMode &= 0x7f;       /* Set highliting bit    */
   InvertRgn(tmpRgn);        /* Invert region         */
  }
 }
 
void CCalendar::Deselect(void)
 {
  inherited::Deselect();     /* Do other stuff first  */
  if (MakeDayOutline()) {    /* Make day’s outline    */
   InsetRgn(tmpRgn,1,1);     /* Shrink it a bit       */
   HiliteMode &= 0x7f;       /* Set highliting bit    */
   InvertRgn(tmpRgn);        /* Invert region         */
  }
 }
 
void CCalendar::Scroll(void)
 {
  if (nextMonth)             /* Got “next” region hdl?*/
   OffsetRgn(nextMonth,drawArea.left - prevArea.left,
        drawArea.top - prevArea.top);
        
  if (prevMonth)             /* Got “prev” region hdl?*/
   OffsetRgn(prevMonth,drawArea.left - prevArea.left,
        drawArea.top - prevArea.top);
 }
 
void CCalendar::DoClick(Point pt, short modifiers, long ticks)
 {
  register short i;          /* Working index         */
  register short lastDay = 0;/* Working last day      */ 
  register short days;       /* Working # of days     */
  register short hiliteMode = TRUE;/* Hilite mode     */
  register unsigned long mask;/* Working mask         */
  short          row;        /* Working row position  */
  short          column;     /*Working column position*/
  Rect           wRect;      /* Working rect area     */

  if (nextMonth) {           /* Selecting next month? */
   if (TrackMouse(pt,nextMonth)) {/* Track da mouse!! */
    daySelect = 0L;          /* Zap current selection */
    month += 1;              /* Go to next month      */
    if (month == 13) {       /* It’s into next year?  */
     month = 1;              /* Reset to “January”    */
     year += 1;              /* Re-draw the calendar  */
    }
    dayIndex = GetDayIndex();/* Set “day” offset      */
    Draw();                  /* Re-draw the calendar  */
   }
  }
  
  if (prevMonth) {           /* Selecting prev month? */
   if (TrackMouse(pt,prevMonth)) {/* Still selecting? */
    daySelect = 0L;          /* Zap current selection */
    month -= 1;              /* Go to previous month  */
    if (month == 0) {        /* It’s into prev year?  */
     month = 12;             /* Reset to “Decemeber”  */
     year -= 1;              /* Go to previous year   */
    }
    dayIndex = GetDayIndex();/* Set “day” offset      */
    Draw();                  /* Re-draw the calendar  */
   }
  }

  days = GetDays();          /* Get # of days         */
   
  do {                       /* Track da mouse!!      */
   for(i = 1; i <= days; i++) {/* Search for day      */
    DayRect(&wRect,row = GetRowIndex(i),
                    column = GetColumnIndex(i));
    if (PtInRect(pt,&wRect)) {/* Point inside day?    */
     mask = (1L << (long)(i - 0));/* Set mask         */
     if (!lastDay) {         /* Check if first time   */
      if (daySelect & mask)  /* Check if hilited      */
       hiliteMode = FALSE;   /* Reset to hiliting mode*/
     }
     if (lastDay != i) {     /* Check if it’s new day */
      if (hiliteMode) {      /* Check if hiliting day?*/
       if (!(daySelect & mask)) {/* Not selected ?    */
        HiliteDay(row,column);/* Hilite day           */
        daySelect ^= mask;   /* Set this day          */
       }
      }
      else {                 /* Nope, unhiliting days */
       if (daySelect & mask) {/* Selected ?           */
        HiliteDay(row,column);/* Unhilite day         */
        daySelect ^= mask;   /* Clear this day        */
       }
      }
     }
     lastDay = i;            /* Save last selected day*/
    }
   }
   GetMouse(&pt);            /* Get next mse position */
  } while(Button());         /* Track while mouse down*/
 }
 
short CCalendar::GetDays(void)
 {
  register short days;       /* Working number of days*/
  static short   monthDays[] = {31,28,31,30,31,30,
                                31,31,30,31,30,31};
  
                             /* Check if “Feburary”   */
  if ((days = monthDays[month - 1]) == 28)
   days += LeapYear();       /* Add leap year day     */
   
  return(days);              /* Return number of days */
 }
 
short CCalendar::GetDayIndex(void)
 {
  DateTimeRec dateTime;      /* Working date/tim stamp*/
  long        secs;          /* Working seconds       */
  
  dateTime.year = year;      /* Init date/time stamp  */
  dateTime.month = month;
  dateTime.day = 1;
  dateTime.hour = 0;
  dateTime.minute = 0;
  dateTime.second = 0;
  
  Date2Secs(&dateTime,&secs);/* Translate to seconds  */
  Secs2Date(secs,&dateTime); /* Get day of week       */
  
  return(dateTime.dayOfWeek - 1);/* Return day of week*/
 }
 
short CCalendar::GetRowIndex(short idx)
 { return(2 + ((idx - 1 + dayIndex) / 7)); }
 
short CCalendar::GetColumnIndex(short idx)
 { return(1 + ((idx - 1 + dayIndex) % 7)); }
 
short CCalendar::LeapYear(void)
 {
  DateTimeRec    dateTime;   /* Working date/tim stamp*/
  long           secs;       /* Working seconds       */
  register short leapDay = 0;/* Working leap year day */
  
  dateTime.year = year;      /* Init date/time stamp  */
  dateTime.month = month;
  dateTime.day = 29;
  dateTime.hour = 0;
  dateTime.minute = 0;
  dateTime.second = 0;
  
  Date2Secs(&dateTime,&secs);/* Translate to seconds  */
  Secs2Date(secs,&dateTime); /* Convert to real day   */
  
  if (dateTime.day == 29)    /* It’s still same day?  */
   leapDay = 1;              /* Yup, it’s leap year!!!*/
   
  return(leapDay);           /* Return leap year day  */
 }
 
/*
 * Source      - GetCalendar.c
 * Author      - Alexander S. Colwell
 *               Copyright © 1990
 * Description - This get calendar’s states.
 */

#include “Calendar.h”        /* Calendar defs         */

#ifndef ExtArea              /* Check if debug mode   */
#undef  main                 /* Remove previous def   */
#define main GetCalendar     /* Set debug proc name   */
#endif

pascal void main(CCalendar **eaObject,
                 short *itsMonth, short *itsYear,
                 long *itsSelect)
 {
  *itsMonth = (*eaObject)->month;/* Copy it           */
  *itsYear = (*eaObject)->year;
  *itsSelect = (*eaObject)->daySelect;
 }
 
/*
 * Source      - SetCalendar.c
 * Author      - Alexander S. Colwell
 *               Copyright © 1990
 * Description - This set new calendar’s states.
 */

#include “Calendar.h”        /* Calendar defs         */

#ifndef ExtArea              /* Check if debug mode   */
#undef  main                 /* Remove previous def   */
#define main SetCalendar     /* Set debug proc name   */
#endif

pascal void main(CCalendar **eaObject,
                 short *itsMonth, short *itsYear,
                 long *itsSelect)
 {
  (*eaObject)->dirty = TRUE; /* Mark ext area dirty   */
  
  (*eaObject)->month = *itsMonth;/* Reset it          */
  (*eaObject)->year = *itsYear;
  (*eaObject)->daySelect = *itsSelect;
 }

/*
 * Source       - 4th Debugger.r
 * Author       - Alexander S. Colwell
 *                Copyright © 1990
 * Description  - This is 4th Debugger resource file.
 */

#include “Types.r”
#include “SysTypes.r”

type ‘EA4h’ { pstring; };

resource ‘BNDL’ (128, purgeable) {
 ‘EA4h’, 0,
 { 
  ‘ICN#’, { 0, 128 },
  ‘FREF’, { 0, 128 }
 }
};

resource ‘FREF’ (128) {
 ‘APPL’, 0, “”
};

resource ‘EA4h’ (0) {
 “External Area Debugger”
};

resource ‘MBAR’ (1, preload) {
 { 1, 2, 3, 128 }
};

resource ‘MENU’ (1, “Apple”) {
 1, textMenuProc, 0x7FFFFFFD, enabled, apple,
 {
  “About 4th Dim Debugger #256”,
  noIcon, noKey, noMark, plain,
  “-”, noIcon, noKey, noMark, plain
 }
};

resource ‘MENU’ (2, “File”) {
 2, textMenuProc, allEnabled, enabled, “File”,
 {
  “Page Setup #8”, noIcon, noKey, noMark, plain,
  “Print #9”, noIcon, “P”, noMark, plain,
  “-”, noIcon, noKey, noMark, plain,
  “Quit#1”, noIcon, “Q”, noMark, plain
 }
};

resource ‘MENU’ (3, “Edit”, preload) {
 3, textMenuProc, 0x7FFFFF80, enabled, “Edit”,
 {
  “Undo#16”, noIcon, “Z”, noMark, plain,
  “-”, noIcon, noKey, noMark, plain,
  “Cut#18”, noIcon, “X”, noMark, plain,
  “Copy#19”, noIcon, “C”, noMark, plain,
  “Paste#20”, noIcon, “V”, noMark, plain,
  “Clear#21”, noIcon, noKey, noMark, plain,
  “-”, noIcon, noKey, noMark, plain,
  “Select All#1035”, noIcon, “A”, noMark, plain,
  “Hide Debugger#1036”, noIcon, “D”, noMark, plain,
  “Show Clipboard#22”, noIcon, noKey, noMark, plain
 }
};

resource ‘MENU’ (128, “Emulate”) {
 128, textMenuProc, allEnabled, enabled, “Emulate”,
 {
  “Open External Area#1024”, noIcon, “O”, noMark, plain,
  “Close External Area#1025”,
  noIcon, “W”, noMark, plain,
  “-”, noIcon, noKey, noMark, plain,
  “Run External Procedure 1#1026”,
  noIcon, “1”, noMark, plain,
  “Run External Procedure 2#1027”,
  noIcon, “2”, noMark, plain,
  “Run External Procedure 3#1028”,
  noIcon, “3”, noMark, plain,
  “Run External Procedure 4#1029”,
  noIcon, “4”, noMark, plain,
  “Run External Procedure 5#1030”,
  noIcon, “5”, noMark, plain,
  “Run External Procedure 6#1031”,
  noIcon, “6”, noMark, plain,
  “Run External Procedure 7#1032”,
  noIcon, “7”, noMark, plain,
  “Run External Procedure 8#1033”,
  noIcon, “8”, noMark, plain,
  “Run External Procedure 9#1034”,
  noIcon, “9”, noMark, plain
 }
};

resource ‘WIND’ (500, “4th External Area”) {
 {40, 4, 210, 352},
 zoomDocProc, invisible, goAway, 0,
 “4th External Area”
};

resource ‘WIND’ (501, “4th External Debugger”) {
 {235, 4, 335, 352},
 zoomDocProc, visible, goAway, 0,
 “Debugger”
};

resource ‘DLOG’ (500, “About This...”) {
 {40, 40, 128, 304},
 dBoxProc, visible, noGoAway, 0, 500,
 “About This...”
};

resource ‘DITL’ (500, “About This...”) {
 {
  {8, 52, 26, 216},
  StaticText { enabled, “4th Dimension Debugger” },
  {27, 95, 45, 173},
  StaticText { enabled, “Version 1.0” },
  {46, 29, 64, 240},
  StaticText{enabled,”Written by Alexander S. Colwell”},
  {65, 76, 83, 194},
  StaticText { enabled, “Copyright © 1990” }
 }
};

resource ‘STR#’ (1036, “Hide/Show Debugger”) {
 {
  “Hide Debugger”,
  “Show Debugger”
 }
};

resource ‘ICN#’ (128, purgeable) {
 {
  $”00 00 00 00 72 00 1F E0 45 00 20 20 67 7F C0 7F”
  $”45 00 80 F8 75 01 01 F0 00 02 03 E0 FF FC 07 FF”
  $”00 08 0F 80 00 10 1F 00 00 20 3E 00 FF C0 7F FF”
  $”00 80 FF F8 01 01 F0 10 02 03 E0 20 FC 07 C0 7F”
  $”08 0F 80 F8 10 1F 01 FC 20 00 00 04 C0 00 00 0F”
  $”40 00 00 1F 40 00 00 3E 40 00 00 7C FF E0 3F FF”
  $”3F C0 7F F0 3F 80 FF E0 3F 01 FF C0 FF FF FF FF”
  $”00 7F C0 00 00 FF 80 00 01 FF 00 00 FF FF FF FF”,

  $”FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF”
  $”FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF”
  $”FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF”
  $”FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF”
  $”FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF”
  $”FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF”
  $”FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF”
  $”FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF”
 }
};

/*
 * Think C Object Resources
 * Copyright © 1989
 */

type ‘Estr’ { pstring; };

resource ‘WIND’ (200, “Clipboard”, purgeable, preload) {
 {130, 158, 238, 444},
 zoomDocProc, invisible, goAway, 0,
 “Clipboard”
};

resource ‘ALRT’ (128, “General”, purgeable) {
 {32, 10, 164, 328},
 128,
 {
  OK, visible, silent,
  OK, visible, silent,
  OK, visible, silent,
  OK, visible, silent
 }
};

resource ‘ALRT’ (150, “Confirm Revert”, purgeable) {
 {100, 120, 190, 420},
 150,
 {
  OK, visible, silent,
  OK, visible, silent,
  OK, visible, silent,
  OK, visible, silent
 }
};

resource ‘ALRT’ (151, “Save Changes”, purgeable) {
 {42, 34, 184, 350},
 151,
 {
  OK, visible, silent,
  OK, visible, silent,
  OK, visible, silent,
  OK, visible, silent
 }
};

resource ‘ALRT’ (200, “Severe Error”, purgeable) {
 {32, 10, 168, 352},
 200,
 {
  OK, visible, sound1,
  OK, visible, sound1,
  OK, visible, sound1,
  OK, visible, sound1
 }
};

resource ‘ALRT’ (250, “No Printer”, purgeable) {
 {40, 40, 156, 382},
 250,
 {
  OK, visible, sound1,
  OK, visible, sound1,
  OK, visible, sound1,
  OK, visible, sound1
 }
};

resource ‘ALRT’ (300, “OS Error”, purgeable) {
 {32, 10, 168, 352},
 300,
 {
  OK, visible, sound1,
  OK, visible, sound1,
  OK, visible, sound1,
  OK, visible, sound1
 }
};

resource ‘DITL’ (128, “General”, purgeable) {
 {
  {98, 231, 118, 291},
  Button { enabled, “OK” },
  {14, 25, 82, 299},
  StaticText { disabled, “^0” }
 }
};

resource ‘DITL’ (150, “Confirm Revert”, purgeable) {
 {
  {60, 208, 80, 290},
  Button { enabled, “OK” },
  {60, 105, 80, 187},
  Button { enabled, “Cancel” },
  {5, 113, 45, 293},
  StaticText { disabled,
               “Revert to the last version saved ?” },
  {47, 10, 64, 66},
  StaticText { disabled, “Caution” }
 }
};

resource ‘DITL’ (151, “Save Changes”, purgeable) {
 {
  {74, 35, 94, 117},
  Button { enabled, “Yes” },
  {111, 35, 131, 117},
  Button { enabled, “No” },
  {111, 205, 131, 287},
  Button { enabled, “Cancel” },
  {14, 25, 55, 291},
  StaticText { disabled,
               “Save changes to “^0” before ^1?” }
 }
};

resource ‘DITL’ (200, “Severe Error”, purgeable) {
 {
  {104, 264, 124, 324},
  Button { enabled, “Proceed” },
  {104, 168, 124, 228},
  Button { enabled, “Quit” },
  {16, 80, 87, 332},
  StaticText { disabled, “^0\n\nResult Code = ^1” }
 }
};

resource ‘DITL’ (250, “No Printer”, purgeable) {
 {
  {85, 262, 105, 327},
  Button { enabled, “OK” },
  {14, 84, 67, 327},
  StaticText { disabled,
       “Printing operations are not possible “
       “until you have selected a Printer using the”
       “ Chooser. “ }
 }
};

resource ‘DITL’ (300, “OS Error”, purgeable) {
 {
  {104, 264, 124, 324},
  Button { enabled, “OK” },
  {16, 80, 87, 332},
  StaticText { disabled, “^0\n\nResult Code = ^1” }
 }
};

resource ‘CNTL’ (300, “Scroll Bar”, preload) {
 {0, 0, 0, 0},
 0, invisible, 0, 0, scrollBarProc, 0,
 “”
};

resource ‘STR#’ (128, “Common”) {
 {
  “quitting”,
  “closing”,
  “Undo “,
  “Redo “,
  “Untitled”,
  “Show Clipboard”,
  “Hide Clipboard”
 }
};

resource ‘STR#’ (129, “Memory Warnings”) {
 {
  “Memory is running low. Please close “
  “windows and save documents to avoid losing “
  “data.”
 }
};

resource ‘STR#’ (130, “Task Names”) {
 {
 }
};

resource ‘STR ‘ (150, “SaveAs Prompt”, purgeable) {
 “Save File As:”
};

resource ‘STR ‘ (300, “OS Error”, purgeable) {
 “Mac OS Error Encountered”
};

resource ‘Estr’ (-192, “resNotFound”, purgeable) {
 “Tried to get a nonexistent resource”
};

resource ‘SICN’ (200, “Grow Box”, preload) {
 {
  $”FF FF 80 01 80 01 9F C1 90 41 90 7D 90 45 90 45"
  $”90 45 9F C5 84 05 84 05 84 05 87 FD 80 01 FF FF”
 }
};


 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Dropbox 193.4.5594 - Cloud backup and sy...
Dropbox is a file hosting service that provides cloud storage, file synchronization, personal cloud, and client software. It is a modern workspace that allows you to get to all of your files, manage... Read more
Google Chrome 122.0.6261.57 - Modern and...
Google Chrome is a Web browser by Google, created to be a modern platform for Web pages and applications. It utilizes very fast loading of Web pages and has a V8 engine, which is a custom built... Read more
Skype 8.113.0.210 - Voice-over-internet...
Skype is a telecommunications app that provides HD video calls, instant messaging, calling to any phone number or landline, and Skype for Business for productive cooperation on the projects. This... Read more
Tor Browser 13.0.10 - Anonymize Web brow...
Using Tor Browser you can protect yourself against tracking, surveillance, and censorship. Tor was originally designed, implemented, and deployed as a third-generation onion-routing project of the U.... Read more
Deeper 3.0.4 - Enable hidden features in...
Deeper is a personalization utility for macOS which allows you to enable and disable the hidden functions of the Finder, Dock, QuickTime, Safari, iTunes, login window, Spotlight, and many of Apple's... Read more
OnyX 4.5.5 - Maintenance and optimizatio...
OnyX is a multifunction utility that you can use to verify the startup disk and the structure of its system files, to run miscellaneous maintenance and cleaning tasks, to configure parameters in the... Read more

Latest Forum Discussions

See All

Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »
Live, Playdate, Live! – The TouchArcade...
In this week’s episode of The TouchArcade Show we kick things off by talking about all the games I splurged on during the recent Playdate Catalog one-year anniversary sale, including the new Lucas Pope jam Mars After Midnight. We haven’t played any... | Read more »
TouchArcade Game of the Week: ‘Vroomies’
So here’s a thing: Vroomies from developer Alex Taber aka Unordered Games is the Game of the Week! Except… Vroomies came out an entire month ago. It wasn’t on my radar until this week, which is why I included it in our weekly new games round-up, but... | Read more »
SwitchArcade Round-Up: ‘MLB The Show 24’...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for March 15th, 2024. We’re closing out the week with a bunch of new games, with Sony’s baseball franchise MLB The Show up to bat yet again. There are several other interesting games to... | Read more »
Steam Deck Weekly: WWE 2K24 and Summerho...
Welcome to this week’s edition of the Steam Deck Weekly. The busy season has begun with games we’ve been looking forward to playing including Dragon’s Dogma 2, Horizon Forbidden West Complete Edition, and also console exclusives like Rise of the... | Read more »
Steam Spring Sale 2024 – The 10 Best Ste...
The Steam Spring Sale 2024 began last night, and while it isn’t as big of a deal as say the Steam Winter Sale, you may as well take advantage of it to save money on some games you were planning to buy. I obviously recommend checking out your own... | Read more »
New ‘SaGa Emerald Beyond’ Gameplay Showc...
Last month, Square Enix posted a Let’s Play video featuring SaGa Localization Director Neil Broadley who showcased the worlds, companions, and more from the upcoming and highly-anticipated RPG SaGa Emerald Beyond. | Read more »
Choose Your Side in the Latest ‘Marvel S...
Last month, Marvel Snap (Free) held its very first “imbalance" event in honor of Valentine’s Day. For a limited time, certain well-known couples were given special boosts when conditions were right. It must have gone over well, because we’ve got a... | Read more »
Warframe welcomes the arrival of a new s...
As a Warframe player one of the best things about it launching on iOS, despite it being arguably the best way to play the game if you have a controller, is that I can now be paid to talk about it. To whit, we are gearing up to receive the first... | Read more »
Apple Arcade Weekly Round-Up: Updates an...
Following the new releases earlier in the month and April 2024’s games being revealed by Apple, this week has seen some notable game updates and events go live for Apple Arcade. What The Golf? has an April Fool’s Day celebration event going live “... | Read more »

Price Scanner via MacPrices.net

Apple Education is offering $100 discounts on...
If you’re a student, teacher, or staff member at any educational institution, you can use your .edu email address when ordering at Apple Education to take $100 off the price of a new M3 MacBook Air.... Read more
Apple Watch Ultra 2 with Blood Oxygen feature...
Best Buy is offering Apple Watch Ultra 2 models for $50 off MSRP on their online store this week. Sale prices available for online orders only, in-store prices may vary. Order online, and choose... Read more
New promo at Sams Club: Apple HomePods for $2...
Sams Club has Apple HomePods on sale for $259 through March 31, 2024. Their price is $40 off Apple’s MSRP, and both Space Gray and White colors are available. Sale price is for online orders only, in... Read more
Get Apple’s 2nd generation Apple Pencil for $...
Apple’s Pencil (2nd generation) works with the 12″ iPad Pro (3rd, 4th, 5th, and 6th generation), 11″ iPad Pro (1st, 2nd, 3rd, and 4th generation), iPad Air (4th and 5th generation), and iPad mini (... Read more
10th generation Apple iPads on sale for $100...
Best Buy has Apple’s 10th-generation WiFi iPads back on sale for $100 off MSRP on their online store, starting at only $349. With the discount, Best Buy’s prices are the lowest currently available... Read more
iPad Airs on sale again starting at $449 on B...
Best Buy has 10.9″ M1 WiFi iPad Airs on record-low sale prices again for $150 off Apple’s MSRP, starting at $449. Sale prices for online orders only, in-store price may vary. Order online, and choose... Read more
Best Buy is blowing out clearance 13-inch M1...
Best Buy is blowing out clearance Apple 13″ M1 MacBook Airs this weekend for only $649.99, or $350 off Apple’s original MSRP. Sale prices for online orders only, in-store prices may vary. Order... Read more
Low price alert! You can now get a 13-inch M1...
Walmart has, for the first time, begun offering new Apple MacBooks for sale on their online store, albeit clearance previous-generation models. They now have the 13″ M1 MacBook Air (8GB RAM, 256GB... Read more
Best Apple MacBook deal this weekend: Get the...
Apple has 13″ M2 MacBook Airs available for only $849 today in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Apple’s one-year warranty is included,... Read more
New 15-inch M3 MacBook Air (Midnight) on sale...
Amazon has the new 15″ M3 MacBook Air (8GB RAM/256GB SSD/Midnight) in stock and on sale today for $1249.99 including free shipping. Their price is $50 off MSRP, and it’s the lowest price currently... Read more

Jobs Board

Early Preschool Teacher - Glenda Drive/ *Appl...
Early Preschool Teacher - Glenda Drive/ Apple ValleyTeacher Share by Email Share on LinkedIn Share on Twitter Read more
Senior Software Engineer - *Apple* Fundamen...
…center of Microsoft's efforts to empower our users to do more. The Apple Fundamentals team focused on defining and improving the end-to-end developer experience in Read more
Relationship Banker *Apple* Valley Main - W...
…Alcohol Policy to learn more. **Company:** WELLS FARGO BANK **Req Number:** R-350696 **Updated:** Mon Mar 11 00:00:00 UTC 2024 **Location:** APPLE VALLEY,California Read more
Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill WellSpan Medical Group, York, PA | Nursing | Nursing Support | FTE: 1 | Regular | Tracking Code: 200555 Apply Now Read more
Early Preschool Teacher - Glenda Drive/ *Appl...
Early Preschool Teacher - Glenda Drive/ Apple ValleyTeacher Share by Email Share on LinkedIn Share on Twitter Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.