TweetFollow Us on Twitter

ADB Demo
Volume Number:5
Issue Number:3
Column Tag:Basic School

Related Info: ADB Manager

ADB Demo in ZBasic 5.0 & LS Pascal 2.0

By Dave Kelly, David E. Smith, MacTutor Editorial Board

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

Exploring the ADB

The Apple Desktop Bus (ADB) is a simple local-area network that connects low-speed input-only devices (for example: keyboard or mouse) to the operating system and Macintosh hardware. ADB is supported only on the Macintosh SE and Macintosh II (and future Macintosh computers). It should first be understood that the standard mouse and keyboard drivers automatically handle the ADB functions.

Communication with the ADB is accomplished with six routines located in the 256K ROM. These routines are used only if you need to access bus devices directly or communicate with a special device. This being the case, you will probably never use them. The typical access to ADB devices is through the Toolbox Event Manager routines (ex: GetNextEvent or WaitNextEvent). In BASIC, the DIALOG statement handles this process. We have discussed the DIALOG statement in detail in previous volumes of MacTutor (see Jan, 1987;Aug, 1987; Sep, 1987).

Macintosh Technical Note #206 is inspiration for this column. #206 explains how ADB works on the SE and II. The question was asked, “How can I turn on/off the LEDs on the Apple Extended Keyboard?”. The answer: “Using the LEDs on the extended keyboard involves the ADBOp call (Inside Macintosh Volume 5 ). Once you determine that you have the extended keyboard, (with CountADBs, GetIndADB), then register 2 of the extended keyboard has the LED toggles in the low 3 bits. Therefore, you would do a talk to register 2 to have the device send you the contents of register 2, manipulate the low three bits to set the LEDs, and then pass the now modified register 2 back to the device with a listen to register 2 command.”

The first task is determining that the extended keyboard is being used. The SysEnvirons Function is another good way to determine if the extended keyboard exists although CountADBs and GetIndADB will have to be used to get the actual keyboard address. The extended keyboard will have an ID of 2 and a device handler of 2. The standard apple keyboard will have an ID of 2 and a device handler ID of 1. Several examples of SysEnvirons have been given in previous articles. The use of the SysEnvirons function in ZBasic is shown in the Basic example in this column.

LS Pascal 2.0 Version

In addition to the ZBasic example, the same program was coded in LS Pascal 2.0 and extensively modified by David Smith, Editor and Publisher of MacTutor. This Pascal example shows how the same information displayed in the ZBasic program can be displayed using Text Edit in a fully operational text edit window. Multifinder is supported with suspend/resume events, text selection, cutting and pasting is supported, the scrap is updated properly for Multifinder, and the use of two new resources, vers and mstr are used. The vers resources allow the version to be displayed in two places in the GetInfo box. The mstr resources allows MultiFinder to find the Quit command so the program can exit gracefully after a shutdown command. Both programs parse and display the SysEnvirons information about the Mac and then blink the keyboard lights if an extended keyboard is present.

Fig. 1 Our ADB Demo in ZBasic: SysEnvirons Dump

Fig. 2 Same program in LS Pascal: MultiFinder Friendly Text Edit Window!

ZBASIC 5.0 Version

To use SysEnvirons in ZBASIC 5.0 you will first need to modify the function using the Toolbox editor program. The SysEnvirons function is register based and so the function is modified to reflect this. When I tried the SysEnvirons function included in ZBASIC 5.0, the function did not return the correct results. Change the function to: D0.W=FN SYSENVIRONS (D0.L, A0.L). This sets the result to register D0 with inputs passed to the function in the D0 and A0 registers as shown in Inside Macintosh Vol. V, pg. 6. An explanation of the SysEnvirons record is given on pg. 6-8. The source code disk for this month includes the ADB ZBasic 5.0 library which the Toolbox editor program can move into ZBasic to create a new version of ZBasic with the correct calling sequence for Sysenvirons. The ability to extend the language to new traps or correct old ones is a very clever ability in ZBasic 5.0. It means you don’t have to get a new version of the program when the toolbox calling routines or traps change.

Accessing an ADB Device

There are 16 possible device locations available on the ADB. Each device can maintain up to four variable-size registers which may be read or written from the device over the ADB network. All devices use register 0 and register 3. Register 0 is used to store input data for device interrupts. Register 3 is used for device identification and operating flags. The chapter on the ADB Manager in Inside Macintosh Vol. V explains these two registers in more detail for writing device drivers. The other two registers may or may not be used depending upon which device is being used. The Extended Keyboard uses register 2 as indicated by the comments in TN#206.

Devices which connect to the ADB contain their own micro-processors, which handle both device routines and the ADB interface. Sending commands to the device is accomplished with the ADBOp function. There are four possible commands which may be sent to the device. The ADB Command Formats are shown on pg. 363 of Inside Macintosh. A description of the commands is given on page 364. We use the Talk command to tell the device that we want to see register 2 by sending a command of $2E (binary ‘0010 1110’). The buffer pointed to by the ADBOpBlock parameter block will contain the contents of register 2 after the ADBOp function is called. As seen in the LightsBug window the contents of the buffer after the Talk command is sent is 02FFFF. Since the technical note states that the LEDs are toggled on/off in the lower three bits, changing the contents of the buffer to 02FFF8 and sending the Listen command should turn on all three lights. The first byte of the buffer ($02) is the number of bytes in the buffer. (See figures 3 & 4)

Fig. 3 Register 2 = 02FFFF after talk command

Fig. 4 Register 2 = 02FFF8 before listen command

The Listen command is used to write the register back to the device. When the Listen command is sent after modifying the lower 3 bytes of register 2 (as stored in the buffer area), the LEDs do in fact turn on. The reverse process may be used to turn off the LEDs or sending the Flush command also clears the LED status.

The ADBOpBlock record (referred to by the ADBOp function) contains a pointer to the buffer where the registers are stored (as discussed above) and a pointer to a completion routine and data pointer. The completion routine is called by ADBOp upon completion of the function. There are three ways that a completion routine may be used. 1) You may pass a nil pointer to ADBOp when you do not wish to have a completion routine. 2) You may use the service routine address which is fetched by the GetIndADB function or GetADBInfo function. Before calling ADBOp, set the completion pointer to the service address. 3) Use your own completion routine. The data pointer is an area which the completion routine may use (optionally) to store its own data.

There is rarely a reason to call ADBOp except to tell the device something or turn on LEDs as in this example. In most cases, the ADB device communication will be handled by the system’s internal polling/service request mechanism.

The two program examples included here, one in ZBasic 5.0, the other in LS Pascal 2.0, illustrate this process. The flow of the program is much easier to follow in Pascal because of the organization of the record structures. The result is the same. In order to get ZBasic to recognize the ADB Manager routines, they must be added using the Toolbox Editor. The definitions of the functions and procedures which must be added are shown below (these are included in a library file on this month’s source code disk):

In the Pascal version, a complete Macintosh text edit application is given. A menu function, ADB, in the File menu, causes the doADB procedure to be called from the procedure which handles a mouse down event. When the doADB proc executes, it parses the SysEnvirons call and inserts the same information as the Basic program into the text edit record for the program’s window. That information is then displayed as the result of an update event. This is how you would duplicate the functionality of Basic’s print statements using a text edit record in a Pascal program that entirely uses the Macintosh toolbox for output into a window. Pay particular attention to the resource file at the end of the program. There in RMaker format, is the two new resources for inserting a version in the GetInfo dialog box, and for helping MultiFinder quit your application. Note also that the SIZE resource has the necessary information to tell MultiFinder that our application understands a suspend/resume event. This event, number 15, is treated much like an activate/deactivate event. By allowing for event 15, we save MultiFinder from sending us a lot of activate/deactivate events we don’t need, thereby making the quasi-multi-tasking scheme work better. These two new resources are described in a recent tech note #189.

Fig. 5 ZBasic SysEnvirons and ADB Functions

