TweetFollow Us on Twitter

BitNapper
Volume Number:2
Issue Number:5
Column Tag:Graphics Lab:Asm

BitNapper DA Steals Bit Maps!

By Chris Yerga, MacTutor Contributing Editor

Anguish and Fear

Welcome to the first installment of the Graphics Lab. This is where we really see what the graphics capability of the Macintosh is like. This month's column will discuss desk accessories and the techniques necessary to implement them using MDS, and in particular, the marvelous BitNapper DA, which will become very important to us next month. I have always had problems understanding what desk accessories really are and why mine never worked. Consequently, when I realized that I needed to write a DA to simplify the development of a game, I was wracked with apprehension. So my special thanks go to BMUG's Dave Burnard, who taught me how to write desk accessories without even realizing it. Thanks Dave.

Cutting Up

First, lets discuss what the desk accessory will do. The BitNapper DA's, function is to allow the user to "cut" rectangular reigons from the screen image. The DA will then create a bitMap out of the data, format it as an MDS source file, and write it out to disk. This allows us to cut graphics from MacPaint or any other application that supports desk accessories, and use them in our own MDS programs. More details on this technique will be presented next month when we use our BitNapper DA with another graphics program to create animated effects.

Since we want access to graphics anywhere on the screen, it is undesirable to have our desk accessory based in a window which will cover up some area of the screen. As a result, we will make our DA menu based. When the desk accessory is opened, it will install it's own menu in the menu bar, and it will remove the menu when it's closed.

The essence of desk accessories

Now lets take a look at the desk accessory itself. From a low-level veiwpoint, a desk accessory is a device driver. That is, desk accessories and device drivers are structured similarly. The structure that they share is somewhat different from that of a standard Macintosh application, and consequently, the programming approach is a bit different. To understand why this is, lets look at figure #1.

Figure #1 shows the structure of a DA header. The first word, drvrFlags, specifies what types of calls are supported by the desk accessory, whether it needs to be called periodically, etc. Our DA will set this to indicate that Control calls are supported, and that the accessory should be locked in memory after it's loaded. The following word is drvrDelay, which determines how often, in ticks, the desk accessory needs to be called. Since we don't need to update an on-screen clock or perform any similar task, we don't require periodic calls and will set this field to NUL.

The next word, drvvrEMask, is the event mask for our DA. We will set ours to NUL, because our DA doesn't respond to event manager events. Rather, our DA will respond to desk manager events that are sent when a menu item is selected. The ID of the menu belonging to our DA is stored in the next field, drvrMenu.

The following 5 words are offsets to the Open, Prime, Control, Status, and Close calls relative to the beginning of the desk accessory. The Open routine is called when the DA is first opened, and is responsible for defining and installing the menu, and other initialization tasks. The Prime routine is called when the accessory needs a periodic event, our Prime routine simply returns. The Control routine is the heart of the DA, and is responsible for handling events. Our DA has no Status routine, since it is not appropriate. Finally, the Close routine removes the DA's menu and frees up any storage allocated by the DA.

Following the offsets is an optional name for the desk accessory. This is not where the name that appears in the menu bar is stored; rather, this is available for internal use by the DA. For example, a DA could look here to find the title for it's window, etc. We don't use this name. The remaining data is the actual code for the DA's routines.

But wait, there's more...

There is another data structure that we must concern ourselves with. This is the Device Control Entry. The DCE is a 40 byte relocatable block that is allocated on the system heap when a desk accessory is opened. As illustrated in figure #2, the DCE contains various information about the DA, and copies of some of the data in the DA header. Although it is primarily intended for internal use by the device manager and the desk manager, there are a couple of fields relevant to our discussion.

The DCE contains a field which the DA may use to store a handle to some private storage which it allocates. This field, dCtlStorage, will be where we store the menuHandle for the DA's menu.

Another important field is dCtlWindow, in which the DA may store the windowPtr of it's main window. Its purpose is analogous to our use of dCtlStorage for DA's which are window based. For such DA's it is important to set the windowKind field of the window record to the DA's driver reference number, which is located in dCtlRefNum. This marks the window as belonging to a DA, and insures that Desk Manager and Event Manager routines work properly.

The tables are turned...

We have dealt with register-based calling conventions in the past. This is where arguments are passed in a data structure pointed to by an address register rather than on the stack. But this time we are on the receiving end. Instead of us having to set up the proper fields of a parameter block, we are passed parameter blocks to use or ignore as we wish. When a DA routine is called, A0 contains a pointer to the IOParamBlock and A1 contains a pointer to the DA's DCE. When a DA routine is finished, it must send an error code back in D0. If D0 is cleared, then no error has occurred.

