TweetFollow Us on Twitter

Multi-Window DA
Volume Number:3
Issue Number:6
Column Tag:Forth Forum

Multi-Window Stick Around DA

By Jörge Langowski, MacTutor Editorial Board, Grenoble, France

“Multi-window, multi-menu, permanent desk accessory”

As mentioned in a previous column, we are going to learn some more about creating desk accessories in Forth (Mach2) this time. The simple desk accessory from V3#2 was useful to show the principle of implementing such a thing in Forth, but in real life DA writing there are a number of things that one might have to add to that example. Therefore, I am going to write this time about the implementation of a desk accessory that supports multiple windows and menus; also it will automatically reinstall itself after it has been closed involuntarily (e.g. when calling an application from the Finder).

This article is by no means comprehensive; there have been several articles in our journal on desk accessories implemented in assembler or C (V2#3,4,6), and I’m making use of some of the ideas described therein. So go back to those old issues (if you don’t have them, order them through us) for any further references.

Making a DA permanent

As you’ll certainly have noticed, there are several occasions when desk accessories will be closed automatically by the system. Whenever you start up a new application from the Finder, or quit an application to go back to the Finder, the application heap will be reinitialized and all desk accessories closed. The two other occasions on which your DA will be closed are copying a file under the Finder and ejecting the startup disk.

Sometimes one would like to have a desk accessory (like a clock) stay active permanently, unless one closes it voluntarily. I’ll tell you further down below how that can be accomplished; however notice that in such a case one would always have to check whether the close box has really been clicked when the DA’s Close routine is called. This is not so easy... since the system handles part of the mouse-down events for a DA automatically before we could even intercept them. Particularly, a mouse-down in the drag region will let the window be dragged around and a click in the Close box will generally cause the Close routine to be called.

So our first problem would be to distinguish a voluntary close from an involuntary one. One easy way to do this is to create the window without a close box and let the user click a button inside it, or select some menu option, to notify the DA that we don’t want it any more. The control - or menu - handling routine would then by itself call CloseDeskAcc but set a flag that indicates to the close routine that we really want to close the window. The close routine then had a way to distinguish voluntary from involuntary close through the flag.

Fig. 1 DA sticks around between applications

There is, however, a more elegant way to go. As was already pointed out by David Dunham in V2#6, there is a system global (undocumented in IM) called CloseOrnHook ($A88). If this location contains a non-NIL pointer, the system assumes that it is the address of a routine that should be called when the close box of a desk accessory window is clicked (instead of calling its Close routine). So all we have to do is to install a pointer to our own Close routine here every time the desk accessory window is activated and remove it when it is deactivated (so that other DAs may be closed correctly). The custom Close routine would then set the flag mentioned above and call CloseDeskAcc with the driver ID number of our DA.

Hooking into SystemTask

Now that our Close routine knows whether we really wanted to call it or not, how do we go about making the desk accessory permanent? After all, the heap will be cleaned on starting up an application, and we won’t be able to keep our DA in the application heap even if we wanted. Even if we put it into the system heap instead, it will stay there - eating up memory - but receive no more system calls, so it will be unusable.

Here a clever trick comes in that I again got to know on one of our developer’s club meetings (idea by L. de Bersuder): Since every application will call SystemTask pretty soon after having been started up, just install a patch (located in the system heap) to the SystemTask routine that reopens the desk accessory, then resets the old SystemTask trap address and thereafter removes itself from the system heap. This method, of course, will work for one such permanent DA at a time only, but provides a good starting point from which on one can do further experimentation.

It is time, now, to look at the program. Listing 1 just contains general Forth definitions that are necessary for the program (and haven’t changed much compared to the V3#2 column). Listing 3 is the RMaker input for generating the desk accessory, and Listing 2 is our example.

The code for the SystemTask intercept routine is at the beginning of the listing. The actual intercept routine does nothing but check whether there is a dialog present in front (in case our DA will set up a dialog as well, this can lead to conflicts), and if that is not the case, restores the old trap address for SystemTask, then opens the desk accessory, using a built-in name string. If you change the name of the accessory, you would have to change this string accordingly. The intercept routine is called by a glue routine which saves the registers and sets up a local A6 stack for the Forth code (our usual method); then the Forth code is entered. The Forth word write-out writes the code for the patch routine to a PROC resource (marked locked, in system heap, and with an ID of -16000, so that it belongs to the desk accessory).

Installation of the SystemTask patch is performed in the Close routine. Here the flag closeflag is checked; if it is =1, it is assumed that the close was involuntary and the patch is installed by calling install.intercept. The latter routine gets the PROC resource containing the patch code (it will be in the system heap), stores the old trap address of SystemTask in trapaddr in the patch routine and sets the new trap address to the beginning of the intercept routine. The appropriate offsets *trapaddr and *inter have been calculated beforehand at compilation time. This, by the way, is one simple method to reference Forth code from outside routines.

After the installation of the intercept routine, the system is set up to reinstall the desk accessory the next time SystemTask gets a call.

Multiple windows and the custom Close routine

To close the desk accessory for good, we make use of the CloseOrnHook system global. Both windows belonging to the DA carry the driver reference number in their WindowKind fields; so the system would normally handle close box clicks for them. To avoid this, we have to put a non-zero value into CloseOrnHook. Since a) we might want to install a different behavior for the close boxes depending which window is closed, and b) we need a custom close routine anyway to disable the automatic reinstallation, we install a pointer to the realclose routine in CloseOrnHook every time one of the DA windows is activated and reset that location to zero when it is deactivated.