The other significant feature of the Pascal program is that it correctly allows the window to be re-sized. This requires a proper Update Event procedure and a Grow procedure. The key is that the rectangles for the text edit viewing rectangle, the scroll bars and the grow box all must be defined properly. Controls are active and updated properly, but no value was assigned the control, so it doesn’t indicate scrolling even if the window is made small enough to cover some of the text. A scrolling unit is needed to match the control to the number of lines of text and the insertion point. For an example of how to do this, see the Text Edit example by David Smith from last year’s MacTutor volume 3. That program had a working multiple window example of text edit with scrollers.

Fig. 6 Our Pascal Demo supports Text Editing

For more information refer to the ADB Manager chapter of Inside Macintosh and technical notes on ADB.

‘ SysEnvirons and ADB Demo
‘ ©1989 MacTutor
‘ by Dave Kelly
‘ ZBasic 5.0
‘
‘******************************************************
‘  First check the System Environments
‘  To do this the SYSENVIRONS function needs to be 
‘modified to work. Replace old SYSENVIRONS with D0.W=FN 
‘SYSENVIRONS(D0.L, A0.L)
‘*******************************************************
WINDOW OFF
COORDINATE WINDOW
‘Find out screen size.
CALL GETWMGRPORT(WMgrPort&)
PortTop=PEEK WORD(WMgrPort&+8)
PortLeft=PEEK WORD(WMgrPort&+10)
PortBottom=PEEK WORD(WMgrPort&+12)
PortRight=PEEK WORD(WMgrPort&+14)

WINDOW 1,”Main Window”,(10,44)-(PortRight-4,PortBottom-4),1
‘Bring window to the front (necessary under Multifinder)
Wptr&=WINDOW(14)
CALL SELECTWINDOW(Wptr&)
‘ Set up SysEnvRec
DIM environsVersion,machineType, systemversion,processor,hasFPU,keyBoardType,atDrvrVersNum,sysVRefNum
OSErr%=FN SYSENVIRONS(1,VARPTR(environsVersion))
LONG IF OSErr%=0
 PRINT “Environment Version:”;environsVersion
 PRINT “Machine Type:”;
SELECT machineType
CASE 0
 PRINT “new version of Macintosh”
CASE 1
 PRINT “Macintosh 512K enhanced”
CASE 2
 PRINT “Macintosh Plus”
CASE 3
 PRINT “Macintosh SE”
CASE 4
 PRINT “Macintosh II”
CASE -1
 PRINT “Macintosh with 64K ROM”
CASE -2
 PRINT “Macintosh XL”
END SELECT
 PRINT “System Version:”;LEFT$(HEX$(systemversion),2);”.”;RIGHT$(HEX$(systemversion),2)
 PRINT “Processor:”;
SELECT processor
CASE 0
 PRINT “new processor”
CASE 1
 PRINT “MC68000 processor”
CASE 2
 PRINT “MC68010 processor”
CASE 3
 PRINT “MC68020 processor”
END SELECT
 b$=”&X”+RIGHT$(BIN$(hasFPU),8)
 hasColorQD=VAL(b$)
 b$=”&X”+LEFT$(BIN$(hasFPU),8)
 hasFPU=VAL(b$)
 PRINT “Has Floating Point Coprocessor:”;
IF hasFPU=1 THEN PRINT “Yes” ELSE PRINT “No”
 PRINT “Has Color QuickDraw:”;
IF hasColorQD=1 THEN PRINT “Yes” ELSE PRINT “No”
 PRINT “Keyboard Type:”;
SELECT keyBoardType
 CASE 0
 PRINT “Macintosh Plus keyboard with keypad”
 CASE 1
 PRINT “Macintosh keyboard”
 CASE 2
 PRINT “Macintosh keyboard and keypad”
 CASE 3
 PRINT “Macintosh Plus keyboard”
 CASE 4
 PRINT “Apple extended keyboard”
 CASE 5
 PRINT “standard Apple Desktop Bus keyboard”
 CASE ELSE
 PRINT “don’t recognize this one!”
END SELECT
 PRINT “AppleTalk Driver version:”;atDrvrVersNum
 PRINT “Working Directory Volume Reference #:”;sysVRefNum
XELSE
 PRINT “Error =”;OSErr%
END IF
‘*******************************************************
‘ Now Read the ADB
‘ This routine turns on and off the
‘ lights of the Extended keyboard
‘ ADB calls and functions need to be added to ZBasic 5.0
‘ using the Toolbox mover program.
‘*******************************************************
‘
IF keyBoardType<>4 THEN END
DIM DeviceType%,ServiceAddress&,DataAddress&:’ GETINDADB Parmeter block
DIM buffer%(2)
bufferptr&=VARPTR(buffer%(0))
compRoutptr&=0
Datablkptr&=0' ADBOP Parameter block
 
numberofADBdevices=FN COUNTADBS
PRINT “There are”;numberofADBdevices;”ADB devices present.”
IF numberofADBdevices=0 THEN STOP
FOR i%=1 TO numberofADBdevices
 ADBAdd%=FN GETINDADB(VARPTR(DeviceType%),i%)
 b$=”&X”+RIGHT$(BIN$(DeviceType%),8)
 OrgADBAddress%=VAL(b$)
 b$=”&X”+LEFT$(BIN$(DeviceType%),8)
 DeviceType%=VAL(b$)
 LONG IF ADBAdd%=2  ‘Got the address for the Extended Keyboard
 Talk%=&H2E:’ Talk command
 Listen%=&H2A:’ Listen command
 Flush%=&H21:’ Flush command
  PRINT “Press any key to continue...”
  DO
  X$=INKEY$
  GOSUB “MagicLights”
  UNTIL X$<>””
 END IF
 NEXT i%
 LONG IF X$=””
  PRINT “Press any key to continue...”
  DO
    X$=INKEY$
  UNTIL X$<>””
 END IF
END

“MagicLights”
 GOSUB “Togglelightson”
 GOSUB “Delay”
  GOSUB “Togglelightsoff”
 GOSUB “Delay”
 GOSUB “Togglelightson”
 GOSUB “Delay”
  GOSUB “Togglelightsoff”
  GOSUB “Delay”
RETURN

“Togglelightson”
compRoutptr&=ServiceAddress&:Datablkptr&=DataAddress&
‘This call reads register 2 of the ext. keyboard.
OSErr%=FN ADBOP(VARPTR(bufferptr&),Talk%)
GOSUB “Delay”
buffer%(1)=&HF800
‘The next call writes register 2 back to
‘the extended keyboard.  For some reason the register is not
‘being written back to the keyboard.  See Pascal version.
OSErr%=FN ADBOP(VARPTR(bufferptr&),Listen%)
RETURN

“Togglelightsoff”
 OSErr%=FN ADBOP(VARPTR(bufferptr&),Flush%)
RETURN

“Delay”
T1&=FN TICKCOUNT
DO
T&=FN TICKCOUNT
UNTIL T&-T1&=20
RETURN

Fig. 7 Our Pascal About Box. Note Memory Function and ID String displayed from resources!

{ ADBDemo }
{ ©1989 MacTutor}
{ By Dave Kelly, modified by David Smith}
{ This program will blink the LEDs of the Extended Keyboard on and off 
twice. This has no real value other than to show how to communication 
with ADB devices. NOTE: It is not clear what Apple has in mind for these 
LEDs, so you are using them at your own risk. Refer to Technical Note 
#206 for more information. Other tidbits include Multifinder friendly, 
about dialog, vers resources, working sizable window. }