For openers

The first thing the Open routine does is save the registers on the stack. Next, it copies the DCE pointer from A1 into a less volatile register. Then it makes sure this is the first call to the Open routine by testing the dCtlStorage field of the DCE. If there isn't a menuHandle stored here (it's NIL) then a menu is created and the menuHandle is stored, otherwise it just returns.

The Close routine does the opposite. It removes the menu from the menu bar, releases the memory occupied by it, and clears the dCtlStorage field.

The Prime and Status routines don't exist, so the offsets in the DA header point to a routine called Null which simply clears D0 to signify that no error has occurred and returns.

On with the show

The Control routine is the functional element of the DA. When it is called, it checks the csCode field of the IOParamBlock to see if an event of interest has occurred. There are 9 possible messages passed in csCode; they are listed on page 14 of the Desk Manager Programmer's Guide in Inside Macintosh. However, our DA only acknowledges 1 of these messages.

This is accMenu, which has a decimal value of 67. When an accMenu message is passed to a DA, the csParam field of the IOParamBlock contains the MenuID of the menu and csParam+2 contains the item number. SInce we only have one menu, we don't need to check the MenuID. Rather, we check the item number to determine which command was selected.

One of the menu items is Word Constraint, which is toggled on and off by repeated selctions. What this does is force the rectangular regions to have widths which occur on word boundaries; this is a convenient format for certain graphic applications. When this item is selected, the DA calls _GetItmMark to determine if the item is checked. It toggles the appearance of the item with _CheckItem and returns.

The main menu item is Steal Bits. When this is called, the cursor is hidden and is replaced by a small rectangle which inverts whatever it is currently over. The user positions this at the upper left corner of the region he wants to steal. Then the user drags to the lower right of the region. The routine inverts the rectangular region selected until the mouse button is released.

When the button is released, the DA calculates the relevant information needed to create a BitMap data structure containing the selected bits. When this is done, a nonrelocatable block of proper size is allocated on the application heap and the screen data is copied via _CopyBits. The user is then prompted for a filename via SFPutFile and so on. I won't go into detail about this portion of the DA, as it is very similar to my icon converter in Vol. 2 No. 1. of MacTutor. That issue also contains additional information about the structure of BitMaps, if the above seems unclear.

Get it where it counts

Before we can use the DA, we must install it into the System file. A DA is a resource of type DRVR. At the beginning of the source file we use the Resource directive of MDS to assemble the code into a DRVR resource. After linking, the DA can be installed into System via the font/DA mover by holding down the option key and clicking on the open button. This allows us to open the output file which contains our DA resource. Other more tedious options include using the resource editor, resource mover, etc. During development of a DA, I usually just link the .REL file of the DA into the resource fork of a shell application that does nothing else but support DA's. This saves me from the tedious work of installing the DA after every assembly.

I hope that I have shed some light onto desk accessories. If you are interested in this particular DA or graphic techniques in general, more specific information will be coming next month in our special animation issue. Enjoy!

;
;      BitNapper
;    by Chris Yerga
;

RESOURCE 'DRVR' 27 'BitNapper'

INCLUDE MacTraps.D
.TRAP _MakeFile  $A008

MACRO CenterString,MidPt,Y =
 
 LEA  '{String}',A3;get stringPtr
 MOVE.L #{MidPt},D4
 MOVE #{Y},D5
 BSR  CenterText
 |
 
MACRO ErrCheck =
 
 TST.L  D0;error code?
 BNE  IOErr ;yes...show a dialog
 |
 
;  Program constants ----
Chicago EQU 0
Geneva  EQU 3
accMenu EQU 67 ;event code for a Menu event
csCode  EQU 26 ;cntrl code offset in ParamBlock
screenBitsEQU  $FFFFFF86  ;[BitMap]
dCtlStorage EQU  $14  ;driver's private storage [handle]
dCtlRefNumEQU  $18 ;refNum of this driver [word]
dCtlWindowEQU  $1E  ;driver's window (if any) [pointer]
JIODone EQU $8FC  ;IODone entry location [pointer]

Start:
 DC.W $4400 ;ctl-enable & lock it
 DC.W 0 ;doesn't need time
 DC.W $0000 ;no events
MenuID: DC.W-12548 ;menu

 DC.W Open-Start ; open routine
 DC.W Null-Start ; prime - unused
 DC.W Control-Start; control
 DC.W Null-Start ; status - unused
 DC.W Close-Start; close