The routine pointed to by CloseOrnHook receives two parameters: the dCtlEntry pointer in A1 and the window pointer in A4. The window pointer is used to determine the action (one window will beep, the other one will close the DA for good when it is closed), and dCtlEntry is needed to determine the DA’s driver reference number so that we can close it.

Multiple Menus

This is only a little more involving than having just a single menu. In order to have the system pass the menu parameters to the DA for one out of several menus, we have to install the DA’s driver reference number in the global MBarEnable ($A20, word). Then, when a window is activated, we get the handle of the current menu bar and save it away, and set up the menu bar using our own list of menus. In our case, I added two menus which will show up when the main window is clicked. When that window is deactivated, we reset the old menu bar from the stored value and set MBarEnable to zero. As long as MBarEnable is <>0, the DA will receive the menu ID in csParam and the menu item number in csParam + 2. This is taken care of in the Ctl routine. Our menu handler again simply displays the names of the items.

Other remarks

The zoom box and grow box are handled differently in this DA than they were in my first example (I briefly mentioned this in the March column). When a mouse down event is detected, we set the windowKind field of the window record to 8 (application-created window) before calling FindWindow again, this time receiving the correct part code from FindWindow. The windowKind is reset to the old value thereafter, so that close box and drag region clicks will again be handled correctly by the system.

Knowing the zoom box or grow box part code, we can then go and take the appropriate actions.

Just for fun, I added a button in the main (resizeable) window which will show or hide the other window. That window displays the time.

Happy threading and see you next month.

{1}
Listing 1: Some general definitions for  Mach2 DA
( © J. Langowski/MacTutor March 1987  )

HEX
44525652 CONSTANT “drvr
50524F43 CONSTANT “proc
434E544C CONSTANT “cntl

( *** System globals *** )
HEX
8FC CONSTANT JioDone 

DECIMAL
( windowrecord fields, starting with grafport )
16 CONSTANT portRect ( Grafport rectangle )

( fields of WindowPeek )
108 CONSTANT windowKind 
110 CONSTANT wVisible
111 CONSTANT wHiLited
112 CONSTANT goAwayFlag
113 CONSTANT spareFlag
130 CONSTANT dataHandle
140 CONSTANT controlList
152 CONSTANT refCon

( fields of device control entry )
 4 CONSTANT dCtlFlags
 6 CONSTANT dCtlQHdr
16 CONSTANT dCtlPosition
20 CONSTANT dCtlStorage
24 CONSTANT dCtlRefNum
26 CONSTANT dCtlCurTicks
30 CONSTANT dCtlWindow
34 CONSTANT dCtlDelay
36 CONSTANT dCtlEMask
38 CONSTANT dCtlMenu

( csCodes for Ctl calls )
-1 CONSTANT goodBye
64 CONSTANT accEvent
65 CONSTANT accRun
66 CONSTANT accCursor
67 CONSTANT accMenu
68 CONSTANT accUndo
70 CONSTANT accCut
71 CONSTANT accCopy
72 CONSTANT accPaste
73 CONSTANT accClear

( *** standard parameter block data structure *** )
0   CONSTANT  qLink ( pointer to next queue entry [long word] )
4   CONSTANT  qType( queue type [word] )
6   CONSTANT  ioTrap ( routine trap [word] )
8   CONSTANT  ioCmdAddr ( routine address [long word] )
12  CONSTANT  ioCompletion( completion routine [long word] )
16  CONSTANT  ioResult    ( result code returned here [word] )
18  CONSTANT  ioNamePtr ( pointer to file name [long word] )
22  CONSTANT  ioVRefNum ( volume reference number )
24  CONSTANT  ioRefNum
26  CONSTANT  csCode ( type of control call )
28  CONSTANT  csParam( control call parameters )