program ADBDemo;

 uses
 OSIntf, PrintTraps, MyADBGlobals, MyADBStuff;

 procedure crash;
 begin
 ExitToShell;
 end;

 procedure InitMac;
 begin
 InitGraf(@thePort);
 InitFonts;
 InitWindows;
 InitMenus;
 TEInit;
 InitDialogs(@crash);
 InitCursor;
 FlushEvents(everyEvent, 0);
 Finished := false;
 end;

 procedure initRects;
 var
 MemoryPtr: ^Integer;
 begin
 MemoryPtr := pointer(mBarHeightGlobal); 
 mBarHeight := MemoryPtr^;
 screen := ScreenBits.Bounds; {current screen device}
 SetRect(DragArea, Screen.left + 4, Screen.top + mBarHeight + 4, Screen.right 
- 4, Screen.bottom - 4);
 SetRect(GrowArea, Screen.left + MinWidth, Screen.top + MinHeight, Screen.right 
- 8, Screen.bottom - 8);
 SetRect(ADBWindowRect, Screen.left + 15, Screen.top + 45, Screen.right 
- 95, Screen.bottom - 95);
 SetRect(ZoomRect, Screen.left + 4, Screen.top + mBarHeight + 4, Screen.right 
- 4, Screen.bottom - 4);
 end;

 procedure InitMyWindow;
 var
 windtype: integer;
 Visible: boolean;
 GoAway: boolean;
 RefVal: LongInt;
 title: str255;
 begin
 Visible := true;
 windtype := documentProc + ZoomBox;
 GoAway := true;
 RefVal := 0;
 title := ‘ADB Demo’;
 ADBWindow := NewWindow(nil, ADBWindowRect, title, Visible, windtype, 
pointer(-1), GoAway, RefVal);
 ADBWindowPeek := WindowPeek(ADBWindow);
 SetPort(ADBWindow);
 TextFont(Geneva);
 TextSize(10);
 TextFace([]); {plain}
 TextMode(1);  {Or}
 PenNormal;
 ForeColor(blackColor);
 BackColor(whiteColor);
 ADBWindowPeek^.windowKind := userKind;
 with ADBWindow^.portRect do
 begin
 SetRect(VCRect, right - (SBarWidth - 1), top - 1, right + 1, bottom 
- (SBarWidth - 2));
 SetRect(HCRect, left - 1, bottom - (SBarWidth - 1), right - (SBarWidth 
- 2), bottom + 1);
 SetRect(GrowRect, HCRect.right, HCRect.top, VCRect.right, HCRect.bottom);
 SetRect(ViewRect, left + 4, top + 4, right - (SBarWidth - 1), bottom 
- (SBarWidth - 1));
 end;  {of with }
 DestRect := ViewRect;
 myTextHandle := TENew(DestRect, ViewRect);
 title := ‘’;
 VControl := NewControl(ADBWindow, VCRect, title, Visible, 0, 0, 0, ScrollBarProc, 
1);
 ValidRect(VCRect);
 HControl := NewControl(ADBWindow, HCRect, title, Visible, 0, 0, 0, ScrollBarProc, 
1);
 ValidRect(HCRect);
 end;

 procedure InitMyPrint;
 begin
 myPrint := THPrint(NewHandle(SIZEOF(TPrint)));
 end;

 procedure InitMyMenus;
 var
 i: integer;
 begin
 myMenus[AppleM] := GetMenu(AppleMenu);
 AddResMenu(myMenus[AppleM], ‘DRVR’);
 myMenus[FileM] := GetMenu(FileMenu);
 myMenus[EditM] := GetMenu(EditMenu);
 for i := 1 to MenuCount do
 InsertMenu(myMenus[i], 0);

 DisableItem(myMenus[FileM], fSave);
 DisableItem(myMenus[FileM], fSaveAs);
 DisableItem(myMenus[FileM], fPageSet);
 DisableItem(myMenus[FileM], fPrint);
 DisableItem(myMenus[EditM], eUndo);
 DrawMenuBar;
 end; {of proc}

 procedure doMouse (myEvent: EventRecord);
 var
 whereIsIt: integer;
 whichWindow: WindowPtr;
 localPt, globalPt: Point;
 oldPort: GrafPtr;
 begin
 globalPt := myEvent.where;
 localPt := globalPt;{global coord of mouse}
 GlobalToLocal(localPt);  {local coord of mouse}
 whereIsIt := FindWindow(globalPt, whichWindow);
 case whereIsIt of
 inDesk:  {0}
 doMessage(‘Mouse Click on Desktop.’, ‘(Not handled in this program.)’, 
‘’, ‘’);
 inMenuBar:  {1}
 doMenuBar(MenuSelect(globalPt));
 inSysWindow:  {2}
 SystemClick(myEvent, whichWindow);
 inContent:      {3}
 doContent(myEvent, whichWindow);
 inDrag:  {4}
 doDrag(whichWindow, globalPt);
 inGrow:  {5}
 doGrow(whichWindow, globalPt, False);
 inGoAway:  {6}
 if TrackGoAway(whichWindow, globalPt) then
 HideWindow(whichWindow);
 inZoomIn, InZoomOut:{7, 8}
 begin
 if TrackBox(whichWindow, globalPt, whereIsIt) then
 begin
 GetPort(OldPort);
 SetPort(whichWindow); {safety device}
 EraseRect(whichWindow^.portRect);
 ZoomWindow(whichWindow, whereIsIt, True);
 doGrow(whichWindow, globalPt, True);
 SetPort(OldPort);
 end;
 end;
 otherwise
 begin
 end;
 end; {of whereIsIt}
 end;

 procedure doKeyDowns (myEvent: EventRecord);
 var
 ch: char;
 charCode: longInt;
 keyCode: longInt;
 begin
 charCode := BitAnd(myEvent.Message, charCodeMask);  {strip off key code}
 keyCode := BitShift(BitAnd(myEvent.Message, keyCodeMask), -8); {strip 
off char}
 ch := Chr(charCode);  {get keyboard char}
 if BitAnd(myEvent.Modifiers, CmdKey) = CmdKey then
 doMenuBar(MenuKey(ch))  { do menu command key}
 else
 begin  { do keystroke }
 ParamText(‘No typing supported ’, ‘’, ‘’, ‘’);
 itemhit := CautionAlert(AlertDialog, nil);
 end;  { of do key stroke }
 end;  { of proc}

 procedure doUpdates (myEvent: EventRecord);
 var
 UpdateWindow: WindowPtr;
 TempPort: GrafPtr;
 myRect: rect;
 begin
 UpdateWindow := WindowPtr(myEvent.message);
 if UpdateWindow = ADBWindow then
 begin
 GetPort(TempPort); {save port}
 SetPort(UpdateWindow);
 BeginUpDate(UpdateWindow);
 EraseRect(UpdateWindow^.portRect);
 DrawGrowIcon(UpdateWindow);
 DrawControls(UpdateWindow);
 TEUpdate(UpdateWindow^.portRect, myTextHandle);
 EndUpDate(UpdateWindow);
 SetPort(TempPort);{restore port}
 end;
 end; {of proc}

 procedure doActivates (myEvent: EventRecord);
 var
 TargetWindow: WindowPtr;
 TargetPeek: WindowPeek;
 begin
 TargetWindow := WindowPtr(myEvent.message);
 TargetPeek := windowPeek(TargetWindow);
 SetPort(TargetWindow);
 if Odd(myEvent.modifiers) then
 begin {activate}
 if TargetWindow = ADBWindow then
 begin
 DisableItem(myMenus[EditM], eUndo);
 DrawGrowIcon(TargetWindow);
 TEActivate(myTextHandle);
 ShowControl(VControl);
 ShowControl(HControl);
 end
 end  { of activate loop}
 else
 begin {deactivate}
 if TargetWindow = ADBWindow then
 begin
 EnableItem(myMenus[EditM], eUndo);
 EnableItem(myMenus[EditM], eCut);
 EnableItem(myMenus[EditM], eCopy);
 EnableItem(myMenus[EditM], ePaste);
 EnableItem(myMenus[EditM], eClear);
 DrawGrowIcon(TargetWindow);
 TEDeactivate(myTextHandle);
 HideControl(VControl);
 HideControl(HControl);
 end; { of my window activation}
 end; {of deactivate loop}
 end; {of proc}

 procedure doMulti (myEvent: EventRecord);
 const
 MouseMovedEvt = $FA;
 var
 HiByte: byte;
 bit0: LongInt;
 sysresult: boolean;
 ResumeWindow: WindowPtr;
 ResumePeek: WindowPeek;
 SuspendWindow: WindowPtr;
 SuspendPeek: WindowPeek;
 MouseMove: LongAndByte;
 begin
 bit0 := 31; {convert 68000 to toolbox}
 {check for mouse moved event}
 MouseMove.longView := myEvent.message;
 HiByte := Byte(MouseMove.byteView.byte0);
 if HiByte = MouseMovedEvt then
 begin {Handle mouse moved event}
 end;
 {check for resume event }
 if Odd(myEvent.message) then
 begin  {resume}
 { treat like activate Event if we are in front}
 ResumeWindow := FrontWindow;
 if ResumeWindow = ADBWindow then
 begin {adbWindow}
 SetPort(ResumeWindow);
 InvalRect(ResumeWindow^.portRect); 
 { force update event}
 DisableItem(myMenus[EditM], eUndo);
 ShowControl(VControl);
 ShowControl(HControl);
 DrawGrowIcon(ResumeWindow);
 end; {adbWindow}
 if FrontWindow <> nil then
 begin {DA check}
 ResumePeek := WindowPeek(FrontWindow);
 if ResumePeek^.windowKind < 0 then {DA}
 begin {da}
 myEvent.what := activateEvt;
 BitSet(@myEvent.modifiers, bit0);
 sysresult := SystemEvent(myEvent);
 end; {da}
 end; {DA check}
 { end of activate Event}
 end {of resume}
 else
 begin  {suspend}
 {de-activate Event}
 SuspendWindow := FrontWindow;
 if SuspendWindow = ADBWindow then
 begin {adbwindow}
 SetPort(SuspendWindow);
 InvalRect(SuspendWindow^.portRect);
 {force update}
 EnableItem(myMenus[EditM], eUndo);
 EnableItem(myMenus[EditM], eCut);
 EnableItem(myMenus[EditM], eCopy);
 EnableItem(myMenus[EditM], ePaste);
 EnableItem(myMenus[EditM], eClear);
 DrawGrowIcon(SuspendWindow);
 HideControl(VControl);
 HideControl(HControl);
 end; {adbwindow}
 if FrontWindow <> nil then
 begin {DA check}
 SuspendPeek := WindowPeek(FrontWindow);
 if SuspendPeek^.windowKind < 0 then
 begin {da}
 myEvent.what := activateEvt;
 BitClr(@myEvent.modifiers, bit0);
 sysresult := SystemEvent(myEvent);
 end; {da}
 end; {DA check}
 { end of de-activate Event}
 end; {suspend}
 end; {of proc}

 procedure MainEventLoop;
 const
 MultiFinderEvt = 15;
 var
 sleep: LongInt;
 Event: EventRecord;
 DoIt: Boolean;
 begin
 sleep := 10;
 repeat
 TEIdle(MyTextHandle);
 DoIt := WaitNextEvent(EveryEvent, Event, sleep, nil); {no mouse tracking}
 if DoIt then
 case Event.what of
 mouseDown: 
 doMouse(Event);
 KeyDown, Autokey: 
 doKeyDowns(Event);
 updateEvt: 
 doUpdates(Event);
 activateEvt: 
 doActivates(Event);
 MultiFinderEvt: 
 doMulti(Event);
 otherwise
 begin
 end;
 end; {of event case}
 until Finished; {end program}
 end;