.ALIGN  2
Open:
 MOVEM.L A0-A6/D0-D7,-(SP)  ;Save the registers
 MOVE.L A1,A4    ;get a copy of the DCE in A4

 ;Check if we already have a menu.
 ;If one exists, its handle would be stored in dCtlStorage
 ;Otherwise,  dCtlStorage would be NIL
 
 TST.L  DCtlStorage(A4)   
 BNE  Restore    ;we have one...skip this code

 ;OK. We need to create our menu:

 CLR.L  -(SP)    ;room for menu handle
 LEA  MenuID,A0
 MOVE (A0),-(SP) ;menu ID
 PEA  'BitNapper';menu title
 _NewMenu
 MOVE.L (SP),dCtlStorage(A4);save handle,  on stack
 PEA  'Steal Bits;Word Constraint;About BitNapper;-;Quit'
 _AppendMenu
 MOVE.L dCtlStorage(A4),-(SP) ;push handle
 CLR  -(SP) ;put at the end of menu bar
 _InsertMenu
 MOVE.L dCtlStorage(A4),-(SP) ;menu handle
 MOVE #4,-(SP)   ;item #3
 _DisableItem    ;disable it
 _DrawMenuBar    ;draw the new menuBar
 
Restore:
 MOVEM.L (SP)+,A0-A6/D0-D7; restore regs
Null:
 MOVE #0,D0 ;return noErr
 RTS    ;and return...

Close:
 MOVEM.L A0-A6/D0-D7,-(SP);save registers
 MOVE.L A1,A4    ;copy DCE to A4
 
 LEA  MenuID,A0  ;Get the Menu ID
 MOVE (A0),-(SP) ;remove menu from list
 _DeleteMenu;MenuHandle stored in dCtlStorage
 MOVE.L DCtlStorage(A4),-(SP) 
 _DisposMenu;free up its memory
 _DrawMenuBar    ;draw the menubar 
 CLR.L  DCtlStorage(A4) ;remove MenuHandle
 
 MOVEM.L (SP)+,A0-A6/D0-D7;restore regs
 MOVE #0,D0 ;return noErr
 RTS    ;and return...

Control:
 MOVEM.L A0-A6/D0-D7,-(SP);save registers
 MOVE.L A1,A4    ;copy DCE pointer to A4
 MOVE csCode(A0),D0; get the control opCode
 CMP  #accMenu,D0; is it a menu event?
 BEQ  DoCtlEvent ; yes, do it...

CtlDone:
 MOVEM.L (SP)+,A0-A6/D0-D7;restore the registers
 MOVE #0,D0 ; return no error
 MOVE.L JIODone,-(SP); jump to IODone
 RTS

DoCtlEvent:
 CMP  #1,30(A0)  ;is it Steal Bits?
 BEQ  GetBits
 CMP  #5,30(A0)  ;is it quit?
 BEQ  ItsQuit
 CMP  #2,30(A0)  ;is it constrain?
 BEQ  Constrain
 CMP  #3,30(A0)  ;is it About?
 BEQ  About
 BRA  CtlDone
 
About:
 CLR.L  -(SP)    ;room for WindowPtr
 CLR.L  -(SP)    ;allocate storage in heap
 PEA  WindowRect ;bounds
 PEA  'Title?'   ;title..unused
 MOVE #$0101,-(SP) ;visible
 MOVE #1,-(SP)   ;dialog-style window
 MOVE.L #-1,-(SP);put it in front
 CLR  -(SP) ;noGoAway
 CLR.L  -(SP)    ;refcon
 _NewWindow
 MOVE.L (SP)+,A2 ;save windowPtr
 PEA  thePort    ;VAR thePort
 _GetPort ;save current grafport
 MOVE.L A2,-(SP) ;make help window current port
 _SetPort

 MOVE #Chicago,-(SP) ;set font
 _TextFont
 MOVE #12,-(SP)  ;12 point
 _TextSize
 Center the BitNapper,178,20
 MOVE #Geneva,-(SP)
 _TextFont
 MOVE #9,-(SP)
 _TextSize
 Center ©1986 by Chris Yerga,178,30
 MOVE #12,-(SP)
 _TextSize
 Center The BitNapper is a tool which simplifies,178,50
 Center the use of BitMapped graphics with the MDS system.,178,62
 Center It allows the user to cut bitmaps directly off,178,74
 Center the screen from any application that supports,178,86
 Center desk accessories.,178,98
 Center To learn about graphic techniques and all other,178,115
 Center aspects of Mac programming read MacTutor magazine.,178,127
 MOVE #1,-(SP)
 _TextFace
 Center call (714) 630-3730  to subscribe,178,150
