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”
 }
};


 
AAPL
$96.87
Apple Inc.
-0.32
MSFT
$44.46
Microsoft Corpora
-0.42
GOOG
$593.16
Google Inc.
-2.82

MacTech Search:
Community Search:

Software Updates via MacUpdate

Airfoil 4.8.7 - Send audio from any app...
Airfoil allows you to send any audio to AirPort Express units, Apple TVs, and even other Macs and PCs, all in sync! It's your audio - everywhere. With Airfoil you can take audio from any... Read more
Microsoft Remote Desktop 8.0.8 - Connect...
With Microsoft Remote Desktop, you can connect to a remote PC and your work resources from almost anywhere. Experience the power of Windows with RemoteFX in a Remote Desktop client designed to help... Read more
xACT 2.30 - Audio compression toolkit. (...
xACT stands for X Aaudio Compression Toolkit, an application that encodes and decodes FLAC, SHN, Monkey’s Audio, TTA, Wavpack, and Apple Lossless files. It also can encode these formats to MP3, AAC... Read more
Firefox 31.0 - Fast, safe Web browser. (...
Firefox for Mac offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals... Read more
Little Snitch 3.3.3 - Alerts you to outg...
Little Snitch gives you control over your private outgoing data. Track background activityAs soon as your computer connects to the Internet, applications often have permission to send any... Read more
Thunderbird 31.0 - Email client from Moz...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more
Together 3.2 - Store and organize all of...
Together helps you organize your Mac, giving you the ability to store, edit and preview your files in a single clean, uncluttered interface. Smart storage. With simple drag-and-drop functionality,... Read more
Cyberduck 4.5 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
iExplorer 3.4 - View and transfer all th...
iExplorer is an iPhone browser for Mac lets you view the files on your iOS device. By using a drag and drop interface, you can quickly copy files and folders between your Mac and your iPhone or... Read more
Airmail 1.4 - Powerful, minimal email cl...
Airmail is a powerful, minimal mail client.It was designed to retain the same experience with a single or multiple accounts and provide a quick, modern and easy-to-use user experience. Airmail... Read more

Latest Forum Discussions

See All

More Paintings Have Been Added to Paint...
More Paintings Have Been Added to Paint it Back! Posted by Jessica Fisher on July 24th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
The Order of Souls Review
The Order of Souls Review By Campbell Bird on July 24th, 2014 Our Rating: :: STORY GRINDUniversal App - Designed for iPhone and iPad The Order of Souls is a free-to-play, turn-based RPG with a genre-mixing art style, interesting... | Read more »
Revolution 60 Review
Revolution 60 Review By Jordan Minor on July 24th, 2014 Our Rating: :: LASS EFFECTUniversal App - Designed for iPhone and iPad Revolution 60 is a bold, cinematic action game with ambition to spare.   | Read more »
Matter (Photography)
Matter 1.0.1 Device: iOS Universal Category: Photography Price: $1.99, Version: 1.0.1 (iTunes) Description: Add stunning 3D effects to your photos with real-time shadows and reflections. Export your creations as photos or video loops... | Read more »
Fanatic Earth Review
Fanatic Earth Review By Brittany Vincent on July 24th, 2014 Our Rating: :: BY-THE-NUMBERSUniversal App - Designed for iPhone and iPad Kemco’s stable of mobile RPGs grows, but in Fanatic Earth’s situation it’s a case of quantity... | Read more »
Together for iOS (Productivity)
Together for iOS 1.0 Device: iOS Universal Category: Productivity Price: $9.99, Version: 1.0 (iTunes) Description: Together is an app for keeping things in one place. Notes, documents, images, movies, sounds, web pages and bookmarks... | Read more »
The Phantom PI Mission Apparition (Game...
The Phantom PI Mission Apparition 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: ** Release sale! 50% off for a limited time! ** The Phantom PI Mission Apparition is a spooky, puzzly, rock’... | Read more »
The Great Prank War (Games)
The Great Prank War 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: Help Mordecai, Rigby, Muscle Man and Skips take the park back from Gene and his goons with a plethora of prank-related... | Read more »
Teenage Mutant Ninja Turtles (Games)
Teenage Mutant Ninja Turtles 1.0.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0.0 (iTunes) Description: Download the all new Teenage Mutant Ninja Turtles Official Movie Game! | Read more »
Dream Revenant (Games)
Dream Revenant 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: EXCLUSIVE LAUNCH PRICE ! Dream Revenant is at $1.99 for a limited time ! | Read more »

Price Scanner via MacPrices.net

What Should Apple’s Next MacBook Priority Be;...
Stabley Times’ Phil Moore says that after expanding its iMac lineup with a new low end model, Apple’s next Mac hardware decision will be how it wants to approach expanding its MacBook lineup as well... Read more
ArtRage For iPhone Painting App Free During C...
ArtRage for iPhone is currently being offered for free (regularly $1.99) during Comic-Con San Diego #SDCC, July 24-27, in celebration of the upcoming ArtRage 4.5 and other 64-bit versions of the... Read more
With The Apple/IBM Alliance, Is The iPad Now...
Almost since the iPad was rolled out in 2010, and especially after Apple made a 128 GB storage configuration available in 2012, there’s been debate over whether the iPad is a serious tool for... Read more
MacBook Airs on sale starting at $799, free s...
B&H Photo has the new 2014 MacBook Airs on sale for up to $100 off MSRP for a limited time. Shipping is free, and B&H charges NY sales tax only. They also include free copies of Parallels... Read more
Apple 27″ Thunderbolt Display (refurbished) a...
The Apple Store has Apple Certified Refurbished 27″ Thunderbolt Displays available for $799 including free shipping. That’s $200 off the cost of new models. Read more
WaterField Designs Unveils Cycling Ride Pouch...
High end computer case and bag maker WaterField Designs of San Francisco now enters the cycling market with the introduction of the Cycling Ride Pouch – an upscale toolkit with a scratch-free iPhone... Read more
Kingston Digital Ships Large Capacity Near 1T...
Kingston Digital, Inc., the Flash memory affiliate of Kingston Technology Company, Inc.,has announced its latest addition to the SSDNow V300 series, the V310. The Kingston SSDNow V310 solid-state... Read more
Apple’s Fiscal Third Quarter Results; Record...
Apple has announced financial results for its fiscal 2014 third quarter ended June 28, 2014, racking up quarterly revenue of $37.4 billion and quarterly net profit of $7.7 billion, or $1.28 per... Read more
15-inch 2.0GHz MacBook Pro Retina on sale for...
B&H Photo has the 15″ 2.0GHz Retina MacBook Pro on sale for $1829 including free shipping plus NY sales tax only. Their price is $170 off MSRP. B&H will also include free copies of Parallels... Read more
Apple restocks refurbished Mac minis for up t...
The Apple Store has restocked Apple Certified Refurbished Mac minis for up to $150 off the cost of new models. Apple’s one-year warranty is included with each mini, and shipping is free: - 2.5GHz Mac... Read more

Jobs Board

Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
Senior Interaction Designer, *Apple* Online...
**Job Summary** Apple is looking for a hands on Senior…will be a key player in designing for the Apple Online Store. The ideal designer will have a Read more
*Apple* Sales Chat Rep - Apple (United State...
…is looking for motivated, outgoing, and tech savvy individuals who want to offer Apple Customers an unparalleled customer experience over chat. At Apple , we believe Read more
Mac Expert - *Apple* Online Store Mexico -...
…MUST be fluent in English and Spanish to be considered for this position At Apple , we believe that hard work, a fun environment, creativity and innovation fuel the Read more
*Apple* Industrial Design CAD Sculptor - App...
**Job Summary** The Apple Industrial Design team is looking for a CAD sculptor/Digital 3D modeler to create high quality CAD models used in the industrial design process Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.