begin  { main }
 InitMac;
 InitRects;
 InitMyWindow;
 InitMyPrint;
 InitMyMenus;
 MainEventLoop;
end.  { end of main }

unit MyADBStuff;

interface

 uses
 OSIntf, PrintTraps, MyADBGlobals;

 procedure doMessage (message0: str255; message1: str255; message2: str255; 
message3: str255);
 procedure doAbout;
 procedure doQuit;
 procedure doMenubar (menuResult: LongInt);
 procedure doContent (ConEvent: EventRecord; contentWindow: windowPtr);
 procedure doDrag (GrabWindow: WindowPtr; GlobalMouse: point);
 procedure doGrow (ResizeWindow: WindowPtr; Globalmouse: point; Zoomflg: 
Boolean);

implementation

 procedure doMessage; {(message0 : str255}
 {message1 : str255}
 {message2 : str255}
 {message3 : str255)}
 var
 dialogP: DialogPtr;
 item: integer;
 begin
 ParamText(message0, message1, message2, message3);
 dialogP := GetNewDialog(MessageDialog, nil, pointer(-1));
 if dialogP = nil then
 begin
 SysBeep(5);
 ExitToShell;
 end;
 initCursor; {change to arrow}
 ModalDialog(nil, item);
 DisposDialog(dialogP);
 end;

 procedure delay;
 const
 stalltime = 15; {quarter seconds in ticks}
 var
 i: LongInt;
 tick1, tick2: LongInt;
 begin
 tick1 := TickCount;
 tick2 := tick1;
 repeat
 tick2 := TickCount;
 until tick2 >= tick1 + stalltime;
 end;

 procedure togglelightsoff;
 const
 flushcommandNum = $21;  { 00100001 }
 begin
 Buf.opServiceRtPtr := Info.dbServiceRtPtr;  
 {service routine pointer}
 Buf.opDataAreaPtr := Info.dbDataAreaAddr;   
 {optional data area address}
 OSEr := ADBOp(nil, nil, Buf.dataBuffPtr, flushcommandNum);  { Flush 
command, clears the device }
 if OSEr = -1 then
 doMessage(‘Unable to flush device’, ‘’, ‘’, ‘’);
 end;

 procedure togglelightson;
 var
 LEDaddress: ptr;
 LEDbyte: signedbyte;
 const
 talkcommandNum = $2E;  { 00101010 }
 listencommandNum = $2A; { 00101110 }
 begin
 if OSEr = noErr then
 begin
 Buf.opServiceRtPtr := Info.dbServiceRtPtr;
 {service routine pointer}
 Buf.opDataAreaPtr := Info.dbDataAreaAddr;
   {optional data area address}
 togglelightsoff;
 OSEr := ADBOp(Buf.opDataAreaPtr, Buf.opServiceRtPtr, Buf.dataBuffPtr, 
talkcommandNum);
 if OSEr = -1 then
 begin
 doMessage(‘Unable to talk to device’, ‘’, ‘’, ‘’);
 exit(togglelightson);
 end;
 delay;
 LEDaddress := POINTER(ORD(Buf.dataBuffPtr) + 2);
 LEDbyte := LEDaddress^;
 if LEDbyte = -1 then
 LEDaddress^ := -8; {turn on}
 OSEr := ADBOp(Buf.opDataAreaPtr, Buf.opServiceRtPtr, Buf.dataBuffPtr, 
listencommandNum);
 if OSEr = -1 then
 begin
 doMessage(‘Unable to listen to device’, ‘’, ‘’, ‘’);
 exit(togglelightson);
 end;
 end; {of noErr}
 end;

 procedure LightsMagic;
 begin
 togglelightson;
 delay;
 togglelightsoff;
 delay;
 togglelightson;
 delay;
 togglelightsoff;
 delay;
 togglelightson;
 delay;
 togglelightsoff;
 delay;
 togglelightson;
 delay;
 togglelightsoff;
 delay;
 end;

 procedure QuerySystem;
 var
 str1, str2: str255;
 begin
 NumToString(LongInt(theWorld.environsVersion), str2);
 str1 := concat(‘Environment Version = ‘, str2, chr(13));
 TEInsert(pointer(ord4(@str1) + 1), Length(str1), MyTextHandle);

 case theWorld.machineType of
 0: 
 str2 := ‘new version of Macintosh’;
 1: 
 str2 := ‘Macintosh 512K enhanced’;
 2: 
 str2 := ‘Macintosh Plus’;
 3: 
 str2 := ‘Macintosh SE’;
 4: 
 str2 := ‘Macintosh II’;
 otherwise
 begin
 if theWorld.machineType = -1 then
 str2 := ‘Macintosh with 64K ROM’;
 if theWorld.machineType = -2 then
 str2 := ‘Macintosh XL’;
 end;
 end; {of case}
 str1 := concat(‘Machine Type = ‘, str2, chr(13));
 TEInsert(pointer(ord4(@str1) + 1), Length(str1), MyTextHandle);

 NumToString(LongInt(theWorld.systemVersion), str2);
 str1 := concat(‘System Version (must convert to hex) = ‘, str2, chr(13));
 TEInsert(pointer(ord4(@str1) + 1), Length(str1), MyTextHandle);

 case theWorld.processor of
 0: 
 str2 := ‘new processor’;
 1: 
 str2 := ‘MC68000 processor’;
 2: 
 str2 := ‘MC68010 processor’;
 3: 
 str2 := ‘MC68020 processor’;
 4: 
 str2 := ‘MC68030 processor’;
 otherwise
 begin
 str2 := ‘unknown processor’;
 end;
 end; {of case}
 str1 := concat(‘Processor = ‘, str2, chr(13));
 TEInsert(pointer(ord4(@str1) + 1), Length(str1), MyTextHandle);

 NumToString(LongInt(theWorld.hasFPU), str2);
 str1 := concat(‘Has Floating Point Coprocessor (1=Y) = ‘, str2, chr(13));
 TEInsert(pointer(ord4(@str1) + 1), Length(str1), MyTextHandle);

 NumToString(LongInt(theWorld.hasColorQD), str2);
 str1 := concat(‘Has Color QuickDraw (1=Y) = ‘, str2, chr(13));
 TEInsert(pointer(ord4(@str1) + 1), Length(str1), MyTextHandle);

 case theWorld.KeyBoardType of
 0: 
 str2 := ‘Macintosh Plus keyboard with keypad’;
 1: 
 str2 := ‘Macintosh keyboard’;
 2: 
 str2 := ‘Macintosh keyboard and keypad’;
 3: 
 str2 := ‘Macintosh Plus keyboard’;
 4: 
 str2 := ‘Apple extended keyboard’;
 5: 
 str2 := ‘Standard Apple Desktop Bus keyboard’;
 otherwise
 begin
 str2 := ‘Unknown keyboard value’;
 end;
 end; {of case}
 str1 := concat(‘Keyboard Type = ‘, str2, chr(13));
 TEInsert(pointer(ord4(@str1) + 1), Length(str1), MyTextHandle);

 NumToString(LongInt(theWorld.atDrvrVersNum), str2);
 str1 := concat(‘Appletalk Driver Version = ‘, str2, chr(13));
 TEInsert(pointer(ord4(@str1) + 1), Length(str1), MyTextHandle);

 NumToString(LongInt(theWorld.sysVRefNum), str2);
 str1 := concat(‘Working Directory Volume Ref = ‘, str2, chr(13));
 TEInsert(pointer(ord4(@str1) + 1), Length(str1), MyTextHandle);
 end;

 procedure doADB;
 var
 devTableIndex: integer;
 str1: str255;
 begin
 TESetSelect(0, TEMax, MyTextHandle);
 TEDelete(MyTextHandle);
 ShowWindow(ADBWindow);

 OSEr := SysEnvirons(versRequested, theWorld);
 if OSEr = envNotPresent then
 doMessage(‘System File older than 4.1!’, ‘’, ‘’, ‘’);
 if OSEr = envBadVers then
 doMessage(‘Bad Version Requested’, ‘’, ‘’, ‘’);
 if OSEr = envVersTooBig then
 doMessage(‘Requested Version Not Available’, ‘’, ‘’, ‘’);
 if OSEr = noErr then
 begin {Query and Blinking routine}

 QuerySystem;

 {toggle keyboard lights on and off}
 if theWorld.keyBoardType = 4 then
 begin {keyboard type 4}
 str1 := concat(chr(13), ‘Watch the keyboard lights blink   ‘, chr(13));
 TEInsert(pointer(ord4(@str1) + 1), Length(str1), MyTextHandle);

 numberofADBs := CountADBs;
 for devTableIndex := 1 to numberofADBs do
 begin {devTableIndex}
 ADBAddr := GetIndADB(info, devTableIndex); 
 { find the device address }
 if ADBAddr = 2 then
 begin {ADBAddr}
 device := info.devType;
 LightsMagic;
 end; {of ADBAddr}
 end; {devTableIndex}
 end; {keybaord type 4}
 end; { of noErr}
 end; {of Proc}

 procedure doAbout;
 var
 IDStrHandle: StringHandle;
 dialogP: DialogPtr;
 item: integer;
 Str1, Str2, Str3: str255;
 myHeapSpace: LongInt;
 FreeSpace: Size;
 begin
 IDStrHandle := StringHandle(GetResource(rsrc, 0));
 if IDStrHandle = nil then
 begin
 doMessage(‘Get About box crash!’, ‘’, ‘’, ‘’);
 ExitToShell;
 end;
 MoveHHi(Handle(IDStrHandle));
 HLock(Handle(IDStrHandle));
 FreeSpace := FreeMem;
 myHeapSpace := MaxMem(FreeSpace);
 NumToString(myHeapSpace, Str2);
 Str2 := concat(‘Memory = ‘, Str2);
 Str3 := ‘’;
 Str1 := ‘’;
 ParamText(IDStrHandle^^, Str1, Str2, Str3);
 dialogP := GetNewDialog(AboutDialog, nil, pointer(-1));
 if dialogP = nil then
 begin
 doMessage(‘Dialog crash!’, ‘We are dead...’, ‘’, ‘’);
 ExitToShell;
 end;
 initCursor;
 ModalDialog(nil, item);
 DisposDialog(dialogP);
 HUnlock(Handle(IDStrHandle));
 end;

 procedure doQuit;
 begin
 DisposeWindow(ADBWindow);
 TEDispose(MyTextHandle);
 Finished := true;
 end; {of proc}

 procedure doSave;
 begin
 end;

 procedure doSaveAs;
 begin
 end;

 procedure doPrint;
 begin
 end;

 procedure doPageSet;
 begin
 end;

 procedure doMenubar; {(menuResult : LongInt)}
 var
 theMenu: integer;
 theItem: integer;
 daName: STR255;
 accItem: integer;
 temp: GrafPtr;
 dummy: LongInt; {Desk Scrap result var}
 ScrapReturn: OSErr; {TEScrap result var}
 TextLength: integer;
 ScrapLength: LongInt;
 begin
 theMenu := HiWord(menuResult); {menu}
 theItem := LoWord(menuResult); {item}
 case theMenu of
 AppleMenu: 
 begin
 if theItem = aAbout then
 doAbout
 else
 begin  {must be DA}
 GetItem(myMenus[AppleM], theItem, daName);
 GetPort(temp);  {protect against flacky DA}
 accItem := OpenDeskAcc(daName);
 SetPort(temp);
 end; {else}
 end; {of AppleMenu}
 FileMenu: 
 begin
 case theItem of
 fADB: 
 begin
 doADB;
 end;
 fSave: 
 begin
 doSave;
 end;
 fSaveAs: 
 begin
 doSaveAs;
 end;
 fPageSet: 
 begin
 doPageSet;
 end;
 fPrint: 
 begin
 doPrint;
 end;
 fQuit: 
 begin
 doQuit;
 end;
 otherwise
 begin
 end;
 end; {of theitem}
 end; {of FileMenu}
 EditMenu: 
 begin
 if not SystemEdit(theitem - 1) then
 begin
 case theItem of
 eUndo: 
 begin
 doMessage(‘Undo not available.’, ‘’, ‘’, ‘’);
 end;
 eCut: 
 begin
 TECut(MyTextHandle);
 dummy := ZeroScrap;
 ScrapReturn := TEToScrap; {update desk scrap}
 end;
 eCopy: 
 begin
 TECopy(MyTextHandle);
 dummy := ZeroScrap;
 ScrapReturn := TEToScrap; {update desk scrap}
 end;
 ePaste: 
 begin
 ScrapReturn := TEFromScrap;
 TextLength := MyTextHandle^^.teLength;
 ScrapLength := TEGetScrapLen;
 if (LongInt(TextLength + ScrapLength)) > longInt(TEMax - 1) then
 begin
 initCursor;
 paramText(‘Paste would exceed text edit 32000 buffer limit!’, ‘’, ‘’, 
‘’);
 ItemHit := StopAlert(AlertDialog, nil);
 end
 else
 TEPaste(MyTextHandle);
 end; { of paste}
 eClear: 
 begin
 TEDelete(MyTextHandle);
 end;
 otherwise
 begin
 end;
 end; {of case}
 end; {of system edit}
 end; {of EditMenu}
 otherwise
 begin
 end;
 end; {of theMenu}
 HiliteMenu(0);  {un-hilite selected menu}
 end;

 procedure doContent; {(ConEvent : EventRecord}
 {contentWindow : windowPtr);}
 var
 localPt, globalPt: Point;
 part: integer;
 myRect: Rect;
 control: ControlHandle;
 begin
 if contentWindow <> FrontWindow then
 SelectWindow(contentWindow);
 globalPt := ConEvent.where;
 localPt := globalPt;{global coord of mouse}
 GlobalToLocal(localPt);  {local coord of mouse}
 part := FindControl(localPt, contentWindow, control);

 if contentWindow = ADBWindow then
 begin
 SetPort(ADBWindow);
 if part <> 0 then
 begin {in control}
 end;
 if part = 0 then
 begin  {content region}
 myRect := ADBWindow^.portRect;
 if PtInRect(localPt, myRect) then
 begin
 TEClick(localPt, BitAnd(ConEvent.modifiers, ShiftKey) = ShiftKey, myTextHandle)
 end;  {of ptInRect}
 end; { of part=0 }
 end; {of contentwindow}
 end;  {of proc}

 procedure doDrag; {(GrabWindow : WindowPtr}
 {GlobalMouse : point);}
 begin
 DragWindow(GrabWindow, GlobalMouse, DragArea);
 end;

 procedure doGrow; {(ResizeWindow : WindowPtr;}
 {Globalmouse : point;}
 {ZoomFlg:Boolean);}
 var
 newSize: LongInt;
 hsize: integer;
 vsize: integer;
 oldPort: GrafPtr;
 myRect: rect;
 tempLong: LongInt;
 l, t, r, b: LongInt;
 begin
 if (ResizeWindow <> FrontWindow) then
 SelectWindow(ResizeWindow)
 else
 begin
 if (ZoomFlg) then
 begin
 with ResizeWindow^.portRect do
 begin
 tempLong := bottom - top;
 newSize := BitShift(tempLong, 16);
 newSize := newSize + (right - left);
 end;
 end
 else
 newSize := GrowWindow(ResizeWindow, Globalmouse, GrowArea);
 if newSize <> 0 then
 begin  {grow the window}
 hsize := LoWord(newSize);
 vsize := HiWord(newSize);
 if ResizeWindow = ADBWindow then
 begin
 with ResizeWindow^.portRect do 
 {Pre-Grow}
 begin
 SetRect(VCRect, right - (SBarWidth - 1), top - 1, right + 1, bottom 
- (SBarWidth - 2));
 SetRect(HCRect, left - 1, bottom - (SBarWidth - 1), right - (SBarWidth 
- 2), bottom + 1);
 SetRect(GrowRect, HCRect.right, HCRect.top, VCRect.right, HCRect.bottom);
 end;  {of with }
 SizeWindow(ResizeWindow, hsize, vsize, TRUE); {new portRect}
 InvalRect(GrowRect);
 EraseRect(GrowRect);
 with ResizeWindow^.portRect do 
 {Post Grow}
 begin
 SetRect(VCRect, right - (SBarWidth - 1), top - 1, right + 1, bottom 
- (SBarWidth - 2));
 SetRect(HCRect, left - 1, bottom - (SBarWidth - 1), right - (SBarWidth 
- 2), bottom + 1);
 SetRect(GrowRect, HCRect.right, HCRect.top, VCRect.right, HCRect.bottom);
 SetRect(ViewRect, left + 4, top + 4, right - (SBarWidth - 1), bottom 
- (SBarWidth - 1));
 end;  {of with }

 InvalRect(GrowRect); 
 HideControl(VControl);
 HideControl(HControl);
 MoveControl(VControl, VCRect.left, VCRect.top);
 MoveControl(HControl, HCRect.left, HCRect.top);
 SizeControl(VControl, SBarWidth, VCRect.bottom - VCRect.top);
 SizeControl(HControl, HCRect.right - HCRect.left, SBarWidth);
 ShowControl(VControl);
 ShowControl(HControl);
 ValidRect(VCRect);
 ValidRect(HCRect);

 MyTextHandle^^.ViewRect := ViewRect;
 InValRect(ViewRect);
 end; {of if ResizeWindow}
 end; {of grow window stuff}
 end; {of if then newsize}
 end;  { of proc }