@1 CLR  -(SP)
 _Button
 MOVE (SP)+,D0
 BEQ  @1
 MOVE.L thePort,-(SP);restore the old grafport
 _SetPort
 MOVE.L A2,-(SP) ;lose the window and free
 _DisposWindow   ;up it's memory
 CLR  -(SP) ;unHiLight the menu
 _HiliteMenu
 BRA  CtlDone
 
CenterText:
 CLR  -(SP) ;room for INTEGER
 MOVE.L A3,-(SP) ;push stringPtr
 _StringWidth
 CLR.L  D3
 MOVE (SP)+,D3 ;get string width
 DIVU #2,D3
 SUB  D3,D4 ;subtract width/2 from center
 MOVE D4,-(SP) ;push x
 MOVE D5,-(SP) ;push y
 _MoveTo
 MOVE.L A3,-(SP)
 _DrawString
 RTS
 
 
Constrain:
 MOVE.L dCtlStorage(A4),-(SP) ;menuHandle
 MOVE #2,-(SP)   ;item #2
 PEA  CheckMark  ;VAR CheckMark
 _GetItmMark
 CLR  D0;set marked to FALSE
 LEA  CheckMark,A1
 TST  (A1);is it marked?
 BNE  @1;Yes..lets unmark it
 MOVE #$0101,D0  ;set marked to TRUE
@1 MOVE.L dCtlStorage(A4),-(SP)  ;menuHandle
 MOVE #2,-(SP)   ;item #2
 MOVE D0,-(SP)   ;marked: BOOLEAN
 _CheckItem
 CLR  -(SP) ;unHiLight the menu
 _HiliteMenu
 BRA  CtlDone
 
Sync:
 SUBQ   #4,SP  ;Room for result
 _TickCount
@1 SUBQ #4,SP  ;Get it again
 _TickCount
 MOVE.L (SP)+,D0 ;Get tickCount in D0
 CMP.L  (SP),D0  ;Has it changed?
 BEQ    @1;No, loop
 ADDQ   #4,SP  ;else pop old tickCount
 RTS    ;and return
 
GetBits:
 PEA  thePort    ;save the GrafPort
 _GetPort
 MOVE.L dCtlStorage(A4),-(SP) ;menuHandle
 MOVE #2,-(SP)   ;item #2
 PEA  CheckMark  ;VAR CheckMark
 _GetItmMark;see if it's marked
 MOVE #$FFFF,D4  ;assume no constraint
 LEA  CheckMark,A1
 TST  (A1);is it marked?
 BEQ  @0;no...no constraint
 MOVE #$FFF0,D4  ;yes...word constraint
@0 _HideCursor   ;hide the cursor
@1 PEA  StartPoint ;VAR MousePoint
 _GetMouse;get the mouse location
 PEA  StartPoint
 _LocalToGlobal  ;convert to global coordinates
 LEA  StartPoint,A3
 AND  D4,2(A3) ;constrain the horiz coord
 MOVE.L (A3),4(A3) ;TopLeft of rect
 ADD  #4,4(A3) ;add 4 to bottom
 ADD  #16,6(A3)  ;add 16 to right
 MOVE.L A3,-(SP)
 _InverRect ;invert the rect
 BSR  Sync;wait for a couple VBL's
 BSR  Sync
 MOVE.L A3,-(SP) ;invert it again
 _InverRect
 CLR  -(SP) ;BOOLEAN
 _Button;see if Button is pressed
 MOVE (SP)+,D0 ;get result
 BNE  @2;button was pressed
 BRA  @1;not pressed...continue
 
@2 PEA  StartPoint ;draw the rect
 _InverRect

@3 PEA  NewPoint ;VAR NewPoint
 _GetMouse;get the mouse location
 PEA  NewPoint
 _LocalToGlobal  ;convert to global coordinates
 LEA  NewPoint,A3;get ptr to NewPoint
 AND  D4,2(A3) ;constrain the horiz
 MOVE.L (A3),D0  ;get newpoint
 LEA  EndPoint,A3
 CMP.L  (A3),D0  ;has it changed?
 BEQ  @4;no...check for Button up
 BSR  Sync
 PEA  StartPoint ;yes...erase old rect
 _InverRect
 MOVE.L 4(A3),(A3) ;make Point the new EndPoint
 PEA  StartPoint
 _InverRect ;and invert the new rect
