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

Latest Forum Discussions

See All

Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »
Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »
MoreFun Studios has announced Season 4,...
Tension has escalated in the ever-volatile world of Arena Breakout, as your old pal Randall Fisher and bosses Fred and Perrero continue to lob insults and explosives at each other, bringing us to a new phase of warfare. Season 4, Into The Fog of... | Read more »
Top Mobile Game Discounts
Every day, we pick out a curated list of the best mobile discounts on the App Store and post them here. This list won't be comprehensive, but it every game on it is recommended. Feel free to check out the coverage we did on them in the links below... | Read more »

Price Scanner via MacPrices.net

Free iPhone 15 plus Unlimited service for $60...
Boost Infinite, part of MVNO Boost Mobile using AT&T and T-Mobile’s networks, is offering a free 128GB iPhone 15 for $60 per month including their Unlimited service plan (30GB of premium data).... Read more
$300 off any new iPhone with service at Red P...
Red Pocket Mobile has new Apple iPhones on sale for $300 off MSRP when you switch and open up a new line of service. Red Pocket Mobile is a nationwide MVNO using all the major wireless carrier... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, available for $759 for 8-Core CPU/7-Core GPU/256GB models and $929 for 8-Core CPU/8-Core GPU/512GB models. Apple’s one-year warranty is... Read more
Updated Apple MacBook Price Trackers
Our Apple award-winning MacBook Price Trackers are continually updated with the latest information on prices, bundles, and availability for 16″ and 14″ MacBook Pros along with 13″ and 15″ MacBook... Read more
Every model of Apple’s 13-inch M3 MacBook Air...
Best Buy has Apple 13″ MacBook Airs with M3 CPUs in stock and on sale today for $100 off MSRP. Prices start at $999. Their prices are the lowest currently available for new 13″ M3 MacBook Airs among... Read more
Sunday Sale: Apple iPad Magic Keyboards for 1...
Walmart has Apple Magic Keyboards for 12.9″ iPad Pros, in Black, on sale for $150 off MSRP on their online store. Sale price for online orders only, in-store price may vary. Order online and choose... Read more
Apple Watch Ultra 2 now available at Apple fo...
Apple has, for the first time, begun offering Certified Refurbished Apple Watch Ultra 2 models in their online store for $679, or $120 off MSRP. Each Watch includes Apple’s standard one-year warranty... Read more
AT&T has the iPhone 14 on sale for only $...
AT&T has the 128GB Apple iPhone 14 available for only $5.99 per month for new and existing customers when you activate unlimited service and use AT&T’s 36 month installment plan. The fine... Read more
Amazon is offering a $100 discount on every M...
Amazon is offering a $100 instant discount on each configuration of Apple’s new 13″ M3 MacBook Air, in Midnight, this weekend. These are the lowest prices currently available for new 13″ M3 MacBook... Read more
You can save $300-$480 on a 14-inch M3 Pro/Ma...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more

Jobs Board

*Apple* Systems Administrator - JAMF - Activ...
…**Public Trust/Other Required:** None **Job Family:** Systems Administration **Skills:** Apple Platforms,Computer Servers,Jamf Pro **Experience:** 3 + years of Read more
IT Systems Engineer ( *Apple* Platforms) - S...
IT Systems Engineer ( Apple Platforms) at SpaceX Hawthorne, CA SpaceX was founded under the belief that a future where humanity is out exploring the stars is Read more
Nurse Anesthetist - *Apple* Hill Surgery Ce...
Nurse Anesthetist - Apple Hill Surgery Center Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Now Read more
Housekeeper, *Apple* Valley Village - Cassi...
Apple Valley Village Health Care Center, a senior care campus, is hiring a Part-Time Housekeeper to join our team! We will train you for this position! In this role, Read more
Sublease Associate Optometrist- *Apple* Val...
Sublease Associate Optometrist- Apple Valley, CA- Target Optical Date: Apr 20, 2024 Brand: Target Optical Location: Apple Valley, CA, US, 92307 **Requisition Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.