end. {of unit}

unit MyADBGlobals;

interface

 uses
 OSIntf, PrintTraps;

 const
 {window constants}
 ZoomBox = 8;  {window type}
 MinWidth = 80;
 MinHeight = 80;
 mBarHeightGlobal = $BAA;
 GrayRgnLowMemGlobal = $9EE;
 sBarWidth = 16;
 TEMax = 32767;
 rsrc = ‘ADBx’;  {creator bytes restype}

 {dialog stuff}
 AboutDialog = 256;
 MessageDialog = 258;
 AlertDialog = 260;

 { menu res id’s}
 AppleMenu = 256;
 FileMenu = 257;
 EditMenu = 258;

 MenuCount = 3;
 AppleM = 1;
 FileM = 2;
 EditM = 3;

 {menu items}
 aAbout = 1;
 fADB = 1;
 fSave = 3;
 fSaveAs = 4;
 fPageSet = 5;
 fPrint = 6;
 fQuit = 8;
 eUndo = 1;
 eCut = 3;
 eCopy = 4;
 ePaste = 5;
 eClear = 6;

 versRequested = 1;
 numlock = 1;
 capslock = 2;
 scrolllock = 4;

 envBadVers = -5501;
 envVersTooBig = -5502;

 type
 LongAndByte = record
 case integer of
 1: ( longView: LongInt);
 2: ( byteView: record
 byte0: SignedByte;
 byte1: Signedbyte;
 byte2: Signedbyte;
 byte3: Signedbyte;
 end; );
 end;

 var
 {my misc stuff}
 Finished: boolean;
 mBarHeight: Integer;

 {menu stuff}
 myMenus: array[1..MenuCount] of MenuHandle;

 {rectangles}
 DragArea: Rect; {window drag area}
 GrowArea: Rect; {window grow area}
 Screen: Rect;   {physical screen area}
 ADBWindowRect: Rect;{beginning window size}
 ZoomRect: Rect; {zoomed window size}
 HCRect, VCRect, GrowRect: Rect; {scroller rects}
 DestRect, ViewRect: Rect;{text edit rects}

 {dialogs stuff}
 ItemHit: integer;
 dialogflg: boolean;

 {Window Stuff}
 ADBWindow: WindowPtr;
 ADBWindowPeek: WindowPeek;
 myTextHandle: TEHandle;
 VControl: ControlHandle;
 HControl: ControlHandle;
 myPrint: THPrint;

 {ADB Stuff}
 theWorld: SysEnvRec;
 OSEr: OSErr;
 numberofADBs: integer;
 info: ADBDataBlock;
 buf: ADBOpBlock;
 ADBAddr: ADBAddress;
 device: byte;