@4 CLR  -(SP)
 _Button;Button up?
 MOVE (SP)+,D0
 BNE  @3;no...keep going
 
 PEA  StartPoint
 _InverRect ;erase the rect
 CLR  -(SP) ;room for BOOLEAN
 PEA  StartPoint
 _EmptyRect ;is the rectangle empty?
 MOVE (SP)+,D0 ;get result
 BNE  StealExit  ;Yes...get lost
 
 LEA  StartPoint,A1;get pointer
 LEA  NewPoint,A0;get pointer
 MOVE.L (A1),(A0);copy TopLeft
 MOVE.L 4(A1),4(A0);copy BottomRight
 MOVE.L (A0),-(SP) ;SrcPoint
 PEA  4(A0) ;VAR DestPoint
 _SubPt ;subtract SrcPt from DestPt
 ;and store result in DestPt
 LEA  NewPoint,A0;get pointer
 CLR.L  (A0);set topleft = 0,0
 MOVE 6(A0),D0 ;get Right in D0
 ADD  #$F,D0
 LSR  #3,D0 ;divide by 8 to get rowBytes
 AND  #$FFFE,D0
 MULU 4(A0),D0 ;multiply by the height
 ADD  #20,D0;make room for header
 LEA  BitMapLen,A0
 MOVE.L D0,(A0)  ;save the length
 _NewPtr;get a nonrelocatable block
 ErrCheck
 
 LEA  BitMapPtr,A1
 MOVE.L A0,(A1)  ;save pointer
 MOVE.L A0,A4    ;copy to A6
 LEA  NewPoint,A0;get pointer
 MOVE 6(A0),D0 ;get Right in D0
 ADD  #$F,D0
 LSR  #3,D0 ;divide by 8 to get rowBytes
 AND  #$FFFE,D0
 CLR.L  (A4)+    ;clear space for BasAddr ptr
 MOVE D0,(A4)+ ;store rowBytes
 CLR.L  (A4)+    ;topLeft of Bounds
 MOVE.L 4(A0),(A4)+;bottomRight...
 MOVE.L (A1),A1  ;get pointer to storage again
 MOVE.L A4,(A1)  ;store basAddr
 
 MOVE.L (A5),A0  ;get globalPtr
 PEA  ScreenBits(A0) ;srcBits
 MOVE.L A1,-(SP) ;destBits
 PEA  StartPoint ;srcRect
 PEA  NewPoint ;destRect
 CLR  -(SP) ;mode = srcCopy
 CLR.L  -(SP)    ;no maskRgn
 _CopyBits;copy the data from the screen
 ;to our BitMap
 
PutFile:
 _ShowCursor
 MOVE #100,-(SP) ;x coordinate of dialog
 MOVE #80,-(SP)  ;y coordinate
 PEA  'Save BitMap as:' ;prompt
 PEA  'Untitled.BMAP';default name
 CLR.L  -(SP)    ;standard dialog
 PEA  SFReply    ;reply record
 MOVE #1,-(SP)   ;routine selector
 _Pack3
 LEA  SFReply,A0
 TST.B  (A0);were we successful?
 BEQ  PurgeBitMap;no...
 
 LEA  IOParam,A2 ;ptr to ParamBlock
 CLR.L  12(A2)   ;no completion
 LEA  FileName,A0
 MOVE.L A0,18(A2);filename ptr
 MOVE VRef,22(A2);VrefNum
 CLR.B  26(A2)   ;vers #
 MOVE.L A2,A0
 _MakeFile;create the file
 ErrCheck ;are we ok?
 
 MOVE.B #2,27(A2);write-only access
 LEA  APBuffer,A0
 MOVE.L A0,28(A2);access path buffer
 MOVE.L A2,A0
 _Open  ;open the file
 ErrCheck ;ok?
 
 MOVE.L BitMapLen,D4 ;get length
 LSR.L  #3,D4    ;divide by 8
 MOVE.L BitMapPtr,A3 ;get ptr to data
DoALine:
 LEA  LineBuffer,A1
 MOVE #7,D3 ;8 bytes per line
 MOVE.L #'DC.B',(A1)+;store the line header
 MOVE.B #' ',(A1)+