( *** eventrecord data structure *** )
0  CONSTANT what
2  CONSTANT message
6  CONSTANT when
10 CONSTANT where
14 CONSTANT modifiers

( *** event codes *** )
0  CONSTANT null-evt
1  CONSTANT mousedn-evt
2  CONSTANT mouseup-evt
3  CONSTANT keydn-evt
4  CONSTANT keyup-evt
5  CONSTANT autokey-evt
6  CONSTANT update-evt
7  CONSTANT disk-evt
8  CONSTANT activate-evt
10 CONSTANT network-evt
11 CONSTANT driver-evt

0 CONSTANT inDesk
1 CONSTANT inMenuBar
2 CONSTANT inSysWindow
3 CONSTANT inContent
4 CONSTANT inDrag
5 CONSTANT inGrow
6 CONSTANT inGoAway
7 CONSTANT inZoomIn
8 CONSTANT inZoomOut

CODE shl ( data #bits )
 MOVE.L (A6)+,D0
 MOVE.L (A6),D1
 LSL.L  D0,D1
 MOVE.L D1,(A6)
 RTS
END-CODEMACH

CODE shr ( data #bits )
 MOVE.L (A6)+,D0
 MOVE.L (A6),D1
 LSR.L  D0,D1
 MOVE.L D1,(A6)
 RTS
END-CODEMACH

CODE on
 MOVEQ.L#1,D0
 MOVE.L (A6)+,A0
 MOVE.L D0,(A0)
 RTS
END-CODE MACH

CODE off
 MOVE.L (A6)+,A0
 CLR.L  (A0)
 RTS
END-CODE MACH

CODE unpack
 MOVE.L (A6),D0
 CLR.L   D1
 MOVE.W D0,D1
 CLR.W  D0
 SWAP.W D0
 MOVE.L D0,(A6)
 MOVE.L D1,-(A6)
 RTS
END-CODE MACH
{2}
Listing 2: The desk accessory
( A multi-window, multi-menu, permanent desk accessory  )
( J. Langowski March 87 )

only forth also assembler also mac

INCLUDE” general defs”

BINARY
0000110111101010 CONSTANT DAEmask

HEX
A20 CONSTANT MBarEnable
A88 CONSTANT CloseOrnHook
1B4 CONSTANT SystemTask

( *** close intercept routine *** )

HEADER inter.start
HEADER DAName
 DC.B   10,0,’Mach 2 DA’
HEADER trapaddr 
 DC.L 0
header inter.stack 40 allot
CODE setup.inter.stack
    LEA -8(PC),A6   ( local stack grows downward from here )
    RTS
END-CODE

: inter 
 call frontwindow windowkind + @
 2 <> IF
 [‘] trapaddr @ SystemTask call SetTrapAddress
 [‘] DAName call OpenDeskAcc drop
 THEN
;
 
CODE intercept
 MOVEM.LA0-A4/A6/D0-D7,-(A7)
 JSR  setup.inter.stack
 JSR  inter
 MOVEM.L (A7)+,A0-A4/A6/D0-D7
 MOVE.L trapaddr,-(A7)
 RTS
END-CODE
HEADER inter.end
( for exportation )
‘ trapaddr ‘ inter.start - CONSTANT *trapaddr
‘ intercept  ‘ inter.start - CONSTANT *inter
DECIMAL


( *** start of desk accessory main code *** )

header testDA ( marker for writing to DRVR resource )
 header drvrFlags  2 allot
 header drvrdelay  2 allot
 header drvrEMask  2 allot 
 header drvrMenu   2 allot
 header drvrOpen   2 allot
 header drvrPrime  2 allot
 header drvrCtl  2 allot
 header drvrStatus 2 allot 
 header drvrClose  2 allot
 header drvrname  32 allot

( *** main desk accessory routines *** )
( globals )
header temprect 8 allot
header SizeRect 8 allot   ( grow size limits )
header NewSize 4 allot  ( for SizeWindow )
header penLoc 4 allot( pen location )
header tempString 256 allot ( for numeric conversion etc. )
header ButtonHdl 4 allot  ( for storage of control handle )
header closeflag 4 allot  ( for storage of close status )
header CurMenuList 4 allot  ( menu list temporary storage )
header CloseOrn 4 allot ( CloseOrnHook temporary storage )
header window2 4 allot  ( second DA window )
header showflag 4 allot   ( state of 2nd window, 1: visible, 0: not)
header myRes0 4 allot( local res ID=0 offset )
header temp 4 allot( general purpose )

: @mouse { | mousept -- point } 
 ^ mousept call getMouse mousept ;

: cl  ( WPtr -- ) portrect + call eraserect ;
 
: tp  call drawstring ;

: crd [‘] penLoc call getpen
 10 ( horizontal boundary )
 [‘] penLoc w@ 12 +
 call moveto
;

: realclose { | dCtlEntry }
 MOVE.L A1,-(A6)
 -> dCtlEntry
 MOVE.L A4,-(A6)
 CASE 
 dCtlEntry dCtlWindow + @ OF
 [‘] closeflag off
 dCtlEntry dCtlRefNum + w@ call CloseDeskAcc
 ENDOF

 [‘] window2 @ OF 5 call sysbeep ENDOF
 ENDCASE
;

( *** event-handling routines *** )
: >oldMBar
 [‘] CurMenuList @ call SetMenuBar
 call DrawMenuBar
 0 MBarEnable w!
;

: activate-handler { DAWind event-rec | menuID -- }
 [‘] myRes0 @ -> menuID
 CloseOrnHook @ [‘] CloseOrn !
 [‘] realclose CloseOrnHook !
 event-rec modifiers + w@ 1 and
 IF ( window activated )
 call frontwindow CASE DAWind OF
 menuID MBarEnable w!
 call GetMenuBar [‘] CurMenuList !
 call ClearMenuBar 
 menuID call getRMenu 0 call InsertMenu
 menuID 1+  call getRMenu 0 call InsertMenu
 call drawMenuBar
 ENDOF
 ENDCASE
 ELSE >oldMBar ( window deactivated )
 [‘] CloseOrn @ CloseOrnHook !
 THEN
;

 
: update-handler { DAWind event-rec | -- }
 [‘] penLoc call GetPen
 DAWind CALL BeginUpdate
    DAWind cl
    DAWind CALL DrawGrowIcon
    DAWind CALL DrawControls
 DAWind CALL EndUpdate
 [‘] penLoc 2+ w@ [‘] penLoc w@ 
 call moveto ( restore pen position )
;

: invalSize { gPort | b r -- }
 gPort 4 + w@ -> b
 gPort 6 + w@ -> r
 [‘] temprect r 16 - 0 r b call setrect
 [‘] temprect call invalrect
 [‘] temprect 0 b 16 - r b call setrect
 [‘] temprect call invalrect
;

: mousedn-handler 
 { DCtlEntry DAWind event-rec | 
 whereM DAPort whichCtl whichWind 
 mouseloc menuID menuRes wKind -- }
 [‘] myRes0 @ -> menuID
 DAWind portrect + -> DAPort
 event-rec where + @ dup -> whereM -> mouseloc
 ^ mouseloc call GlobalToLocal
 whereM ^ whichWind call FindWindow drop ( result code )

whichWind CASE
 DAWind OF
 DAWind windowkind + dup w@ -> wKind 
 8 swap w! ( set to application-created window )
 whereM ^ whichWind call FindWindow 
 CASE  
 inGrow OF
 DAPort invalSize
 DAWind whereM [‘] SizeRect call GrowWindow 
 DAWind swap unpack swap -1 call sizewindow
 DAPort invalSize
 ENDOF

 inZoomIn OF 
    DAWind whereM 7 call TrackBox
 IF DAPort invalSize
    DAWind 7 0 call ZoomWindow THEN
 ENDOF

 inZoomOut OF 
    DAWind whereM 8 call TrackBox
 IF DAPort invalSize
    DAWind 8 0 call ZoomWindow THEN
 ENDOF

 mouseloc DAWind ^ whichCtl call FindControl
 IF
 whichCtl mouseLoc 0 call TrackControl
 IF [‘] window2 @ 
    1 [‘] showflag @ - [‘] showflag !
    [‘] showflag @
    IF call showwindow ELSE call hidewindow THEN  
 THEN
 ELSE
 “ Mouse down” tp crd
 THEN
 
 ENDCASE
 wKind DAWind windowkind + w! ( reset to DA window )

 ENDOF

 [‘] window2 @ OF 5 call sysbeep ENDOF

ENDCASE
;

: update-cursor  { DAWind | -- }
 @mouse DAWind portrect + call PtInRect
 IF call InitCursor THEN
;

: getDrvrID { dCtlEntry | -- num }
 dCtlEntry dCtlRefNum + w@ l_ext
 1+ negate
;

: ownResID ( resID drvrID )
 5 shl + -16384 +
;

: install.intercept { dCtlEntry | procHdl -- }
 “proc [‘] myRes0 @ call GetResource -> procHdl
 SystemTask call GetTrapAddr
 procHdl @ *trapaddr + !
 procHdl @ *inter + SystemTask call SetTrapAddr 
;

: Open { DCtlEntry ParamBlockRec | 
 DAWind DAWind2 Res0 oldPort -- }
 ^ oldPort call GetPort
 dCtlEntry dCtlWindow + @
 0= IF ( not open already )
 [‘] closeflag on
 [‘] showflag off
 0 dCtlEntry getDrvrID ownResID -> Res0
 Res0 [‘] myRes0 !
 “proc Res0 call GetResource
 call ReleaseResource ( remove from sysheap )
 Res0 dCtlEntry DCtlMenu + w! 
 ( menu ref has to be updated )
 Res0 0 0 call getNewWindow -> DAWind
 DAWind  dCtlEntry dCtlWindow + !  
 ( store window pointer )
 DAWind  dCtlEntry dCtlRefNum + w@  
 swap windowKind + w!
 Res0 1+ 0 0 call getNewWindow -> DAWind2
 DAWind2 [‘] window2 !
 DAWind2  dCtlEntry dCtlRefNum + w@  
 swap windowKind + w!
 DAWind  call setport
 [‘] sizerect 50 50 500 320 call setrect
 10 40   call moveto
 Res0 DAWind call GetNewControl [‘] ButtonHdl ! 
 oldPort call setPort
 THEN
;

: Close { DCtlEntry ParamBlockRec | -- }
 dCtlEntry dCtlWindow + 
 dup @ call DisposWindow  0 swap ! 
 ( so that Open will work again )
 [‘] window2 @ call disposWindow
 [‘] closeflag @ IF DCtlEntry install.intercept THEN
 >oldMBar
;

: Ctl { DCtlEntry ParamBlockRec | 
 DAWind oldPort event-rec menuID menuRes -- }
 
 ^ oldPort call GetPort
 dCtlEntry dCtlWindow + @ dup -> DAWind call setport
 4 call textfont 9 call textsize
 DCtlEntry DCtlMenu + w@ l_ext -> menuID
 ParamBlockRec csCode + w@ l_ext 
 CASE
 goodByeOF 10 call sysbeep
 dCtlEntry ParamBlockRec Close
 [‘] closeflag off ENDOF
 accEvent OF 
 ParamBlockRec csParam + @ -> event-rec
 event-rec what + w@ 
 CASE
 mousedn-evtOF   
 DCtlEntry DAWind event-rec
  mousedn-handler  ENDOF

 keydn-evtOF DAWind cl
 DAWind call DrawGrowIcon
 DAWind call DrawControls
 10 40 call moveto 
 “ Key down.” tp crd
 ENDOF

 autokey-evtOF ENDOF

 update-evt OF
  DAWind event-rec update-handler   ENDOF
 
 disk-evt OFENDOF

 activate-evt  OF
  DAWind event-rec activate-handler  ENDOF

 network-evtOF ENDOF
 driver-evt OF ENDOF

 ENDCASE

 ENDOF

 accRun OF  [‘] window2 @ dup call setport cl
 4 call textfont 9 call textsize
 20 10 call moveto
 [‘] temp call readdatetime drop
 [‘] temp @ -1 [‘] tempstring 
 call IUTimeString
 [‘] tempstring tp  
 ENDOF
 accCursorOFDAWind update-cursor ENDOF
 accMenuOF
 ParamBlockRec csParam + @ 
 unpack -> menuRes
 l_ext  
 CASE menuID OF
 menuRes
 CASE   1 OF “ Item1-1!” tp crd ENDOF
 2 OF “ Item1-2!” tp crd ENDOF
 3 OF “ Item1-3!” tp crd ENDOF
 4 OF “ Item1-4!” tp crd ENDOF
 6 OF “ Item1-6!” tp crd ENDOF
 ENDCASE ENDOF
  menuID 1+ OF
 menuRes
 CASE   1 OF “ Item2-1!” tp crd ENDOF
 2 OF “ Item2-2!” tp crd ENDOF
 3 OF “ Item2-3!” tp crd ENDOF
 4 OF “ Item2-4!” tp crd ENDOF
 6 OF “ Item2-6!” tp crd ENDOF
 ENDCASE 
 ENDOF
 ENDCASE 
 0 call HiLiteMenu
 ENDOF 
 accUndoOFENDOF
 accCut OFENDOF
 accCopyOFENDOF
 accPaste OFENDOF
 accClear OFENDOF
 ENDCASE
 oldport call setPort
;


: DrStatus { DCtlEntry ParamBlockRec | -- }
 ;

: Prime { DCtlEntry ParamBlockRec | -- }
 ;

( *** glue routines *** )
header local.stack 1000 allot

CODE setup.local.stack
    LEA -8(PC),A6   ( local stack grows downward from here )
    RTS
END-CODE

CODE DAOpen 
 MOVEM.L A0-A1,-(A7)
 setup.local.stack
 MOVE.L  A1,-(A6) 
 MOVE.L  A0,-(A6)
 Open
 CLR.L  D0
 MOVEM.L (A7)+,A0-A1 
RTS END-CODE

CODE DAClose  
 MOVEM.L A0-A1,-(A7)
 setup.local.stack
 MOVE.L  A1,-(A6) 
 MOVE.L  A0,-(A6)
 Close
 CLR.L   D0
 MOVEM.L (A7)+,A0-A1 
RTS END-CODE

CODE DACtl 
 MOVEM.L A0-A1,-(A7)
 setup.local.stack
 MOVE.L  A1,-(A6) 
 MOVE.L  A0,-(A6)
 Ctl
 CLR.L   D0
 MOVEM.L (A7)+,A0-A1
 MOVE.L  JioDone,-(A7) 
RTS END-CODE

CODE DAStatus 
 MOVEM.L A0-A1,-(A7)
 setup.local.stack
 MOVE.L  A1,-(A6) 
 MOVE.L  A0,-(A6)
 DrStatus
 CLR.L   D0
 MOVEM.L (A7)+,A0-A1 
RTS END-CODE

CODE DAPrime 
 MOVEM.L A0-A1,-(A7)
 setup.local.stack
 MOVE.L  A1,-(A6) 
 MOVE.L  A0,-(A6)
 Prime
 CLR.L   D0
 MOVEM.L (A7)+,A0-A1 
RTS END-CODE

header endDA 
( *** code written to DRVR resource ends here *** )

( *** initialization routines *** ) 

: setFlags  [‘] drvrFlags w! ;
: setDelay  [‘] drvrDelay w! ;
: setEMask  [‘] drvrEMask w! ;
: setMenuID [‘] drvrMenu  w! ;

: setOpen [‘] drvrOpen  w! ;
: setPrime[‘] drvrPrime w! ;
: setCtl[‘] drvrCtlw! ;
: setStatus [‘] drvrStatusw! ;
: setClose[‘] drvrClose w! ;

: setName { addr len | target -- }
 [‘] drvrName -> target
 len target c!
 addr target 1+
 len 31 > if  31 else len then
 cmove
;
 

( write resource to file ) 
: $create-res ( str-addr - errcode )
 call CreateResFile
 call ResError L_ext
;

: $open-res { addr | refNum - refNum or errcode }
 addr call OpenResFile -> refNum
 call ResError L_ext
 ?dup IF ELSE refNum THEN
; 

: close-res ( refNum - errcode )
 call CloseResFile
 call ResError L_ext
;

: make-res { addr len rtype ID name | -- }
 addr len call PtrToHand 
 abort” Could not create resource handle”
 rtype ID name call AddResource
;

: write-out { filename | refnum -- } 
 filename $create-res 
 abort” That resource file already exists”
 filename $open-res
 dup 0< abort” Open resource file failed”
 -> refnum
 refnum call UseResFile
 [‘] testDA [‘] endDA over - 
 “drvr 12 “ Mach 2 DA” make-res
 [‘] inter.start [‘] inter.end over - 
 “proc -16000 “ Mach 2 DA” make-res
 “proc -16000 call GetResource
 dup 80 call SetResAttrs  ( 64: sysheap + 16: locked )
 call ChangedResource
 refnum close-res abort” Could not close resource file”
;

: init-DA
( initialize offsets )
 [‘] DAOpen [‘] testDA -  setOpen 
 [‘] DAPrime   [‘] testDA -  setPrime
 [‘] DACtl     [‘] testDA -  setCtl 
 [‘] DAStatus  [‘] testDA -  setStatus
 [‘] DAClose   [‘] testDA -  setClose
( initialize driver name )
 “ Mach 2 DA” count setname
( initialize driver flags, 
 NeedLock, NeedTime, NeedGoodBye, CtlEnable )
 [ hex ] 7400 setFlags [ decimal ]
( initialize delay time )
 60 setDelay
( initialize event mask, events recommended in IM )
 DAEMask setEMask 
( initialize menu ID, local ID=0 for DRVR ID=12 )
 -16000 setMenuID ( careful! this field will NOT be changed
 by the DA Mover when ID is changed )
;
 
: make-DA
 init-DA
 “ Mach2 DA.rsrc” $delete drop
 “ Mach2 DA.rsrc” write-out
;
{3}
Listing 3: RMaker input file
*   Resources for MACH 2 desk accessory 

Mach2 DA
DFILDMOV

INCLUDE Mach2 DA.rsrc

Type MENU
     ,-16000
First
Item 1-1
Item 1-2
Item 1-3
Item 1-4
(-
Item 1-6

Type MENU
     ,-15999
Second
Item 2-1
Item 2-2
Item 2-3
Item 2-4
(-
Item 2-6


Type WIND
     ,-16000
Mach2 Desk Accessory
240 10 320 250
Visible GoAway
8
0

Type WIND
     ,-15999
Time
140 400 165 500
Invisible GoAway
16
0

Type CNTL
     ,-16000
Time
10 10 27 50
Visible
0
0
0 0 0
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

OmniOutliner Pro 4.2 - Pro version of th...
OmniOutliner Pro is a flexible program for creating, collecting, and organizing information. Give your creativity a kick start by using an application that's actually designed to help you think. It's... Read more
VLC Media Player 2.2.1 - Popular multime...
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
Nisus Writer Pro 2.1.1 - Multilingual wo...
Nisus Writer Pro is a powerful multilingual word processor, similar to its entry level products, but brings new features such as table of contents, indexing, bookmarks, widow and orphan control,... Read more
Tinderbox 6.2.0 - Store and organize you...
Tinderbox is a personal content management assistant. It stores your notes, ideas, and plans. It can help you organize and understand them. And Tinderbox helps you share ideas through Web journals... Read more
OmniOutliner 4.2 - Organize your ideas,...
OmniOutliner is a flexible program for creating, collecting, and organizing information. Give your creativity a kick start by using an application that's actually designed to help you think. It's... Read more
Things 2.5.4 - Elegant personal task man...
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
NeoOffice 2014.10 - Mac-tailored, OpenOf...
NeoOffice is a complete office suite for OS X. With NeoOffice, users can view, edit, and save OpenOffice documents, PDF files, and most Microsoft Word, Excel, and PowerPoint documents. NeoOffice 3.x... Read more
iPhoto Library Manager 4.2 - Manage mult...
iPhoto Library Manager allows you to organize your photos among multiple iPhoto libraries, rather than having to store all of your photos in one giant library. You can browse the photos in all your... Read more
Web Snapper 3.3.8 - Capture entire Web p...
Web Snapper lets you capture Web pages exactly as they appear in your browser. You can send them to a file as images or vector-based, multi-page PDFs. It captures the whole Web page - eliminating the... Read more
TeamViewer 10.0.41404 - Establish remote...
TeamViewer gives you remote control of any computer or Mac over the Internet within seconds, or can be used for online meetings. Find out why more than 200 million users trust TeamViewer! Free for... Read more

Chainsaw Warrior: Lords of the Night has...
It's time to put the Darkness back in its place now that Chainsaw Warrior: Lords of the Night has officially made it to iOS. | Read more »
A World of Ice and Fire Lets You Stalk 2...
George R. R. Martin’s A World of Ice and Fire, by Random House, is a mobile guide to the epic series. The new update gives you the Journeys map feture that will let you track the movements of 25 different characters. But don't worry, you can protect... | Read more »
Gameloft Announces Battle Odyssey, a New...
Battle Odyssey, Gameloft's newest puzzle RPG, is coming to the App Store next week. Set in the world of Pondera, you will need to control the power of the elements to defend the world from evil. You'll be able to entlist over 500 allies to aid you... | Read more »
Fusion - HDR Camera (Photography)
Fusion - HDR Camera 1.0.0 Device: iOS Universal Category: Photography Price: $1.99, Version: 1.0.0 (iTunes) Description: Fusion creates HDR (high dynamic range) photos by capturing different exposures and then combining them into one... | Read more »
Sago Mini Toolbox (Education)
Sago Mini Toolbox 1.1 Device: iOS Universal Category: Education Price: $2.99, Version: 1.1 (iTunes) Description: Come build with the Sago Mini friends! Use a wrench, try a saw, or hammer some nails. From sewing hand puppets to... | Read more »
You Should Probably Grab Hitman GO While...
Hitman GO is a surprisingly cool (yet also incredibly drastic) departure from the Hitman series. It's well worth playing for any puzzle game fans out there, and at the moment you can get your hands - or garrotte if you will - on it for a mere $0.99... | Read more »
IFTTT is Bringing Do Button and Do Note...
IFTTT has announced Do Button and Do Note for the Apple Watch. Do Button lets you make your own personalized button that can connect to things like your Google Drive, control the temperature in your home with Nest Thermostat, or turn the lights on... | Read more »
How Many Days, Hours, and Minutes Are Le...
Countdown, by Yves Tscherry, is now available on the App Store. The app keeps track of countdowns to your favorite things such as someones birthday or days till the New Year. You can display the time in seconds, minutes, hours, days, weeks, months,... | Read more »
The All-New Misfit 2.0 App is Available...
Misfit has just given their app a complete overhaul. Misfit 2.0 now has a brand new interface with a sleek design and is easier to navigate. You'll be able to sync your Misfit device and look up health and fitness information faster than ever before... | Read more »
Halo: Spartan Strike (Games)
Halo: Spartan Strike 1.0 Device: iOS Universal Category: Games Price: $5.99, Version: 1.0 (iTunes) Description: Delve into 30 challenging missions through cities and jungles using a devastating arsenal of weapons, abilities and... | Read more »

Price Scanner via MacPrices.net

TigerText Introduces First Secure Enterprise...
TigerText, a provider of secure, real-time messaging for the enterprise, has announced the launch of TigerText for the Apple Watch. TigerText for the Apple Watch enables users to securely send and... Read more
The Conservation Fund Partners with Apple To...
The Conservation Fund has announced that it will partner with Apple to help protect working forests in the United States. The Apple initiative will conserve more than 36,000 acres of working... Read more
Clearance 13-inch 2.6GHz Retina MacBook Pro a...
B&H Photo has clearance 2014 13″ 2.6GHz/128GB Retina MacBook Pros now available for $1099, or $200 off original MSRP. Shipping is free, and B&H charges NY sales tax only. Read more
Apple refurbished 2014 13-inch Retina MacBook...
The Apple Store has Apple Certified Refurbished 2014 13″ Retina MacBook Pros available for up to $400 off original MSRP, starting at $979. An Apple one-year warranty is included with each model, and... Read more
iMacs on sale for up to $205 off MSRP, NY tax...
B&H Photo has 21″ and 27″ iMacs on sale for up to $205 off MSRP including free shipping plus NY sales tax only: - 21″ 1.4GHz iMac: $1019 $80 off - 21″ 2.7GHz iMac: $1189 $110 off - 21″ 2.9GHz... Read more
Sale! 16GB iPhone 5S for $1 with service
Best Buy is offering 16GB iPhone 5Ss for $1.00 with 2-year activation at a participating cellular provider. Choose free home shipping and activation, or buy online and activate during in-store pickup... Read more
Apple refurbished 2014 MacBook Airs available...
The Apple Store has Apple Certified Refurbished 2014 MacBook Airs available starting at $679. An Apple one-year warranty is included with each MacBook, and shipping is free. These are currently the... Read more
27-inch 3.5GHz 5K iMac on sale for $2349, sav...
 Adorama has the 27″ 3.5GHz 5K iMac in stock today and on sale for $2349 including free shipping plus NY & NJ sales tax only. Their price is $150 off MSRP. For a limited time, Adorama will... Read more
Save up to $380 on an iMac with Apple refurbi...
The Apple Store has Apple Certified Refurbished iMacs available for up to $380 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 27″ 3.5GHz 5K iMac – $2119 $... Read more
iFixIt Teardown Awards 12-IInch Retina MacBoo...
iFixIt has posted its illustrated teardown of the new 12-inch MacBook Retina. They note that this new MacBook is less than half the thickness of the last Apple notebook called just “MacBook” back in... Read more

Jobs Board

*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the 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* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* TV Live Streaming Frameworks Test En...
**Job Summary** Work and contribute towards the engineering of Apple 's state-of-the-art products involving video, audio, and graphics in Interactive Media Group (IMG) at Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.