implementation

end.
* ADB.R
*

ADB.RSRC
????ADBx

Type ADBx = STR 
 ,0
ADB Demo \0D© by Dave Kelly & Dave Smith \0Dver 2 MAR 1989

* Multifinder Menu for Quit Cmd
Type mstr = STR 
 ,100
File

* Multifinder Quit name
Type mstr = STR 
 ,101
Quit

Type FREF
,128
APPL 0
,129
TEXT 1

Type BNDL
,128
ADBx 0
ICN#
0 128 1 129
FREF 
0 128 1 129

* ------ Multifinder events --------

* bit 15 = reserved
* bit 14 = accept suspend resume events
* bit 13 = reserved
* bit 12 = can do background on null events
* bit 11 = multifinder aware 
*         (activates & deactivates topmost 
*           window at resume, suspend events)

Type SIZE = GNRL
 ,-1
.H
4800    ;; $4800 = bits 14,11 set
.L
128000  ;; (for 150K recomended)
.L
80000 ;; (for 80K minimum)
.I

Type vers = GNRL
 , 1
.H
01 ;; byte vers # in BCD
10 ;; byte vers part 2 & 3
50 ;; byte release stage $50=release
00 ;; byte stage of non-release
00 00 ;; integer country 0=US
.P
V1.1 (US)
.P
ADB Demo 1.1, © by Dave Kelly & David Smith for MacTutor 1989