@1 MOVE.B (A3)+,D0 ;get the next byte of data
 BSR  HexToAscii ;convert it
 MOVE.B #'$',(A1)+ ;store it as $xx
 MOVE D1,(A1)+
 MOVE.B #',',(A1)+
 DBRA D3,@1 ;have we done 7 bytes?
 SUBA #1,A1 ;yes...finish the line
 MOVE.L #$200D2020,(A1)+
 
 LEA  LineBuffer,A0;and write it to disk
 MOVE.L A0,32(A2);ptr to our line of text
 MOVE.L #38,36(A2) ;write 38 bytes
 CLR  44(A2);standard positioning
 CLR.L  46(A2)
 MOVE.L A2,A0
 _Write ;write it
 ErrCheck
 DBRA D4,DoALine ;are we done?
 ;yes...finish it off
 CLR  28(A2)
 MOVE.L A2,A0
 _GetFileInfo
 ErrCheck
 
 MOVE.L #'TEXT',32(A2)  ;set the filetype
 MOVE.L #'EDIT',36(A2)    ;and the creator
 MOVE.L A2,A0
 _SetFileInfo
 ErrCheck
 MOVE.L A2,A0    ;close the file
 _Close
 ErrCheck
 MOVE.L A2,A0    ;flush out any buffers
 _FlushVol
 ErrCheck
 
PurgeBitMap:
 LEA  BitMapPtr,A0 ;get ptr
 MOVE.L (A0),A0
 _DisposPtr ;release the block
StealExit:
 MOVE.L thePort,-(SP);restore the grafPort
 _SetPort
 _ShowCursor
 CLR  -(SP) ;unHiLight the menu
 _HiliteMenu
 BRA  CtlDone
 
ItsQuit:
 LEA  MenuID,A1
 MOVE (A1),-(SP) ;remove the menu from the list
 _DeleteMenu
 move.l DCtlStorage(A4),-(SP) ;push the handle
 _DisposMenu;free up the memory
 _DrawMenuBar
 clr.l  DCtlStorage(A4) ;no longer have a window.
 MOVEM.L (SP)+,A0-A6/D0-D7;restore regs
 MOVEQ  #0,D0
 RTS

;  HexToAscii routine -> converts a hex byte to an ASCII word
;
;on entry:
;D0 = Hex byte to be converted
;
;on return:
;D1 = ASCII word result
;
;uses D0,D1,D4,A0

HexToAscii:
 MOVE.B D0,D2    ;save copy of byte
 LSR  #4,D0 ;Get the high nibble
 ANDI #$0F,D0    ;mask out all extraneous bits
 LEA  ByteTable,A0 ;Get base address of table
 MOVE.B (A0,D0),D1 ;Move 1st ascii byte into D1
 ASL  #8,D1 ;move  byte to the proper position
 ANDI #$0F,D2    ;get the low nibble
 MOVE.B (A0,D2),D0 ;Get 2nd ascii byte
 OR.W D0,D1 ;store 2nd byte in word
 RTS
 
ByteTable:
 DC.B '0123456789ABCDEF'

IOErr:  
 MOVE D0,D6 ;get a copy of the error code
 CLR.L  -(SP)    ;room for WindowPtr
 CLR.L  -(SP)    ;allocate storage in heap
 PEA  ErrorRect  ;bounds
 PEA  'Title?'   ;title..unused
 MOVE #$0101,-(SP) ;visible
 MOVE #1,-(SP)   ;dialog-style window
 MOVE.L #-1,-(SP);put it in front
 CLR  -(SP) ;noGoAway
 CLR.L  -(SP)    ;refcon
 _NewWindow
 MOVE.L (SP)+,A2 ;save windowPtr
 PEA  thePort    ;VAR thePort
 _GetPort ;save current grafport
 MOVE.L A2,-(SP) ;make help window current port
 _SetPort

 MOVE #Chicago,-(SP) ;set font
 _TextFont
 MOVE #12,-(SP)  ;12 point
 _TextSize
 Center That operation was interrupted by an,158,30
 Center I/O error.  Make sure that your disk is,158,43
 Center not write-protected.,158,56
 MOVE.L #158,D4  ;midPoint
 MOVE #75,D5;Y coordinate
 LEA  ErrString,A0 ;stringPtr
 MOVE D6,D0 ;get the error code in D0
 EXT.L  D0;extend to 32 bit precision
 MOVE #0,-(SP)   ;routine selector for numtostring
 _Pack7
 MOVE.L A0,A3
 BSR  CenterText ;display the error code
@1 CLR  -(SP)    ;wait for a button press
 _Button
 MOVE (SP)+,D0
 BEQ  @1
 MOVE.L thePort,-(SP);restore the old grafport
 _SetPort
 MOVE.L A2,-(SP) ;lose the window and free
 _DisposWindow   ;up it's memory
 BRA  PurgeBitMap;clean up and exit

 
CheckMark DC.W 0 ;determine if item is checked
StartPointDC.L 0 ;topLeft of rectangle
EndPointDC.L0  ;bottomRight
NewPointDC.L0,0  ;temp storage of points & rects
BitMapPtr DC.L 0 ;pointer to bitMap mem block
BitMapLen DC.L 0 ;length of bitMap mem block
thePort DC.L0  ;temp storage for grafPtr

WindowRectDC.W 60,78,220,434
ErrorRect DC.W 100,98,185,414

IOParam DCB.W  40,0;IO ParamBlock

SFReply DC.W0  ;Standard file reply record
 DC.L '????'
VRef  DC.W0
Vers  DC.W0
FileNameDCB.B  64,0

APBufferDCB.B  522,0 ;access path buffer
LineBufferDCB.B  44,0;buffer for TEXT line 
ErrString DCB.B  8,0 ;storage for string  of errorcode

 END
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Macs Fan Control 1.5.14 - Monitor and co...
Macs Fan Control allows you to monitor and control almost any aspect of your computer's fans, with support for controlling fan speed, temperature sensors pane, menu-bar icon, and autostart with... Read more
VueScan 9.7.96 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
FileMaker Pro 19.6.1 - Quickly build cus...
FileMaker Pro is the tool you use to create a custom app. You also use FileMaker Pro to access your app on a computer. Start by importing data from a spreadsheet or using a built-in Starter app to... Read more
Duet 3.1.0.0 - Use your iPad as an exter...
Duet is the first app that allows you to use your iDevice as an extra display for your Mac using the Lightning or 30-pin cable. Note: This app requires a iOS companion app. Release notes were... Read more
Firefox 107.0.1 - Fast, safe Web browser...
Firefox 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 and casual... Read more
War Thunder 2.21.1.91 - Multiplayer war...
In War Thunder, aircraft, attack helicopters, ground forces and naval ships collaborate in realistic competitive battles. You can choose from over 1,500 vehicles and an extensive variety of combat... Read more
Numbers 12.2.1 - Apple's spreadshee...
With Apple Numbers, sophisticated spreadsheets are just the start. The whole sheet is your canvas. Just add dramatic interactive charts, tables, and images that paint a revealing picture of your data... Read more
DEVONthink Pro 3.8.7 - Knowledge base, i...
DEVONthink is DEVONtechnologies' document and information management solution. It supports a large variety of file formats and stores them in a database enhanced by artificial intelligence (AI). Many... Read more
Drive Genius 6.2.3 - $79.00
Drive Genius features a comprehensive Malware Scan. Automate your malware protection. Protect your investment from any threat. The Malware Scan is part of the automated DrivePulse utility. DrivePulse... Read more
VLC Media Player 3.0.18 - Popular multim...
VLC Media Player is a highly portable multimedia player for various audio and video formats (MPEG-1, MPEG-2, MPEG-4, DivX, MP3, OGG, ...) as well as DVDs, VCDs, and various streaming protocols. It... Read more

Latest Forum Discussions

See All