Type vers = GNRL
 , 2
.H
05 ;; byte vers # in BCD
30 ;; byte vers part 2 & 3
50 ;; byte release stage $50=release
00 ;; byte stage of non-release
00 00 ;; integer country 0=US
.P
V5.3
.P
MacTutor Volume 5 Number 3

* ------------ menus ------------

Type MENU
* the desk acc menu
 ,256
\14;;apple menu
 About ADB Demo 
 (-

* the file menu
 ,257
File
 ADB /A
 (-
 (Save /S
 Save as 
 Page Setup  /U
 (Print  /O
 (-
   Quit /Q

* the edit menu
 ,258
Edit
 (Undo /Z
 (-
 Cut /X
 Copy /C
 Paste /V
 Clear


* ------ Dialogs --------
* About Box dialog...
type DLOG
 ,256
About ADB Demo 
100 100 250 400 
visible NoGoAway 
1
0
256

type DITL
 ,256
3
BtnItem Enabled
112 235 141 284 
OK

StatText Disabled
10 88 141 289 
ADB Demo\0D\0D++
Queries System, blinks lights\0D^0\0D^1\0D^2\0D^3

PicItem Disabled
10 10 96 81 
128

* Program Messages Dialog box...
type DLOG
 ,258
Program Messages
100 100 200 400
Visible NoGoAway
1
0
258

type DITL
 ,258
3
BtnItem Enabled
65 230 95 285
OK

StatText Disabled
15 60 85 222 
^0\0D^1\0D^2\0D^3

IconItem Disabled
10 10 42 42
1

* ------ Alerts ------------

* Program error alerts...
type ALRT
 ,260
100 100 200 400
260
5555

type DITL
 ,260
2

BtnItem
65 230 95 285
OK

StatText Disabled
15 60 60 275 
Program Problem Alert:\0D^0^1^2^3

* misc resources
Type ICN# = GNRL
  ,128 (0)
.H
0001 0000 0002 8000 0004 4000 000B E000 
0015 5000 0026 B800 0045 5400 0086 B200 
0105 5100 0213 E080 0428 0040 0810 0020 
1102 0010 2204 0008 4480 3F04 8910 4082 
4220 8041 2441 3022 1081 C814 081E 7F8F 
0402 3005 0201 0007 0100 8005 0080 6007 
0040 1FE5 0020 021F 0010 0407 0008 0800 
0004 1000 0002 2000 0001 4000 0000 8000
*
0001 0000 0003 8000 0007 C000 000F E000 
001F F000 003F F800 007F FC00 00FF FE00 
01FF FF00 03FF FF80 07FF FFC0 0FFF FFE0 
1FFF FFF0 3FFF FFF8 7FFF FFFC FFFF FFFE 
7FFF FFFF 3FFF FFFE 1FFF FFFC 0FFF FFFF 
07FF FFFF 03FF FFFF 01FF FFFF 00FF FFFF 
007F FFFF 003F FE1F 001F FC07 000F F800 
0007 F000 0003 E000 0001 C000 0000 8000 

Type ICN# = GNRL
  ,129 (0)
.H
0FFF FE00 0800 0300 0800 0280 0800 0240 
0800 0220 0800 0210 0800 03F8 0800 0008 
0800 0008 0801 0008 0802 8008 0805 4008 
080A A008 0815 5008 082A A808 0815 5008 
080A A008 0805 4008 0802 8008 0801 0008 
0800 0008 0800 0008 0800 0008 0800 0008 
0820 79E8 0850 4528 0888 45E8 09FC 4528 
0A02 79E8 0800 0008 0800 0008 0FFF FFF8
*
0FFF FE00 0FFF FF00 0FFF FF80 0FFF FFC0 
0FFF FFE0 0FFF FFF0 0FFF FFF8 0FFF FFF8 
0FFF FFF8 0FFF FFF8 0FFF FFF8 0FFF FFF8 
0FFF FFF8 0FFF FFF8 0FFF FFF8 0FFF FFF8 
0FFF FFF8 0FFF FFF8 0FFF FFF8 0FFF FFF8 
0FFF FFF8 0FFF FFF8 0FFF FFF8 0FFF FFF8 
0FFF FFF8 0FFF FFF8 0FFF FFF8 0FFF FFF8 
0FFF FFF8 0FFF FFF8 0FFF FFF8 0FFF FFF8 

TYPE PICT = GNRL
 ,128
.I
891
195 254 281 325
.H
1101 A000 82A0 008E 0100 0A00 0000 0002
D002 4098 000A 00C3 00F8 00FF 0148 00C3
00FE 00FF 0145 00C3 00FE 00FF 0145 0000
02F7 0002 F700 02F7 0002 F700 02F7 0002
F700 02F7 0002 F700 02F7 0002 F700 02F7
0006 FD00 000E FC00 07FD 0001 1F80 FD00
07FD 0001 7FC0 FD00 07FD 0001 FFF0 FD00
08FE 0002 03FF FCFD 0008 FE00 0207 FFFE
FD00 09FE 0003 1FFF FF80 FE00 09FE 0003
3FFF FFE0 FE00 09FE 0003 7FFF FFF8 FE00
0A02 0000 01FE FF00 FCFE 0008 0200 0003
FDFF FE00 0A02 0000 0FFD FF00 C0FF 000B
0700 001F FFFF 3FFF E0FF 000B 0700 007F
FFFE 1FFF F8FF 000B 0700 00FF FFFE 1FFF
FCFF 000B 0100 01FE FF02 27FF FCFF 000B
0100 01FE FF02 F9FF F8FF 000B 0100 00FE
FF02 FE7F F0FF 000B 0200 003F FEFF 019F
E0FF 000B 0200 001F FEFF 01E7 C0FF 000B
0200 003F FEFF 01F9 80FF 000B 0200 0033
FEFF 01FE 80FF 000A 0200 0060 FDFF 00C0
FF00 0B07 0000 607F FFFF FCC0 FF00 0B07
0000 601F FFFF F870 FF00 0B07 0000 6007
FFFF F0F8 FF00 0B07 0000 6001 FFFF F0F8
FF00 0B07 0000 6000 FFFF F0F8 FF00 0B07
0000 6038 3FFF B050 FF00 0A06 0000 607C
0FFF 30FE 000B 0700 0060 F603 FE30 A8FF
000B 0700 0060 E301 FC30 50FF 000B 0700
0060 C000 7830 20FF 000B 0700 0060 0000
1030 88FF 000B 0200 0060 FE00 0130 50FF
000A 0200 0060 FE00 0030 FE00 0B02 0000
60FE 0001 30A8 FF00 0B07 0000 6807 0700
B050 FF00 0A06 0000 681F 8FC0 B0FE 000B
0700 006C 7FDF F1B0 A8FF 000A 0200 0067
FEFF 0030 FE00 0B09 0000 63FF FFFE 31F4
1000 0B09 0000 307F DFF0 6046 3000 0B09
0000 381F 8FC0 E045 5000 0B09 0000 1C00
0001 C044 9000 0B09 0000 0E00 0003 8044
1000 0802 0000 07FE FFFD 0009 0500 0001
FFFF FCFD 0008 FE00 0280 0004 FD00 9800
0A00 FF00 F801 1901 4800 FF00 FE01 1901
4500 FF00 FE01 1901 4500 0008 FE00 0280
0004 FD00 08FE 0002 FFFF FCFD 0008 0200
0001 FEAA FD00 0802 0000 03FE 55FD 000A
0600 0006 FEAF EA80 FE00 0A06 0000 0D83
5835 40FE 000A 0600 001B 01B0 1AA0 FE00
0A06 0000 3501 5015 50FE 000A 0600 006A
82A8 2AA8 FE00 0A06 0000 D57D 57D7 F4FE
000A 0600 01AF AAFA AC1A FE00 0A06 0003
5055 0558 0DFE 000B 0700 06A0 2A02 A80A
80FF 000B 0700 0D60 3603 5415 40FF 000B
0700 0AB0 6B06 ABEA C0FF 000B 0700 0D5F
D5FD 5555 40FF 0009 0100 0AFC AA00 C0FF
0009 0100 0DFC 5500 40FF 0009 0100 0FFC
FF00 C0FF 0002 F700 02F7 0002 F700 02F7
0002 F700 02F7 0002 F700 A000 8FA0 0083
FF

Link Segments for our Project

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Civilization VI 1.0.6 - Next iteration o...
Sid Meier’s Civilization VI is the next entry in the popular Civilization franchise. Originally created by legendary game designer Sid Meier, Civilization is a strategy game in which you attempt to... Read more
Civilization VI 1.0.6 - Next iteration o...
Sid Meier’s Civilization VI is the next entry in the popular Civilization franchise. Originally created by legendary game designer Sid Meier, Civilization is a strategy game in which you attempt to... Read more
djay Pro 2.0.1 - Transform your Mac into...
djay Pro provides a complete toolkit for performing DJs. Its unique modern interface is built around a sophisticated integration with iTunes and Spotify, giving you instant access to millions of... Read more
Microsoft OneNote 15.41 - Free digital n...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that's too important to forget. Whether you're at... Read more
TechTool Pro 9.6 - Hard drive and system...
TechTool Pro has long been one of the foremost utilities for keeping your Mac running smoothly and efficiently. With the release of version 9, it has become more proficient than ever. TechTool... Read more
Apple iOS 11.2.1 - The latest version of...
iOS 11 sets a new standard for what is already the world’s most advanced mobile operating system. It makes iPhone better than before. It makes iPad more capable than ever. And now it opens up both to... Read more
Things 3.3 - Elegant personal task manag...
Things is a task management solution that helps to organize your tasks in an elegant and intuitive way. Things combines powerful features with simplicity through the use of tags and its intelligent... Read more
RapidWeaver 7.5.5 - Create template-base...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
Adobe Animate CC 2018 18.0.1.115 - Anima...
Animate CC 2018 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Flash Professional customer). Animate CC 2018 (was Flash CC) lets you... Read more
Postbox 5.0.22 - Powerful and flexible e...
Postbox is a new email application that helps you organize your work life and get stuff done. It has all the elegance and simplicity of Apple Mail, but with more power and flexibility to manage even... Read more

Latest Forum Discussions

See All

The 5 best Star Wars games on iOS
The time has almost come.Star Wars: The Last Jedifinally hits theaters in the cinematic event that might be bigger than Christmas. To celebrate, we're taking a look at the best--and only the best--Star Warsmobile games to date. [Read more] | Read more »
Life Is Strange (Games)
Life Is Strange 1.1 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1 (iTunes) Description: Life Is Strange is a five part episodic game that sets out to revolutionize story-based choice and consequence games by... | Read more »
Oddworld: New 'n' Tasty (Game...
Oddworld: New 'n' Tasty 1.0 Device: iOS Universal Category: Games Price: $7.99, Version: 1.0 (iTunes) Description: ** PLEASE NOTE: Requires 3.6GB free space to install. Runs at variable resolutions based on device capabilities.... | Read more »
Gorogoa (Games)
Gorogoa 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Gorogoa is an elegant evolution of the puzzle genre, told through a beautifully hand-drawn story designed and illustrated by Jason... | Read more »
Why Guns of Boom will be big for mobile...
Earlier this week, Game Insight, the minds that brought you Guns of Boom, revealed plans for an esports mode in the popular FPS title, with big implications for the game's future. Guns of Boom has been quite popular for some time now, so it's... | Read more »
Rules of Survival guide - how to boost y...
It's not easy surviving in the "every-man-for-himself" world of Rules of Survival. You'll be facing off against many other players who might be more skilled than you, or are luckier than you. There are a lot of factors weighing against you. With... | Read more »
FEZ Pocket Edition (Games)
FEZ Pocket Edition 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: | Read more »
Amazing Katamari Damacy guide - beginner...
Amazing Katamari Damacy brings the bizarro world of the original games to mobile and shifts them into an endless format that's just as addictive as the PlayStation entries. Your goal is still to roll as much random stuff as you possibly can, though... | Read more »
Portal Knights guide - crafting tips and...
In Portal Knights, you're only as strong as the items you have at your disposal. This sandbox adventure is all about crafting and building up the next big thing. Whether you're an avid explorer or collector, crafting will likely play a large part... | Read more »
The best deals on the App Store this wee...
A new week means new discounts on the App Store. This week's deals run the gamut of action-adventure titles, puzzle games, and one of the best narrative adventure series out there. If you're looking to fill out your mobile gaming library on a... | Read more »

Price Scanner via MacPrices.net

Beats Holiday sale at B&H, headphones and...
B&H Photo has Beats by Dr. Dre headphones, earphones, and speakers on sale for up to $80 off MSRP as part of their Holiday sale. Expedited shipping is free, and B&H charges sales tax to NY... Read more
Holiday sale: Apple resellers offer 2017 15″...
MacMall has 15″ MacBook Pros on sale for $220-$300 off MSRP, each including free shipping: – 15″ 2.8GHz MacBook Pro Space Gray (MPTR2LL/A): $2179, $220 off MSRP – 15″ 2.8GHz MacBook Pro Silver (... Read more
Holiday sale: Apple resellers offer 13″ MacBo...
B&H Photo has 13″ MacBook Pros on sale for up to $150 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13-inch 2.3GHz/128GB Space Gray MacBook Pro (... Read more
Apple Watch Series 2, Certified Refurbished,...
Apple has Certified Refurbished Apple Watch Nike+ Series 2s, 42mm Space Gray Aluminum Case with Anthracite/Black Nike Sport Bands, available for $249 (38mm) or $279 (42mm). The 38mm model was out of... Read more
Apple offers Certified Refurbished 2016 12″ R...
Apple has Certified Refurbished 2016 12″ Retina MacBooks available starting at $949. Apple will include a standard one-year warranty with each MacBook, and shipping is free. The following... Read more
B&H drops price on 13″ 256GB MacBook Air...
B&H has the 13″ 1.8GHz/256GB Apple MacBook Air (MQD42LL/A) now on sale for $1079 including free shipping plus NY & NJ sales tax only. Their price is $120 off MSRP, and it’s the lowest price... Read more
Holiday sale: 9″ iPads starting at $299, take...
MacMall has 9″ WiFi iPads on sale for $30 off including free shipping: – 9″ 32GB WiFi iPad: $299 – 9″ 128GB WiFi iPad: $399 Read more
Green Monday deal: 15″ 2.8GHz MacBook Pro on...
B&H Photo has the 15″ 2.8GHz Space Gray MacBook Pro on sale for $250 off MSRP for today only as part of their Green Monday/Holiday sale. Shipping is free, and B&H charges sales tax for NY... Read more
Green Monday sale: B&H offers 12″ Apple i...
B&H Photo has 12″ iPad Pros on sale for up to $150 off MSRP as part of their Green Monday/Holiday sale. Shipping is free, and B&H charges sales tax in NY & NJ only: – 12″ 64GB WiFi iPad... Read more
Holiday deal: 21″ and 27″ Apple iMacs on sale...
MacMall has 2017 21″ and 27″ Apple iMacs on sale for up to $200 off MSRP. Shipping is free: – 21″ 2.3GHz iMac: $999 $100 off MSRP – 21″ 3.0GHz iMac: $1199 $100 off MSRP – 21″ 3.4GHz iMac: $1379 $120... Read more

Jobs Board

*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 113124408 Waterford, CT, Connecticut, United States Posted: 17-Oct-2017 Weekly Hours: 40.00 **Job Summary** Are you Read more
QA Automation Engineer, *Apple* Pay - Apple...
# QA Automation Engineer, Apple Pay Job Number: 113202642 Santa Clara Valley, California, United States Posted: 11-Dec-2017 Weekly Hours: 40.00 **Job Summary** At Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.