‘Genshin Impact’ Version 3.3 Pre-Install...
Following the reveal of the release date and more for Genshin Impact (Free) version 3.3 ‘All Senses Clear, All Existence Void’, HoYoverse showcased the Genius Invokation TCG that arrives this week in the update. | Read more »
TouchArcade Game of the Week: ‘Sling Min...
The world of PC games has always blown my mind because there’s just SO MUCH stuff out there that it’s not uncommon at all for there to be a game that’s well-liked and well-reviewed, and seemingly quite popular with a solid fanbase, and have it be... | Read more »
SwitchArcade Round-Up: Reviews Featuring...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for December 2nd, 2022. So, today turned out a little quieter than the usual Friday. It was so quiet, in fact, that I decided to pen a few reviews. The Knight Witch, Railbound, and Donut... | Read more »
Blue Archive reveals its latest event st...
Nexon has announced the new update for Blue Archive, under the name of An Unconcealed Heart. Featuring a battle between two academies, the story will follow a group struggling to gain recognition, and will bring three new students to recruit. [... | Read more »
Dead Cells+ Is Out Now on Apple Arcade a...
Following the major update for Dead Cells on iOS and Android a few days ago, Playdigious has brought Dead Cells+ () to Apple Arcade. As an App Store Great, Dead Cells+ includes all prior paid DLC and content updates. It also has exclusive mobile... | Read more »
SwitchArcade Round-Up: ‘Romancing SaGa’,...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for December 1st, 2022. Wow, December. We’re already at the last month of the year? Phew. I have a lot of work to finish in the next few weeks. As for today, we’ve got a little news, a... | Read more »
‘Railbound’ Update Now Available Adding...
One of our favorite puzzlers released this year is Railbound from Afterburn Games, which hit in early September and earned our Game of the Week recognition for being an absolutely ace logic puzzler. The goal is to place rail pieces down in order to... | Read more »
The Seven Deadly Sins: Grand Cross celeb...
Netmarble Corporation has pulled out all the stops to celebrate the 3 and a half year anniversary of The Seven Deadly Sins: Grand Cross. The Grand Cross 3.5th Year Anniversary the Ultimate One, a rather wordy title, brings with it a brand new... | Read more »
‘Skullgirls Mobile’ Major Update 5.2 Out...
Developer Hidden Variable pushed out a major update for Skullgirls Mobile (Free) a few hours ago. The version 5.2 update brings in Black Dahlia (before the console and PC game), Retakes, XP Treats, free gifts, and more. Since launch, Skullgirls... | Read more »
Out Now: ‘Disgaea 4’, ‘Romancing SaGa: M...
Each and every day new mobile games are hitting the App Store, and so each week we put together a big old list of all the best new releases of the past seven days. Back in the day the App Store would showcase the same games for a week, and then... | Read more »

Price Scanner via MacPrices.net

Holiday Sale: Apple AirPods Pro for only $199...
Amazon has new 2022 AirPods Pro in stock and on sale for $199.99 shipped as part of their Holiday sale. Their price is $50 off Apple’s MSRP, equaling their Black Friday price, and it’s the lowest... Read more
New Holiday Sale: Apple retailers are offerin...
Several Apple retailers lowered prices on 10.9″ iPad Airs overnight to lows of $100 off MSRP starting at $499. Their prices are the lowest available for iPad Airs anywhere this Holiday season right... Read more
New Holiday sale at Amazon: Take $50 off Appl...
Amazon has Apple’s new 10th-generation iPads in stock and on sale, for the first time, for $50 off MSRP starting at only $399. Their discount applies to all models and all colors. With the discount,... Read more
Holiday Sale: Get an 8.3″ Apple iPad mini for...
Sams Club has 10.9″ 64GB iPad minis on Holiday sale for $80-$100 off MSRP through December 7, 2022. With their discount, prices start at $399 — the cheapest price for a new iPad mini from any of the... Read more
Sams Club Holiday December Event sale: Apple...
Apple AirPods Max headphones are on sale at Sams Club for $110 off MSRP ($439) as part of their December Event sale, ending on December 7, 2022, valid for all colors. Sale price for online orders... Read more
Apple’s 10.2″ 64GB 9th-generation iPads are o...
Sams Club has 9th-generation 64GB iPads on Holiday sale for $60 off MSRP through December 7, 2022. With their discount, prices start at $259 — the cheapest price for a new iPad from any of the Apple... Read more
11″ 128GB WiFi M2 iPad Pro on sale for $749,...
B&H Photo has the new 11″ 128GB WiFi M2-powered iPad Pro (in Space Gray or Silver) on Holiday sale for $749 including free 1-2 day shipping to most US addresses. Their price is $50 off MSRP and... Read more
Find the best Holiday sale price on an iPad u...
We’ve updated our iPad Price Trackers with the latest information on the new 10th-generation iPads, M2-powered iPad Pros, M1 iPad Airs, iPad minis, and 9th generation iPads from Apple’s authorized... Read more
Apple retailers are offering $100-$150 Holida...
Apple retailers have posted their most-recent Holiday sale prices on 13″ MacBook Airs. Take up to $150 off MSRP on M2-powered Airs with these sales with prices starting at only $1099. Free shipping... Read more
Holiday Sale: Apple’s 14″ MacBook Pros with M...
B&H Photo is offering $200-$300 discounts on Apple’s 14″ MacBook Pros with M1 Pro CPUs as part of their Holiday 2022 sale, with prices starting at $1799. Free 1-2 day shipping is available to... Read more

Jobs Board

Support Technician II - *Apple* Support - O...
…problems and acting as a liaison between customers and resolving groups. As an Apple Technical Specialist, you will be supporting many of our popular Apple Read more
*Apple* Electronic Repair Technician - PlanI...
…a highly motivated individual to join our Production Department as an Apple Electronic Repair Technician. The computer repair technician will diagnose, assemble, Read more
Lead Developer - *Apple* tvOS - Rumble (Uni...
…earnings, and positive sentiment About the role: We are looking for a Lead Apple tvOS Developer to join our application engineering team to expand our video centric Read more
Tier 1 Endpoint Engineer - *Apple* - Red Ri...
…Desk on site, at our Client's location, with a focus on support to Apple products. This position will handle technical support requests directly from customers and Read more
Product Manager II - *Apple* - DISH (United...
…you will be doing We seek an ambitious, data-driven thinker to assist the Apple Product Development team as our new Retail Wireless division continues to grow and Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.